diff --git a/src/java/org/lwjgl/input/Controller.java b/src/java/org/lwjgl/input/Controller.java new file mode 100644 index 00000000..d840bdf5 --- /dev/null +++ b/src/java/org/lwjgl/input/Controller.java @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2002 Lightweight Java Game Library Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'Light Weight Java Game Library' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.lwjgl.input; + +import java.util.HashMap; +import java.util.Map; + +import org.lwjgl.Sys; + +/** + * $Id$ + *
+ * A raw Controller interface. This can be used to poll the current state of a + * controllers buttons, and axis positions. The axis positions + * are returned as ints in the range -1000 to 1000. + * + * No buffering is available. + * + * Currently n (native limits) buttons, the x, y, z axis (also rotational x,y , + * z axis) is supported along with a POV (or HAT) and a slider + * + * The Controller implementation currently only supports the first attached device. + * + * @author Brian Matzon + * @version $Revision$ + */ +public class Controller { + + static { + initialize(); + } + + /** Has the controller been created? */ + private static boolean created; + + /** The controller buttons status */ + private static boolean[] buttons; + + /** X position, range -1000 to 1000 */ + public static int x = 0; + + /** X rotational position, range -1000 to 1000 */ + public static int rx = 0; + + /** Y position, range -1000 to 1000 */ + public static int y = 0; + + /** Y rotational position, range -1000 to 1000 */ + public static int ry = 0; + + /** Z position, range -1000 to 1000 */ + public static int z = 0; + + /** Z rotational position, range -1000 to 1000 */ + public static int rz = 0; + + /** Position of Point of View from -1 to 27000 (360 degrees) */ + public static int pov; + + /** Slider position, range -1000 to 1000 */ + public static int slider = 0; + + /** Constant specifying centered POV */ + public static final int POV_CENTER = -1; + + /** Constant specifying nortward POV */ + public static final int POV_NORTH = 0; + + /** Constant specifying southward POV */ + public static final int POV_SOUTH = 18000; + + /** Constant specifying eastward POV */ + public static final int POV_EAST = 27000; + + /** Constant specifying westward POV */ + public static final int POV_WEST = 9000; + + /** Number of buttons on the controller */ + public static int buttonCount = -1; + + /** Does this controller support a x axis */ + public static boolean hasXAxis = false; + + /** Does this controller support a rotational x axis */ + public static boolean hasRXAxis = false; + + /** Does this controller support an y axis */ + public static boolean hasYAxis = false; + + /** Does this controller support a rotational y axis */ + public static boolean hasRYAxis = false; + + /** Does this controller support a z axis */ + public static boolean hasZAxis = false; + + /** Does this controller support a rotational z axis */ + public static boolean hasRZAxis = false; + + /** Does this controller support a Point-Of-View (hat) */ + public static boolean hasPOV = false; + + /** Does this controller support a slider */ + public static boolean hasSlider = false; + + /** Button names. These are set upon create(), to names like BUTTON0, BUTTON1, etc. */ + private static String[] buttonName; + private static final Map buttonMap = new HashMap(8); + + /** + * Controller cannot be constructed. + */ + private Controller() { + } + + /** + * Static initialization + */ + private static void initialize() { + System.loadLibrary(Sys.getLibraryName()); + initIDs(); + + // Assign names to all the buttons + buttonName = new String[8]; + for (int i = 0; i < 8; i ++) { + buttonName[i] = "BUTTON" + i; + buttonMap.put(buttonName[i], new Integer(i)); + } + + } + + /** + * "Create" the controller. The display must first have been created. + * @throws Exception if the controller could not be created for any reason + */ + public static void create() throws Exception { + if (created) { + return; + } + + if (!nCreate()) { + throw new Exception("The controller could not be created."); + } + + created = true; + } + + /** + * @return true if the controller has been created + */ + public static boolean isCreated() { + return created; + } + + /** + * "Destroy" the controller + */ + public static void destroy() { + if (!created) { + return; + } + + created = false; + nDestroy(); + } + + /** + * Polls the controller. + */ + public static void poll() { + assert created : "The controller has not been created."; + nPoll(); + } + + /** + * Tests if a particular button is down. + * + * @param button The index of the button you wish to test (0..buttonCount-1) + * @return true if the specified button is down + * @see #buttonCount + */ + public static boolean isButtonDown(int button) { + assert created : "The controller has not been created."; + return buttons[button]; + } + + /** + * Gets a button's name + * @param button The button + * @return a String with the button's human readable name in it or null if the button is unnamed + */ + public static String getButtonName(int button) { + if (button < 0 || button >= buttonName.length) + return null; + else + return buttonName[button]; + } + + /** + * Get's a button's index. If the button is unrecognised then -1 is returned. + * @param buttonName The button name + */ + public static int getButtonIndex(String buttonName) { + Integer ret = (Integer) buttonMap.get(buttonName); + if (ret == null) + return -1; + else + return ret.intValue(); + } + + /** + * Native method to poll the controller + */ + private static native void nPoll(); + + /** + * Native method to create the controller + * + * @return true if the controller was created + */ + private static native boolean nCreate(); + + /** + * Native method the destroy the controller + */ + private static native void nDestroy(); + + /** + * Register fields with the native library + */ + private static native void initIDs(); +} \ No newline at end of file diff --git a/src/java/org/lwjgl/input/Keyboard.java b/src/java/org/lwjgl/input/Keyboard.java new file mode 100644 index 00000000..bb1efcef --- /dev/null +++ b/src/java/org/lwjgl/input/Keyboard.java @@ -0,0 +1,451 @@ +/* + * Copyright (c) 2002 Lightweight Java Game Library Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'Light Weight Java Game Library' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.lwjgl.input; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.HashMap; +import java.util.Map; + +import org.lwjgl.Sys; + +/** + * $Id$ + * + * A raw Keyboard interface. This can be used to poll the current state of the + * keys, or read all the keyboard presses / releases since the last read. + * Buffering must be explicitly enabled; the size of the buffer is determined + * by the native implementation at its discretion. + * + * @author cix_foo + * @version $Revision$ + */ +public class Keyboard { + /** + * The special character meaning that no + * character was translated for the event. + */ + public static final char CHAR_NONE = '\0'; + + /** + * The special keycode meaning that only the + * translated character is valid. + */ + public static final int KEY_NONE = 0x00; + + public static final int KEY_ESCAPE = 0x01; + public static final int KEY_1 = 0x02; + public static final int KEY_2 = 0x03; + public static final int KEY_3 = 0x04; + public static final int KEY_4 = 0x05; + public static final int KEY_5 = 0x06; + public static final int KEY_6 = 0x07; + public static final int KEY_7 = 0x08; + public static final int KEY_8 = 0x09; + public static final int KEY_9 = 0x0A; + public static final int KEY_0 = 0x0B; + public static final int KEY_MINUS = 0x0C; /* - on main keyboard */ + public static final int KEY_EQUALS = 0x0D; + public static final int KEY_BACK = 0x0E; /* backspace */ + public static final int KEY_TAB = 0x0F; + public static final int KEY_Q = 0x10; + public static final int KEY_W = 0x11; + public static final int KEY_E = 0x12; + public static final int KEY_R = 0x13; + public static final int KEY_T = 0x14; + public static final int KEY_Y = 0x15; + public static final int KEY_U = 0x16; + public static final int KEY_I = 0x17; + public static final int KEY_O = 0x18; + public static final int KEY_P = 0x19; + public static final int KEY_LBRACKET = 0x1A; + public static final int KEY_RBRACKET = 0x1B; + public static final int KEY_RETURN = 0x1C; /* Enter on main keyboard */ + public static final int KEY_LCONTROL = 0x1D; + public static final int KEY_A = 0x1E; + public static final int KEY_S = 0x1F; + public static final int KEY_D = 0x20; + public static final int KEY_F = 0x21; + public static final int KEY_G = 0x22; + public static final int KEY_H = 0x23; + public static final int KEY_J = 0x24; + public static final int KEY_K = 0x25; + public static final int KEY_L = 0x26; + public static final int KEY_SEMICOLON = 0x27; + public static final int KEY_APOSTROPHE = 0x28; + public static final int KEY_GRAVE = 0x29; /* accent grave */ + public static final int KEY_LSHIFT = 0x2A; + public static final int KEY_BACKSLASH = 0x2B; + public static final int KEY_Z = 0x2C; + public static final int KEY_X = 0x2D; + public static final int KEY_C = 0x2E; + public static final int KEY_V = 0x2F; + public static final int KEY_B = 0x30; + public static final int KEY_N = 0x31; + public static final int KEY_M = 0x32; + public static final int KEY_COMMA = 0x33; + public static final int KEY_PERIOD = 0x34; /* . on main keyboard */ + public static final int KEY_SLASH = 0x35; /* / on main keyboard */ + public static final int KEY_RSHIFT = 0x36; + public static final int KEY_MULTIPLY = 0x37; /* * on numeric keypad */ + public static final int KEY_LMENU = 0x38; /* left Alt */ + public static final int KEY_SPACE = 0x39; + public static final int KEY_CAPITAL = 0x3A; + public static final int KEY_F1 = 0x3B; + public static final int KEY_F2 = 0x3C; + public static final int KEY_F3 = 0x3D; + public static final int KEY_F4 = 0x3E; + public static final int KEY_F5 = 0x3F; + public static final int KEY_F6 = 0x40; + public static final int KEY_F7 = 0x41; + public static final int KEY_F8 = 0x42; + public static final int KEY_F9 = 0x43; + public static final int KEY_F10 = 0x44; + public static final int KEY_NUMLOCK = 0x45; + public static final int KEY_SCROLL = 0x46; /* Scroll Lock */ + public static final int KEY_NUMPAD7 = 0x47; + public static final int KEY_NUMPAD8 = 0x48; + public static final int KEY_NUMPAD9 = 0x49; + public static final int KEY_SUBTRACT = 0x4A; /* - on numeric keypad */ + public static final int KEY_NUMPAD4 = 0x4B; + public static final int KEY_NUMPAD5 = 0x4C; + public static final int KEY_NUMPAD6 = 0x4D; + public static final int KEY_ADD = 0x4E; /* + on numeric keypad */ + public static final int KEY_NUMPAD1 = 0x4F; + public static final int KEY_NUMPAD2 = 0x50; + public static final int KEY_NUMPAD3 = 0x51; + public static final int KEY_NUMPAD0 = 0x52; + public static final int KEY_DECIMAL = 0x53; /* . on numeric keypad */ + public static final int KEY_F11 = 0x57; + public static final int KEY_F12 = 0x58; + public static final int KEY_F13 = 0x64; /* (NEC PC98) */ + public static final int KEY_F14 = 0x65; /* (NEC PC98) */ + public static final int KEY_F15 = 0x66; /* (NEC PC98) */ + public static final int KEY_KANA = 0x70; /* (Japanese keyboard) */ + public static final int KEY_CONVERT = 0x79; /* (Japanese keyboard) */ + public static final int KEY_NOCONVERT = 0x7B; /* (Japanese keyboard) */ + public static final int KEY_YEN = 0x7D; /* (Japanese keyboard) */ + public static final int KEY_NUMPADEQUALS = 0x8D; /* = on numeric keypad (NEC PC98) */ + public static final int KEY_CIRCUMFLEX = 0x90; /* (Japanese keyboard) */ + public static final int KEY_AT = 0x91; /* (NEC PC98) */ + public static final int KEY_COLON = 0x92; /* (NEC PC98) */ + public static final int KEY_UNDERLINE = 0x93; /* (NEC PC98) */ + public static final int KEY_KANJI = 0x94; /* (Japanese keyboard) */ + public static final int KEY_STOP = 0x95; /* (NEC PC98) */ + public static final int KEY_AX = 0x96; /* (Japan AX) */ + public static final int KEY_UNLABELED = 0x97; /* (J3100) */ + public static final int KEY_NUMPADENTER = 0x9C; /* Enter on numeric keypad */ + public static final int KEY_RCONTROL = 0x9D; + public static final int KEY_NUMPADCOMMA = 0xB3; /* , on numeric keypad (NEC PC98) */ + public static final int KEY_DIVIDE = 0xB5; /* / on numeric keypad */ + public static final int KEY_SYSRQ = 0xB7; + public static final int KEY_RMENU = 0xB8; /* right Alt */ + public static final int KEY_PAUSE = 0xC5; /* Pause */ + public static final int KEY_HOME = 0xC7; /* Home on arrow keypad */ + public static final int KEY_UP = 0xC8; /* UpArrow on arrow keypad */ + public static final int KEY_PRIOR = 0xC9; /* PgUp on arrow keypad */ + public static final int KEY_LEFT = 0xCB; /* LeftArrow on arrow keypad */ + public static final int KEY_RIGHT = 0xCD; /* RightArrow on arrow keypad */ + public static final int KEY_END = 0xCF; /* End on arrow keypad */ + public static final int KEY_DOWN = 0xD0; /* DownArrow on arrow keypad */ + public static final int KEY_NEXT = 0xD1; /* PgDn on arrow keypad */ + public static final int KEY_INSERT = 0xD2; /* Insert on arrow keypad */ + public static final int KEY_DELETE = 0xD3; /* Delete on arrow keypad */ + public static final int KEY_LWIN = 0xDB; /* Left Windows key */ + public static final int KEY_RWIN = 0xDC; /* Right Windows key */ + public static final int KEY_APPS = 0xDD; /* AppMenu key */ + public static final int KEY_POWER = 0xDE; + public static final int KEY_SLEEP = 0xDF; + + /** Key names */ + private static final String[] keyName = new String[255]; + private static final Map keyMap = new HashMap(253); + private static int counter = 0; + static { + // Use reflection to find out key names + Field[] field = Keyboard.class.getFields(); + try { + for (int i = 0; i < field.length; i++) { + if (Modifier.isStatic(field[i].getModifiers()) + && Modifier.isPublic(field[i].getModifiers()) + && Modifier.isFinal(field[i].getModifiers()) + && field[i].getType() == int.class + && field[i].getName().startsWith("KEY_")) { + + int key = field[i].getInt(null); + String name = field[i].getName().substring(4); + keyName[key] = name; + keyMap.put(name, new Integer(key)); + counter ++; + } + + } + } catch (Exception e) { + } + + } + + /** The number of keys supported */ + public static final int keyCount = counter; + + /** Has the keyboard been created? */ + private static boolean created; + + /** The keys status from the last poll */ + private static final ByteBuffer keyDownBuffer = ByteBuffer.allocateDirect(256); + + /** + * The key events from the last read: a sequence of pairs of key number, + * followed by state. If translation is enabled, the state is followed by + * a 2 byte java char representing the translated character. + */ + private static ByteBuffer readBuffer; + + /** True if translation is enabled */ + private static boolean translationEnabled; + + /** The number of events read in the last read() */ + private static int numEvents; + + /** The current keyboard character being examined */ + public static char character; + + /** The current keyboard event key being examined */ + public static int key; + + /** The current state of the key being examined in the event queue */ + public static boolean state; + + static { + initialize(); + } + + /** + * Keyboard cannot be constructed. + */ + private Keyboard() { + } + + /** + * Static initialization + */ + private static void initialize() { + System.loadLibrary(Sys.getLibraryName()); + initIDs(); + } + + /** + * Register fields with the native library + */ + private static native void initIDs(); + + /** + * "Create" the keyboard. The display must first have been created. The + * reason for this is so the keyboard has a window to "focus" in. + * + * @throws Exception if the keyboard could not be created for any reason + */ + public static void create() throws Exception { + if (created) + return; + if (!nCreate()) + throw new Exception("The keyboard could not be created."); + created = true; + } + + /** + * Native method to create the keyboard + * + * @return true if the keyboard was created + */ + private static native boolean nCreate(); + + /** + * @return true if the keyboard has been created + */ + public static boolean isCreated() { + return created; + } + + /** + * "Destroy" the keyboard + */ + public static void destroy() { + if (!created) + return; + created = false; + nDestroy(); + } + + /** + * Native method to destroy the keyboard + */ + private static native void nDestroy(); + + /** + * Polls the keyboard. + */ + public static void poll() { + assert created : "The keyboard has not been created."; + nPoll(keyDownBuffer); + } + + /** + * Native method to poll the keyboard. + * + * @param keyDownBufferAddress the address of a 256-byte buffer to place + * key states in. + */ + private static native void nPoll(ByteBuffer keyDownBuffer); + + /** + * Reads the keyboard buffer. + */ + public static void read() { + assert created : "The keyboard has not been created."; + assert readBuffer != null : "Keyboard buffering has not been enabled."; + numEvents = nRead(); + readBuffer.clear(); + if (translationEnabled) + readBuffer.limit(numEvents << 2); + else + readBuffer.limit(numEvents << 1); + } + + /** + * Native method to read the keyboard buffer + * @return the total number of events read. + */ + private static native int nRead(); + + /** + * Enable keyboard translation. Must be called after the keyboard is created, + * and keyboard buffering must be enabled. + * @return false if translation cannot be enabled; true if it can + */ + public static boolean enableTranslation() { + assert created : "The keyboard has not been created."; + assert readBuffer != null : "Keyboard buffering has not been enabled."; + + translationEnabled = nEnableTranslation(); + return translationEnabled; + } + + /** + * Native method to enable the translation buffer + */ + private static native boolean nEnableTranslation(); + + /** + * Enable keyboard buffering. Must be called after the keyboard is created. + * @return the size of the keyboard buffer in events, or 0 if no buffering + * can be enabled for any reason + */ + public static int enableBuffer() { + assert created : "The keyboard has not been created."; + int buf_len = nEnableBuffer(); + if (readBuffer != null) + readBuffer.order(ByteOrder.nativeOrder()); + return buf_len; + } + + /** + * Native method to enable the buffer + * @return the size of the buffer allocated, in events (1 event is 2 bytes), + * or 0 if no buffer can be allocated + */ + private static native int nEnableBuffer(); + + /** + * Checks to see if a key is down. + * @param key Keycode to check + * @return true if the key is down according to the last poll() + */ + public static boolean isKeyDown(int key) { + assert created : "The keyboard has not been created."; + return keyDownBuffer.get(key) != 0; + } + + /** + * Gets a key's name + * @param key The key + * @return a String with the key's human readable name in it or null if the key is unnamed + */ + public static String getKeyName(int key) { + return keyName[key]; + } + + /** + * Get's a key's index. If the key is unrecognised then KEY_NONE is returned. + * @param keyName The key name + */ + public static int getKeyIndex(String keyName) { + Integer ret = (Integer) keyMap.get(keyName); + if (ret == null) + return KEY_NONE; + else + return ret.intValue(); + } + + /** + * Gets the number of keyboard events waiting after doing a read(). + * @return the number of keyboard events + */ + public static int getNumKeyboardEvents() { + assert created : "The keyboard has not been created."; + assert readBuffer != null : "Keyboard buffering has not been enabled."; + + return numEvents; + } + + /** + * Gets the next keyboard event. This is stored in the publicly accessible + * static fields key and state. + * @return true if a keyboard event was read, false otherwise + */ + public static boolean next() { + assert created : "The keyboard has not been created."; + assert readBuffer != null : "Keyboard buffering has not been enabled."; + + if (readBuffer.hasRemaining()) { + key = readBuffer.get() & 0xFF; + state = readBuffer.get() != 0; + if (translationEnabled) + character = readBuffer.getChar(); + return true; + } else + return false; + } +} diff --git a/src/java/org/lwjgl/input/Mouse.java b/src/java/org/lwjgl/input/Mouse.java new file mode 100644 index 00000000..2eebeb8e --- /dev/null +++ b/src/java/org/lwjgl/input/Mouse.java @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2002 Lightweight Java Game Library Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'Light Weight Java Game Library' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.lwjgl.input; + +import java.util.HashMap; +import java.util.Map; + +import org.lwjgl.*; + +/** + * $Id$ + * + * A raw Mouse interface. This can be used to poll the current state of the + * mouse buttons, and determine the mouse movement delta since the last poll. + * + * n buttons supported, n being a native limit. A scrolly wheel is also + * supported, if one such is available. All movement is reported as delta from + * last position. + * + * @author cix_foo + * @version $Revision$ + */ +public class Mouse { + public final static int CURSOR_ONE_BIT_TRANSPARANCY = 1; + public final static int CURSOR_8_BIT_ALPHA = 2; + public final static int CURSOR_ANIMATION = 4; + + /** Has the mouse been created? */ + private static boolean created; + + /** The mouse buttons status from the last poll */ + private static boolean[] buttons; + + /** Delta X */ + public static int dx; + + /** Delta Y */ + public static int dy; + + /** Delta Z */ + public static int dwheel; + + /** Number of buttons supported by the mouse */ + public static int buttonCount = -1; + + /** Does this mouse support a scroll wheel */ + public static boolean hasWheel = false; + + /** The current native cursor, if any */ + private static Cursor currentCursor; + + /** Button names. These are set upon create(), to names like BUTTON0, BUTTON1, etc. */ + private static String[] buttonName; + private static final Map buttonMap = new HashMap(16); + + static { + initialize(); + } + + /** + * Mouse cannot be constructed. + */ + private Mouse() { + } + + /** + * Gets the currently bound native cursor, if any. + * + * @return the currently bound native cursor, if any. + */ + public static Cursor getNativeCursor() { + return currentCursor; + } + + /** + * Get the capabilities of the native cursor. Return a bit mask of the native cursor capabilities. + * The CURSOR_ONE_BIT_TRANSPARANCY indicates support for cursors with one bit transparancy, + * the CURSOR_8_BIT_ALPHA indicates support for 8 bit alpha and CURSOR_ANIMATION indicates + * support for cursor animations. + * + * @return A bit mask with native cursor capabilities. + */ + public static int getNativeCursorCaps() { + return nGetNativeCursorCaps(); + } + + /** + * Native function to determine native cursor support + */ + private static native int nGetNativeCursorCaps(); + + /** + * Binds a native cursor. If the cursor argument is null, the + * native cursor is disabled, as if native cursors were not supported. + * The Mouse must be created before a native cursor can be bound. + * + * NOTE: The native cursor is not constrained to the window, but + * relative events will not be generated if the cursor is outside. + * The initial position of the cursor is in the upper left corner of + * the window, and the cursor will be moved to this origin when a + * native cursor is set and the previous cursor is null. + * + * @param cursor the native cursor object to bind. May be null. + * @return The previous Cursor object set, or null. + * @throws Exception if the cursor could not be set for any reason + */ + public static Cursor setNativeCursor(Cursor cursor) throws Exception { + assert created && ((getNativeCursorCaps() | CURSOR_ONE_BIT_TRANSPARANCY) != 0); + Cursor oldCursor = currentCursor; + currentCursor = cursor; + if (currentCursor != null) { + nSetNativeCursor(currentCursor.getHandle()); + } else { + nSetNativeCursor(0); + } + return oldCursor; + } + + /** Native method to set the native cursor */ + private static native void nSetNativeCursor(int handle); + + /** + * Gets the minimum size of a native cursor. Can only be called if + * The Mouse is created and cursor caps includes at least + * CURSOR_ONE_BIT_TRANSPARANCY. + * + * @return the maximum size of a native cursor + */ + public static int getMinCursorSize() { + return nGetMinCursorSize(); + } + + /** Native method returning the minimum cursor size */ + private static native int nGetMinCursorSize(); + + /** + * Gets the maximum size of a native cursor. Can only be called if + * The Mouse is created and cursor caps includes at least + * CURSOR_ONE_BIT_TRANSPARANCY. + * + * @return the maximum size of a native cursor + */ + public static int getMaxCursorSize() { + return nGetMaxCursorSize(); + } + + /** Native method returning the maximum cursor size */ + private static native int nGetMaxCursorSize(); + + /** + * Static initialization + */ + private static void initialize() { + System.loadLibrary(Sys.getLibraryName()); + initIDs(); + + // Assign names to all the buttons + buttonName = new String[16]; + for (int i = 0; i < 16; i ++) { + buttonName[i] = "BUTTON" + i; + buttonMap.put(buttonName[i], new Integer(i)); + } + } + + /** + * Register fields with the native library + */ + private static native void initIDs(); + + /** + * "Create" the mouse. The display must first have been created. + * + * @throws Exception if the mouse could not be created for any reason + */ + public static void create() throws Exception { + if (created) + return; + if (!nCreate()) + throw new Exception("The mouse could not be created."); + created = true; + currentCursor = null; + + //set mouse buttons + buttons = new boolean[buttonCount]; + + + } + + /** + * Native method to create the mouse. + * + * @return true if the mouse was created + */ + private static native boolean nCreate(); + + /** + * @return true if the mouse has been created + */ + public static boolean isCreated() { + return created; + } + + /** + * "Destroy" the mouse. Remember to reset the native cursor if + * setNativeCursor() has been called with anything else than null. + */ + public static void destroy() { + assert currentCursor == null; + if (!created) + return; + created = false; + buttons = null; + currentCursor = null; + + nDestroy(); + } + + /** + * Native method the destroy the mouse + */ + private static native void nDestroy(); + + /** + * Polls the mouse. + */ + public static void poll() { + assert created : "The mouse has not been created."; + nPoll(); + } + + /** + * Native method to poll the mouse + */ + private static native void nPoll(); + + /** + * See if a particular mouse button is down. + * + * @param button The index of the button you wish to test (0..buttonCount-1) + * @return true if the specified button is down + */ + public static boolean isButtonDown(int button) { + assert created : "The mouse has not been created."; + return buttons[button]; + } + + /** + * Gets a button's name + * @param button The button + * @return a String with the button's human readable name in it or null if the button is unnamed + */ + public static String getButtonName(int button) { + if (button < 0 || button >= buttonName.length) + return null; + else + return buttonName[button]; + } + + /** + * Get's a button's index. If the button is unrecognised then -1 is returned. + * @param buttonName The button name + */ + public static int getButtonIndex(String buttonName) { + Integer ret = (Integer) buttonMap.get(buttonName); + if (ret == null) + return -1; + else + return ret.intValue(); + } + +}