From 4e6c112d2857732661ff75a482794fcfbde831c7 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 29 Aug 2022 19:50:42 -0400 Subject: [PATCH] Fiix keyboard ghosting. Original commit: From a95a8ddf71ed4806748a4809066a283b5436f3d2 Mon Sep 17 00:00:00 2001 From: Ico Doornekamp Date: Fri, 20 Jul 2018 13:22:04 +0200 Subject: [PATCH] Updated gemini keyboard driver to prevent ghosting ... aka key rollover when certain key combinations are pressed. Original patch from Nathan Banks in the Gemian repo --- drivers/misc/mediatek/aw9523/aw9523_key.c | 240 +++++++++++----------- 1 file changed, 122 insertions(+), 118 deletions(-) diff --git a/drivers/misc/mediatek/aw9523/aw9523_key.c b/drivers/misc/mediatek/aw9523/aw9523_key.c index 32d2d0a0e4de..b0eda4295c22 100755 --- a/drivers/misc/mediatek/aw9523/aw9523_key.c +++ b/drivers/misc/mediatek/aw9523/aw9523_key.c @@ -307,16 +307,19 @@ static void aw9523_key_eint_work(struct work_struct *work) { struct aw9523_key_data *pdata; KEY_STATE *keymap; - unsigned char i,j,cnt; + unsigned char i, j, idx; unsigned char val; + bool update_now = false; // Used to detect ghosting int keymap_len; int x=0; int y=0; int t; - int keyIn; - int keyCodes[100]; - int keyValues[100]; - int discardKeyCheck; + // These data structures are large enough they can't overflow. + int press_count = 0; + int press_codes[P0_NUM_MAX*P1_NUM_MAX]; + int release_count = 0; + int release_codes[P0_NUM_MAX*P1_NUM_MAX]; + int discardKeyCheck; AW9523_LOG("Handling Interrupt\n"); @@ -360,130 +363,131 @@ static void aw9523_key_eint_work(struct work_struct *work) } // AW9523_LOG("\n"); + + /* This routine prevents ghosting. As an example, if Control+L_Shift+N is pressed, + * the keyboard detects both N & M at the same time due to the electronic circuit. + * Rather than detect both keys, block both keys until either Control or L_Shift is + * released, then detect the correct keypress. See youtu.be/L3ByBtM-w9I */ if (memcmp(keyst_old, keyst_new, P1_NUM_MAX)) { // keyst changed - keyIn = 0; - for (t=0; t1) { + val &= keyst_new[i]; + } + } + } + + // update_now is set when the key state changes and there's no ghosting right now. + if (update_now) { + for (t = 0; t < P1_NUM_MAX; t++) { i = t; if (t== 3) i = 6; if (t == 6) i = 3; - if (keyst_old[i] != keyst_new[i]) - { // keyst of i col changed - for (j=0; j MAX_KEYS_TOGETHER) { - if (x >= 4 || y >= 3) { - AW9523_LOG("Too many keys\n"); - skipCycles = 50; - forceCycles = 0; - } - - //if (x < 4 && y < 3) { - //if (keyIn < 10) { - //AW9523_LOG("Cycle %d - Storing key in position %d\n code %d val %d", keyCurrentCycle, keyIn, keymap[cnt].key_code, keymap[cnt].key_val); - //keyValues[keyIn] = keymap[cnt].key_val; - //keyCodes[keyIn] = keymap[cnt].key_code; - //keyIn++; - //} - //input_report_key(aw9523_key->input_dev, keymap[cnt].key_code, keymap[cnt].key_val); - //input_sync(aw9523_key->input_dev); - //AW9523_LOG("%s: key_report: p0-row=%d, p1-col=%d, key_code=%d, key_val=%d\n", - // __func__, j, i, keymap[cnt].key_code, keymap[cnt].key_val); - //if (keymap[cnt].key_code == KEY_Z && keymap[cnt].key_val == 0) { - // if (keySkipCycle < 6) - // keySkipCycle++; - // else - // keySkipCycle = 1; - // AW9523_LOG("Cycle %d - Setting skip cycle to %d\n", keyCurrentCycle, keySkipCycle); - //} - //} - } + if (keyst_old[i] == keyst_new[i]) { + continue; // Skip if keyst of i didn't change. + } + for (j = 0; j < P0_NUM_MAX; j++) { + if ((keyst_old[i] & (1 << j)) != (keyst_new[i] & (1 << j))) { // j row & i col changed + // The keymap datastructure is organized this way. + idx = i * P0_NUM_MAX + j; + if (keyst_new[i] & (1 << j)) { // release + keymap[idx].key_val = 0; + release_codes[release_count] = keymap[idx].key_code; + release_count++; + } else { // press + keymap[idx].key_val = 1; + press_codes[press_count] = keymap[idx].key_code; + press_count++; + } + AW9523_LOG("Storing key code %d val %d\n", + keymap[idx].key_code, + keymap[idx].key_val); + } + } + } + + /* Process key presses before releases because sometimes a release of one key will + * unblock another key press, and we want to keep all modifier keys pressed. */ + for (t = 0; t < press_count; t++) { + if (skipCycles == 0) { + if (discardKeyIdx > 0) { + AW9523_LOG("Clearing discarded keys\n"); + discardKeyIdx = 0; + } + AW9523_LOG("Processing key press in position %d code %d\n", + t, press_codes[t]); + input_report_key(aw9523_key->input_dev, + press_codes[t], + 1); // The one records a press + input_sync(aw9523_key->input_dev); + forceCycles = 100; + } else { + if (discardKeyIdx < 99) { + AW9523_LOG("Putting key press %d in discardKeys %d\n", + press_codes[t], + discardKeyIdx); + discardKeys[discardKeyIdx] = press_codes[t]; + discardKeyIdx++; + } + } + } + // Now go through all the relaeses. + for (t = 0; t < release_count; t++) { + if (skipCycles == 0) { + if (discardKeyIdx > 0) { + AW9523_LOG("Clearing discarded keys\n"); + discardKeyIdx = 0; + } + AW9523_LOG("Processing key release in position %d code %d\n", + t, release_codes[t]); + input_report_key(aw9523_key->input_dev, + release_codes[t], + 0); // The zero records a release + input_sync(aw9523_key->input_dev); + forceCycles = 100; + } else { + // Key is released + for (discardKeyCheck = 0; discardKeyCheck < discardKeyIdx; discardKeyCheck++) { + if (discardKeys[discardKeyCheck] == release_codes[t]) { + AW9523_LOG("Found key %d in discardKeys %d, discarding\n", + release_codes[t], + discardKeyCheck); + discardKeyCheck = 999; } } + if (discardKeyCheck != 1000) { + AW9523_LOG("Releasing key in position %d code %d (%d)\n", + t, relase_key_code[t], + discardKeyCheck); + input_report_key(aw9523_key->input_dev, + release_codes[t], + 0); // Report the release. + input_sync(aw9523_key->input_dev); + } } } - //if ((keyIn <= MAX_KEYS_TOGETHER)) { - for (t=0; t < keyIn; t++) { - if (skipCycles == 0) { - if (discardKeyIdx > 0) { - AW9523_LOG("Clearing discarded keys\n"); - discardKeyIdx = 0; - } - AW9523_LOG("Processing key in position %d code %d val %d\n", t, keyCodes[t], keyValues[t]); - input_report_key(aw9523_key->input_dev, keyCodes[t], keyValues[t]); - input_sync(aw9523_key->input_dev); - forceCycles = 100; - } - else { - if (keyValues[t] == 1) { - // Key is pressed - if (discardKeyIdx < 99) { - AW9523_LOG("Putting key %d in discardKeys %d\n", keyCodes[t], discardKeyIdx); - discardKeys[discardKeyIdx] = keyCodes[t]; - discardKeyIdx++; - } - } - else { - // Key is released - for (discardKeyCheck=0;discardKeyCheckinput_dev, keyCodes[t], keyValues[t]); - input_sync(aw9523_key->input_dev); - } - - //switch(keyCodes[t]) { - //case 464: - // fnPressed = keyValues[t]; - // break; - //case 29: - // ctrlPressed = keyValues[t]; - // break; - //case 56: - // altPressed = keyValues[t]; - // break; - //case 42: - // shiftLeftPressed = keyValues[t]; - // break; - //case 54: - // shiftRightPressed = keyValues[t]; - // break; - } - } - } - //} + // Store the current state so we can detect a change next time. memcpy(keyst_old, keyst_new, P1_NUM_MAX); }