Accept scancodes with Input.press?/Input.trigger?/Input.repeat?

This commit is contained in:
Inori 2019-09-18 22:50:28 -04:00 committed by Inori
parent 374891a82c
commit bfa60cc065
4 changed files with 360 additions and 85 deletions

View file

@ -116,7 +116,7 @@ To smooth over cross-platform compatibility, functionality that you won't find i
### Input ### 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 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`. * 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`.

View file

@ -25,6 +25,7 @@
#include "binding-util.h" #include "binding-util.h"
#include "util.h" #include "util.h"
#include <string>
#include <SDL_joystick.h> #include <SDL_joystick.h>
RB_METHOD(inputUpdate) RB_METHOD(inputUpdate)
@ -36,23 +37,21 @@ RB_METHOD(inputUpdate)
return Qnil; return Qnil;
} }
static int getButtonArg(int argc, VALUE *argv) static int getButtonArg(VALUE *argv)
{ {
int num; int num;
rb_check_argc(argc, 1); if (FIXNUM_P(*argv))
if (FIXNUM_P(argv[0]))
{ {
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; VALUE symHash = getRbData()->buttoncodeHash;
#ifndef OLD_RUBY #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 #else
VALUE res = rb_hash_aref(symHash, argv[0]); VALUE res = rb_hash_aref(symHash, *argv);
if (!NIL_P(res)) if (!NIL_P(res))
num = FIX2INT(res); num = FIX2INT(res);
else else
@ -69,11 +68,40 @@ static int getButtonArg(int argc, VALUE *argv)
return num; 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_METHOD(inputPress)
{ {
RB_UNUSED_PARAM; 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)); return rb_bool_new(shState->input().isPressed(num));
} }
@ -82,7 +110,20 @@ RB_METHOD(inputTrigger)
{ {
RB_UNUSED_PARAM; 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().isTriggeredEx(num, 0));
}
num = getButtonArg(&button);
return rb_bool_new(shState->input().isTriggered(num)); return rb_bool_new(shState->input().isTriggered(num));
} }
@ -91,7 +132,20 @@ RB_METHOD(inputRepeat)
{ {
RB_UNUSED_PARAM; 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)); return rb_bool_new(shState->input().isRepeated(num));
} }
@ -103,7 +157,7 @@ RB_METHOD(inputPressEx)
int num; int num;
rb_get_args(argc, argv, "i", &num RB_ARG_END); 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) RB_METHOD(inputTriggerEx)
@ -113,7 +167,7 @@ RB_METHOD(inputTriggerEx)
int num; int num;
rb_get_args(argc, argv, "i", &num RB_ARG_END); 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) RB_METHOD(inputRepeatEx)
@ -123,7 +177,7 @@ RB_METHOD(inputRepeatEx)
int num; int num;
rb_get_args(argc, argv, "i", &num RB_ARG_END); 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) RB_METHOD(inputDir4)

View file

@ -32,16 +32,14 @@
#include <SDL_clipboard.h> #include <SDL_clipboard.h>
#include <vector> #include <vector>
#include <map> #include <unordered_map>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#define BUTTON_CODE_COUNT 24 #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 } #define m(vk,sc) { vk, SDL_SCANCODE_##sc }
std::map<int, int> vKeyToScancode{ std::unordered_map<int, int> vKeyToScancode{
// 0x01 LEFT MOUSE // 0x01 LEFT MOUSE
// 0x02 RIGHT MOUSE // 0x02 RIGHT MOUSE
m(0x03, CANCEL), m(0x03, CANCEL),
@ -201,6 +199,225 @@ std::map<int, int> vKeyToScancode{
// 0xfd PA1 // 0xfd PA1
m(0xfe, CLEAR) m(0xfe, CLEAR)
}; };
#undef m
#define m(keycode) { #keycode, SDL_SCANCODE_##keycode }
std::unordered_map<std::string, int> 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 #undef m
struct ButtonState struct ButtonState
@ -522,11 +739,12 @@ struct InputPrivate
return statesOld[mapToIndex[code]]; return statesOld[mapToIndex[code]];
} }
inline ButtonState getStateRaw(int code) inline ButtonState getStateRaw(int code, bool useVKey)
{ {
ButtonState b; ButtonState b;
int scancode = -1; int scancode = (useVKey) ? -1 : code;
if (scancode < 0)
{
switch (code) switch (code)
{ {
case 0x10: case 0x10:
@ -561,6 +779,9 @@ struct InputPrivate
} }
catch (...) {} catch (...) {}
if (scancode == -1) return b; if (scancode == -1) return b;
break;
}
}
b.pressed = rawStates[scancode]; b.pressed = rawStates[scancode];
b.triggered = (rawStates[scancode] && !rawStatesOld[scancode]); b.triggered = (rawStates[scancode] && !rawStatesOld[scancode]);
@ -576,8 +797,6 @@ struct InputPrivate
b.repeated = repeated; b.repeated = repeated;
return b; return b;
break;
}
} }
void swapBuffers() void swapBuffers()
@ -920,19 +1139,19 @@ bool Input::isRepeated(int button)
return p->getStateCheck(button).repeated; 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() int Input::dir4Value()

View file

@ -22,9 +22,11 @@
#ifndef INPUT_H #ifndef INPUT_H
#define INPUT_H #define INPUT_H
#include <map> #include <unordered_map>
#include <string>
extern std::map<int, int> vKeyToScancode; extern std::unordered_map<int, int> vKeyToScancode;
extern std::unordered_map<std::string, int> strToScancode;
struct InputPrivate; struct InputPrivate;
struct RGSSThreadData; struct RGSSThreadData;
@ -55,9 +57,9 @@ public:
bool isPressed(int button); bool isPressed(int button);
bool isTriggered(int button); bool isTriggered(int button);
bool isRepeated(int button); bool isRepeated(int button);
bool isPressedEx(int vKey); bool isPressedEx(int code, bool isVKey);
bool isTriggeredEx(int vKey); bool isTriggeredEx(int code, bool isVKey);
bool isRepeatedEx(int vKey); bool isRepeatedEx(int code, bool isVKey);
int dir4Value(); int dir4Value();
int dir8Value(); int dir8Value();