diff --git a/port/linux/src/xinput_sdl.c b/port/linux/src/xinput_sdl.c index 2e42ebb7..d1994f4a 100644 --- a/port/linux/src/xinput_sdl.c +++ b/port/linux/src/xinput_sdl.c @@ -305,12 +305,13 @@ the one that closes it pause the game again */ static void keys_held_over_switch(struct platform_input_state *input) { static unsigned char held[SDL_SCANCODE_COUNT]; - static int menus = -1; + static int context = -1; + int next_context = (input->menus != FALSE) | (text_typing ? 2 : 0); int scancode; - if (menus != (input->menus != FALSE)) + if (context != next_context) { - menus = input->menus != FALSE; + context = next_context; memcpy(held, input->keys, sizeof(held)); } for (scancode = 0; scancode < SDL_SCANCODE_COUNT; scancode++) diff --git a/tools/harness/tests/profile_keyboard.c b/tools/harness/tests/profile_keyboard.c index 6a30b337..5b33f50a 100644 --- a/tools/harness/tests/profile_keyboard.c +++ b/tools/harness/tests/profile_keyboard.c @@ -7,7 +7,9 @@ typedef unsigned char BYTE; typedef short SHORT; #include "config.inc" -struct platform_input_state { unsigned char keys[TEST_SCANCODE_COUNT], mouse_buttons[8]; BOOL mouse_released; }; +struct platform_input_state { unsigned char keys[TEST_SCANCODE_COUNT], mouse_buttons[8]; BOOL mouse_released, menus; }; +#define SDL_SCANCODE_COUNT TEST_SCANCODE_COUNT +#define console_is_active() FALSE typedef struct { unsigned short wButtons; BYTE bAnalogButtons[8]; SHORT sThumbLX, sThumbLY; } XINPUT_GAMEPAD; #define SDL_BUTTON_X1 4 static BOOL text_typing, text_typing_enter_armed, text_typing_keyboard, text_typing_field; @@ -108,6 +110,22 @@ int main(int argc, char **argv) virtual_keyboard_dispose(); keyboard_available=FALSE; virtual_keyboard_initialize(); CHECK(!virtual_keyboard_launch(name,sizeof(name),8), "missing keyboard launched"); } + else CASE("held-enter") + { + struct platform_input_state input = { .menus = TRUE }; XINPUT_GAMEPAD pad = {0}; + keys_held_over_switch(&input); + input.keys[SDL_SCANCODE_RETURN] = 1; + keys_held_over_switch(&input); keyboard_gamepad(&input,&pad); + CHECK(pad.wButtons & XINPUT_GAMEPAD_START, "Enter did not accept keyboard"); + virtual_keyboard_select(); + memset(&pad,0,sizeof(pad)); + keys_held_over_switch(&input); keyboard_gamepad(&input,&pad); + CHECK(!pad.wButtons && !pad.bAnalogButtons[XINPUT_GAMEPAD_A], "held Done also activated the next menu"); + input.keys[SDL_SCANCODE_RETURN] = 0; keys_held_over_switch(&input); + input.keys[SDL_SCANCODE_RETURN] = 1; keys_held_over_switch(&input); + keyboard_gamepad(&input,&pad); + CHECK(pad.bAnalogButtons[XINPUT_GAMEPAD_A], "fresh Enter was still suppressed"); + } else CHECK(FALSE, "unknown case"); ordinary_input(); int before = processed; virtual_keyboard_process(); diff --git a/tools/harness/tests/test_profile_keyboard.py b/tools/harness/tests/test_profile_keyboard.py index 93fa6d51..25b41ec9 100644 --- a/tools/harness/tests/test_profile_keyboard.py +++ b/tools/harness/tests/test_profile_keyboard.py @@ -10,7 +10,7 @@ sys.path.insert(0, str(Path(__file__).resolve().parents[2])) from harness import CHECK_FAILED, build, enum_with, function, mutated, read, run # noqa: E402 CASES = ['done', 'cancel', 'external-close', 'dispose', 'initialize', - 'invalid-name', 'duplicate-name', 'field-owner', 'reopen', 'launch-failure'] + 'invalid-name', 'duplicate-name', 'field-owner', 'reopen', 'launch-failure', 'held-enter'] def generated(fault=False): @@ -26,10 +26,13 @@ def generated(fault=False): start = vk.index('static char const virtual_keyboard_layout_table') config += vk[start:vk.index('\n};', start)+3] + '\n' names = ['text_typing_update', 'platform_text_typing', 'platform_text_field', - 'analog', 'typing_gamepad', 'keyboard_gamepad'] + 'analog', 'typing_gamepad', 'keyboard_gamepad', 'keys_held_over_switch'] code = '\n'.join(function(inputs, name) for name in names) + '\n' + if fault == 'held-enter': + code, count = re.subn(r' \| \(text_typing \? [24] : 0\)', '', code) + assert count == 1 setter = function(vk, 'virtual_keyboard_set_active') - if fault: + if fault is True: setter = mutated(setter, 'platform_text_typing(active);', 'if (active) platform_text_typing(active);') code += setter + '\n' code += '\n'.join(function(vk, name) for name in @@ -51,6 +54,11 @@ def test_original_sticky_typing_detected(case): assert status == CHECK_FAILED, output +def test_held_enter_guard_detected(): + status, output = run(build('profile_keyboard', generated('held-enter')), 'held-enter') + assert status == CHECK_FAILED, output + + def test_profiles_accept_destinations(): root = ET.fromstring(read('port/assets/menus/ce/main_menu.xml')) widgets = {widget.get('name'): widget for widget in root.findall('widget')}