Implemented the ability to change the mouse cursor.

The way to do this is by calling inputManager.setMouseCursor("path/to/cursor/in/assets/cursor.ani").

NOTE: Supported formats are  "RIFF-wrapped" .ani, .cur and .ico. Those can be found everywhere on the web and are the majority of icons found. If the file format is unrecognized the loader will crash with an appropriate message (hopefully).

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9484 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
dan..om 13 years ago
parent 4e419a854c
commit 5ac9953f62
  1. 672
      engine/src/core-plugins/com/jme3/cursors/plugins/CursorLoader.java
  2. 151
      engine/src/core-plugins/com/jme3/cursors/plugins/JmeCursor.java
  3. 3
      engine/src/core/com/jme3/asset/Desktop.cfg
  4. 147
      engine/src/core/com/jme3/input/InputManager.java
  5. 20
      engine/src/core/com/jme3/input/MouseInput.java
  6. 6
      engine/src/core/com/jme3/input/dummy/DummyMouseInput.java
  7. 10
      engine/src/desktop/com/jme3/input/awt/AwtMouseInput.java
  8. 21
      engine/src/lwjgl/com/jme3/input/lwjgl/LwjglMouseInput.java
  9. 4
      engine/src/niftygui/com/jme3/niftygui/InputSystemJme.java

