mirror of
https://github.com/4jcraft/4jcraft.git
synced 2026-04-23 13:13:37 +00:00
671 lines
28 KiB
C++
671 lines
28 KiB
C++
#include "4J_Input.h"
|
|
|
|
#include <SDL2/SDL.h>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include <string>
|
|
|
|
#include "../4J.Common/4J_InputActions.h"
|
|
|
|
C_4JInput InputManager;
|
|
|
|
static const int KEY_COUNT = SDL_NUM_SCANCODES;
|
|
static const int BTN_COUNT = SDL_CONTROLLER_BUTTON_MAX;
|
|
static const int AXS_COUNT = SDL_CONTROLLER_AXIS_MAX;
|
|
static const float MOUSE_SCALE = 0.015f;
|
|
// Vars
|
|
static bool s_sdlInitialized = false;
|
|
static bool s_keysCurrent[KEY_COUNT] = {};
|
|
static bool s_keysPrev[KEY_COUNT] = {};
|
|
static bool s_btnsCurrent[BTN_COUNT] = {};
|
|
static bool s_btnsPrev[BTN_COUNT] = {};
|
|
static bool s_axisCurrent[AXS_COUNT] = {};
|
|
static bool s_axisPrev[AXS_COUNT] = {};
|
|
static float axisVal[AXS_COUNT] = {};
|
|
static bool s_mouseLeftCurrent = false, s_mouseLeftPrev = false;
|
|
static bool s_mouseRightCurrent = false, s_mouseRightPrev = false;
|
|
static bool s_menuDisplayed[4] = {};
|
|
static bool s_prevMenuDisplayed = false;
|
|
static bool s_snapTaken = false;
|
|
static float s_accumRelX = 0, s_accumRelY = 0;
|
|
static float s_snapRelX = 0, s_snapRelY = 0;
|
|
static int s_mouseX = 0, s_mouseY = 0;
|
|
|
|
static int s_scrollTicksForButtonPressed = 0;
|
|
static int s_scrollTicksForGetValue = 0;
|
|
static int s_scrollTicksSnap = 0;
|
|
static bool s_scrollSnapTaken = false;
|
|
|
|
// Text input state (non-blocking keyboard)
|
|
static bool s_keyboardActive = false;
|
|
static std::string s_textInputBuf;
|
|
static int (*s_keyboardCallback)(void*, const bool) = nullptr;
|
|
static void* s_keyboardCallbackParam = nullptr;
|
|
|
|
// We set all the watched keys
|
|
// I don't know if I'll need to change this if we add chat support soon.
|
|
static const int s_watchedKeys[] = {
|
|
SDL_SCANCODE_W, SDL_SCANCODE_A, SDL_SCANCODE_S,
|
|
SDL_SCANCODE_D, SDL_SCANCODE_SPACE, SDL_SCANCODE_LSHIFT,
|
|
SDL_SCANCODE_RSHIFT, SDL_SCANCODE_E, SDL_SCANCODE_Q,
|
|
SDL_SCANCODE_F, SDL_SCANCODE_C, SDL_SCANCODE_ESCAPE,
|
|
SDL_SCANCODE_RETURN, SDL_SCANCODE_F3, SDL_SCANCODE_F5,
|
|
SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT,
|
|
SDL_SCANCODE_RIGHT, SDL_SCANCODE_PAGEUP, SDL_SCANCODE_PAGEDOWN,
|
|
SDL_SCANCODE_TAB, SDL_SCANCODE_LCTRL, SDL_SCANCODE_RCTRL,
|
|
SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3,
|
|
SDL_SCANCODE_4, SDL_SCANCODE_5, SDL_SCANCODE_6,
|
|
SDL_SCANCODE_7, SDL_SCANCODE_8, SDL_SCANCODE_9,
|
|
SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_C,
|
|
SDL_SCANCODE_V};
|
|
static const int s_watchedKeyCount =
|
|
(int)(sizeof(s_watchedKeys) / sizeof(s_watchedKeys[0]));
|
|
|
|
static inline bool KDown(int sc) {
|
|
return (sc > 0 && sc < KEY_COUNT) ? s_keysCurrent[sc] : false;
|
|
}
|
|
static inline bool KPressed(int sc) {
|
|
return (sc > 0 && sc < KEY_COUNT) ? !s_keysPrev[sc] && s_keysCurrent[sc]
|
|
: false;
|
|
}
|
|
static inline bool KReleased(int sc) {
|
|
return (sc > 0 && sc < KEY_COUNT) ? s_keysPrev[sc] && !s_keysCurrent[sc]
|
|
: false;
|
|
}
|
|
|
|
static inline bool MouseLDown() { return s_mouseLeftCurrent; }
|
|
static inline bool MouseLPressed() {
|
|
return s_mouseLeftCurrent && !s_mouseLeftPrev;
|
|
}
|
|
static inline bool MouseLReleased() {
|
|
return !s_mouseLeftCurrent && s_mouseLeftPrev;
|
|
}
|
|
static inline bool MouseRDown() { return s_mouseRightCurrent; }
|
|
static inline bool MouseRPressed() {
|
|
return s_mouseRightCurrent && !s_mouseRightPrev;
|
|
}
|
|
static inline bool MouseRReleased() {
|
|
return !s_mouseRightCurrent && s_mouseRightPrev;
|
|
}
|
|
|
|
// holds controller object
|
|
static SDL_GameController* controller = nullptr;
|
|
|
|
// Watched controller buttons set
|
|
static const SDL_GameControllerButton s_watchedBtns[] = {
|
|
SDL_CONTROLLER_BUTTON_A,
|
|
SDL_CONTROLLER_BUTTON_B,
|
|
SDL_CONTROLLER_BUTTON_X,
|
|
SDL_CONTROLLER_BUTTON_Y,
|
|
SDL_CONTROLLER_BUTTON_BACK,
|
|
SDL_CONTROLLER_BUTTON_GUIDE,
|
|
SDL_CONTROLLER_BUTTON_START,
|
|
SDL_CONTROLLER_BUTTON_LEFTSTICK,
|
|
SDL_CONTROLLER_BUTTON_RIGHTSTICK,
|
|
SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
|
|
SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
|
|
SDL_CONTROLLER_BUTTON_DPAD_UP,
|
|
SDL_CONTROLLER_BUTTON_DPAD_DOWN,
|
|
SDL_CONTROLLER_BUTTON_DPAD_LEFT,
|
|
SDL_CONTROLLER_BUTTON_DPAD_RIGHT};
|
|
static const int s_watchedBtnsCount =
|
|
(int)(sizeof(s_watchedBtns) / sizeof(s_watchedBtns[0]));
|
|
|
|
static inline bool CDown(int cb) {
|
|
return (cb >= 0 && cb < BTN_COUNT) ? s_btnsCurrent[cb] : false;
|
|
}
|
|
static inline bool CPressed(int cb) {
|
|
return (cb >= 0 && cb < BTN_COUNT) ? !s_btnsPrev[cb] && s_btnsCurrent[cb]
|
|
: false;
|
|
}
|
|
static inline bool CReleased(int cb) {
|
|
return (cb >= 0 && cb < BTN_COUNT) ? s_btnsPrev[cb] && !s_btnsCurrent[cb]
|
|
: false;
|
|
}
|
|
|
|
// Sets controller dead zone
|
|
static int deadZone = 8000;
|
|
|
|
// Watched controller axes set
|
|
static const SDL_GameControllerAxis s_watchedAxis[] = {
|
|
SDL_CONTROLLER_AXIS_LEFTX, SDL_CONTROLLER_AXIS_LEFTY,
|
|
SDL_CONTROLLER_AXIS_RIGHTX, SDL_CONTROLLER_AXIS_RIGHTY,
|
|
SDL_CONTROLLER_AXIS_TRIGGERLEFT, SDL_CONTROLLER_AXIS_TRIGGERRIGHT};
|
|
static const int s_watchedAxisCount =
|
|
(int)(sizeof(s_watchedAxis) / sizeof(s_watchedAxis[0]));
|
|
|
|
static inline bool ADown(int ca) {
|
|
return (ca >= 0 && ca < AXS_COUNT) ? s_axisCurrent[ca] : false;
|
|
}
|
|
static inline bool APressed(int ca) {
|
|
return (ca >= 0 && ca < AXS_COUNT) ? !s_axisPrev[ca] && s_axisCurrent[ca]
|
|
: false;
|
|
}
|
|
static inline bool AReleased(int ca) {
|
|
return (ca >= 0 && ca < AXS_COUNT) ? s_axisPrev[ca] && !s_axisCurrent[ca]
|
|
: false;
|
|
}
|
|
|
|
// get directly into SDL events before the game queue can steal them.
|
|
// this took me a while.
|
|
static int SDLCALL EventWatcher(void*, SDL_Event* e) {
|
|
if (e->type == SDL_MOUSEWHEEL) {
|
|
int y = e->wheel.y;
|
|
if (e->wheel.direction == SDL_MOUSEWHEEL_FLIPPED) {
|
|
y = -y;
|
|
}
|
|
s_scrollTicksForGetValue += y;
|
|
s_scrollTicksForButtonPressed += y;
|
|
} else if (e->type == SDL_MOUSEBUTTONDOWN) {
|
|
if (e->button.button == 4) {
|
|
s_scrollTicksForGetValue++;
|
|
s_scrollTicksForButtonPressed++;
|
|
} else if (e->button.button == 5) {
|
|
s_scrollTicksForGetValue--;
|
|
s_scrollTicksForButtonPressed--;
|
|
}
|
|
} else if (e->type == SDL_MOUSEMOTION) {
|
|
s_accumRelX += (float)e->motion.xrel;
|
|
s_accumRelY += (float)e->motion.yrel;
|
|
} else if (e->type == SDL_TEXTINPUT && s_keyboardActive) {
|
|
s_textInputBuf += e->text.text;
|
|
} else if (e->type == SDL_CONTROLLERDEVICEADDED) { // Will search for
|
|
// controller if none
|
|
for (int i = 0; i < SDL_NumJoysticks(); i++) {
|
|
if (SDL_IsGameController(i)) {
|
|
controller = SDL_GameControllerOpen(i);
|
|
break;
|
|
}
|
|
}
|
|
} else if (controller) { // only checks when a controller exists
|
|
if (e->type == SDL_CONTROLLERDEVICEREMOVED) {
|
|
SDL_Joystick* joy = SDL_GameControllerGetJoystick(controller);
|
|
if (SDL_JoystickInstanceID(joy) == e->cdevice.which) {
|
|
SDL_GameControllerClose(controller);
|
|
controller = nullptr;
|
|
}
|
|
} else if (e->type == SDL_CONTROLLERBUTTONDOWN) {
|
|
if (e->cbutton.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
|
|
s_scrollTicksForGetValue++;
|
|
s_scrollTicksForButtonPressed++;
|
|
} else if (e->cbutton.button ==
|
|
SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) {
|
|
s_scrollTicksForGetValue--;
|
|
s_scrollTicksForButtonPressed--;
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int ScrollSnap() {
|
|
if (!s_scrollSnapTaken) {
|
|
s_scrollTicksSnap = s_scrollTicksForButtonPressed;
|
|
s_scrollTicksForButtonPressed = 0;
|
|
s_scrollSnapTaken = true;
|
|
}
|
|
return s_scrollTicksSnap;
|
|
}
|
|
|
|
static void TakeSnapIfNeeded() {
|
|
if (!s_snapTaken) {
|
|
s_snapRelX = s_accumRelX;
|
|
s_accumRelX = 0;
|
|
s_snapRelY = s_accumRelY;
|
|
s_accumRelY = 0;
|
|
s_snapTaken = true;
|
|
}
|
|
}
|
|
// We initialize the SDL input
|
|
void C_4JInput::Initialise(int, unsigned char, unsigned char, unsigned char) {
|
|
if (!s_sdlInitialized) {
|
|
if (SDL_WasInit(SDL_INIT_VIDEO) == 0) {
|
|
SDL_Init(SDL_INIT_VIDEO);
|
|
}
|
|
if (SDL_WasInit(SDL_INIT_GAMECONTROLLER) == 0) {
|
|
SDL_Init(SDL_INIT_GAMECONTROLLER);
|
|
}
|
|
SDL_AddEventWatch(EventWatcher, NULL);
|
|
s_sdlInitialized = true;
|
|
}
|
|
|
|
memset(s_keysCurrent, 0, sizeof(s_keysCurrent));
|
|
memset(s_keysPrev, 0, sizeof(s_keysPrev));
|
|
memset(s_btnsCurrent, 0, sizeof(s_btnsCurrent));
|
|
memset(s_btnsPrev, 0, sizeof(s_btnsPrev));
|
|
memset(s_axisCurrent, 0, sizeof(s_axisCurrent));
|
|
memset(s_axisPrev, 0, sizeof(s_axisPrev));
|
|
memset(s_menuDisplayed, 0, sizeof(s_menuDisplayed));
|
|
|
|
s_mouseLeftCurrent = s_mouseLeftPrev = s_mouseRightCurrent =
|
|
s_mouseRightPrev = false;
|
|
s_accumRelX = s_accumRelY = s_snapRelX = s_snapRelY = 0;
|
|
// i really gotta name these vars better..
|
|
s_scrollTicksForButtonPressed = s_scrollTicksForGetValue =
|
|
s_scrollTicksSnap = 0;
|
|
s_snapTaken = s_scrollSnapTaken = s_prevMenuDisplayed = false;
|
|
|
|
if (s_sdlInitialized) {
|
|
SDL_SetRelativeMouseMode(SDL_TRUE);
|
|
|
|
// looks for controller
|
|
for (int i = 0; i < SDL_NumJoysticks(); i++) {
|
|
if (SDL_IsGameController(i)) {
|
|
controller = SDL_GameControllerOpen(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Erase one UTF-8 codepoint from the end of a string.
|
|
static void utf8_pop_back(std::string& str) {
|
|
if (str.empty()) return;
|
|
size_t i = str.size() - 1;
|
|
while (i > 0 && (str[i] & 0xC0) == 0x80) --i;
|
|
str.erase(i);
|
|
}
|
|
|
|
// Each tick we update the input state by polling SDL, this is where we get the
|
|
// kbd and mouse state.
|
|
void C_4JInput::Tick() {
|
|
if (!s_sdlInitialized) return;
|
|
|
|
memcpy(s_keysPrev, s_keysCurrent, sizeof(s_keysCurrent));
|
|
memcpy(s_btnsPrev, s_btnsCurrent, sizeof(s_btnsCurrent));
|
|
memcpy(s_axisPrev, s_axisCurrent, sizeof(s_axisCurrent));
|
|
s_mouseLeftPrev = s_mouseLeftCurrent;
|
|
s_mouseRightPrev = s_mouseRightCurrent;
|
|
s_snapTaken = false;
|
|
s_scrollSnapTaken = false;
|
|
s_snapRelX = s_snapRelY = 0;
|
|
s_scrollTicksSnap = 0;
|
|
|
|
SDL_PumpEvents();
|
|
|
|
if (s_menuDisplayed[0]) {
|
|
s_scrollTicksForGetValue = 0;
|
|
}
|
|
|
|
const Uint8* state = SDL_GetKeyboardState(NULL);
|
|
for (int i = 0; i < s_watchedKeyCount; ++i) {
|
|
int sc = s_watchedKeys[i];
|
|
if (sc > 0 && sc < KEY_COUNT) s_keysCurrent[sc] = state[sc] != 0;
|
|
}
|
|
|
|
Uint32 btns = SDL_GetMouseState(&s_mouseX, &s_mouseY);
|
|
s_mouseLeftCurrent = (btns & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0;
|
|
s_mouseRightCurrent = (btns & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
|
|
|
|
if (!SDL_GetRelativeMouseMode()) {
|
|
s_accumRelX = 0;
|
|
s_accumRelY = 0;
|
|
}
|
|
|
|
if (!SDL_GetKeyboardFocus()) {
|
|
SDL_Window* mf = SDL_GetMouseFocus();
|
|
if (mf) {
|
|
SDL_RaiseWindow(mf);
|
|
SDL_SetWindowGrab(mf, SDL_TRUE);
|
|
}
|
|
}
|
|
|
|
// If there is a controller update the buttons and sticks
|
|
if (controller) {
|
|
for (int i = 0; i < s_watchedBtnsCount; ++i) {
|
|
int cb = s_watchedBtns[i];
|
|
if (cb >= 0 && cb < BTN_COUNT)
|
|
s_btnsCurrent[cb] =
|
|
SDL_GameControllerGetButton(controller, s_watchedBtns[i]);
|
|
}
|
|
for (int i = 0; i < s_watchedAxisCount; ++i) {
|
|
int ca = s_watchedAxis[i];
|
|
if (ca >= 0 && ca < AXS_COUNT) {
|
|
int aVal =
|
|
SDL_GameControllerGetAxis(controller, s_watchedAxis[i]);
|
|
if (s_watchedAxis[i] == SDL_CONTROLLER_AXIS_TRIGGERLEFT ||
|
|
s_watchedAxis[i] == SDL_CONTROLLER_AXIS_TRIGGERRIGHT)
|
|
s_axisCurrent[ca] = aVal > deadZone;
|
|
else {
|
|
s_axisCurrent[ca] = (aVal > deadZone || aVal < -deadZone);
|
|
axisVal[ca] = aVal / 32768.0f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle non-blocking keyboard input completion
|
|
if (s_keyboardActive) {
|
|
if (KPressed(SDL_SCANCODE_BACKSPACE)) {
|
|
utf8_pop_back(s_textInputBuf);
|
|
}
|
|
if (KPressed(SDL_SCANCODE_RETURN) || KPressed(SDL_SCANCODE_KP_ENTER)) {
|
|
s_keyboardActive = false;
|
|
SDL_StopTextInput();
|
|
// Consume the key so it doesn't also trigger ACTION_MENU_OK
|
|
s_keysCurrent[SDL_SCANCODE_RETURN] = false;
|
|
s_keysCurrent[SDL_SCANCODE_KP_ENTER] = false;
|
|
if (s_keyboardCallback) {
|
|
s_keyboardCallback(s_keyboardCallbackParam, true);
|
|
s_keyboardCallback = nullptr;
|
|
s_keyboardCallbackParam = nullptr;
|
|
}
|
|
} else if (KPressed(SDL_SCANCODE_ESCAPE)) {
|
|
s_keyboardActive = false;
|
|
s_textInputBuf.clear();
|
|
SDL_StopTextInput();
|
|
// Consume the key so it doesn't also trigger ACTION_MENU_CANCEL
|
|
s_keysCurrent[SDL_SCANCODE_ESCAPE] = false;
|
|
if (s_keyboardCallback) {
|
|
s_keyboardCallback(s_keyboardCallbackParam, false);
|
|
s_keyboardCallback = nullptr;
|
|
s_keyboardCallbackParam = nullptr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int C_4JInput::GetHotbarSlotPressed(int iPad) {
|
|
if (iPad != 0) return -1;
|
|
|
|
constexpr size_t NUM_HOTBAR_SLOTS = 9;
|
|
|
|
static const int sc[NUM_HOTBAR_SLOTS] = {
|
|
SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3,
|
|
SDL_SCANCODE_4, SDL_SCANCODE_5, SDL_SCANCODE_6,
|
|
SDL_SCANCODE_7, SDL_SCANCODE_8, SDL_SCANCODE_9,
|
|
};
|
|
static bool s_wasDown[NUM_HOTBAR_SLOTS] = {};
|
|
|
|
for (int i = 0; i < NUM_HOTBAR_SLOTS; ++i) {
|
|
bool down = KDown(sc[i]);
|
|
bool pressed = down && !s_wasDown[i];
|
|
s_wasDown[i] = down;
|
|
if (pressed) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// KFN = Keyboard functions, CFN = Controller functions, AFN = Axis functions
|
|
#define ACTION_CASES(KFN, CFN, AFN) \
|
|
case ACTION_MENU_UP: \
|
|
return KFN(SDL_SCANCODE_UP) || CFN(SDL_CONTROLLER_BUTTON_DPAD_UP); \
|
|
case ACTION_MENU_DOWN: \
|
|
return KFN(SDL_SCANCODE_DOWN) || CFN(SDL_CONTROLLER_BUTTON_DPAD_DOWN); \
|
|
case ACTION_MENU_LEFT: \
|
|
return KFN(SDL_SCANCODE_LEFT) || CFN(SDL_CONTROLLER_BUTTON_DPAD_LEFT); \
|
|
case ACTION_MENU_RIGHT: \
|
|
return KFN(SDL_SCANCODE_RIGHT) || \
|
|
CFN(SDL_CONTROLLER_BUTTON_DPAD_RIGHT); \
|
|
case ACTION_MENU_PAGEUP: \
|
|
return KFN(SDL_SCANCODE_PAGEUP); \
|
|
case ACTION_MENU_PAGEDOWN: \
|
|
return KFN(SDL_SCANCODE_PAGEDOWN); \
|
|
case ACTION_MENU_OK: \
|
|
return KFN(SDL_SCANCODE_RETURN) || KFN(SDL_SCANCODE_Z) || \
|
|
CFN(SDL_CONTROLLER_BUTTON_A); \
|
|
case ACTION_MENU_CANCEL: \
|
|
return KFN(SDL_SCANCODE_ESCAPE) || KFN(SDL_SCANCODE_X) || \
|
|
CFN(SDL_CONTROLLER_BUTTON_B); \
|
|
case ACTION_MENU_A: \
|
|
return KFN(SDL_SCANCODE_Z) || KFN(SDL_SCANCODE_RETURN) || \
|
|
CFN(SDL_CONTROLLER_BUTTON_A); \
|
|
case ACTION_MENU_B: \
|
|
return KFN(SDL_SCANCODE_X) || KFN(SDL_SCANCODE_ESCAPE) || \
|
|
CFN(SDL_CONTROLLER_BUTTON_B); \
|
|
case ACTION_MENU_X: \
|
|
return KFN(SDL_SCANCODE_C) || CFN(SDL_CONTROLLER_BUTTON_X); \
|
|
case ACTION_MENU_Y: \
|
|
return KFN(SDL_SCANCODE_V) || CFN(SDL_CONTROLLER_BUTTON_Y); \
|
|
case MINECRAFT_ACTION_JUMP: \
|
|
return KFN(SDL_SCANCODE_SPACE) || CFN(SDL_CONTROLLER_BUTTON_A); \
|
|
case MINECRAFT_ACTION_FORWARD: \
|
|
return KFN(SDL_SCANCODE_W) || AFN(SDL_CONTROLLER_AXIS_LEFTY); \
|
|
case MINECRAFT_ACTION_BACKWARD: \
|
|
return KFN(SDL_SCANCODE_S) || AFN(SDL_CONTROLLER_AXIS_LEFTY); \
|
|
case MINECRAFT_ACTION_LEFT: \
|
|
return KFN(SDL_SCANCODE_A) || AFN(SDL_CONTROLLER_AXIS_LEFTX); \
|
|
case MINECRAFT_ACTION_RIGHT: \
|
|
return KFN(SDL_SCANCODE_D) || AFN(SDL_CONTROLLER_AXIS_LEFTX); \
|
|
case MINECRAFT_ACTION_INVENTORY: \
|
|
return KFN(SDL_SCANCODE_E) || CFN(SDL_CONTROLLER_BUTTON_Y); \
|
|
case MINECRAFT_ACTION_PAUSEMENU: \
|
|
return KFN(SDL_SCANCODE_ESCAPE) || CFN(SDL_CONTROLLER_BUTTON_START); \
|
|
case MINECRAFT_ACTION_DROP: \
|
|
return KFN(SDL_SCANCODE_Q) || CFN(SDL_CONTROLLER_BUTTON_B); \
|
|
case MINECRAFT_ACTION_CRAFTING: \
|
|
return KFN(SDL_SCANCODE_C) || CFN(SDL_CONTROLLER_BUTTON_X); \
|
|
case MINECRAFT_ACTION_RENDER_THIRD_PERSON: \
|
|
return KFN(SDL_SCANCODE_F5) || CFN(SDL_CONTROLLER_BUTTON_LEFTSTICK); \
|
|
case MINECRAFT_ACTION_GAME_INFO: \
|
|
return KFN(SDL_SCANCODE_F3); \
|
|
case MINECRAFT_ACTION_DPAD_LEFT: \
|
|
return KFN(SDL_SCANCODE_LEFT) || CFN(SDL_CONTROLLER_BUTTON_DPAD_LEFT); \
|
|
case MINECRAFT_ACTION_DPAD_RIGHT: \
|
|
return KFN(SDL_SCANCODE_RIGHT) || \
|
|
CFN(SDL_CONTROLLER_BUTTON_DPAD_RIGHT); \
|
|
case MINECRAFT_ACTION_DPAD_UP: \
|
|
return KFN(SDL_SCANCODE_UP) || CFN(SDL_CONTROLLER_BUTTON_DPAD_UP); \
|
|
case MINECRAFT_ACTION_DPAD_DOWN: \
|
|
return KFN(SDL_SCANCODE_DOWN) || CFN(SDL_CONTROLLER_BUTTON_DPAD_DOWN); \
|
|
default: \
|
|
return false;
|
|
|
|
bool C_4JInput::ButtonDown(int iPad, unsigned char ucAction) {
|
|
if (iPad != 0) return false;
|
|
if (s_keyboardActive) return false;
|
|
if (ucAction == 255) {
|
|
for (int i = 0; i < s_watchedKeyCount; ++i)
|
|
if (s_keysCurrent[s_watchedKeys[i]]) return true;
|
|
return s_mouseLeftCurrent || s_mouseRightCurrent;
|
|
}
|
|
switch (ucAction) {
|
|
case MINECRAFT_ACTION_ACTION:
|
|
return MouseLDown() || KDown(SDL_SCANCODE_RETURN) ||
|
|
ADown(SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
|
|
case MINECRAFT_ACTION_USE:
|
|
return MouseRDown() || KDown(SDL_SCANCODE_F) ||
|
|
ADown(SDL_CONTROLLER_AXIS_TRIGGERLEFT);
|
|
case MINECRAFT_ACTION_SNEAK_TOGGLE:
|
|
return KDown(SDL_SCANCODE_LSHIFT) || KDown(SDL_SCANCODE_RSHIFT) ||
|
|
CDown(SDL_CONTROLLER_BUTTON_RIGHTSTICK);
|
|
case MINECRAFT_ACTION_SPRINT:
|
|
return KDown(SDL_SCANCODE_LCTRL) || KDown(SDL_SCANCODE_RCTRL);
|
|
case MINECRAFT_ACTION_LEFT_SCROLL:
|
|
case ACTION_MENU_LEFT_SCROLL:
|
|
return ScrollSnap() > 0;
|
|
case MINECRAFT_ACTION_RIGHT_SCROLL:
|
|
case ACTION_MENU_RIGHT_SCROLL:
|
|
return ScrollSnap() < 0;
|
|
ACTION_CASES(KDown, CDown, ADown)
|
|
}
|
|
}
|
|
// The part that handles completing the action of pressing a button.
|
|
bool C_4JInput::ButtonPressed(int iPad, unsigned char ucAction) {
|
|
if (iPad != 0 || ucAction == 255) return false;
|
|
if (s_keyboardActive) return false;
|
|
switch (ucAction) {
|
|
case MINECRAFT_ACTION_ACTION:
|
|
return MouseLPressed() || KPressed(SDL_SCANCODE_RETURN) ||
|
|
APressed(SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
|
|
case MINECRAFT_ACTION_USE:
|
|
return MouseRPressed() || KPressed(SDL_SCANCODE_F) ||
|
|
APressed(SDL_CONTROLLER_AXIS_TRIGGERLEFT);
|
|
case MINECRAFT_ACTION_SNEAK_TOGGLE:
|
|
return KPressed(SDL_SCANCODE_LSHIFT) ||
|
|
KPressed(SDL_SCANCODE_RSHIFT) ||
|
|
CPressed(SDL_CONTROLLER_BUTTON_RIGHTSTICK);
|
|
case MINECRAFT_ACTION_SPRINT:
|
|
return KPressed(SDL_SCANCODE_LCTRL) || KPressed(SDL_SCANCODE_RCTRL);
|
|
case MINECRAFT_ACTION_LEFT_SCROLL:
|
|
case ACTION_MENU_LEFT_SCROLL:
|
|
return ScrollSnap() > 0;
|
|
case MINECRAFT_ACTION_RIGHT_SCROLL:
|
|
case ACTION_MENU_RIGHT_SCROLL:
|
|
return ScrollSnap() < 0;
|
|
ACTION_CASES(KPressed, CPressed, APressed)
|
|
}
|
|
}
|
|
// The part that handles Releasing a button.
|
|
bool C_4JInput::ButtonReleased(int iPad, unsigned char ucAction) {
|
|
if (iPad != 0 || ucAction == 255) return false;
|
|
if (s_keyboardActive) return false;
|
|
switch (ucAction) {
|
|
case MINECRAFT_ACTION_ACTION:
|
|
return MouseLReleased() || KReleased(SDL_SCANCODE_RETURN) ||
|
|
AReleased(SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
|
|
case MINECRAFT_ACTION_USE:
|
|
return MouseRReleased() || KReleased(SDL_SCANCODE_F) ||
|
|
AReleased(SDL_CONTROLLER_AXIS_TRIGGERLEFT);
|
|
case MINECRAFT_ACTION_SNEAK_TOGGLE:
|
|
return KReleased(SDL_SCANCODE_LSHIFT) ||
|
|
KReleased(SDL_SCANCODE_RSHIFT) ||
|
|
CReleased(SDL_CONTROLLER_BUTTON_RIGHTSTICK);
|
|
case MINECRAFT_ACTION_SPRINT:
|
|
KReleased(SDL_SCANCODE_LCTRL) || KReleased(SDL_SCANCODE_RCTRL);
|
|
case MINECRAFT_ACTION_LEFT_SCROLL:
|
|
case ACTION_MENU_LEFT_SCROLL:
|
|
case MINECRAFT_ACTION_RIGHT_SCROLL:
|
|
case ACTION_MENU_RIGHT_SCROLL:
|
|
return false;
|
|
ACTION_CASES(KReleased, CReleased, AReleased)
|
|
}
|
|
}
|
|
|
|
unsigned int C_4JInput::GetValue(int iPad, unsigned char ucAction, bool) {
|
|
if (iPad != 0) return 0;
|
|
if (ucAction == MINECRAFT_ACTION_LEFT_SCROLL) {
|
|
if (s_scrollTicksForGetValue > 0) {
|
|
unsigned int v = (unsigned int)s_scrollTicksForGetValue;
|
|
s_scrollTicksForGetValue = 0;
|
|
return v;
|
|
}
|
|
return 0u;
|
|
}
|
|
if (ucAction == MINECRAFT_ACTION_RIGHT_SCROLL) {
|
|
if (s_scrollTicksForGetValue < 0) {
|
|
unsigned int v = (unsigned int)(-s_scrollTicksForGetValue);
|
|
s_scrollTicksForGetValue = 0;
|
|
return v;
|
|
}
|
|
return 0u;
|
|
}
|
|
return ButtonDown(iPad, ucAction) ? 1u : 0u;
|
|
}
|
|
// Left stick movement, the one that moves the player around or selects menu
|
|
// options. (Soon be tested.)
|
|
float C_4JInput::GetJoypadStick_LX(int, bool) {
|
|
if (ADown(SDL_CONTROLLER_AXIS_LEFTX))
|
|
return axisVal[SDL_CONTROLLER_AXIS_LEFTX];
|
|
return (KDown(SDL_SCANCODE_D) ? 1.f : 0.f) -
|
|
(KDown(SDL_SCANCODE_A) ? 1.f : 0.f);
|
|
}
|
|
float C_4JInput::GetJoypadStick_LY(int, bool) {
|
|
if (ADown(SDL_CONTROLLER_AXIS_LEFTY))
|
|
return -axisVal[SDL_CONTROLLER_AXIS_LEFTY];
|
|
return (KDown(SDL_SCANCODE_W) ? 1.f : 0.f) -
|
|
(KDown(SDL_SCANCODE_S) ? 1.f : 0.f);
|
|
}
|
|
// We use mouse movement and convert it into a Right Stick output using
|
|
// logarithmic scaling This is the most important mouse part. Yet it's so small.
|
|
static float MouseAxis(float raw) {
|
|
if (fabsf(raw) < 0.0001f) return 0.f; // from 4j previous code
|
|
return (raw >= 0.f ? 1.f : -1.f) * sqrtf(fabsf(raw));
|
|
}
|
|
// We apply the Stick movement on the R(Right) X(2D Position)
|
|
float C_4JInput::GetJoypadStick_RX(int, bool) {
|
|
if (ADown(SDL_CONTROLLER_AXIS_RIGHTX))
|
|
return axisVal[SDL_CONTROLLER_AXIS_RIGHTX];
|
|
if (!SDL_GetRelativeMouseMode()) return 0.f;
|
|
TakeSnapIfNeeded();
|
|
return MouseAxis(s_snapRelX * MOUSE_SCALE);
|
|
}
|
|
// Bis. but with Y(2D Position)
|
|
float C_4JInput::GetJoypadStick_RY(int, bool) {
|
|
if (ADown(SDL_CONTROLLER_AXIS_RIGHTY))
|
|
return -axisVal[SDL_CONTROLLER_AXIS_RIGHTY];
|
|
if (!SDL_GetRelativeMouseMode()) return 0.f;
|
|
TakeSnapIfNeeded();
|
|
return MouseAxis(-s_snapRelY * MOUSE_SCALE);
|
|
}
|
|
|
|
unsigned char C_4JInput::GetJoypadLTrigger(int, bool) {
|
|
return (s_mouseRightCurrent ||
|
|
s_axisCurrent[SDL_CONTROLLER_AXIS_TRIGGERLEFT])
|
|
? 255
|
|
: 0;
|
|
}
|
|
unsigned char C_4JInput::GetJoypadRTrigger(int, bool) {
|
|
return (s_mouseLeftCurrent ||
|
|
s_axisCurrent[SDL_CONTROLLER_AXIS_TRIGGERRIGHT])
|
|
? 255
|
|
: 0;
|
|
}
|
|
|
|
int C_4JInput::GetMouseX() { return s_mouseX; }
|
|
int C_4JInput::GetMouseY() { return s_mouseY; }
|
|
|
|
// We detect if a Menu is visible on the player's screen to the mouse being
|
|
// stuck.
|
|
void C_4JInput::SetMenuDisplayed(int iPad, bool bVal) {
|
|
if (iPad >= 0 && iPad < 4) s_menuDisplayed[iPad] = bVal;
|
|
if (!s_sdlInitialized || bVal == s_prevMenuDisplayed) return;
|
|
SDL_SetRelativeMouseMode(bVal ? SDL_FALSE : SDL_TRUE);
|
|
s_prevMenuDisplayed = bVal;
|
|
}
|
|
|
|
int C_4JInput::GetScrollDelta() {
|
|
int v = s_scrollTicksForButtonPressed;
|
|
s_scrollTicksForButtonPressed = 0;
|
|
return v;
|
|
}
|
|
|
|
void C_4JInput::SetDeadzoneAndMovementRange(unsigned int, unsigned int) {}
|
|
void C_4JInput::SetGameJoypadMaps(unsigned char, unsigned char, unsigned int) {}
|
|
unsigned int C_4JInput::GetGameJoypadMaps(unsigned char, unsigned char) {
|
|
return 0;
|
|
}
|
|
void C_4JInput::SetJoypadMapVal(int, unsigned char) {}
|
|
unsigned char C_4JInput::GetJoypadMapVal(int) { return 0; }
|
|
void C_4JInput::SetJoypadSensitivity(int, float) {}
|
|
void C_4JInput::SetJoypadStickAxisMap(int, unsigned int, unsigned int) {}
|
|
void C_4JInput::SetJoypadStickTriggerMap(int, unsigned int, unsigned int) {}
|
|
void C_4JInput::SetKeyRepeatRate(float, float) {}
|
|
void C_4JInput::SetDebugSequence(const char*, int (*)(void*), void*) {}
|
|
float C_4JInput::GetIdleSeconds(int) { return 0.f; }
|
|
bool C_4JInput::IsPadConnected(int iPad) { return iPad == 0; }
|
|
|
|
EKeyboardResult C_4JInput::RequestKeyboard(const wchar_t*, const wchar_t*, int,
|
|
unsigned int,
|
|
int (*callback)(void*, const bool),
|
|
void* scene,
|
|
C_4JInput::EKeyboardMode) {
|
|
s_keyboardActive = true;
|
|
s_textInputBuf.clear();
|
|
s_keyboardCallback = callback;
|
|
s_keyboardCallbackParam = scene;
|
|
SDL_StartTextInput();
|
|
return EKeyboard_Pending;
|
|
}
|
|
bool C_4JInput::GetMenuDisplayed(int iPad) {
|
|
if (iPad >= 0 && iPad < 4) return s_menuDisplayed[iPad];
|
|
return false;
|
|
}
|
|
const char* C_4JInput::GetText() { return s_textInputBuf.c_str(); }
|
|
bool C_4JInput::VerifyStrings(wchar_t**, int,
|
|
int (*)(void*, STRING_VERIFY_RESPONSE*), void*) {
|
|
return true;
|
|
}
|
|
void C_4JInput::CancelQueuedVerifyStrings(int (*)(void*,
|
|
STRING_VERIFY_RESPONSE*),
|
|
void*) {}
|
|
void C_4JInput::CancelAllVerifyInProgress() {}
|
|
|
|
// Primary pad (moved from Profile)
|
|
namespace {
|
|
int s_inputPrimaryPad = 0;
|
|
}
|
|
int C_4JInput::GetPrimaryPad() { return s_inputPrimaryPad; }
|
|
void C_4JInput::SetPrimaryPad(int iPad) { s_inputPrimaryPad = iPad; }
|