From 4773ae55076b402646c00a4d8e98aa5daf81d76c Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Wed, 31 May 2023 22:07:40 +0300 Subject: [PATCH] Add keyboard opcodes --- CMakeLists.txt | 2 + src/sfall_kb_helpers.cc | 291 ++++++++++++++++++++++++++++++++++++++++ src/sfall_kb_helpers.h | 10 ++ src/sfall_opcodes.cc | 15 ++- 4 files changed, 314 insertions(+), 4 deletions(-) create mode 100644 src/sfall_kb_helpers.cc create mode 100644 src/sfall_kb_helpers.h diff --git a/CMakeLists.txt b/CMakeLists.txt index cd91dbd..4c6c918 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -271,6 +271,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC "src/sfall_global_scripts.h" "src/sfall_ini.cc" "src/sfall_ini.h" + "src/sfall_kb_helpers.cc" + "src/sfall_kb_helpers.h" "src/sfall_lists.cc" "src/sfall_lists.h" "src/sfall_opcodes.cc" diff --git a/src/sfall_kb_helpers.cc b/src/sfall_kb_helpers.cc new file mode 100644 index 0000000..3331833 --- /dev/null +++ b/src/sfall_kb_helpers.cc @@ -0,0 +1,291 @@ +#include "sfall_kb_helpers.h" + +#include + +/// Maps DirectInput DIK constants to SDL scancodes. +static constexpr SDL_Scancode kDiks[256] = { + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_ESCAPE, // DIK_ESCAPE + SDL_SCANCODE_1, // DIK_1 + SDL_SCANCODE_2, // DIK_2 + SDL_SCANCODE_3, // DIK_3 + SDL_SCANCODE_4, // DIK_4 + SDL_SCANCODE_5, // DIK_5 + SDL_SCANCODE_6, // DIK_6 + SDL_SCANCODE_7, // DIK_7 + SDL_SCANCODE_8, // DIK_8 + SDL_SCANCODE_9, // DIK_9 + SDL_SCANCODE_0, // DIK_0 + SDL_SCANCODE_MINUS, // DIK_MINUS + SDL_SCANCODE_EQUALS, // DIK_EQUALS + SDL_SCANCODE_BACKSPACE, // DIK_BACK + SDL_SCANCODE_TAB, // DIK_TAB + SDL_SCANCODE_Q, // DIK_Q + SDL_SCANCODE_W, // DIK_W + SDL_SCANCODE_E, // DIK_E + SDL_SCANCODE_R, // DIK_R + SDL_SCANCODE_T, // DIK_T + SDL_SCANCODE_Y, // DIK_Y + SDL_SCANCODE_U, // DIK_U + SDL_SCANCODE_I, // DIK_I + SDL_SCANCODE_O, // DIK_O + SDL_SCANCODE_P, // DIK_P + SDL_SCANCODE_LEFTBRACKET, // DIK_LBRACKET + SDL_SCANCODE_RIGHTBRACKET, // DIK_RBRACKET + SDL_SCANCODE_RETURN, // DIK_RETURN + SDL_SCANCODE_LCTRL, // DIK_LCONTROL + SDL_SCANCODE_A, // DIK_A + SDL_SCANCODE_S, // DIK_S + SDL_SCANCODE_D, // DIK_D + SDL_SCANCODE_F, // DIK_F + SDL_SCANCODE_G, // DIK_G + SDL_SCANCODE_H, // DIK_H + SDL_SCANCODE_J, // DIK_J + SDL_SCANCODE_K, // DIK_K + SDL_SCANCODE_L, // DIK_L + SDL_SCANCODE_SEMICOLON, // DIK_SEMICOLON + SDL_SCANCODE_APOSTROPHE, // DIK_APOSTROPHE + SDL_SCANCODE_GRAVE, // DIK_GRAVE + SDL_SCANCODE_LSHIFT, // DIK_LSHIFT + SDL_SCANCODE_BACKSLASH, // DIK_BACKSLASH + SDL_SCANCODE_Z, // DIK_Z + SDL_SCANCODE_X, // DIK_X + SDL_SCANCODE_C, // DIK_C + SDL_SCANCODE_V, // DIK_V + SDL_SCANCODE_B, // DIK_B + SDL_SCANCODE_N, // DIK_N + SDL_SCANCODE_M, // DIK_M + SDL_SCANCODE_COMMA, // DIK_COMMA + SDL_SCANCODE_PERIOD, // DIK_PERIOD + SDL_SCANCODE_SLASH, // DIK_SLASH + SDL_SCANCODE_RSHIFT, // DIK_RSHIFT + SDL_SCANCODE_KP_MULTIPLY, // DIK_MULTIPLY + SDL_SCANCODE_LALT, // DIK_LMENU + SDL_SCANCODE_SPACE, // DIK_SPACE + SDL_SCANCODE_CAPSLOCK, // DIK_CAPITAL + SDL_SCANCODE_F1, // DIK_F1 + SDL_SCANCODE_F2, // DIK_F2 + SDL_SCANCODE_F3, // DIK_F3 + SDL_SCANCODE_F4, // DIK_F4 + SDL_SCANCODE_F5, // DIK_F5 + SDL_SCANCODE_F6, // DIK_F6 + SDL_SCANCODE_F7, // DIK_F7 + SDL_SCANCODE_F8, // DIK_F8 + SDL_SCANCODE_F9, // DIK_F9 + SDL_SCANCODE_F10, // DIK_F10 + SDL_SCANCODE_NUMLOCKCLEAR, // DIK_NUMLOCK + SDL_SCANCODE_SCROLLLOCK, // DIK_SCROLL + SDL_SCANCODE_KP_7, // DIK_NUMPAD7 + SDL_SCANCODE_KP_8, // DIK_NUMPAD8 + SDL_SCANCODE_KP_9, // DIK_NUMPAD9 + SDL_SCANCODE_KP_MINUS, // DIK_SUBTRACT + SDL_SCANCODE_KP_4, // DIK_NUMPAD4 + SDL_SCANCODE_KP_5, // DIK_NUMPAD5 + SDL_SCANCODE_KP_6, // DIK_NUMPAD6 + SDL_SCANCODE_KP_PLUS, // DIK_ADD + SDL_SCANCODE_KP_1, // DIK_NUMPAD1 + SDL_SCANCODE_KP_2, // DIK_NUMPAD2 + SDL_SCANCODE_KP_3, // DIK_NUMPAD3 + SDL_SCANCODE_KP_0, // DIK_NUMPAD0 + SDL_SCANCODE_KP_PERIOD, // DIK_DECIMAL + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_F11, // DIK_F11 + SDL_SCANCODE_F12, // DIK_F12 + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_KP_EQUALS, // DIK_NUMPADEQUALS + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, // DIK_AT + SDL_SCANCODE_UNKNOWN, // DIK_COLON + SDL_SCANCODE_UNKNOWN, // DIK_UNDERLINE + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, // DIK_STOP + SDL_SCANCODE_UNKNOWN, // DIK_AX + SDL_SCANCODE_UNKNOWN, // DIK_UNLABELED + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_KP_ENTER, // DIK_NUMPADENTER + SDL_SCANCODE_RCTRL, // DIK_RCONTROL + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_KP_COMMA, // DIK_NUMPADCOMMA + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_SLASH, // DIK_DIVIDE + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_SYSREQ, // DIK_SYSRQ + SDL_SCANCODE_RALT, // DIK_RMENU + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_HOME, // DIK_HOME + SDL_SCANCODE_UP, // DIK_UP + SDL_SCANCODE_PAGEUP, // DIK_PRIOR + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_LEFT, // DIK_LEFT + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_RIGHT, // DIK_RIGHT + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_END, // DIK_END + SDL_SCANCODE_DOWN, // DIK_DOWN + SDL_SCANCODE_PAGEDOWN, // DIK_NEXT + SDL_SCANCODE_INSERT, // DIK_INSERT + SDL_SCANCODE_DELETE, // DIK_DELETE + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_LGUI, // DIK_LWIN + SDL_SCANCODE_RGUI, // DIK_RWIN + SDL_SCANCODE_APPLICATION, // DIK_APPS + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, +}; + +/// Translates Sfall key code (DIK or VK constant) to SDL scancode. +static SDL_Scancode get_scancode_from_key(int key) +{ + return kDiks[key & 0xFF]; +} + +bool sfall_kb_is_key_pressed(int key) +{ + const Uint8* state = SDL_GetKeyboardState(nullptr); + SDL_Scancode scancode = get_scancode_from_key(key); + return state[scancode] != 0; +} + +void sfall_kb_press_key(int key) +{ + SDL_Scancode scancode = get_scancode_from_key(key); + if (scancode != SDL_SCANCODE_UNKNOWN) { + SDL_Event event; + event.key.keysym.scancode = scancode; + + event.type = SDL_KEYDOWN; + SDL_PushEvent(&event); + + event.type = SDL_KEYUP; + SDL_PushEvent(&event); + } +} diff --git a/src/sfall_kb_helpers.h b/src/sfall_kb_helpers.h new file mode 100644 index 0000000..ff22959 --- /dev/null +++ b/src/sfall_kb_helpers.h @@ -0,0 +1,10 @@ +#ifndef FALLOUT_SFALL_KB_HELPERS_H_ +#define FALLOUT_SFALL_KB_HELPERS_H_ + +/// Returns `true` if given key is pressed. +bool sfall_kb_is_key_pressed(int key); + +/// Simulates pressing `key`. +void sfall_kb_press_key(int key); + +#endif /* FALLOUT_SFALL_KB_HELPERS_H_ */ diff --git a/src/sfall_opcodes.cc b/src/sfall_opcodes.cc index e21a079..802889c 100644 --- a/src/sfall_opcodes.cc +++ b/src/sfall_opcodes.cc @@ -24,6 +24,7 @@ #include "sfall_global_scripts.h" #include "sfall_global_vars.h" #include "sfall_ini.h" +#include "sfall_kb_helpers.h" #include "sfall_lists.h" #include "stat.h" #include "svga.h" @@ -94,6 +95,13 @@ static void opGetPcBonusStat(Program* program) programStackPushInteger(program, value); } +// tap_key +static void op_tap_key(Program* program) +{ + int key = programStackPopInteger(); + sfall_kb_press_key(key); +} + // get_year static void op_get_year(Program* program) { @@ -120,10 +128,8 @@ static void op_set_global_script_repeat(Program* program) static void op_key_pressed(Program* program) { int key = programStackPopInteger(program); - - // TODO: Incomplete. - - programStackPushInteger(program, 0); + bool pressed = sfall_kb_is_key_pressed(key); + programStackPushInteger(program, pressed ? 1 : 0); } // in_world_map @@ -882,6 +888,7 @@ void sfallOpcodesInit() interpreterRegisterOpcode(0x815B, opSetPcBonusStat); interpreterRegisterOpcode(0x815C, op_get_pc_base_stat); interpreterRegisterOpcode(0x815D, opGetPcBonusStat); + interpreterRegisterOpcode(0x8162, op_tap_key); interpreterRegisterOpcode(0x8163, op_get_year); interpreterRegisterOpcode(0x8164, op_game_loaded); interpreterRegisterOpcode(0x816A, op_set_global_script_repeat);