@ -0,0 +1,672 @@
package com.jme3.cursors.plugins;
import com.jme3.asset.AssetInfo;
import com.jme3.asset.AssetKey;
import com.jme3.asset.AssetLoader;
import com.jme3.util.BufferUtils;
import com.jme3.util.LittleEndien;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.ByteArrayInputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.IntBuffer;
import java.util.ArrayList;
import javax.imageio.ImageIO;
/**
*
* @author MadJack
* @creation Jun 5, 2012 9:45:58 AM
*/
public class CursorLoader implements AssetLoader {
private boolean isIco;
private boolean isAni;
/**
* Loads and return a cursor file of one of the following format: .ani, .cur and .ico.
* @param info The {@link AssetInfo} describing the cursor file.
* @return A JmeCursor representation of the LWJGL's Cursor.
* @throws IOException if the file is not found.
*/
public JmeCursor load(AssetInfo info) throws IOException {
isIco = ((AssetKey) info.getKey()).getExtension().equals("ico");
if (!isIco) {
isIco = ((AssetKey) info.getKey()).getExtension().equals("cur");
if (!isIco) {
isAni = ((AssetKey) info.getKey()).getExtension().equals("ani");
}
}
if (!isAni && !isIco) {
throw new IllegalArgumentException("Cursors supported are .ico, .cur or .ani");
}
InputStream in = null;
try {
in = info.openStream();
return loadCursor(in);
} finally {
if (in != null) {
in.close();
}
}
}
private JmeCursor loadCursor(InputStream inStream) throws IOException {
byte[] icoimages = new byte[0]; // new byte [0] facilitates read()
if (isAni) {
CursorImageData ciDat = new CursorImageData();
int numIcons = 0;
int jiffy = 0;
// not using those but keeping references for now.
int steps = 0;
int width = 0;
int height = 0;
int flag = 0; // we don't use that.
int[] rate = null;
int[] animSeq = null;
ArrayList<byte[]> icons;
DataInput leIn = new LittleEndien(inStream);
int riff = leIn.readInt();
if (riff == 0x46464952) { // RIFF
// read next int (file length), discarding it, we don't need that.
leIn.readInt();
int nextInt = 0;
nextInt = getNext(leIn);
if (nextInt == 0x4e4f4341) {
// We have ACON, we do nothing
// System.out.println("We have ACON. Next!");
nextInt = getNext(leIn);
while (nextInt >= 0) {
if (nextInt == 0x68696e61) {
// System.out.println("we have 'anih' header");
leIn.skipBytes(8); // internal struct length (always 36)
numIcons = leIn.readInt();
steps = leIn.readInt(); // number of blits for ani cycles
width = leIn.readInt();
height = leIn.readInt();
leIn.skipBytes(8);
jiffy = leIn.readInt();
flag = leIn.readInt();
nextInt = leIn.readInt();
} else if (nextInt == 0x65746172) { // found a 'rate' of animation
// System.out.println("we have 'rate'.");
// Fill rate here.
// Rate is synchronous with frames.
int length = leIn.readInt();
rate = new int[length / 4];
for (int i = 0; i < length / 4; i++) {
rate[i] = leIn.readInt();
}
nextInt = leIn.readInt();
} else if (nextInt == 0x20716573) { // found a 'seq ' of animation
// System.out.println("we have 'seq '.");
// Fill animation sequence here
int length = leIn.readInt();
animSeq = new int[length / 4];
for (int i = 0; i < length / 4; i++) {
animSeq[i] = leIn.readInt();
}
nextInt = leIn.readInt();
} else if (nextInt == 0x5453494c) { // Found a LIST
// System.out.println("we have 'LIST'.");
int length = leIn.readInt();
nextInt = leIn.readInt();
if (nextInt == 0x4f464e49) { // Got an INFO, skip its length
// this part consist of Author, title, etc
// int skipped = leIn.skipBytes(length - 4);
// System.out.println(" Discarding INFO (skipped = " + skipped + ")");
nextInt = leIn.readInt();
} else if (nextInt == 0x6d617266) { // found a 'fram' for animation
// System.out.println("we have 'fram'.");
if (leIn.readInt() == 0x6e6f6369) { // we have 'icon'
// We have an icon and from this point on
// the rest is only icons.
int icoLength = leIn.readInt();
ciDat.numImages = numIcons;
icons = new ArrayList<byte[]>(numIcons);
for (int i = 0; i < numIcons; i++) {
if (i > 0) {
// skip 'icon' header and length as they are
// known already and won't change.
leIn.skipBytes(8);
}
byte[] data = new byte[icoLength];
((InputStream) leIn).read(data, 0, icoLength);
icons.add(data);
}
// at this point we have the icons, rates (either
// through jiffy or rate array, the sequence (if
// applicable) and the ani header info.
// Put things together.
ciDat.assembleCursor(icons, rate, animSeq, jiffy, steps, width, height);
ciDat.completeCursor();
nextInt = leIn.readInt();
// if for some reason there's JUNK (nextInt > -1)
// bail out.
nextInt = nextInt > -1 ? -1 : nextInt;
}
}
}
}
}
return setJmeCursor(ciDat);
} else if (riff == 0x58464952) {
throw new IllegalArgumentException("Big-Endian RIFX is not supported. Sorry.");
} else {
throw new IllegalArgumentException("Unknown format.");
}
} else if (isIco) {
DataInputStream in = new DataInputStream(inStream);
int bytesToRead;
while ((bytesToRead = in.available()) != 0) {
byte[] icoimage2 = new byte[icoimages.length + bytesToRead];
System.arraycopy(icoimages, 0, icoimage2, 0, icoimages.length);
in.read(icoimage2, icoimages.length, bytesToRead);
icoimages = icoimage2;
}
}
BufferedImage bi[] = parseICOImage(icoimages);
CursorImageData cid = new CursorImageData(bi, 0, 0, 0);
cid.completeCursor();
return setJmeCursor(cid);
}
private JmeCursor setJmeCursor(CursorImageData cid) {
JmeCursor jmeCursor = new JmeCursor();
// set cursor's params.
jmeCursor.setWidth(cid.width);
jmeCursor.setHeight(cid.height);
jmeCursor.setxHotSpot(cid.xHotSpot);
jmeCursor.setyHotSpot(cid.yHotSpot);
jmeCursor.setNumImages(cid.numImages);
jmeCursor.setImagesDelay(cid.imgDelay);
jmeCursor.setImagesData(cid.data);
// System.out.println("Width = " + cid.width);
// System.out.println("Height = " + cid.height);
// System.out.println("HSx = " + cid.xHotSpot);
// System.out.println("HSy = " + cid.yHotSpot);
// System.out.println("# img = " + cid.numImages);
return jmeCursor;
}
private BufferedImage[] parseICOImage(byte[] icoimage) throws IOException {
/*
* Most of this is original code by Jeff Friesen at
* http://www.informit.com/articles/article.aspx?p=1186882&seqNum=3
*/
BufferedImage[] bi;
// Check resource type field.
int FDE_OFFSET = 6; // first directory entry offset
int DE_LENGTH = 16; // directory entry length
int BMIH_LENGTH = 40; // BITMAPINFOHEADER length
if (icoimage[2] != 1 && icoimage[2] != 2 || icoimage[3] != 0) {
throw new IllegalArgumentException("Bad data in ICO/CUR file. ImageType has to be either 1 or 2.");
}
int numImages = ubyte(icoimage[5]);
numImages <<= 8;
numImages |= icoimage[4];
bi = new BufferedImage[numImages];
int[] colorCount = new int[numImages];
for (int i = 0; i < numImages; i++) {
int width = ubyte(icoimage[FDE_OFFSET + i * DE_LENGTH]);
int height = ubyte(icoimage[FDE_OFFSET + i * DE_LENGTH + 1]);
colorCount[i] = ubyte(icoimage[FDE_OFFSET + i * DE_LENGTH + 2]);
int bytesInRes = ubyte(icoimage[FDE_OFFSET + i * DE_LENGTH + 11]);
bytesInRes <<= 8;
bytesInRes |= ubyte(icoimage[FDE_OFFSET + i * DE_LENGTH + 10]);
bytesInRes <<= 8;
bytesInRes |= ubyte(icoimage[FDE_OFFSET + i * DE_LENGTH + 9]);
bytesInRes <<= 8;
bytesInRes |= ubyte(icoimage[FDE_OFFSET + i * DE_LENGTH + 8]);
int imageOffset = ubyte(icoimage[FDE_OFFSET + i * DE_LENGTH + 15]);
imageOffset <<= 8;
imageOffset |= ubyte(icoimage[FDE_OFFSET + i * DE_LENGTH + 14]);
imageOffset <<= 8;
imageOffset |= ubyte(icoimage[FDE_OFFSET + i * DE_LENGTH + 13]);
imageOffset <<= 8;
imageOffset |= ubyte(icoimage[FDE_OFFSET + i * DE_LENGTH + 12]);
if (icoimage[imageOffset] == 40
&& icoimage[imageOffset + 1] == 0
&& icoimage[imageOffset + 2] == 0
&& icoimage[imageOffset + 3] == 0) {
// BITMAPINFOHEADER detected
int _width = ubyte(icoimage[imageOffset + 7]);
_width <<= 8;
_width |= ubyte(icoimage[imageOffset + 6]);
_width <<= 8;
_width |= ubyte(icoimage[imageOffset + 5]);
_width <<= 8;
_width |= ubyte(icoimage[imageOffset + 4]);
// If width is 0 (for 256 pixels or higher), _width contains
// actual width.
if (width == 0) {
width = _width;
}
int _height = ubyte(icoimage[imageOffset + 11]);
_height <<= 8;
_height |= ubyte(icoimage[imageOffset + 10]);
_height <<= 8;
_height |= ubyte(icoimage[imageOffset + 9]);
_height <<= 8;
_height |= ubyte(icoimage[imageOffset + 8]);
// If height is 0 (for 256 pixels or higher), _height contains
// actual height times 2.
if (height == 0) {
height = _height >> 1; // Divide by 2.
}
int planes = ubyte(icoimage[imageOffset + 13]);
planes <<= 8;
planes |= ubyte(icoimage[imageOffset + 12]);
int bitCount = ubyte(icoimage[imageOffset + 15]);
bitCount <<= 8;
bitCount |= ubyte(icoimage[imageOffset + 14]);
// If colorCount [i] is 0, the number of colors is determined
// from the planes and bitCount values. For example, the number
// of colors is 256 when planes is 1 and bitCount is 8. Leave
// colorCount [i] set to 0 when planes is 1 and bitCount is 32.
if (colorCount[i] == 0) {
if (planes == 1) {
if (bitCount == 1) {
colorCount[i] = 2;
} else if (bitCount == 4) {
colorCount[i] = 16;
} else if (bitCount == 8) {
colorCount[i] = 256;
} else if (bitCount != 32) {
colorCount[i] = (int) Math.pow(2, bitCount);
}
} else {
colorCount[i] = (int) Math.pow(2, bitCount * planes);
}
}
bi[i] = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
// Parse image to image buffer.
int colorTableOffset = imageOffset + BMIH_LENGTH;
if (colorCount[i] == 2) {
int xorImageOffset = colorTableOffset + 2 * 4;
int scanlineBytes = calcScanlineBytes(width, 1);
int andImageOffset = xorImageOffset + scanlineBytes * height;
int[] masks = {128, 64, 32, 16, 8, 4, 2, 1};
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
int index;
if ((ubyte(icoimage[xorImageOffset + row
* scanlineBytes + col / 8])
& masks[col % 8]) != 0) {
index = 1;
} else {
index = 0;
}
int rgb = 0;
rgb |= (ubyte(icoimage[colorTableOffset + index * 4
+ 2]));
rgb <<= 8;
rgb |= (ubyte(icoimage[colorTableOffset + index * 4
+ 1]));
rgb <<= 8;
rgb |= (ubyte(icoimage[colorTableOffset + index
* 4]));
if ((ubyte(icoimage[andImageOffset + row
* scanlineBytes + col / 8])
& masks[col % 8]) != 0) {
bi[i].setRGB(col, height - 1 - row, rgb);
} else {
bi[i].setRGB(col, height - 1 - row,
0xff000000 | rgb);
}
}
}
} else if (colorCount[i] == 16) {
int xorImageOffset = colorTableOffset + 16 * 4;
int scanlineBytes = calcScanlineBytes(width, 4);
int andImageOffset = xorImageOffset + scanlineBytes * height;
int[] masks = {128, 64, 32, 16, 8, 4, 2, 1};
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
int index;
if ((col & 1) == 0) // even
{
index = ubyte(icoimage[xorImageOffset + row
* scanlineBytes + col / 2]);
index >>= 4;
} else {
index = ubyte(icoimage[xorImageOffset + row
* scanlineBytes + col / 2])
& 15;
}
int rgb = 0;
rgb |= (ubyte(icoimage[colorTableOffset + index * 4
+ 2]));
rgb <<= 8;
rgb |= (ubyte(icoimage[colorTableOffset + index * 4
+ 1]));
rgb <<= 8;
rgb |= (ubyte(icoimage[colorTableOffset + index
* 4]));
if ((ubyte(icoimage[andImageOffset + row
* calcScanlineBytes(width, 1)
+ col / 8]) & masks[col % 8])
!= 0) {
bi[i].setRGB(col, height - 1 - row, rgb);
} else {
bi[i].setRGB(col, height - 1 - row,
0xff000000 | rgb);
}
}
}
} else if (colorCount[i] == 256) {
int xorImageOffset = colorTableOffset + 256 * 4;
int scanlineBytes = calcScanlineBytes(width, 8);
int andImageOffset = xorImageOffset + scanlineBytes * height;
int[] masks = {128, 64, 32, 16, 8, 4, 2, 1};
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
int index;
index = ubyte(icoimage[xorImageOffset + row
* scanlineBytes + col]);
int rgb = 0;
rgb |= (ubyte(icoimage[colorTableOffset + index * 4
+ 2]));
rgb <<= 8;
rgb |= (ubyte(icoimage[colorTableOffset + index * 4
+ 1]));
rgb <<= 8;
rgb |= (ubyte(icoimage[colorTableOffset + index * 4]));
if ((ubyte(icoimage[andImageOffset + row
* calcScanlineBytes(width, 1)
+ col / 8]) & masks[col % 8])
!= 0) {
bi[i].setRGB(col, height - 1 - row, rgb);
} else {
bi[i].setRGB(col, height - 1 - row,
0xff000000 | rgb);
}
}
}
} else if (colorCount[i] == 0) {
int scanlineBytes = calcScanlineBytes(width, 32);
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
int rgb = ubyte(icoimage[colorTableOffset + row
* scanlineBytes + col * 4 + 3]);
rgb <<= 8;
rgb |= ubyte(icoimage[colorTableOffset + row
* scanlineBytes + col * 4 + 2]);
rgb <<= 8;
rgb |= ubyte(icoimage[colorTableOffset + row
* scanlineBytes + col * 4 + 1]);
rgb <<= 8;
rgb |= ubyte(icoimage[colorTableOffset + row
* scanlineBytes + col * 4]);
bi[i].setRGB(col, height - 1 - row, rgb);
}
}
}
} else if (ubyte(icoimage[imageOffset]) == 0x89
&& icoimage[imageOffset + 1] == 0x50
&& icoimage[imageOffset + 2] == 0x4e
&& icoimage[imageOffset + 3] == 0x47
&& icoimage[imageOffset + 4] == 0x0d
&& icoimage[imageOffset + 5] == 0x0a
&& icoimage[imageOffset + 6] == 0x1a
&& icoimage[imageOffset + 7] == 0x0a) {
// PNG detected
ByteArrayInputStream bais;
bais = new ByteArrayInputStream(icoimage, imageOffset,
bytesInRes);
bi[i] = ImageIO.read(bais);
} else {
throw new IllegalArgumentException("Bad data in ICO/CUR file. BITMAPINFOHEADER or PNG "
+ "expected");
}
}
icoimage = null; // This array can now be garbage collected.
return bi;
}
private int ubyte(byte b) {
return (b < 0) ? 256 + b : b; // Convert byte to unsigned byte.
}
private int calcScanlineBytes(int width, int bitCount) {
// Calculate minimum number of double-words required to store width
// pixels where each pixel occupies bitCount bits. XOR and AND bitmaps
// are stored such that each scanline is aligned on a double-word
// boundary.
return (((width * bitCount) + 31) / 32) * 4;
}
private int getNext(DataInput in) throws IOException {
return in.readInt();
}
private class CursorImageData {
int width;
int height;
int xHotSpot;
int yHotSpot;
int numImages;
IntBuffer imgDelay;
IntBuffer data;
public CursorImageData() {
}
CursorImageData(BufferedImage[] bi, int delay, int hsX, int hsY) {
IntBuffer singleCursor = null;
ArrayList<IntBuffer> cursors = new ArrayList<IntBuffer>();
int bwidth = 0;
int bheight = 0;
// cursor type
// 1 - ICO
// 2 - CUR
// Anything else is invalid.
int curType = 0;
// make the cursor image
for (int i = 0; i < bi.length; i++) {
BufferedImage img = bi[i];
bwidth = img.getWidth();
bheight = img.getHeight();
curType = img.getType();
if (curType == 1) {
hsX = 0;
hsY = bheight - 1;
} else if (curType == 2) {
if (hsY == 0) {
// make sure we flip if 0
hsY = bheight - 1;
}
} else {
throw new IllegalArgumentException(
"An image contained is not of the right type! Only proper ICO and CUR formats are valid.");
}
// We flip our image because .ICO and .CUR will always be reversed.
AffineTransform trans = AffineTransform.getScaleInstance(1, -1);
trans.translate(0, -img.getHeight(null));
AffineTransformOp op = new AffineTransformOp(trans, AffineTransformOp.TYPE_BILINEAR);
img = op.filter(img, null);
singleCursor = BufferUtils.createIntBuffer(img.getWidth() * img.getHeight());
DataBufferInt dataIntBuf = (DataBufferInt) img.getData().getDataBuffer();
singleCursor = IntBuffer.wrap(dataIntBuf.getData());
cursors.add(singleCursor);
}
// put the image in the IntBuffer
data = BufferUtils.createIntBuffer(bwidth * bheight);
imgDelay = BufferUtils.createIntBuffer(bi.length);
for (int i = 0; i < cursors.size(); i++) {
data.put(cursors.get(i));
if (delay > 0) {
imgDelay.put(delay);
}
}
width = bwidth;
height = bheight;
xHotSpot = hsX;
yHotSpot = hsY;
numImages = cursors.size();
data.rewind();
if (imgDelay != null) {
imgDelay.rewind();
}
}
private void addFrame(byte[] imgData, int rate, int jiffy, int width, int height) throws IOException {
BufferedImage bi[] = parseICOImage(imgData);
int hotspotx = 0;
int hotspoty = 0;
int type = imgData[2] | imgData[3];
if (type == 2) {
// CUR type, hotspot might be stored.
hotspotx = imgData[10] | imgData[11];
hotspoty = imgData[12] | imgData[13];
} else if (type == 1) {
// ICO type, hotspot not stored. Leave at 0;
hotspotx = 0;
hotspoty = 0;
}
// System.out.println("Image type = " + (type == 1 ? "CUR" : "ICO"));
if (rate == 0) {
rate = jiffy;
}
CursorImageData cid = new CursorImageData(bi, rate, hotspotx, hotspoty);
if (width == 0) {
this.width = cid.width;
} else {
this.width = width;
}
if (height == 0) {
this.height = cid.height;
} else {
this.height = height;
}
if (data == null) {
data = BufferUtils.createIntBuffer(this.width * this.height * numImages);
data.put(cid.data);
} else {
data.put(cid.data);
}
if (imgDelay == null && numImages > 1) {
imgDelay = BufferUtils.createIntBuffer(numImages);
imgDelay.put(cid.imgDelay);
} else if (imgData != null) {
imgDelay.put(cid.imgDelay);
}
xHotSpot = cid.xHotSpot;
yHotSpot = cid.yHotSpot;
cid = null;
}
void assembleCursor(ArrayList<byte[]> icons, int[] rate, int[] animSeq, int jiffy, int steps, int width, int height) throws IOException {
// Jiffy multiplicator for LWJGL's delay, which is in milisecond.
final int MULT = 17;
numImages = icons.size();
int frRate = 0;
byte[] frame = new byte[0];
// if we have an animation sequence we use that
// since the sequence can be larger than the number
// of images in the ani if it reuses one or more of those
// images.
if (animSeq != null) {
for (int i = 0 ; i < animSeq.length ; i++) {
if (rate != null) {
frRate = rate[i] * MULT;
} else {
frRate = jiffy * MULT;
}
// the frame # is the one in the animation sequence
frame = icons.get(animSeq[i]);
addFrame(frame, frRate, jiffy, width, height);
// System.out.println("delay of " + frRate);
}
} else {
for (int i = 0 ; i < icons.size() ; i++) {
frame = icons.get(i);
if (rate == null) {
frRate = jiffy * MULT;
} else {
frRate = rate[i] * MULT;
}
addFrame(frame, frRate, jiffy, width, height);
// System.out.println("delay of " + frRate);
}
}
}
/**
* Called to rewind the buffers after filling them.
*/
void completeCursor() {
if (numImages == 1) {
imgDelay = null;
} else {
imgDelay.rewind();
}
data.rewind();
}
}
}

