From a85696d5e07d8906b0bebeb3f4947281a23b4db4 Mon Sep 17 00:00:00 2001 From: Dmytro Maluka Date: Mon, 10 Jun 2024 02:30:55 +0200 Subject: [PATCH 1/2] Don't use tcell's Rune() for non-KeyRune events According to tcell documentation, Rune() should only be used for KeyRune events. Otherwise its return value is not guaranteed and should not be relied upon. This fixes issue #2947: Esc key not working on Windows, since tcell sends lone Esc key event with rune == 0 on Unix but with rune == 27 (the keycode) on Windows. --- internal/action/bindings.go | 13 ------------- internal/action/bufpane.go | 4 +++- internal/action/events.go | 11 +++++++---- internal/action/infopane.go | 4 +++- internal/action/termpane.go | 4 +++- 5 files changed, 16 insertions(+), 20 deletions(-) diff --git a/internal/action/bindings.go b/internal/action/bindings.go index 0b940ebf..01ea7845 100644 --- a/internal/action/bindings.go +++ b/internal/action/bindings.go @@ -176,31 +176,18 @@ modSearch: // see if the key is in bindingKeys with the Ctrl prefix. k = string(unicode.ToUpper(rune(k[0]))) + k[1:] if code, ok := keyEvents["Ctrl"+k]; ok { - var r tcell.Key - // Special case for escape, for some reason tcell doesn't send it with the esc character - if code < 256 && code != 27 { - r = code - } - // It is, we're done. return KeyEvent{ code: code, mod: modifiers, - r: rune(r), }, true } } // See if we can find the key in bindingKeys if code, ok := keyEvents[k]; ok { - var r tcell.Key - // Special case for escape, for some reason tcell doesn't send it with the esc character - if code < 256 && code != 27 { - r = code - } return KeyEvent{ code: code, mod: modifiers, - r: rune(r), }, true } diff --git a/internal/action/bufpane.go b/internal/action/bufpane.go index 7b348b79..369749f5 100644 --- a/internal/action/bufpane.go +++ b/internal/action/bufpane.go @@ -472,7 +472,9 @@ func (h *BufPane) HandleEvent(event tcell.Event) { ke := KeyEvent{ code: e.Key(), mod: metaToAlt(e.Modifiers()), - r: e.Rune(), + } + if e.Key() == tcell.KeyRune { + ke.r = e.Rune() } done := h.DoKeyEvent(ke) diff --git a/internal/action/events.go b/internal/action/events.go index 4addf1b5..c0d5b7be 100644 --- a/internal/action/events.go +++ b/internal/action/events.go @@ -68,7 +68,7 @@ func (k KeyEvent) Name() string { if k.code == tcell.KeyRune { s = string(k.r) } else { - s = fmt.Sprintf("Key[%d,%d]", k.code, int(k.r)) + s = fmt.Sprintf("Key[%d]", k.code) } } if len(m) != 0 { @@ -155,11 +155,14 @@ func (m MouseEvent) Name() string { func ConstructEvent(event tcell.Event) (Event, error) { switch e := event.(type) { case *tcell.EventKey: - return KeyEvent{ + ke := KeyEvent{ code: e.Key(), mod: metaToAlt(e.Modifiers()), - r: e.Rune(), - }, nil + } + if e.Key() == tcell.KeyRune { + ke.r = e.Rune() + } + return ke, nil case *tcell.EventRaw: return RawEvent{ esc: e.EscSeq(), diff --git a/internal/action/infopane.go b/internal/action/infopane.go index d3f30fd4..8f13c184 100644 --- a/internal/action/infopane.go +++ b/internal/action/infopane.go @@ -89,7 +89,9 @@ func (h *InfoPane) HandleEvent(event tcell.Event) { ke := KeyEvent{ code: e.Key(), mod: metaToAlt(e.Modifiers()), - r: e.Rune(), + } + if e.Key() == tcell.KeyRune { + ke.r = e.Rune() } done := h.DoKeyEvent(ke) diff --git a/internal/action/termpane.go b/internal/action/termpane.go index f440f0cd..0cb50706 100644 --- a/internal/action/termpane.go +++ b/internal/action/termpane.go @@ -128,7 +128,9 @@ func (t *TermPane) HandleEvent(event tcell.Event) { ke := KeyEvent{ code: e.Key(), mod: metaToAlt(e.Modifiers()), - r: e.Rune(), + } + if e.Key() == tcell.KeyRune { + ke.r = e.Rune() } action, more := TermBindings.NextEvent(ke, nil) From 25c7fa55b1136742088026925175a4d2127eeba7 Mon Sep 17 00:00:00 2001 From: Dmytro Maluka Date: Mon, 10 Jun 2024 02:54:37 +0200 Subject: [PATCH 2/2] De-duplicate code for KeyEvent creation --- internal/action/bufpane.go | 8 +------- internal/action/events.go | 20 ++++++++++++-------- internal/action/infopane.go | 8 +------- internal/action/termpane.go | 8 +------- 4 files changed, 15 insertions(+), 29 deletions(-) diff --git a/internal/action/bufpane.go b/internal/action/bufpane.go index 369749f5..34808eca 100644 --- a/internal/action/bufpane.go +++ b/internal/action/bufpane.go @@ -469,13 +469,7 @@ func (h *BufPane) HandleEvent(event tcell.Event) { h.paste(e.Text()) h.Relocate() case *tcell.EventKey: - ke := KeyEvent{ - code: e.Key(), - mod: metaToAlt(e.Modifiers()), - } - if e.Key() == tcell.KeyRune { - ke.r = e.Rune() - } + ke := keyEvent(e) done := h.DoKeyEvent(ke) if !done && e.Key() == tcell.KeyRune { diff --git a/internal/action/events.go b/internal/action/events.go index c0d5b7be..9b6a0ee6 100644 --- a/internal/action/events.go +++ b/internal/action/events.go @@ -44,6 +44,17 @@ func metaToAlt(mod tcell.ModMask) tcell.ModMask { return mod } +func keyEvent(e *tcell.EventKey) KeyEvent { + ke := KeyEvent{ + code: e.Key(), + mod: metaToAlt(e.Modifiers()), + } + if e.Key() == tcell.KeyRune { + ke.r = e.Rune() + } + return ke +} + func (k KeyEvent) Name() string { if k.any { return "" @@ -155,14 +166,7 @@ func (m MouseEvent) Name() string { func ConstructEvent(event tcell.Event) (Event, error) { switch e := event.(type) { case *tcell.EventKey: - ke := KeyEvent{ - code: e.Key(), - mod: metaToAlt(e.Modifiers()), - } - if e.Key() == tcell.KeyRune { - ke.r = e.Rune() - } - return ke, nil + return keyEvent(e), nil case *tcell.EventRaw: return RawEvent{ esc: e.EscSeq(), diff --git a/internal/action/infopane.go b/internal/action/infopane.go index 8f13c184..93dd9453 100644 --- a/internal/action/infopane.go +++ b/internal/action/infopane.go @@ -86,13 +86,7 @@ func (h *InfoPane) HandleEvent(event tcell.Event) { case *tcell.EventResize: // TODO case *tcell.EventKey: - ke := KeyEvent{ - code: e.Key(), - mod: metaToAlt(e.Modifiers()), - } - if e.Key() == tcell.KeyRune { - ke.r = e.Rune() - } + ke := keyEvent(e) done := h.DoKeyEvent(ke) hasYN := h.HasYN diff --git a/internal/action/termpane.go b/internal/action/termpane.go index 0cb50706..46d14d91 100644 --- a/internal/action/termpane.go +++ b/internal/action/termpane.go @@ -125,13 +125,7 @@ func (t *TermPane) Unsplit() { // copy-paste func (t *TermPane) HandleEvent(event tcell.Event) { if e, ok := event.(*tcell.EventKey); ok { - ke := KeyEvent{ - code: e.Key(), - mod: metaToAlt(e.Modifiers()), - } - if e.Key() == tcell.KeyRune { - ke.r = e.Rune() - } + ke := keyEvent(e) action, more := TermBindings.NextEvent(ke, nil) if !more {