package io;
import org.lwjgl.input.Controller;
import org.lwjgl.input.Controllers;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import frame.ADXGame;
/**
* Input management class that manages all inputs from the mouse, keyboard and multiple gamepads.
* It buffers the previous state of every key, button or axis and can then compute their current state more accurately.
* Functions like keyPressed and keyReleased are made possible with this.
* @author Alexandre Desbiens
*/
public class ADXInput {
private static final int KEY_MAX = 256;
private static final int BUTTON_MAX = 16;
private static int GAMEPAD_MAX;
private static int[] GAMEPAD_BUTTON_MAX;
private static int[] GAMEPAD_AXIS_MAX;
private static int[] GAMEPAD_RUMBLER_MAX;
private static final byte RELEASED = 0;
private static final byte JUST_RELEASED = 1;
private static final byte PRESSED = 2;
private static final byte JUST_PRESSED = 3;
/** Mouse left button */
public static final byte MOUSE_LEFT = 0;
/** Mouse right button */
public static final byte MOUSE_RIGHT = 1;
/** Mouse middle wheel click */
public static final byte MOUSE_MIDDLE = 2;
private ADXGame game;
private int mouseX;
private int mouseY;
private int mouseWheel;
private byte[] aKey;
private int[] aKeyTimer;
private boolean[] aKeyDouble;
private byte[] aButton;
private byte[][] aGButton;
private float[][] apGAxis;
private float[][] aGAxis;
private boolean controllers;
private String keyString = "";
private int keyStringIndex = 0;
private int keyStringIndex2 = 0;
private int lastKey = -1;
private int[] lastGButton;
private int[] lastGAxis;
private boolean[] lastGAxisPos;
/**
* Initialize the input manager and enables or disables the controllers.
* @param game Pointer to the game instance
* @param controllers Controllers enabled flag
*/
public ADXInput(ADXGame game, boolean controllers) {
this.game = game;
this.controllers = controllers;
aKey = new byte[KEY_MAX];
aKeyTimer = new int[KEY_MAX];
aKeyDouble = new boolean[KEY_MAX];
aButton = new byte[BUTTON_MAX];
for (int i = 0; i < KEY_MAX; i++) {
aKeyTimer[i] = 100;
}
if (controllers) {
GAMEPAD_MAX = Controllers.getControllerCount();
GAMEPAD_BUTTON_MAX = new int[GAMEPAD_MAX];
GAMEPAD_AXIS_MAX = new int[GAMEPAD_MAX];
GAMEPAD_RUMBLER_MAX = new int[GAMEPAD_MAX];
aGButton = new byte[GAMEPAD_MAX][];
apGAxis = new float[GAMEPAD_MAX][];
aGAxis = new float[GAMEPAD_MAX][];
lastGButton = new int[GAMEPAD_MAX];
lastGAxis = new int[GAMEPAD_MAX];
lastGAxisPos = new boolean[GAMEPAD_MAX];
Controller c;
for (int i = 0; i < GAMEPAD_MAX; i++) {
c = Controllers.getController(i);
GAMEPAD_BUTTON_MAX[i] = c.getButtonCount();
GAMEPAD_AXIS_MAX[i] = c.getAxisCount();
GAMEPAD_RUMBLER_MAX[i] = c.getRumblerCount();
aGButton[i] = new byte[GAMEPAD_BUTTON_MAX[i]];
apGAxis[i] = new float[GAMEPAD_AXIS_MAX[i]];
aGAxis[i] = new float[GAMEPAD_AXIS_MAX[i]];
lastGButton[i] = -1;
lastGAxis[i] = -1;
lastGAxisPos[i] = false;
}
}
}
/**
* Updates the states of the mouse, keyboard and controllers (if enabled).
* Builds a keyboard string made of all the readable keyboard inputs that can be used in text fields, cheats, etc.
*/
public void update() {
// Keyboard keys
for (int i = 0; i < KEY_MAX; i++) {
aKeyTimer[i]++;
if (Keyboard.isKeyDown(i)) {
if (aKey[i] == RELEASED || aKey[i] == JUST_RELEASED) {
aKey[i] = JUST_PRESSED;
lastKey = i;
if (aKeyTimer[i] <= 10) {
if (aKeyDouble[i]) {
aKeyDouble[i] = false;
} else {
aKeyDouble[i] = true;
}
} else {
aKeyDouble[i] = false;
}
aKeyTimer[i] = 0;
} else if (aKey[i] == JUST_PRESSED) {
aKey[i] = PRESSED;
}
} else {
if (aKey[i] == PRESSED || aKey[i] == JUST_PRESSED) {
aKey[i] = JUST_RELEASED;
} else if (aKey[i] == JUST_RELEASED) {
aKey[i] = RELEASED;
}
}
}
// Mouse position
mouseX = (int) ((Mouse.getX() - game.getRenderX()) / game.getRenderXScale());
mouseY = (int) ((game.getDisplayHeight() - Mouse.getY() - game.getRenderY()) / game.getRenderYScale());
// Mouse wheel
mouseWheel = Mouse.getDWheel() / 120;
// Mouse buttons
for (int i = 0; i < BUTTON_MAX; i++) {
if (Mouse.isButtonDown(i)) {
if (aButton[i] == RELEASED || aButton[i] == JUST_RELEASED) {
aButton[i] = JUST_PRESSED;
} else if (aButton[i] == JUST_PRESSED) {
aButton[i] = PRESSED;
}
} else {
if (aButton[i] == PRESSED || aButton[i] == JUST_PRESSED) {
aButton[i] = JUST_RELEASED;
} else if (aButton[i] == JUST_RELEASED) {
aButton[i] = RELEASED;
}
}
}
// Controller buttons
if (controllers) {
Controller c;
for (int i = 0; i < GAMEPAD_MAX; i++) {
c = Controllers.getController(i);
for (int j = 0; j < GAMEPAD_BUTTON_MAX[i]; j++) {
if (c.isButtonPressed(j)) {
if (aGButton[i][j] == RELEASED || aGButton[i][j] == JUST_RELEASED) {
aGButton[i][j] = JUST_PRESSED;
lastGButton[i] = j;
} else if (aGButton[i][j] == JUST_PRESSED) {
aGButton[i][j] = PRESSED;
}
} else {
if (aGButton[i][j] == PRESSED || aGButton[i][j] == JUST_PRESSED) {
aGButton[i][j] = JUST_RELEASED;
} else if (aGButton[i][j] == JUST_RELEASED) {
aGButton[i][j] = RELEASED;
}
}
}
for (int j = 0; j < GAMEPAD_AXIS_MAX[i]; j++) {
apGAxis[i][j] = aGAxis[i][j];
aGAxis[i][j] = c.getAxisValue(j);
if (apGAxis[i][j] < 0.75f && aGAxis[i][j] >= 0.75f) {
lastGAxis[i] = j;
lastGAxisPos[i] = true;
} else if (apGAxis[i][j] > -0.75f && aGAxis[i][j] <= -0.75f) {
lastGAxis[i] = j;
lastGAxisPos[i] = false;
}
}
}
}
// Keyboard string
Keyboard.poll();
while (Keyboard.next()) {
if (Keyboard.getEventKeyState()) {
int key = Keyboard.getEventKey();
switch (key) {
case 1: // Escape
case 15: // Tab
case 28: // Enter
case 29: // Left Control
case 41: // Right Control
case 42: // Left Shift
case 54: // Right Shift
case 56: // Left Alt
case 58: // Caps lock
case 59: // F1
case 60: // F2
case 61: // F3
case 62: // F4
case 63: // F5
case 64: // F6
case 65: // F7
case 66: // F8
case 67: // F9
case 68: // F10
case 69: // Num Lock
case 70: // Scroll Lock
case 87: // F11
case 88: // F12
case 183: // Print Screen
case 184: // Right Alt Char
case 197: // Pause
case 199: // Home
case 200: // Up arrow
case 201: // Page Up
case 207: // End
case 208: // Down arrow
case 209: // Page Down
case 210: // Insert
case 211: // Delete
case 219: // Left Windows
case 221: // Menu
break;
case 14: // Backspace
if (keyString.length() > 0) {
if (keyStringIndex == keyStringIndex2 && keyStringIndex > 0) {
keyString = keyString.substring(0, keyStringIndex - 1) + keyString.substring(keyStringIndex, keyString.length());
keyStringIndex -= 1;
keyStringIndex2 -= 1;
} else {
int x1 = 0;
int x2 = 0;
if (keyStringIndex > keyStringIndex2) {
x1 = keyStringIndex2;
x2 = keyStringIndex;
} else {
x1 = keyStringIndex;
x2 = keyStringIndex2;
}
keyString = keyString.substring(0, x1) + keyString.substring(x2, keyString.length());
keyStringIndex = x1;
keyStringIndex2 = x1;
}
}
break;
case 203: // Left key
if (keyStringIndex > 0) {
keyStringIndex -= 1;
}
if (!getKey(Keyboard.KEY_LSHIFT)) {
keyStringIndex2 = keyStringIndex;
}
break;
case 205: // Right key
if (keyStringIndex < keyString.length()) {
keyStringIndex += 1;
}
if (!getKey(Keyboard.KEY_LSHIFT)) {
keyStringIndex2 = keyStringIndex;
}
break;
default:
keyString = keyString.substring(0, keyStringIndex) + Keyboard.getEventCharacter() + keyString.substring(keyStringIndex, keyString.length());
keyStringIndex += 1;
keyStringIndex2 += 1;
break;
}
}
}
}
/* Keyboard functions */
/**
* Returns the string built with the readable keyboard inputs of the user.
* @return Keyboard string
*/
public String getKeyString() {
return keyString;
}
/**
* Sets the keyboard string to the given value and updates the indexes.
* @param keyString Keyboard string
*/
public void setKeyString(String keyString) {
this.keyString = keyString;
if (keyStringIndex > keyString.length()) {
keyStringIndex = keyString.length();
}
if (keyStringIndex2 > keyString.length()) {
keyStringIndex2 = keyString.length();
}
}
/**
* Returns the index of the first keyboard string index.
* @return Keyboard string index
*/
public int getKeyStringIndex() {
return keyStringIndex;
}
/**
* Sets the value of the first keyboard string index to the given index.
* @param index Keyboars string index
*/
public void setKeyStringIndex(int index) {
keyStringIndex = index;
}
/**
* Returns the index of the second string index.
* @return Keyboard string index 2
*/
public int getKeyStringIndex2() {
return keyStringIndex2;
}
/**
* Sets the value of the second keyboard string index to the given value.
* @param index Keyboard string index 2
*/
public void setKeyStringIndex2(int index) {
keyStringIndex2 = index;
}
/** Resets the last key pressed to none. */
public void resetLastKey() {
lastKey = -1;
}
/**
* Returns the keyboard code of the last key pressed.
* @return Last key code
*/
public int getLastKey() {
return lastKey;
}
/**
* Tests for a certain key to be down.
* @param key Key code
* @return True if key is currently down
*/
public boolean getKey(int key) {
if (key < 0 || key >= KEY_MAX) {
return false;
}
return aKey[key] == PRESSED || aKey[key] == JUST_PRESSED;
}
/**
* Tests if the given key was just pressed.
* @param key Key code
* @return True if the key has just been pressed
*/
public boolean getKeyPressed(int key) {
if (key < 0 || key >= KEY_MAX) {
return false;
}
return aKey[key] == JUST_PRESSED;
}
/**
* Tests for a double click on the given key.
* @param key Key code
* @return True if the key has been double-clicked
*/
public boolean getKeyDoublePressed(int key) {
if (key < 0 || key >= KEY_MAX) {
return false;
}
return aKeyDouble[key];
}
/**
* Tests if the given key was just released.
* @param key Key code
* @return True if the key has just been released
*/
public boolean getKeyReleased(int key) {
if (key < 0 || key >= KEY_MAX) {
return false;
}
return aKey[key] == JUST_RELEASED;
}
/**
* Virtually releases a key, making all calls to {@link #getKeyPressed(int) getKeyPressed} false.
* @param key Key code
*/
public void releaseKey(int key) {
if (key < 0 || key >= KEY_MAX) {
return;
}
if (aKey[key] == JUST_PRESSED) {
aKey[key] = PRESSED;
} else if (aKey[key] == JUST_RELEASED) {
aKey[key] = RELEASED;
}
}
/* Mouse functions */
/**
* Tests if a button is currently held down.
* @param button Button code
* @return True if the button is currently down
*/
public boolean getButton(int button) {
if (button < 0 || button > BUTTON_MAX) {
return false;
}
return aButton[button] == PRESSED || aButton[button] == JUST_PRESSED;
}
/**
* Tests if the given button just has been pressed.
* @param button Button code
* @return True if the button has just been pressed
*/
public boolean getButtonPressed(int button) {
if (button < 0 || button > BUTTON_MAX) {
return false;
}
return aButton[button] == JUST_PRESSED;
}
/**
* Tests if a button has just been released.
* @param button Button code
* @return True if the button has just been released
*/
public boolean getButtonReleased(int button) {
if (button < 0 || button > BUTTON_MAX) {
return false;
}
return aButton[button] == JUST_RELEASED;
}
public int getMouseWheel() {
return mouseWheel;
}
/**
* Virtually releases a button, making all calls to {@link #getButtonPressed(int) getButtonPressed} false.
* @param button Button code
*/
public void releaseButton(int button) {
if (button < 0 || button >= BUTTON_MAX) {
return;
}
if (aButton[button] == JUST_PRESSED) {
aButton[button] = PRESSED;
} else if (aButton[button] == JUST_RELEASED) {
aButton[button] = RELEASED;
}
}
/**
* Returns the current X position of the mouse in the game.
* This value is calculated with the current render offset and scale of the game texture.
* It does not represent the X position of the mouse relative to the display.
* @return Mouse X position
*/
public int getMouseX() {
return mouseX;
}
/**
* Returns the current Y position of the mouse in the game.
* This value is calculated with the current render offset and scale of the game texture.
* It does not represent the Y position of the mouse relative to the display.
* @return Mouse Y position
*/
public int getMouseY() {
return mouseY;
}
/** Virtually puts the mouse out of any plausible range, disabling mouse position calls. */
public void disableMousePosition() {
mouseX = Integer.MAX_VALUE;
mouseY = Integer.MAX_VALUE;
}
/* Gamepad functions */
/**
* Returns the number of gamepads currently connected to the computer and recognized.
* @return Number of gamepads
*/
public int getGamepadCount() {
if (!controllers) {
return -1;
}
return GAMEPAD_MAX;
}
/**
* Gets the number of button on the gamepad at the given index.
* @param index Gamepad index
* @return Number of buttons
*/
public int getGamepadButtonCount(int index) {
if (!controllers || index < 0 || index >= GAMEPAD_MAX) {
return 0;
}
return GAMEPAD_BUTTON_MAX[index];
}
/**
* Gets the number of axis on the gampad at the given index.
* @param index Gamepad index
* @return Number of buttons
*/
public int getGamepadAxisCount(int index) {
if (!controllers || index < 0 || index >= GAMEPAD_MAX) {
return 0;
}
return GAMEPAD_AXIS_MAX[index];
}
/**
* Returns the value of the X Axis of the gamepad.
* @param index Gamepad index
* @return X Axis value
*/
public float getGStickX(int index) {
if (!controllers || index < 0 || index >= GAMEPAD_MAX) {
return 0;
}
return Controllers.getController(index).getXAxisValue();
}
/**
* Returns the value of the Y Axis of the gamepad.
* @param index Gamepad index
* @return Y Axis value
*/
public float getGStickY(int index) {
if (!controllers || index < 0 || index >= GAMEPAD_MAX) {
return 0;
}
return Controllers.getController(index).getYAxisValue();
}
/**
* Returns the value of the axis at the given index for a gamepad.
* @param index Gamepad index
* @param axis Axis index
* @return Axis value
*/
public float getGAxisValue(int index, int axis) {
if (!controllers || index < 0 || index >= GAMEPAD_MAX) {
return 0;
}
if (axis < 0 || axis >= GAMEPAD_AXIS_MAX[index]) {
return 0;
}
return aGAxis[index][axis];
}
public boolean getGAxisPosPressed(int index, int axis) {
if (!controllers || index < 0 || index >= GAMEPAD_MAX) {
return false;
}
if (axis < 0 || axis >= GAMEPAD_AXIS_MAX[index]) {
return false;
}
return aGAxis[index][axis] >= 0.75f && apGAxis[index][axis] < 0.75f;
}
public boolean getGAxisNegPressed(int index, int axis) {
if (!controllers || index < 0 || index >= GAMEPAD_MAX) {
return false;
}
if (axis < 0 || axis >= GAMEPAD_AXIS_MAX[index]) {
return false;
}
return aGAxis[index][axis] <= -0.75f && apGAxis[index][axis] > -0.75f;
}
/**
* Tests if a button is currently down on the gamepad.
* @param index Gamepad index
* @param button Button index
* @return True if the button is currently down
*/
public boolean getGButton(int index, int button) {
if (!controllers || index < 0 || index >= GAMEPAD_MAX) {
return false;
}
if (button < 0 || button >= GAMEPAD_BUTTON_MAX[index]) {
return false;
}
return aGButton[index][button] == PRESSED || aGButton[index][button] == JUST_PRESSED;
}
/**
* Tests if the gamepad button at the given index has just been pressed.
* @param index Gamepad index
* @param button Button index
* @return True if the button has just been pressed
*/
public boolean getGButtonPressed(int index, int button) {
if (!controllers || index < 0 || index >= GAMEPAD_MAX) {
return false;
}
if (button < 0 || button >= GAMEPAD_BUTTON_MAX[index]) {
return false;
}
return aGButton[index][button] == JUST_PRESSED;
}
/**
* Tests if the gamepad button at the given index has just been released.
* @param index Gamepad index
* @param button Button index
* @return True if the button has just been released
*/
public boolean getGButtonReleased(int index, int button) {
if (!controllers || index < 0 || index >= GAMEPAD_MAX) {
return false;
}
if (button < 0 || button >= GAMEPAD_BUTTON_MAX[index]) {
return false;
}
return aGButton[index][button] == JUST_RELEASED;
}
/**
* Sets the rumbler at the given index to the value passed.
* @param index Gamepad index
* @param rumbler Rumbler index
* @param value Rumbling value (1.0f is 100%)
*/
public void setRumbler(int index, int rumbler, float value) {
if (!controllers || index < 0 || index >= GAMEPAD_MAX) {
return;
}
if (rumbler < 0 || rumbler >= GAMEPAD_RUMBLER_MAX[index]) {
return;
}
Controllers.getController(index).setRumblerStrength(rumbler, value);
}
/** Resets the last gamepad button pressed to none. */
public void resetLastGButton(int index) {
lastGButton[index] = -1;
}
/**
* Returns the gamepad button code of the last gamepad button pressed.
* @param index Gamepad index
* @return Last button code
*/
public int getLastGButton(int index) {
return lastGButton[index];
}
/** Resets the last gamepad axis pressed to none. */
public void resetLastGAxis(int index) {
lastGAxis[index] = -1;
}
/**
* Returns the gamepad axis index of the last axis pressed.
* @param index Gamepad index
* @return Last axis index
*/
public int getLastGAxis(int index) {
return lastGAxis[index];
}
/**
* Returns true if the last axis pressed was pressed towards the positive side, and false towards the negative.
* @param index Gamepad index
* @return Positive press flag
*/
public boolean getLastGAxisPos(int index) {
return lastGAxisPos[index];
}
/**
* Virtually releases a gamepad button, making all calls to {@link #getGButtonPressed(int) getGButtonPressed} false.
* @param index Gamepad index
* @param button Button index
*/
public void releaseGButton(int index, int button) {
if (!controllers || index < 0 || index >= GAMEPAD_MAX) {
return;
}
if (button < 0 || button >= GAMEPAD_BUTTON_MAX[index]) {
return;
}
if (aGButton[index][button] == JUST_PRESSED) {
aGButton[index][button] = PRESSED;
} else if (aButton[button] == JUST_RELEASED) {
aGButton[index][button] = RELEASED;
}
}
}