@ -0,0 +1,151 @@
package com.jme3.cursors.plugins;
import java.nio.IntBuffer;
/**
* A Jme representation of the LWJGL Cursor class.
*
* @author MadJack
* @creation Jun 6, 2012 12:12:38 PM
*/
public class JmeCursor {
private int width;
private int height;
private int xHotSpot;
private int yHotSpot;
private int numImages;
private IntBuffer imagesData;
private IntBuffer imagesDelay;
/**
* Queries the cursor's height. Note that
* the coordinate system is the same as OpenGL. 0, 0 being lower left.
* @return the height in pixel.
*/
public int getHeight() {
return height;
}
/**
* Queries the cursor's images' data.
* @return An {@link IntBuffer} containing the cursor's image(s) data in
* sequence.
*/
public IntBuffer getImagesData() {
return imagesData;
}
/**
* Queries the cursor's delay for each frame.
* @return An {@link IntBuffer} containing the cursor's delay in
* sequence. The delay is expressed in milliseconds.
*/
public IntBuffer getImagesDelay() {
return imagesDelay;
}
/**
* Queries the number of images contained in the cursor. Static cursors should
* contain only 1 image.
* @return The number of image(s) composing the cursor. 1 if the cursor is
* static.
*/
public int getNumImages() {
return numImages;
}
/**
* Queries the cursor's width. Note that
* the coordinate system is the same as OpenGL. 0, 0 being lower left.
* @return the width of the cursor in pixel.
*/
public int getWidth() {
return width;
}
/**
* Queries the cursor's X hotspot coordinate. Note that
* the coordinate system is the same as OpenGL. 0, 0 being lower left.
* @return the coordinate on the cursor's X axis where the hotspot is located.
*/
public int getXHotSpot() {
return xHotSpot;
}
/**
* Queries the cursor's Y hotspot coordinate. Note that
* the coordinate system is the same as OpenGL. 0, 0 being lower left.
* @return the coordinate on the cursor's Y axis where the hotspot is located.
*/
public int getYHotSpot() {
return yHotSpot;
}
/**
* Sets the cursor's height.
* @param height The height of the cursor in pixels. Note that all images
* in a cursor have to be the same size.
*/
public void setHeight(int height) {
this.height = height;
}
/**
* Sets the cursor's image(s) data. Each image data should be consecutively
* stored in the {@link IntBuffer} if more tha one image is contained in the
* cursor.
* @param imagesData the cursor's image(s) data. Each image data should be consecutively
* stored in the {@link IntBuffer} if more than one image is contained in the
* cursor.
*/
public void setImagesData(IntBuffer imagesData) {
this.imagesData = imagesData;
}
/**
* Sets the cursor image delay for each frame of an animated cursor. If the
* cursor has no animation and consist of only 1 image, null is expected.
* @param imagesDelay
*/
public void setImagesDelay(IntBuffer imagesDelay) {
this.imagesDelay = imagesDelay;
}
/**
* Sets the number of images in the cursor.
* @param numImages number of images in the cursor.
*/
public void setNumImages(int numImages) {
this.numImages = numImages;
}
/**
* Sets the cursor's width.
* @param width The width of the cursor in pixels. Note that all images
* in a cursor have to be the same size.
*/
public void setWidth(int width) {
this.width = width;
}
/**
* Sets the cursor's X coordinate for its hotspot.
* @param xHotSpot the cursor's X axis coordinate for its hotspot. Note that
* the coordinate system is the same as OpenGL. 0, 0 being lower left.
*/
public void setxHotSpot(int xHotSpot) {
this.xHotSpot = xHotSpot;
}
/**
* Sets the cursor's Y axis coordinate for its hotspot.
* @param yHotSpot the cursor's Y axis coordinate for its hotspot. Note that
* the coordinate system is the same as OpenGL. 0, 0 being lower left.
*/
public void setyHotSpot(int yHotSpot) {
this.yHotSpot = yHotSpot;
}
}

