From bfa60cc065c71b39c19fade43499d8d3392ca4ee Mon Sep 17 00:00:00 2001 From: Inori Date: Wed, 18 Sep 2019 22:50:28 -0400 Subject: [PATCH] Accept scancodes with Input.press?/Input.trigger?/Input.repeat? --- README.md | 2 +- binding/input-binding.cpp | 88 ++++++++-- src/input.cpp | 343 +++++++++++++++++++++++++++++++------- src/input.h | 12 +- 4 files changed, 360 insertions(+), 85 deletions(-) diff --git a/README.md b/README.md index 176d9831..2b0eacf5 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ To smooth over cross-platform compatibility, functionality that you won't find i ### Input -* The `Input.press?` family of functions accepts three additional button constants: `::MOUSELEFT`, `::MOUSEMIDDLE` and `::MOUSERIGHT` for the respective mouse buttons. +* The `Input.press?` family of functions accepts three additional button constants: `::MOUSELEFT`, `::MOUSEMIDDLE` and `::MOUSERIGHT` for the respective mouse buttons. It will now also accept [SDL scancodes](https://wiki.libsdl.org/SDL_Scancode?highlight=%28%5CbCategoryEnum%5Cb%29%7C%28CategoryKeyboard%29) in the form of symbols corresponding to each scancode (e.g. `SDL_SCANCODE_RETURN` would be requested through `Input.press? :RETURN`) * The `Input` module has two additional properties: `text_input` determines whether to accept text editing events. `clipboard` gets and sets the user's clipboard. * The `Input` module has seven additional functions, `#mouse_x` and `#mouse_y` to query the mouse pointer position relative to the game screen. `#pressex?`, `#triggerex?` and `#repeatex?` provide input states for raw key codes, which are provided in the form of [Microsoft Virtual-Key Codes](https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes). Only buttons which are also [tracked by SDL](https://wiki.libsdl.org/SDL_Scancode) are supported. `#gets` returns a UTF-8 string of any text that was input by the user since the last time `#gets` was called. The `text_input` property must be set to true for it to work. `#joystick` returns (if a joystick is connected) a hash containing the `:name` and `:power` entries, or `nil` if there is not a joystick connected. `:name` is a string corresponding to the joystick's name, and `:power` can be any from: `:MAX`, `:WIRED`, `:FULL`, `:MEDIUM`, `:LOW`, `:EMPTY`, and `:UNKNOWN`. diff --git a/binding/input-binding.cpp b/binding/input-binding.cpp index 044cdef9..1d0f5ce4 100644 --- a/binding/input-binding.cpp +++ b/binding/input-binding.cpp @@ -25,6 +25,7 @@ #include "binding-util.h" #include "util.h" +#include #include RB_METHOD(inputUpdate) @@ -36,23 +37,21 @@ RB_METHOD(inputUpdate) return Qnil; } -static int getButtonArg(int argc, VALUE *argv) +static int getButtonArg(VALUE *argv) { int num; - - rb_check_argc(argc, 1); - - if (FIXNUM_P(argv[0])) + + if (FIXNUM_P(*argv)) { - num = FIX2INT(argv[0]); + num = FIX2INT(*argv); } - else if (SYMBOL_P(argv[0]) && rgssVer >= 3) + else if (SYMBOL_P(*argv) && rgssVer >= 3) { VALUE symHash = getRbData()->buttoncodeHash; #ifndef OLD_RUBY - num = FIX2INT(rb_hash_lookup2(symHash, argv[0], INT2FIX(Input::None))); + num = FIX2INT(rb_hash_lookup2(symHash, *argv, INT2FIX(Input::None))); #else - VALUE res = rb_hash_aref(symHash, argv[0]); + VALUE res = rb_hash_aref(symHash, *argv); if (!NIL_P(res)) num = FIX2INT(res); else @@ -69,11 +68,40 @@ static int getButtonArg(int argc, VALUE *argv) return num; } +static int getScancodeArg(VALUE *argv) +{ + const char *scancode = rb_id2name(SYM2ID(argv)); + int code{}; + try + { + code = strToScancode[scancode]; + } + catch (...) + { + rb_raise(rb_eRuntimeError, "%s is not a valid key.", scancode); + } + + return rb_bool_new(shState->input().isPressedEx(code, 0)); +} + RB_METHOD(inputPress) { RB_UNUSED_PARAM; - - int num = getButtonArg(argc, argv); + + rb_check_argc(argc, 1); + + VALUE button; + rb_scan_args(argc, argv, "1", &button); + + int num{}; + + if (SYMBOL_P(button)) + { + num = getScancodeArg(&button); + return rb_bool_new(shState->input().isPressedEx(num, 0)); + } + + num = getButtonArg(&button); return rb_bool_new(shState->input().isPressed(num)); } @@ -81,8 +109,21 @@ RB_METHOD(inputPress) RB_METHOD(inputTrigger) { RB_UNUSED_PARAM; + + rb_check_argc(argc, 1); - int num = getButtonArg(argc, argv); + VALUE button; + rb_scan_args(argc, argv, "1", &button); + + int num{}; + + if (SYMBOL_P(button)) + { + num = getScancodeArg(&button); + return rb_bool_new(shState->input().isTriggeredEx(num, 0)); + } + + num = getButtonArg(&button); return rb_bool_new(shState->input().isTriggered(num)); } @@ -90,8 +131,21 @@ RB_METHOD(inputTrigger) RB_METHOD(inputRepeat) { RB_UNUSED_PARAM; - - int num = getButtonArg(argc, argv); + + rb_check_argc(argc, 1); + + VALUE button; + rb_scan_args(argc, argv, "1", &button); + + int num{}; + + if (SYMBOL_P(button)) + { + num = getScancodeArg(&button); + return rb_bool_new(shState->input().isRepeatedEx(num, 0)); + } + + num = getButtonArg(&button); return rb_bool_new(shState->input().isRepeated(num)); } @@ -103,7 +157,7 @@ RB_METHOD(inputPressEx) int num; rb_get_args(argc, argv, "i", &num RB_ARG_END); - return rb_bool_new(shState->input().isPressedEx(num)); + return rb_bool_new(shState->input().isPressedEx(num, 1)); } RB_METHOD(inputTriggerEx) @@ -113,7 +167,7 @@ RB_METHOD(inputTriggerEx) int num; rb_get_args(argc, argv, "i", &num RB_ARG_END); - return rb_bool_new(shState->input().isTriggeredEx(num)); + return rb_bool_new(shState->input().isTriggeredEx(num, 1)); } RB_METHOD(inputRepeatEx) @@ -123,7 +177,7 @@ RB_METHOD(inputRepeatEx) int num; rb_get_args(argc, argv, "i", &num RB_ARG_END); - return rb_bool_new(shState->input().isRepeatedEx(num)); + return rb_bool_new(shState->input().isRepeatedEx(num, 1)); } RB_METHOD(inputDir4) diff --git a/src/input.cpp b/src/input.cpp index 42306839..21c13d69 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -32,16 +32,14 @@ #include #include -#include +#include #include #include #define BUTTON_CODE_COUNT 24 -// Map of Windows virtualkey codes to SDL scancodes. -// Used for pressex, triggerex and repeatex #define m(vk,sc) { vk, SDL_SCANCODE_##sc } -std::map vKeyToScancode{ +std::unordered_map vKeyToScancode{ // 0x01 LEFT MOUSE // 0x02 RIGHT MOUSE m(0x03, CANCEL), @@ -201,6 +199,225 @@ std::map vKeyToScancode{ // 0xfd PA1 m(0xfe, CLEAR) }; +#undef m +#define m(keycode) { #keycode, SDL_SCANCODE_##keycode } +std::unordered_map strToScancode{ + m(0), m(1), + m(2), m(3), + m(4), m(5), + m(6), m(7), + m(8), m(9), + m(A), + m(AC_BACK), + m(AC_BOOKMARKS), + m(AC_FORWARD), + m(AC_HOME), + m(AC_REFRESH), + m(AC_SEARCH), + m(AC_STOP), + m(AGAIN), + m(ALTERASE), + m(APOSTROPHE), + m(APPLICATION), + m(AUDIOMUTE), + m(AUDIONEXT), + m(AUDIOPLAY), + m(AUDIOPREV), + m(AUDIOSTOP), + m(B), + m(BACKSLASH), + m(BACKSPACE), + m(BRIGHTNESSDOWN), + m(BRIGHTNESSUP), + m(C), + m(CALCULATOR), + m(CANCEL), + m(CAPSLOCK), + m(CLEAR), + m(CLEARAGAIN), + m(COMMA), + m(COMPUTER), + m(COPY), + m(CRSEL), + m(CURRENCYSUBUNIT), + m(CURRENCYUNIT), + m(CUT), + m(D), + m(DECIMALSEPARATOR), + m(DELETE), + m(DISPLAYSWITCH), + m(DOWN), + m(E), + m(EJECT), + m(END), + m(EQUALS), + m(ESCAPE), + m(EXECUTE), + m(EXSEL), + m(F), + m(F1), m(F2), + m(F3), m(F4), + m(F5), m(F6), + m(F7), m(F8), + m(F9), m(F10), + m(F11), m(F12), + m(F13), m(F14), + m(F15), m(F16), + m(F17), m(F18), + m(F19), m(F20), + m(F21), m(F22), + m(F23), m(F24), + m(FIND), + m(G), + m(GRAVE), + m(H), + m(HELP), + m(HOME), + m(I), + m(INSERT), + m(J), + m(K), + m(KBDILLUMDOWN), + m(KBDILLUMTOGGLE), + m(KBDILLUMUP), + m(KP_0), + m(KP_00), + m(KP_000), + m(KP_1), m(KP_2), + m(KP_3), m(KP_4), + m(KP_5), m(KP_6), + m(KP_7), m(KP_8), + m(KP_9), + m(KP_A), + m(KP_AMPERSAND), + m(KP_AT), + m(KP_B), + m(KP_BACKSPACE), + m(KP_BINARY), + m(KP_C), + m(KP_CLEAR), + m(KP_CLEARENTRY), + m(KP_COLON), + m(KP_COMMA), + m(KP_D), + m(KP_DBLAMPERSAND), + m(KP_DBLVERTICALBAR), + m(KP_DECIMAL), + m(KP_DIVIDE), + m(KP_E), + m(KP_ENTER), + m(KP_EQUALS), + m(KP_EQUALSAS400), + m(KP_EXCLAM), + m(KP_F), + m(KP_GREATER), + m(KP_HASH), + m(KP_HEXADECIMAL), + m(KP_LEFTBRACE), + m(KP_LEFTPAREN), + m(KP_LESS), + m(KP_MEMADD), + m(KP_MEMCLEAR), + m(KP_MEMDIVIDE), + m(KP_MEMMULTIPLY), + m(KP_MEMRECALL), + m(KP_MEMSTORE), + m(KP_MEMSUBTRACT), + m(KP_MINUS), + m(KP_MULTIPLY), + m(KP_OCTAL), + m(KP_PERCENT), + m(KP_PERIOD), + m(KP_PLUS), + m(KP_PLUSMINUS), + m(KP_POWER), + m(KP_RIGHTBRACE), + m(KP_RIGHTPAREN), + m(KP_SPACE), + m(KP_TAB), + m(KP_VERTICALBAR), + m(KP_XOR), + m(L), + m(LALT), + m(LCTRL), + m(LEFT), + m(LEFTBRACKET), + m(LGUI), + m(LSHIFT), + m(M), + m(MAIL), + m(MEDIASELECT), + m(MENU), + m(MINUS), + m(MODE), + m(MUTE), + m(N), + m(NUMLOCKCLEAR), + m(O), + m(OPER), + m(OUT), + m(P), + m(PAGEDOWN), + m(PAGEUP), + m(PASTE), + m(PAUSE), + m(PERIOD), + m(POWER), + m(PRINTSCREEN), + m(PRIOR), + m(Q), + m(R), + m(RALT), + m(RCTRL), + m(RETURN), + m(RETURN2), + m(RGUI), + m(RIGHT), + m(RIGHTBRACKET), + m(RSHIFT), + m(S), + m(SCROLLLOCK), + m(SELECT), + m(SEMICOLON), + m(SEPARATOR), + m(SLASH), + m(SLEEP), + m(SPACE), + m(STOP), + m(SYSREQ), + m(T), + m(TAB), + m(THOUSANDSSEPARATOR), + m(U), + m(UNDO), + m(UNKNOWN), + m(UP), + m(V), + m(VOLUMEDOWN), + m(VOLUMEUP), + m(W), + m(WWW), + m(X), + m(Y), + m(Z), + m(INTERNATIONAL1), + m(INTERNATIONAL2), + m(INTERNATIONAL3), + m(INTERNATIONAL4), + m(INTERNATIONAL5), + m(INTERNATIONAL6), + m(INTERNATIONAL7), + m(INTERNATIONAL8), + m(INTERNATIONAL9), + m(LANG1), m(LANG2), + m(LANG3), m(LANG4), + m(LANG5), m(LANG6), + m(LANG7), m(LANG8), + m(LANG9), + m(NONUSBACKSLASH), + m(NONUSHASH) +}; + #undef m struct ButtonState @@ -522,62 +739,64 @@ struct InputPrivate return statesOld[mapToIndex[code]]; } - inline ButtonState getStateRaw(int code) + inline ButtonState getStateRaw(int code, bool useVKey) { ButtonState b; - int scancode = -1; - - switch (code) + int scancode = (useVKey) ? -1 : code; + if (scancode < 0) { - case 0x10: - return getState(Input::Shift); - break; - - case 0x11: - return getState(Input::Ctrl); - break; - - case 0x12: - return getState(Input::Alt); - break; - - case 0x1: - return getState(Input::MouseLeft); - break; - - case 0x2: - return getState(Input::MouseRight); - break; - - case 0x4: - return getState(Input::MouseMiddle); - break; - - default: - ButtonState b; - try - { - scancode = vKeyToScancode[code]; - } - catch (...) {} - if (scancode == -1) return b; - - b.pressed = rawStates[scancode]; - b.triggered = (rawStates[scancode] && !rawStatesOld[scancode]); - - bool repeated = false; - if (scancode == rawRepeating) - { - if (rgssVer >= 2) - repeated = rawRepeatCount >= 23 && ((rawRepeatCount+1) % 6) == 0; - else - repeated = rawRepeatCount >= 15 && ((rawRepeatCount+1) % 4) == 0; - } - b.repeated = repeated; - - return b; - break; + switch (code) + { + case 0x10: + return getState(Input::Shift); + break; + + case 0x11: + return getState(Input::Ctrl); + break; + + case 0x12: + return getState(Input::Alt); + break; + + case 0x1: + return getState(Input::MouseLeft); + break; + + case 0x2: + return getState(Input::MouseRight); + break; + + case 0x4: + return getState(Input::MouseMiddle); + break; + + default: + ButtonState b; + try + { + scancode = vKeyToScancode[code]; + } + catch (...) {} + if (scancode == -1) return b; + break; + } } + + b.pressed = rawStates[scancode]; + b.triggered = (rawStates[scancode] && !rawStatesOld[scancode]); + + bool repeated = false; + if (scancode == rawRepeating) + { + if (rgssVer >= 2) + repeated = rawRepeatCount >= 23 && ((rawRepeatCount+1) % 6) == 0; + else + repeated = rawRepeatCount >= 15 && ((rawRepeatCount+1) % 4) == 0; + } + b.repeated = repeated; + + return b; } void swapBuffers() @@ -920,19 +1139,19 @@ bool Input::isRepeated(int button) return p->getStateCheck(button).repeated; } -bool Input::isPressedEx(int vKey) +bool Input::isPressedEx(int code, bool isVKey) { - return p->getStateRaw(vKey).pressed; + return p->getStateRaw(code, isVKey).pressed; } -bool Input::isTriggeredEx(int vKey) +bool Input::isTriggeredEx(int code, bool isVKey) { - return p->getStateRaw(vKey).triggered; + return p->getStateRaw(code, isVKey).triggered; } -bool Input::isRepeatedEx(int vKey) +bool Input::isRepeatedEx(int code, bool isVKey) { - return p->getStateRaw(vKey).repeated; + return p->getStateRaw(code, isVKey).repeated; } int Input::dir4Value() diff --git a/src/input.h b/src/input.h index 65762628..33f12356 100644 --- a/src/input.h +++ b/src/input.h @@ -22,9 +22,11 @@ #ifndef INPUT_H #define INPUT_H -#include +#include +#include -extern std::map vKeyToScancode; +extern std::unordered_map vKeyToScancode; +extern std::unordered_map strToScancode; struct InputPrivate; struct RGSSThreadData; @@ -55,9 +57,9 @@ public: bool isPressed(int button); bool isTriggered(int button); bool isRepeated(int button); - bool isPressedEx(int vKey); - bool isTriggeredEx(int vKey); - bool isRepeatedEx(int vKey); + bool isPressedEx(int code, bool isVKey); + bool isTriggeredEx(int code, bool isVKey); + bool isRepeatedEx(int code, bool isVKey); int dir4Value(); int dir8Value();