@@ -8,6 +8,7 @@ import (
12 "unicode/utf16"
13 "unicode/utf16"
13 "unicode/utf8"
14 "unicode/utf8"
@@ -22,7 +23,7 @@ import (
22// given event channel.
23// given event channel.
23func (d *TerminalReader) ReceiveEvents(ctx context.Context, events chan<- Event) error {
24func (d *TerminalReader) ReceiveEvents(ctx context.Context, events chan<- Event) error {
25− evs, err := d.handleConInput(readConsoleInput)
26+ evs, err := d.handleConInput()
26 if errors.Is(err, errNotConInputReader) {
27 if errors.Is(err, errNotConInputReader) {
27 return d.receiveEvents(ctx, events)
28 return d.receiveEvents(ctx, events)
@@ -41,31 +42,45 @@ func (d *TerminalReader) ReceiveEvents(ctx context.Context, events chan<- Event)
42var errNotConInputReader = fmt.Errorf("handleConInput: not a conInputReader")
43var errNotConInputReader = fmt.Errorf("handleConInput: not a conInputReader")
44−func (d *TerminalReader) handleConInput(
45+func (d *TerminalReader) handleConInput() ([]Event, error) {
45− finput func(windows.Handle, []xwindows.InputRecord) (uint32, error),
47 cc, ok := d.rd.(*conInputReader)
46 cc, ok := d.rd.(*conInputReader)
49 return nil, errNotConInputReader
48 return nil, errNotConInputReader
52+ events []xwindows.InputRecord
52− // read up to 256 events, this is to allow for sequences events reported as
56+ // Peek up to 256 events, this is to allow for sequences events reported as
53− // key events.
57+ // key events.
54− var events [256]xwindows.InputRecord
58+ events, err = peekNConsoleInputs(cc.conin, 256)
55− _, err := finput(cc.conin, events[:])
57 if cc.isCanceled() {
59 if cc.isCanceled() {
58 return nil, cancelreader.ErrCanceled
60 return nil, cancelreader.ErrCanceled
63+ return nil, fmt.Errorf("peek coninput events: %w", err)
69+ // Sleep for a bit to avoid busy waiting.
70+ time.Sleep(10 * time.Millisecond)
73+ events, err = readNConsoleInputs(cc.conin, uint32(len(events)))
75+ return nil, cancelreader.ErrCanceled
60 return nil, fmt.Errorf("read coninput events: %w", err)
78 return nil, fmt.Errorf("read coninput events: %w", err)
63 var evs []Event
81 var evs []Event
64 for _, event := range events {
82 for _, event := range events {
65 if e := d.SequenceParser.parseConInputEvent(event, &d.keyState, d.MouseMode, d.logger); e != nil {
83 if e := d.SequenceParser.parseConInputEvent(event, &d.keyState, d.MouseMode, d.logger); e != nil {
69 if multi, ok := e.(MultiEvent); ok {
84 if multi, ok := e.(MultiEvent); ok {
70 if d.logger != nil {
85 if d.logger != nil {
71 for _, ev := range multi {
86 for _, ev := range multi {
@@ -223,6 +238,16 @@ func highWord(data uint32) uint16 {
223 return uint16((data & 0xFFFF0000) >> 16) //nolint:gosec
238 return uint16((data & 0xFFFF0000) >> 16) //nolint:gosec
241+func readNConsoleInputs(console windows.Handle, maxEvents uint32) ([]xwindows.InputRecord, error) {
243+ return nil, fmt.Errorf("maxEvents cannot be zero")
246+ records := make([]xwindows.InputRecord, maxEvents)
247+ n, err := readConsoleInput(console, records)
248+ return records[:n], err
226func readConsoleInput(console windows.Handle, inputRecords []xwindows.InputRecord) (uint32, error) {
251func readConsoleInput(console windows.Handle, inputRecords []xwindows.InputRecord) (uint32, error) {
227 if len(inputRecords) == 0 {
252 if len(inputRecords) == 0 {
228 return 0, fmt.Errorf("size of input record buffer cannot be zero")
253 return 0, fmt.Errorf("size of input record buffer cannot be zero")
@@ -235,7 +260,6 @@ func readConsoleInput(console windows.Handle, inputRecords []xwindows.InputRecor
235 return read, err //nolint:wrapcheck
260 return read, err //nolint:wrapcheck
239func peekConsoleInput(console windows.Handle, inputRecords []xwindows.InputRecord) (uint32, error) {
263func peekConsoleInput(console windows.Handle, inputRecords []xwindows.InputRecord) (uint32, error) {
240 if len(inputRecords) == 0 {
264 if len(inputRecords) == 0 {
241 return 0, fmt.Errorf("size of input record buffer cannot be zero")
265 return 0, fmt.Errorf("size of input record buffer cannot be zero")
@@ -248,6 +272,16 @@ func peekConsoleInput(console windows.Handle, inputRecords []xwindows.InputRecor
248 return read, err //nolint:wrapcheck
272 return read, err //nolint:wrapcheck
275+func peekNConsoleInputs(console windows.Handle, maxEvents uint32) ([]xwindows.InputRecord, error) {
277+ return nil, fmt.Errorf("maxEvents cannot be zero")
280+ records := make([]xwindows.InputRecord, maxEvents)
281+ n, err := peekConsoleInput(console, records)
282+ return records[:n], err
251// parseWin32InputKeyEvent parses a single key event from either the Windows
285// parseWin32InputKeyEvent parses a single key event from either the Windows
252// Console API or win32-input-mode events. When state is nil, it means this is
286// Console API or win32-input-mode events. When state is nil, it means this is
253// an event from win32-input-mode. Otherwise, it's a key event from the Windows
287// an event from win32-input-mode. Otherwise, it's a key event from the Windows
@@ -506,7 +540,9 @@ func (p *SequenceParser) parseWin32InputKeyEvent(state *win32InputState, vkc uin
507 var text string
541 var text string
508 keyCode := baseCode
542 keyCode := baseCode
509− if !unicode.IsControl(r) {
543+ if unicode.IsControl(r) {
544+ return p.parseControl(byte(r))
510 rw := utf8.EncodeRune(utf8Buf[:], r)
546 rw := utf8.EncodeRune(utf8Buf[:], r)
511 keyCode, _ = utf8.DecodeRune(utf8Buf[:rw])
547 keyCode, _ = utf8.DecodeRune(utf8Buf[:rw])
512 if unicode.IsPrint(keyCode) && (cks == 0 ||
548 if unicode.IsPrint(keyCode) && (cks == 0 ||
@@ -517,18 +553,18 @@ func (p *SequenceParser) parseWin32InputKeyEvent(state *win32InputState, vkc uin
517 // then the key event is a printable event i.e. [text] is not empty.
553 // then the key event is a printable event i.e. [text] is not empty.
518 text = string(keyCode)
554 text = string(keyCode)
522− key.Code = keyCode
557+ key.Code = keyCode
523− key.Text = text
558+ key.Text = text
524− key.Mod = translateControlKeyState(cks)
559+ key.Mod = translateControlKeyState(cks)
525− key.BaseCode = baseCode
560+ key.BaseCode = baseCode
526− key = ensureKeyCase(key, cks)
561+ key = ensureKeyCase(key, cks)
527− if keyDown {
562+ if keyDown {
528− return KeyPressEvent(key)
563+ return KeyPressEvent(key)
531− return KeyReleaseEvent(key)
566+ return KeyReleaseEvent(key)
534// ensureKeyCase ensures that the key's text is in the correct case based on the
570// ensureKeyCase ensures that the key's text is in the correct case based on the