@ -3,6 +3,7 @@ LOCATOR / com.jme3.asset.plugins.ClasspathLocator
LOADER com.jme3.texture.plugins.AWTLoader : jpg, bmp, gif, png, jpeg LOADER com.jme3.texture.plugins.AWTLoader : jpg, bmp, gif, png, jpeg
LOADER com.jme3.audio.plugins.WAVLoader : wav LOADER com.jme3.audio.plugins.WAVLoader : wav
LOADER com.jme3.audio.plugins.OGGLoader : ogg LOADER com.jme3.audio.plugins.OGGLoader : ogg
LOADER com.jme3.cursors.plugins.CursorLoader : ani, cur, ico
LOADER com.jme3.material.plugins.J3MLoader : j3m LOADER com.jme3.material.plugins.J3MLoader : j3m
LOADER com.jme3.material.plugins.J3MLoader : j3md LOADER com.jme3.material.plugins.J3MLoader : j3md
LOADER com.jme3.font.plugins.BitmapFontLoader : fnt LOADER com.jme3.font.plugins.BitmapFontLoader : fnt
@ -19,4 +20,4 @@ LOADER com.jme3.scene.plugins.ogre.SkeletonLoader : skeletonxml, skeleton.xml
LOADER com.jme3.scene.plugins.ogre.MaterialLoader : material LOADER com.jme3.scene.plugins.ogre.MaterialLoader : material
LOADER com.jme3.scene.plugins.ogre.SceneLoader : scene LOADER com.jme3.scene.plugins.ogre.SceneLoader : scene
LOADER com.jme3.scene.plugins.blender.BlenderModelLoader : blend LOADER com.jme3.scene.plugins.blender.BlenderModelLoader : blend
LOADER com.jme3.shader.plugins.GLSLLoader : vert, frag, glsl, glsllib LOADER com.jme3.shader.plugins.GLSLLoader : vert, frag, glsl, glsllib

