aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/fhandler_console.cc58
1 files changed, 38 insertions, 20 deletions
diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc
index 241ca48..b92d758 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -180,6 +180,29 @@ cons_master_thread (VOID *arg)
return 0;
}
+/* Compare two INPUT_RECORD sequences */
+static inline bool
+inrec_eq (const INPUT_RECORD *a, const INPUT_RECORD *b, DWORD n)
+{
+ for (DWORD i = 0; i < n; i++)
+ {
+ if (a[i].EventType == KEY_EVENT && b[i].EventType == KEY_EVENT)
+ { /* wVirtualKeyCode and wVirtualScanCode of the readback
+ key event may be different from that of written event. */
+ const KEY_EVENT_RECORD *ak = &a[i].Event.KeyEvent;
+ const KEY_EVENT_RECORD *bk = &b[i].Event.KeyEvent;
+ if (ak->bKeyDown != bk->bKeyDown
+ || ak->uChar.UnicodeChar != bk->uChar.UnicodeChar
+ || ak->dwControlKeyState != bk->dwControlKeyState
+ || ak->wRepeatCount != bk->wRepeatCount)
+ return false;
+ }
+ else if (memcmp (a + i, b + i, sizeof (INPUT_RECORD)) != 0)
+ return false;
+ }
+ return true;
+}
+
/* This thread processes signals derived from input messages.
Without this thread, those signals can be handled only when
the process calls read() or select(). This thread reads input
@@ -328,30 +351,25 @@ remove_record:
if (n < total_read)
break; /* Someone has read input without acquiring
input_mutex. ConEmu cygwin-connector? */
- if (memcmp (input_rec, tmp, m::bytes (total_read)) == 0)
+ if (inrec_eq (input_rec, tmp, total_read))
break; /* OK */
/* Try to fix */
- DWORD incr = n - total_read;
- DWORD ofst;
- for (ofst = 1; ofst <= incr; ofst++)
- if (memcmp (input_rec, tmp + ofst, m::bytes (total_read)) == 0)
+ acquire_attach_mutex (mutex_timeout);
+ ReadConsoleInputW (p->input_handle, tmp, inrec_size, &n);
+ release_attach_mutex ();
+ for (DWORD i = 0, j = 0; j < n; j++)
+ if (i == total_read || !inrec_eq (input_rec + i, tmp + j, 1))
{
- acquire_attach_mutex (mutex_timeout);
- ReadConsoleInputW (p->input_handle, tmp, inrec_size, &n);
- release_attach_mutex ();
- memcpy (input_rec, tmp + ofst, m::bytes (total_read));
- memcpy (input_rec + total_read, tmp, m::bytes (ofst));
- if (n > ofst + total_read)
- memcpy (input_rec + total_read + ofst,
- tmp + ofst + total_read,
- m::bytes (n - (ofst + total_read)));
- total_read = n;
- break;
+ if (total_read + j - i >= n)
+ { /* Something is wrong. Giving up. */
+ WriteConsoleInputW (p->input_handle, tmp, n, &n);
+ goto skip_writeback;
+ }
+ input_rec[total_read + j - i] = tmp[j];
}
- if (ofst > incr)
- break; /* Writeback was not atomic. Or someone has read
- input without acquiring input_mutex.
- Giving up because hard to fix. */
+ else
+ i++;
+ total_read = n;
}
while (true);
}