diff --git a/twin/screen.go b/twin/screen.go index a01f91e0..4f00ddfe 100644 --- a/twin/screen.go +++ b/twin/screen.go @@ -260,14 +260,14 @@ func consumeEncodedEvent(encodedEventSequences string) (*Event, string) { mouseMatch := MOUSE_EVENT_REGEX.FindStringSubmatch(encodedEventSequences) if mouseMatch != nil { - if mouseMatch[1] == "65" { - var event Event = EventMouse{buttons: MouseWheelDown} - return &event, strings.TrimPrefix(encodedEventSequences, mouseMatch[0]) - } if mouseMatch[1] == "64" { var event Event = EventMouse{buttons: MouseWheelUp} return &event, strings.TrimPrefix(encodedEventSequences, mouseMatch[0]) } + if mouseMatch[1] == "65" { + var event Event = EventMouse{buttons: MouseWheelDown} + return &event, strings.TrimPrefix(encodedEventSequences, mouseMatch[0]) + } log.Debug("Unhandled multi character mouse escape sequence(s): ", encodedEventSequences) return nil, "" @@ -275,26 +275,32 @@ func consumeEncodedEvent(encodedEventSequences string) (*Event, string) { // No escape sequence prefix matched runes := []rune(encodedEventSequences) - if len(runes) != 1 { - // This means one or more sequences should be added to - // escapeSequenceToKeyCode in keys.go. - log.Debug("Unhandled multi character terminal escape sequence(s): ", encodedEventSequences) - - // Mark everything as consumed since we don't know how to proceed otherwise. + if len(runes) == 0 { return nil, "" } - var event Event if runes[0] == '\x1b' { - event = EventKeyCode{KeyEscape} - } else if runes[0] == '\r' { - event = EventKeyCode{KeyEnter} - } else { - // Report the single rune - event = EventRune{rune: runes[0]} + if len(runes) != 1 { + // This means one or more sequences should be added to + // escapeSequenceToKeyCode in keys.go. + log.Debug("Unhandled multi character terminal escape sequence(s): ", encodedEventSequences) + + // Mark everything as consumed since we don't know how to proceed otherwise. + return nil, "" + } + + var event Event = EventKeyCode{KeyEscape} + return &event, string(runes[1:]) + } + + if runes[0] == '\r' { + var event Event = EventKeyCode{KeyEnter} + return &event, string(runes[1:]) } - return &event, "" + // Report the single rune + var event Event = EventRune{rune: runes[0]} + return &event, string(runes[1:]) } // Returns screen width and height. diff --git a/twin/screen_test.go b/twin/screen_test.go new file mode 100644 index 00000000..0649b3e9 --- /dev/null +++ b/twin/screen_test.go @@ -0,0 +1,50 @@ +package twin + +import ( + "strings" + "testing" + + "gotest.tools/v3/assert" +) + +func assertEncode(t *testing.T, incomingString string, expectedEvent Event, expectedRemainder string) { + actualEvent, actualRemainder := consumeEncodedEvent(incomingString) + + message := strings.Replace(incomingString, "\x1b", "ESC", -1) + message = strings.Replace(message, "\r", "RET", -1) + + assert.Assert(t, actualEvent != nil, + "Input: %s Result: %#v Expected: %#v", message, "nil", expectedEvent) + assert.Equal(t, *actualEvent, expectedEvent, + "Input: %s Result: %#v Expected: %#v", message, *actualEvent, expectedEvent) + assert.Equal(t, actualRemainder, expectedRemainder, message) +} + +func TestConsumeEncodedEvent(t *testing.T) { + assertEncode(t, "a", EventRune{rune: 'a'}, "") + assertEncode(t, "\r", EventKeyCode{keyCode: KeyEnter}, "") + assertEncode(t, "\x1b", EventKeyCode{keyCode: KeyEscape}, "") + + // Implicitly test having a remaining rune at the end + assertEncode(t, "\x1b[Ax", EventKeyCode{keyCode: KeyUp}, "x") + + assertEncode(t, "\x1b[<64;127;41M", EventMouse{buttons: MouseWheelUp}, "") + assertEncode(t, "\x1b[<65;127;41M", EventMouse{buttons: MouseWheelDown}, "") + + // This happens when users paste. + // + // Ref: https://github.com/walles/moar/issues/73 + assertEncode(t, "1234", EventRune{rune: '1'}, "234") +} + +func TestConsumeEncodedEventWithUnsupportedEscapeCode(t *testing.T) { + event, remainder := consumeEncodedEvent("\x1bXXXXX") + assert.Assert(t, event == nil) + assert.Equal(t, remainder, "") +} + +func TestConsumeEncodedEventWithNoInput(t *testing.T) { + event, remainder := consumeEncodedEvent("") + assert.Assert(t, event == nil) + assert.Equal(t, remainder, "") +}