@ -32,6 +32,7 @@
package com.jme3.input; package com.jme3.input;
import com.jme3.app.Application; import com.jme3.app.Application;
import com.jme3.cursors.plugins.JmeCursor;
import com.jme3.input.controls.*; import com.jme3.input.controls.*;
import com.jme3.input.event.*; import com.jme3.input.event.*;
import com.jme3.math.FastMath; import com.jme3.math.FastMath;
@ -53,16 +54,16 @@ import java.util.logging.Logger;
* or with input explicitly disabled. * or with input explicitly disabled.
* <p> * <p>
* The input manager has two concepts, a {@link Trigger} and a mapping. * The input manager has two concepts, a {@link Trigger} and a mapping.
* A trigger represents a specific input trigger, such as a key button, * A trigger represents a specific input trigger, such as a key button,
* or a mouse axis. A mapping represents a link onto one or several triggers, * or a mouse axis. A mapping represents a link onto one or several triggers,
* when the appropriate trigger is activated (e.g. a key is pressed), the * when the appropriate trigger is activated (e.g. a key is pressed), the
* mapping will be invoked. Any listeners registered to receive an event * mapping will be invoked. Any listeners registered to receive an event
* from the mapping will have an event raised. * from the mapping will have an event raised.
* <p> * <p>
* There are two types of events that {@link InputListener input listeners} * There are two types of events that {@link InputListener input listeners}
* can receive, one is {@link ActionListener#onAction(java.lang.String, boolean, float) action} * can receive, one is {@link ActionListener#onAction(java.lang.String, boolean, float) action}
* events and another is {@link AnalogListener#onAnalog(java.lang.String, float, float) analog} * events and another is {@link AnalogListener#onAnalog(java.lang.String, float, float) analog}
* events. * events.
* <p> * <p>
* <code>onAction</code> events are raised when the specific input * <code>onAction</code> events are raised when the specific input
* activates or deactivates. For a digital input such as key press, the <code>onAction()</code> * activates or deactivates. For a digital input such as key press, the <code>onAction()</code>
@ -119,7 +120,7 @@ public class InputManager implements RawInputListener {
/** /**
* Initializes the InputManager. * Initializes the InputManager.
* *
* <p>This should only be called internally in {@link Application}. * <p>This should only be called internally in {@link Application}.
* *
* @param mouse * @param mouse
@ -386,6 +387,10 @@ public class InputManager implements RawInputListener {
} }
} }
public void setMouseCursor(JmeCursor jmeCursor) {
mouse.setNativeCursor(jmeCursor);
}
/** /**
* Callback from RawInputListener. Do not use. * Callback from RawInputListener. Do not use.
*/ */
@ -420,7 +425,7 @@ public class InputManager implements RawInputListener {
if (evt.isRepeating()) { if (evt.isRepeating()) {
return; // repeat events not used for bindings return; // repeat events not used for bindings
} }
int hash = KeyTrigger.keyHash(evt.getKeyCode()); int hash = KeyTrigger.keyHash(evt.getKeyCode());
invokeActions(hash, evt.isPressed()); invokeActions(hash, evt.isPressed());
invokeTimedActions(hash, evt.getTime(), evt.isPressed()); invokeTimedActions(hash, evt.getTime(), evt.isPressed());
@ -439,12 +444,12 @@ public class InputManager implements RawInputListener {
/** /**
* Set the deadzone for joystick axes. * Set the deadzone for joystick axes.
* *
* <p>{@link ActionListener#onAction(java.lang.String, boolean, float) } * <p>{@link ActionListener#onAction(java.lang.String, boolean, float) }
* events will only be raised if the joystick axis value is greater than * events will only be raised if the joystick axis value is greater than
* the <code>deadZone</code>. * the <code>deadZone</code>.
* *
* @param deadZone the deadzone for joystick axes. * @param deadZone the deadzone for joystick axes.
*/ */
public void setAxisDeadZone(float deadZone) { public void setAxisDeadZone(float deadZone) {
this.axisDeadZone = deadZone; this.axisDeadZone = deadZone;
@ -452,30 +457,30 @@ public class InputManager implements RawInputListener {
/** /**
* Returns the deadzone for joystick axes. * Returns the deadzone for joystick axes.
* *
* @return the deadzone for joystick axes. * @return the deadzone for joystick axes.
*/ */
public float getAxisDeadZone() { public float getAxisDeadZone() {
return axisDeadZone; return axisDeadZone;
} }
/** /**
* Adds a new listener to receive events on the given mappings. * Adds a new listener to receive events on the given mappings.
* *
* <p>The given InputListener will be registered to receive events * <p>The given InputListener will be registered to receive events
* on the specified mapping names. When a mapping raises an event, the * on the specified mapping names. When a mapping raises an event, the
* listener will have its appropriate method invoked, either * listener will have its appropriate method invoked, either
* {@link ActionListener#onAction(java.lang.String, boolean, float) } * {@link ActionListener#onAction(java.lang.String, boolean, float) }
* or {@link AnalogListener#onAnalog(java.lang.String, float, float) } * or {@link AnalogListener#onAnalog(java.lang.String, float, float) }
* depending on which interface the <code>listener</code> implements. * depending on which interface the <code>listener</code> implements.
* If the listener implements both interfaces, then it will receive the * If the listener implements both interfaces, then it will receive the
* appropriate event for each method. * appropriate event for each method.
* *
* @param listener The listener to register to receive input events. * @param listener The listener to register to receive input events.
* @param mappingNames The mapping names which the listener will receive * @param mappingNames The mapping names which the listener will receive
* events from. * events from.
* *
* @see InputManager#removeListener(com.jme3.input.controls.InputListener) * @see InputManager#removeListener(com.jme3.input.controls.InputListener)
*/ */
public void addListener(InputListener listener, String... mappingNames) { public void addListener(InputListener listener, String... mappingNames) {
for (String mappingName : mappingNames) { for (String mappingName : mappingNames) {
@ -492,14 +497,14 @@ public class InputManager implements RawInputListener {
/** /**
* Removes a listener from receiving events. * Removes a listener from receiving events.
* *
* <p>This will unregister the listener from any mappings that it * <p>This will unregister the listener from any mappings that it
* was previously registered with via * was previously registered with via
* {@link InputManager#addListener(com.jme3.input.controls.InputListener, java.lang.String[]) }. * {@link InputManager#addListener(com.jme3.input.controls.InputListener, java.lang.String[]) }.
* *
* @param listener The listener to unregister. * @param listener The listener to unregister.
* *
* @see InputManager#addListener(com.jme3.input.controls.InputListener, java.lang.String[]) * @see InputManager#addListener(com.jme3.input.controls.InputListener, java.lang.String[])
*/ */
public void removeListener(InputListener listener) { public void removeListener(InputListener listener) {
for (Mapping mapping : mappings.values()) { for (Mapping mapping : mappings.values()) {
@ -509,16 +514,16 @@ public class InputManager implements RawInputListener {
/** /**
* Create a new mapping to the given triggers. * Create a new mapping to the given triggers.
* *
* <p> * <p>
* The given mapping will be assigned to the given triggers, when * The given mapping will be assigned to the given triggers, when
* any of the triggers given raise an event, the listeners * any of the triggers given raise an event, the listeners
* registered to the mappings will receive appropriate events. * registered to the mappings will receive appropriate events.
* *
* @param mappingName The mapping name to assign. * @param mappingName The mapping name to assign.
* @param triggers The triggers to which the mapping is to be registered. * @param triggers The triggers to which the mapping is to be registered.
* *
* @see InputManager#deleteMapping(java.lang.String) * @see InputManager#deleteMapping(java.lang.String)
*/ */
public void addMapping(String mappingName, Trigger... triggers) { public void addMapping(String mappingName, Trigger... triggers) {
Mapping mapping = mappings.get(mappingName); Mapping mapping = mappings.get(mappingName);
@ -549,23 +554,23 @@ public class InputManager implements RawInputListener {
* *
* @param mappingName The mapping name to check. * @param mappingName The mapping name to check.
* *
* @see InputManager#addMapping(java.lang.String, com.jme3.input.controls.Trigger[]) * @see InputManager#addMapping(java.lang.String, com.jme3.input.controls.Trigger[])
* @see InputManager#deleteMapping(java.lang.String) * @see InputManager#deleteMapping(java.lang.String)
*/ */
public boolean hasMapping(String mappingName) { public boolean hasMapping(String mappingName) {
return mappings.containsKey(mappingName); return mappings.containsKey(mappingName);
} }
/** /**
* Deletes a mapping from receiving trigger events. * Deletes a mapping from receiving trigger events.
* *
* <p> * <p>
* The given mapping will no longer be assigned to receive trigger * The given mapping will no longer be assigned to receive trigger
* events. * events.
* *
* @param mappingName The mapping name to unregister. * @param mappingName The mapping name to unregister.
* *
* @see InputManager#addMapping(java.lang.String, com.jme3.input.controls.Trigger[]) * @see InputManager#addMapping(java.lang.String, com.jme3.input.controls.Trigger[])
*/ */
public void deleteMapping(String mappingName) { public void deleteMapping(String mappingName) {
Mapping mapping = mappings.remove(mappingName); Mapping mapping = mappings.remove(mappingName);
@ -583,12 +588,12 @@ public class InputManager implements RawInputListener {
/** /**
* Deletes a specific trigger registered to a mapping. * Deletes a specific trigger registered to a mapping.
* *
* <p> * <p>
* The given mapping will no longer receive events raised by the * The given mapping will no longer receive events raised by the
* trigger. * trigger.
* *
* @param mappingName The mapping name to cease receiving events from the * @param mappingName The mapping name to cease receiving events from the
* trigger. * trigger.
* @param trigger The trigger to no longer invoke events on the mapping. * @param trigger The trigger to no longer invoke events on the mapping.
*/ */
@ -604,7 +609,7 @@ public class InputManager implements RawInputListener {
} }
/** /**
* Clears all the input mappings from this InputManager. * Clears all the input mappings from this InputManager.
* Consequently, also clears all of the * Consequently, also clears all of the
* InputListeners as well. * InputListeners as well.
*/ */
@ -625,12 +630,12 @@ public class InputManager implements RawInputListener {
/** /**
* Returns whether the mouse cursor is visible or not. * Returns whether the mouse cursor is visible or not.
* *
* <p>By default the cursor is visible. * <p>By default the cursor is visible.
* *
* @return whether the mouse cursor is visible or not. * @return whether the mouse cursor is visible or not.
* *
* @see InputManager#setCursorVisible(boolean) * @see InputManager#setCursorVisible(boolean)
*/ */
public boolean isCursorVisible() { public boolean isCursorVisible() {
return mouseVisible; return mouseVisible;
@ -638,7 +643,7 @@ public class InputManager implements RawInputListener {
/** /**
* Set whether the mouse cursor should be visible or not. * Set whether the mouse cursor should be visible or not.
* *
* @param visible whether the mouse cursor should be visible or not. * @param visible whether the mouse cursor should be visible or not.
*/ */
public void setCursorVisible(boolean visible) { public void setCursorVisible(boolean visible) {
@ -651,7 +656,7 @@ public class InputManager implements RawInputListener {
/** /**
* Returns the current cursor position. The position is relative to the * Returns the current cursor position. The position is relative to the
* bottom-left of the screen and is in pixels. * bottom-left of the screen and is in pixels.
* *
* @return the current cursor position * @return the current cursor position
*/ */
public Vector2f getCursorPosition() { public Vector2f getCursorPosition() {
@ -660,7 +665,7 @@ public class InputManager implements RawInputListener {
/** /**
* Returns an array of all joysticks installed on the system. * Returns an array of all joysticks installed on the system.
* *
* @return an array of all joysticks installed on the system. * @return an array of all joysticks installed on the system.
*/ */
public Joystick[] getJoysticks() { public Joystick[] getJoysticks() {
@ -669,22 +674,22 @@ public class InputManager implements RawInputListener {
/** /**
* Adds a {@link RawInputListener} to receive raw input events. * Adds a {@link RawInputListener} to receive raw input events.
* *
* <p> * <p>
* Any raw input listeners registered to this <code>InputManager</code> * Any raw input listeners registered to this <code>InputManager</code>
* will receive raw input events first, before they get handled * will receive raw input events first, before they get handled
* by the <code>InputManager</code> itself. The listeners are * by the <code>InputManager</code> itself. The listeners are
* each processed in the order they were added, e.g. FIFO. * each processed in the order they were added, e.g. FIFO.
* <p> * <p>
* If a raw input listener has handled the event and does not wish * If a raw input listener has handled the event and does not wish
* other listeners down the list to process the event, it may set the * other listeners down the list to process the event, it may set the
* {@link InputEvent#setConsumed() consumed flag} to indicate the * {@link InputEvent#setConsumed() consumed flag} to indicate the
* event was consumed and shouldn't be processed any further. * event was consumed and shouldn't be processed any further.
* The listener may do this either at each of the event callbacks * The listener may do this either at each of the event callbacks
* or at the {@link RawInputListener#endInput() } method. * or at the {@link RawInputListener#endInput() } method.
* *
* @param listener A listener to receive raw input events. * @param listener A listener to receive raw input events.
* *
* @see RawInputListener * @see RawInputListener
*/ */
public void addRawInputListener(RawInputListener listener) { public void addRawInputListener(RawInputListener listener) {
@ -695,10 +700,10 @@ public class InputManager implements RawInputListener {
/** /**
* Removes a {@link RawInputListener} so that it no longer * Removes a {@link RawInputListener} so that it no longer
* receives raw input events. * receives raw input events.
* *
* @param listener The listener to cease receiving raw input events. * @param listener The listener to cease receiving raw input events.
* *
* @see InputManager#addRawInputListener(com.jme3.input.RawInputListener) * @see InputManager#addRawInputListener(com.jme3.input.RawInputListener)
*/ */
public void removeRawInputListener(RawInputListener listener) { public void removeRawInputListener(RawInputListener listener) {
rawListeners.remove(listener); rawListeners.remove(listener);
@ -707,8 +712,8 @@ public class InputManager implements RawInputListener {
/** /**
* Clears all {@link RawInputListener}s. * Clears all {@link RawInputListener}s.
* *
* @see InputManager#addRawInputListener(com.jme3.input.RawInputListener) * @see InputManager#addRawInputListener(com.jme3.input.RawInputListener)
*/ */
public void clearRawInputListeners() { public void clearRawInputListeners() {
rawListeners.clear(); rawListeners.clear();
@ -716,14 +721,14 @@ public class InputManager implements RawInputListener {
} }
private RawInputListener[] getRawListenerArray() { private RawInputListener[] getRawListenerArray() {
if (rawListenerArray == null) if (rawListenerArray == null)
rawListenerArray = rawListeners.toArray(new RawInputListener[rawListeners.size()]); rawListenerArray = rawListeners.toArray(new RawInputListener[rawListeners.size()]);
return rawListenerArray; return rawListenerArray;
} }
/** /**
* Enable simulation of mouse events. Used for touchscreen input only. * Enable simulation of mouse events. Used for touchscreen input only.
* *
* @param value True to enable simulation of mouse events * @param value True to enable simulation of mouse events
*/ */
public void setSimulateMouse(boolean value) { public void setSimulateMouse(boolean value) {
@ -736,16 +741,16 @@ public class InputManager implements RawInputListener {
* *
*/ */
public boolean getSimulateMouse() { public boolean getSimulateMouse() {
if (touch != null) { if (touch != null) {
return touch.getSimulateMouse(); return touch.getSimulateMouse();
} else { } else {
return false; return false;
} }
} }
/** /**
* Enable simulation of keyboard events. Used for touchscreen input only. * Enable simulation of keyboard events. Used for touchscreen input only.
* *
* @param value True to enable simulation of keyboard events * @param value True to enable simulation of keyboard events
*/ */
public void setSimulateKeyboard(boolean value) { public void setSimulateKeyboard(boolean value) {
@ -757,7 +762,7 @@ public class InputManager implements RawInputListener {
private void processQueue() { private void processQueue() {
int queueSize = inputQueue.size(); int queueSize = inputQueue.size();
RawInputListener[] array = getRawListenerArray(); RawInputListener[] array = getRawListenerArray();
for (RawInputListener listener : array) { for (RawInputListener listener : array) {
listener.beginInput(); listener.beginInput();
@ -819,7 +824,7 @@ public class InputManager implements RawInputListener {
} }
/** /**
* Updates the <code>InputManager</code>. * Updates the <code>InputManager</code>.
* This will query current input devices and send * This will query current input devices and send
* appropriate events to registered listeners. * appropriate events to registered listeners.
* *
@ -827,11 +832,11 @@ public class InputManager implements RawInputListener {
*/ */
public void update(float tpf) { public void update(float tpf) {
frameTPF = tpf; frameTPF = tpf;
// Activate safemode if the TPF value is so small // Activate safemode if the TPF value is so small
// that rounding errors are inevitable // that rounding errors are inevitable
safeMode = tpf < 0.015f; safeMode = tpf < 0.015f;
long currentTime = keys.getInputTimeNanos(); long currentTime = keys.getInputTimeNanos();
frameDelta = currentTime - lastUpdateTime; frameDelta = currentTime - lastUpdateTime;
@ -859,7 +864,7 @@ public class InputManager implements RawInputListener {
* Dispatches touch events to touch listeners * Dispatches touch events to touch listeners
* @param evt The touch event to be dispatched to all onTouch listeners * @param evt The touch event to be dispatched to all onTouch listeners
*/ */
public void onTouchEventQueued(TouchEvent evt) { public void onTouchEventQueued(TouchEvent evt) {
ArrayList<Mapping> maps = bindings.get(TouchTrigger.touchHash(evt.getKeyCode())); ArrayList<Mapping> maps = bindings.get(TouchTrigger.touchHash(evt.getKeyCode()));
if (maps == null) { if (maps == null) {
return; return;
@ -873,12 +878,12 @@ public class InputManager implements RawInputListener {
for (int j = listenerSize - 1; j >= 0; j--) { for (int j = listenerSize - 1; j >= 0; j--) {
InputListener listener = listeners.get(j); InputListener listener = listeners.get(j);
if (listener instanceof TouchListener) { if (listener instanceof TouchListener) {
((TouchListener) listener).onTouch(mapping.name, evt, frameTPF); ((TouchListener) listener).onTouch(mapping.name, evt, frameTPF);
} }
} }
} }
} }
/** /**
* Callback from RawInputListener. Do not use. * Callback from RawInputListener. Do not use.
*/ */
@ -887,6 +892,6 @@ public class InputManager implements RawInputListener {
if (!eventsPermitted) { if (!eventsPermitted) {
throw new UnsupportedOperationException("TouchInput has raised an event at an illegal time."); throw new UnsupportedOperationException("TouchInput has raised an event at an illegal time.");
} }
inputQueue.add(evt); inputQueue.add(evt);
} }
} }

@ -32,6 +32,8 @@
package com.jme3.input; package com.jme3.input;
import com.jme3.cursors.plugins.JmeCursor;
/** /**
* A specific API for interfacing with the mouse. * A specific API for interfacing with the mouse.
*/ */
@ -41,12 +43,12 @@ public interface MouseInput extends Input {
* Mouse X axis. * Mouse X axis.
*/ */
public static final int AXIS_X = 0; public static final int AXIS_X = 0;
/** /**
* Mouse Y axis. * Mouse Y axis.
*/ */
public static final int AXIS_Y = 1; public static final int AXIS_Y = 1;
/** /**
* Mouse wheel axis. * Mouse wheel axis.
*/ */
@ -56,12 +58,12 @@ public interface MouseInput extends Input {
* Left mouse button. * Left mouse button.
*/ */
public static final int BUTTON_LEFT = 0; public static final int BUTTON_LEFT = 0;
/** /**
* Right mouse button. * Right mouse button.
*/ */
public static final int BUTTON_RIGHT = 1; public static final int BUTTON_RIGHT = 1;
/** /**
* Middle mouse button. * Middle mouse button.
*/ */
@ -69,15 +71,21 @@ public interface MouseInput extends Input {
/** /**
* Set whether the mouse cursor should be visible or not. * Set whether the mouse cursor should be visible or not.
* *
* @param visible Whether the mouse cursor should be visible or not. * @param visible Whether the mouse cursor should be visible or not.
*/ */
public void setCursorVisible(boolean visible); public void setCursorVisible(boolean visible);
/** /**
* Returns the number of buttons the mouse has. Typically 3 for most mice. * Returns the number of buttons the mouse has. Typically 3 for most mice.
* *
* @return the number of buttons the mouse has. * @return the number of buttons the mouse has.
*/ */
public int getButtonCount(); public int getButtonCount();
/**
* Sets the cursor to use.
* @param cursor The cursor to use.
*/
public void setNativeCursor(JmeCursor cursor);
} }

@ -32,12 +32,13 @@
package com.jme3.input.dummy; package com.jme3.input.dummy;
import com.jme3.cursors.plugins.JmeCursor;
import com.jme3.input.MouseInput; import com.jme3.input.MouseInput;
/** /**
* DummyMouseInput as an implementation of <code>MouseInput</code> that raises no * DummyMouseInput as an implementation of <code>MouseInput</code> that raises no
* input events. * input events.
* *
* @author Kirill Vainer. * @author Kirill Vainer.
*/ */
public class DummyMouseInput extends DummyInput implements MouseInput { public class DummyMouseInput extends DummyInput implements MouseInput {
@ -51,4 +52,7 @@ public class DummyMouseInput extends DummyInput implements MouseInput {
return 0; return 0;
} }
public void setNativeCursor(JmeCursor cursor) {
}
} }

@ -32,6 +32,7 @@
package com.jme3.input.awt; package com.jme3.input.awt;
import com.jme3.cursors.plugins.JmeCursor;
import com.jme3.input.MouseInput; import com.jme3.input.MouseInput;
import com.jme3.input.RawInputListener; import com.jme3.input.RawInputListener;
import com.jme3.input.event.MouseButtonEvent; import com.jme3.input.event.MouseButtonEvent;
@ -49,7 +50,7 @@ import javax.swing.SwingUtilities;
* *
* @author Joshua Slack * @author Joshua Slack
* @author MHenze (cylab) * @author MHenze (cylab)
* *
* @version $Revision$ * @version $Revision$
*/ */
public class AwtMouseInput implements MouseInput, MouseListener, MouseWheelListener, MouseMotionListener { public class AwtMouseInput implements MouseInput, MouseListener, MouseWheelListener, MouseMotionListener {
@ -66,7 +67,7 @@ public class AwtMouseInput implements MouseInput, MouseListener, MouseWheelListe
private final ArrayList<MouseButtonEvent> eventQueue = new ArrayList<MouseButtonEvent>(); private final ArrayList<MouseButtonEvent> eventQueue = new ArrayList<MouseButtonEvent>();
private final ArrayList<MouseButtonEvent> eventQueueCopy = new ArrayList<MouseButtonEvent>(); private final ArrayList<MouseButtonEvent> eventQueueCopy = new ArrayList<MouseButtonEvent>();
private int lastEventX; private int lastEventX;
private int lastEventY; private int lastEventY;
private int lastEventWheel; private int lastEventWheel;
@ -95,7 +96,7 @@ public class AwtMouseInput implements MouseInput, MouseListener, MouseWheelListe
logger.log(Level.SEVERE, "Could not create a robot, so the mouse cannot be grabbed! ", e); logger.log(Level.SEVERE, "Could not create a robot, so the mouse cannot be grabbed! ", e);
} }
} }
public void setInputSource(Component comp) { public void setInputSource(Component comp) {
if (component != null) { if (component != null) {
component.removeMouseListener(this); component.removeMouseListener(this);
@ -312,4 +313,7 @@ public class AwtMouseInput implements MouseInput, MouseListener, MouseWheelListe
} }
return index; return index;
} }
public void setNativeCursor(JmeCursor cursor) {
}
} }

@ -32,6 +32,7 @@
package com.jme3.input.lwjgl; package com.jme3.input.lwjgl;
import com.jme3.cursors.plugins.JmeCursor;
import com.jme3.input.MouseInput; import com.jme3.input.MouseInput;
import com.jme3.input.RawInputListener; import com.jme3.input.RawInputListener;
import com.jme3.input.event.MouseButtonEvent; import com.jme3.input.event.MouseButtonEvent;
@ -70,7 +71,7 @@ public class LwjglMouseInput implements MouseInput {
Mouse.create(); Mouse.create();
logger.info("Mouse created."); logger.info("Mouse created.");
supportHardwareCursor = (Cursor.getCapabilities() & Cursor.CURSOR_ONE_BIT_TRANSPARENCY) != 0; supportHardwareCursor = (Cursor.getCapabilities() & Cursor.CURSOR_ONE_BIT_TRANSPARENCY) != 0;
// Recall state that was set before initialization // Recall state that was set before initialization
Mouse.setGrabbed(!cursorVisible); Mouse.setGrabbed(!cursorVisible);
} catch (LWJGLException ex) { } catch (LWJGLException ex) {
@ -138,7 +139,7 @@ public class LwjglMouseInput implements MouseInput {
cursorVisible = visible; cursorVisible = visible;
if (!context.isRenderable()) if (!context.isRenderable())
return; return;
Mouse.setGrabbed(!visible); Mouse.setGrabbed(!visible);
} }
@ -150,4 +151,20 @@ public class LwjglMouseInput implements MouseInput {
return Sys.getTime() * LwjglTimer.LWJGL_TIME_TO_NANOS; return Sys.getTime() * LwjglTimer.LWJGL_TIME_TO_NANOS;
} }
public void setNativeCursor(JmeCursor jmeCursor) {
try {
Cursor newCursor = new Cursor(
jmeCursor.getWidth(),
jmeCursor.getHeight(),
jmeCursor.getXHotSpot(),
jmeCursor.getYHotSpot(),
jmeCursor.getNumImages(),
jmeCursor.getImagesData(),
jmeCursor.getImagesDelay());
Mouse.setNativeCursor(newCursor);
} catch (LWJGLException ex) {
Logger.getLogger(LwjglMouseInput.class.getName()).log(Level.SEVERE, null, ex);
}
}
} }

@ -98,7 +98,7 @@ public class InputSystemJme implements InputSystem, RawInputListener {
x = (int) evt.getX(); x = (int) evt.getX();
y = (int) (height - evt.getY()); y = (int) (height - evt.getY());
if (!inputManager.getSimulateMouse()) { if (!inputManager.getSimulateMouse()) {
switch (evt.getType()) { switch (evt.getType()) {
case DOWN: case DOWN:
consumed = nic.processMouseEvent(x, y, 0, 0, true); consumed = nic.processMouseEvent(x, y, 0, 0, true);
@ -150,7 +150,7 @@ public class InputSystemJme implements InputSystem, RawInputListener {
// Mouse button raised. End dragging // Mouse button raised. End dragging
if (wasPressed && !pressed) { if (wasPressed && !pressed) {
if (!niftyOwnsDragging) { if (!niftyOwnsDragging) {
forwardToNifty = false; forwardToNifty = true;
} }
isDragging = false; isDragging = false;
niftyOwnsDragging = false; niftyOwnsDragging = false;

Loading…
Cancel
Save