aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorneonloop2021-08-22 15:18:02 +0000
committerneonloop2021-08-22 15:18:02 +0000
commitf0ecf48685329ad2d90c2bed1472f93a6c11f00e (patch)
tree6ba7f97f8d6e84fbeb683dba73929e568b6030c4
parent41fff233f29b6ee7274f4bf525052dcf0fa56c00 (diff)
downloadpicoarch-f0ecf48685329ad2d90c2bed1472f93a6c11f00e.tar.gz
picoarch-f0ecf48685329ad2d90c2bed1472f93a6c11f00e.tar.bz2
picoarch-f0ecf48685329ad2d90c2bed1472f93a6c11f00e.zip
Fixes ordering of events when using combo keys
Sometimes menu would get stuck, because the simulated events would be pushed after real events. Now transform all keyboard events first, so the transform code has complete control over the order.
-rw-r--r--patches/libpicofe/0001-key-combos.patch186
1 files changed, 114 insertions, 72 deletions
diff --git a/patches/libpicofe/0001-key-combos.patch b/patches/libpicofe/0001-key-combos.patch
index 69cb4be..7105fc3 100644
--- a/patches/libpicofe/0001-key-combos.patch
+++ b/patches/libpicofe/0001-key-combos.patch
@@ -1,5 +1,5 @@
diff --git a/in_sdl.c b/in_sdl.c
-index a84c781..518e8cf 100644
+index a84c781..bab649a 100644
--- a/in_sdl.c
+++ b/in_sdl.c
@@ -19,11 +19,18 @@
@@ -21,78 +21,102 @@ index a84c781..518e8cf 100644
keybits_t keystate[SDLK_LAST / KEYBITS_WORD_BITS + 1];
// emulator keys should always be processed immediately lest one is lost
keybits_t emu_keys[SDLK_LAST / KEYBITS_WORD_BITS + 1];
-@@ -259,6 +266,97 @@ static int get_keystate(keybits_t *keystate, int sym)
+@@ -259,6 +266,139 @@ static int get_keystate(keybits_t *keystate, int sym)
return !!(*ks_word & mask);
}
-+static int translate_keystate(struct in_sdl_state *state, SDL_Event *event)
++static inline void switch_key(SDL_Event *event, keybits_t *keystate, short upkey, short downkey)
++{
++ event->type = SDL_KEYUP;
++ event->key.state = SDL_RELEASED;
++ event->key.keysym.sym = upkey;
++
++ update_keystate(keystate, upkey, 0);
++ SDL_PushEvent(event);
++
++ event->type = SDL_KEYDOWN;
++ event->key.state = SDL_PRESSED;
++ event->key.keysym.sym = downkey;
++
++ update_keystate(keystate, downkey, 1);
++ SDL_PushEvent(event);
++}
++
++static void translate_combo_event(struct in_sdl_state *state, SDL_Event *event, keybits_t *keystate)
+{
+ const struct in_pdata *pdata = state->drv->pdata;
+ const struct mod_keymap *map;
-+ SDL_Event new_event;
+ short key = (short)event->key.keysym.sym;
+ uint8_t type = event->type;
+ short mod_key = pdata->mod_key;
+ int i;
-+ int ret = 1;
+
-+ if (!mod_key)
-+ return 1;
++ if (event->type != SDL_KEYDOWN && event->type != SDL_KEYUP) {
++ SDL_PushEvent(event);
++ return;
++ }
+
-+ if (state->mod_state == MOD_NO && key != mod_key)
-+ return 1;
++ if (state->mod_state == MOD_NO && key != mod_key) {
++ update_keystate(keystate, event->key.keysym.sym, event->type == SDL_KEYDOWN);
++ SDL_PushEvent(event);
++ return;
++ }
+
+ if (key == mod_key) {
-+ if (type == SDL_KEYDOWN) {
-+ /* Pressed mod, maybe a combo? Ignore the keypress
-+ * until it's determined */
-+ state->mod_state = MOD_MAYBE;
-+
-+ for (i = 0; i < pdata->modmap_size; i++) {
-+ map = &pdata->mod_keymap[i];
-+
-+ if (get_keystate(state->keystate, map->inkey)) {
-+ state->mod_state = MOD_YES;
-+ new_event.type = SDL_KEYUP;
-+ new_event.key.state = SDL_RELEASED;
-+ new_event.key.keysym.sym = map->inkey;
-+ SDL_PushEvent(&new_event);
-+
-+ new_event.type = SDL_KEYDOWN;
-+ new_event.key.state = SDL_PRESSED;
-+ new_event.key.keysym.sym = map->outkey;
-+ SDL_PushEvent(&new_event);
++ switch (state->mod_state) {
++ case MOD_NO:
++ if (type == SDL_KEYDOWN) {
++ /* Pressed mod, maybe a combo? Ignore the keypress
++ * until it's determined */
++ state->mod_state = MOD_MAYBE;
++
++ for (i = 0; i < pdata->modmap_size; i++) {
++ map = &pdata->mod_keymap[i];
++
++ if (get_keystate(keystate, map->inkey)) {
++ state->mod_state = MOD_YES;
++ switch_key(event, keystate, map->inkey, map->outkey);
++ }
+ }
++ } else {
++ SDL_PushEvent(event);
+ }
-+
-+ ret = -1;
-+ } else if (state->mod_state == MOD_MAYBE) {
-+ /* Released mod without combo, simulate down and up */
-+ SDL_PushEvent(event);
-+ state->mod_state = MOD_NO;
-+ event->type = SDL_KEYDOWN;
-+ ret = 1;
-+ } else if (state->mod_state == MOD_YES) {
-+ /* Released mod, switch all mod keys to unmod */
-+ state->mod_state = MOD_NO;
-+
-+ for (i = 0; i < pdata->modmap_size; i++) {
-+ map = &pdata->mod_keymap[i];
-+
-+ if (get_keystate(state->keystate, map->outkey)) {
-+ state->mod_state = MOD_NO;
-+ new_event.type = SDL_KEYUP;
-+ new_event.key.state = SDL_RELEASED;
-+ new_event.key.keysym.sym = map->outkey;
-+ SDL_PushEvent(&new_event);
-+
-+ new_event.type = SDL_KEYDOWN;
-+ new_event.key.state = SDL_PRESSED;
-+ new_event.key.keysym.sym = map->inkey;
-+ SDL_PushEvent(&new_event);
++ break;
++ case MOD_MAYBE:
++ if (type == SDL_KEYDOWN) {
++ SDL_PushEvent(event);
++ } else {
++ /* Released mod without combo, simulate down and up */
++ state->mod_state = MOD_NO;
++
++ event->type = SDL_KEYDOWN;
++ event->key.state = SDL_PRESSED;
++ SDL_PushEvent(event);
++
++ event->type = SDL_KEYUP;
++ event->key.state = SDL_RELEASED;
++ SDL_PushEvent(event);
++ }
++ break;
++ case MOD_YES:
++ if (type == SDL_KEYDOWN) {
++ SDL_PushEvent(event);
++ } else {
++ /* Released mod, switch all mod keys to unmod and ignore mod press */
++ state->mod_state = MOD_NO;
++
++ for (i = 0; i < pdata->modmap_size; i++) {
++ map = &pdata->mod_keymap[i];
++
++ if (get_keystate(keystate, map->outkey)) {
++ switch_key(event, keystate, map->outkey, map->inkey);
++ }
+ }
+ }
-+ ret = -1;
++ break;
++ default:
++ SDL_PushEvent(event);
++ break;
+ }
+ } else {
+ for (i = 0; i < pdata->modmap_size; i++) {
@@ -101,34 +125,52 @@ index a84c781..518e8cf 100644
+ if (map->inkey == key) {
+ state->mod_state = MOD_YES;
+
-+ /* Releasing the original key? Allow it through,
-+ * Otherwise, replace with modified key. */
-+ if (!(event->type == SDL_KEYUP &&
-+ get_keystate(state->keystate, map->inkey)))
-+ event->key.keysym.sym = map->outkey;
-+
-+ break;
++ event->key.keysym.sym = map->outkey;
++ update_keystate(keystate, map->outkey, event->type == SDL_KEYDOWN);
++ SDL_PushEvent(event);
+ }
+ }
-+ ret = 1;
+ }
++}
++
++static void translate_combo_events(struct in_sdl_state *state, Uint32 mask)
++{
++ const struct in_pdata *pdata = state->drv->pdata;
++ SDL_Event events[10]; /* Must be bigger than events size in collect_events */
++ keybits_t keystate[SDLK_LAST / KEYBITS_WORD_BITS + 1];
++ int count;
++ int has_events;
++ int i;
++
++ if (!pdata->mod_key)
++ return;
+
-+ return ret;
++ has_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, mask);
++
++ if (!has_events)
++ return;
++
++ memcpy(keystate, state->keystate, sizeof(keystate));
++
++ count = SDL_PeepEvents(events, (sizeof(events) / sizeof(events[0])), SDL_GETEVENT, mask);
++ for (i = 0; i < count; i++) {
++ translate_combo_event(state, &events[i], keystate);
++ }
+}
+
static int handle_event(struct in_sdl_state *state, SDL_Event *event,
int *kc_out, int *down_out, int *emu_out)
{
-@@ -267,6 +365,9 @@ static int handle_event(struct in_sdl_state *state, SDL_Event *event,
- if (event->type != SDL_KEYDOWN && event->type != SDL_KEYUP)
- return -1;
+@@ -363,6 +503,9 @@ static int collect_events(struct in_sdl_state *state, int *one_kc, int *one_down
+
+ SDL_PumpEvents();
-+ if (translate_keystate(state, event) < 0)
-+ return -1;
++ if (!state->joy)
++ translate_combo_events(state, mask);
+
- emu = get_keystate(state->emu_keys, event->key.keysym.sym);
- update_keystate(state->keystate, event->key.keysym.sym,
- event->type == SDL_KEYDOWN);
+ num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, mask);
+
+ for (num_peeped_events = 0; num_peeped_events < num_events; num_peeped_events += count) {
diff --git a/input.h b/input.h
index 360b65b..895ad61 100644
--- a/input.h