diff options
author | Avi Halachmi (:avih) <avihpit@yahoo.com> | 2023-07-20 22:48:41 +0300 |
---|---|---|
committer | Avi Halachmi (:avih) <avihpit@yahoo.com> | 2023-07-21 10:13:12 +0300 |
commit | 4fe7e7cdd0441e9455cc93c17b40a7a96704e61f (patch) | |
tree | 7facce159f51486696dd2adf180800c32b3f9444 | |
parent | 72b97c86c6c1a1902d6dcda3da7c38db13585cdc (diff) | |
download | busybox-w32-4fe7e7cdd0441e9455cc93c17b40a7a96704e61f.tar.gz busybox-w32-4fe7e7cdd0441e9455cc93c17b40a7a96704e61f.tar.bz2 busybox-w32-4fe7e7cdd0441e9455cc93c17b40a7a96704e61f.zip |
win32: UTF8 input: improve missing-key-down hack
The UTF8 input code works around an issue when pasting at the
windows console (but not terminal) that sometimes we get key-up
without a prior matching key-down - at which case it generates down.
However, previously it detected this by comparing an up-event to the
last down-event, which could result in false-positive in cases like:
X-down Y-down X-up Y-up (e.g. when typing quickly).
Now it remembers the last 8 key-down events when searching a prior
matching key-down, which fixes an issue of incorrect repeated keys
(in the example above Y-up was incorrectly changed to Y-down).
-rw-r--r-- | win32/winansi.c | 58 |
1 files changed, 47 insertions, 11 deletions
diff --git a/win32/winansi.c b/win32/winansi.c index bc3e69163..f280177e6 100644 --- a/win32/winansi.c +++ b/win32/winansi.c | |||
@@ -1284,6 +1284,44 @@ static void maybeEatUpto2ndHalfUp(HANDLE h, DWORD *ph1) | |||
1284 | } | 1284 | } |
1285 | } | 1285 | } |
1286 | 1286 | ||
1287 | // if the codepoint is a key-down event, remember it, else if | ||
1288 | // it's a key-up event with matching prior down - forget the down, | ||
1289 | // else (up without matching prior key-down) - change it to down. | ||
1290 | // We remember few prior key-down events so that a sequence | ||
1291 | // like X-down Y-down X-up Y-up won't trigger this hack for Y-up. | ||
1292 | // When up is changed into down there won't be further key-up event, | ||
1293 | // but that's OK because the caller ignores key-up events anyway. | ||
1294 | static void maybe_change_up_to_down(wchar_t key, BOOL *isdown) | ||
1295 | { | ||
1296 | #define DOWN_BUF_SIZ 8 | ||
1297 | static wchar_t downbuf[DOWN_BUF_SIZ] = {0}; | ||
1298 | static int pos = 0; | ||
1299 | |||
1300 | if (*isdown) { | ||
1301 | downbuf[pos++] = key; | ||
1302 | pos = pos % DOWN_BUF_SIZ; | ||
1303 | return; | ||
1304 | } | ||
1305 | |||
1306 | // the missing-key-down issue was only observed with unicode values, | ||
1307 | // so limit this hack to non-ASCII-7 values. | ||
1308 | // also, launching a new shell/read process from CLI captures | ||
1309 | // an ENTER-up event without prior down at this new process, which | ||
1310 | // would otherwise change it to down - creating a wrong ENTER keypress. | ||
1311 | if (key <= 127) | ||
1312 | return; | ||
1313 | |||
1314 | // key up, try to match a prior down | ||
1315 | for (int i = 0; i < DOWN_BUF_SIZ; ++i) { | ||
1316 | if (downbuf[i] == key) { | ||
1317 | downbuf[i] = 0; // "forget" this down | ||
1318 | return; | ||
1319 | } | ||
1320 | } | ||
1321 | |||
1322 | // no prior key-down - replace the up with down | ||
1323 | *isdown = TRUE; | ||
1324 | } | ||
1287 | 1325 | ||
1288 | /* | 1326 | /* |
1289 | * readConsoleInput_utf8 behaves similar enough to ReadConsoleInputA when | 1327 | * readConsoleInput_utf8 behaves similar enough to ReadConsoleInputA when |
@@ -1355,20 +1393,18 @@ BOOL readConsoleInput_utf8(HANDLE h, INPUT_RECORD *r, DWORD len, DWORD *got) | |||
1355 | srec = *r; | 1393 | srec = *r; |
1356 | codepoint = srec.Event.KeyEvent.uChar.UnicodeChar; | 1394 | codepoint = srec.Event.KeyEvent.uChar.UnicodeChar; |
1357 | 1395 | ||
1358 | // At the cmd.exe console (but not windows terminal) we sometimes | 1396 | // Observed when pasting unicode at cmd.exe console (but not |
1359 | // get key-up without the prior expected key-down event, sometimes | 1397 | // windows terminal), we sometimes get key-up event without |
1360 | // with UnicodeChar of 0 instead the key-down event. work around it. | 1398 | // a prior matching key-down (or with key-down codepoint 0), |
1361 | if (codepoint) { | 1399 | // so this call would change the up into down in such case. |
1362 | static wchar_t last_down = 0; | 1400 | // E.g. pastes fixed by this hack: U+1F600 "😀", or U+0C80 "ಀ" |
1363 | 1401 | if (codepoint) | |
1364 | if (srec.Event.KeyEvent.bKeyDown) | 1402 | maybe_change_up_to_down(codepoint, &srec.Event.KeyEvent.bKeyDown); |
1365 | last_down = codepoint; | ||
1366 | else if (codepoint > 127 && codepoint != last_down) | ||
1367 | srec.Event.KeyEvent.bKeyDown = TRUE; | ||
1368 | } | ||
1369 | 1403 | ||
1370 | // if it's a 1st (high) surrogate pair half, try to eat upto and | 1404 | // if it's a 1st (high) surrogate pair half, try to eat upto and |
1371 | // excluding the 2nd (low) half, and combine them into codepoint. | 1405 | // excluding the 2nd (low) half, and combine them into codepoint. |
1406 | // this does not interfere with the missing-key-down workaround | ||
1407 | // (no issue if the down-buffer has 1st-half-down without up). | ||
1372 | if (codepoint >= 0xD800 && codepoint <= 0xDBFF) | 1408 | if (codepoint >= 0xD800 && codepoint <= 0xDBFF) |
1373 | maybeEatUpto2ndHalfUp(h, &codepoint); | 1409 | maybeEatUpto2ndHalfUp(h, &codepoint); |
1374 | 1410 | ||