diff --git a/go.mod b/go.mod index 88d79b39c65..15aa2c40abf 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/aybabtme/humanlog v0.4.1 github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 github.com/creack/pty v1.1.11 - github.com/gdamore/tcell/v2 v2.13.5 + github.com/gdamore/tcell/v2 v2.13.7-0.20260111024317-4739cfe77a24 github.com/go-errors/errors v1.5.1 github.com/gookit/color v1.4.2 github.com/integrii/flaggy v1.4.0 diff --git a/go.sum b/go.sum index cf91248a30f..8e8d9dea4c7 100644 --- a/go.sum +++ b/go.sum @@ -95,8 +95,8 @@ github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw= github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo= -github.com/gdamore/tcell/v2 v2.13.5 h1:YvWYCSr6gr2Ovs84dXbZLjDuOfQchhj8buOEqY52rpA= -github.com/gdamore/tcell/v2 v2.13.5/go.mod h1:+Wfe208WDdB7INEtCsNrAN6O2m+wsTPk1RAovjaILlo= +github.com/gdamore/tcell/v2 v2.13.7-0.20260111024317-4739cfe77a24 h1:evl5XktHhmK3oAyAp3VcU/1NwhfQllxstUpd2m5fZUk= +github.com/gdamore/tcell/v2 v2.13.7-0.20260111024317-4739cfe77a24/go.mod h1:+Wfe208WDdB7INEtCsNrAN6O2m+wsTPk1RAovjaILlo= github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= diff --git a/vendor/github.com/gdamore/tcell/v2/input.go b/vendor/github.com/gdamore/tcell/v2/input.go index 32bc88ea306..d5dbf51a616 100644 --- a/vendor/github.com/gdamore/tcell/v2/input.go +++ b/vendor/github.com/gdamore/tcell/v2/input.go @@ -84,6 +84,7 @@ type inputProcessor struct { evch chan<- Event rows int // used for clipping mouse coordinates cols int // used for clipping mouse coordinates + surrogate rune nested *inputProcessor } @@ -135,8 +136,9 @@ type csiParamMode struct { } type keyMap struct { - Key Key - Mod ModMask + Key Key + Mod ModMask + Rune rune } var csiAllKeys = map[csiParamMode]keyMap{ @@ -275,41 +277,70 @@ var csiAllKeys = map[csiParamMode]keyMap{ } // keys reported using Kitty csi-u protocol -var csiUKeys = map[int]Key{ - 27: KeyESC, - 9: KeyTAB, - 13: KeyEnter, - 127: KeyBS, - 57358: KeyCapsLock, - 57359: KeyScrollLock, - 57360: KeyNumLock, - 57361: KeyPrint, - 57362: KeyPause, - 57363: KeyMenu, - 57376: KeyF13, - 57377: KeyF14, - 57378: KeyF15, - 57379: KeyF16, - 57380: KeyF17, - 57381: KeyF18, - 57382: KeyF19, - 57383: KeyF20, - 57384: KeyF21, - 57385: KeyF22, - 57386: KeyF23, - 57387: KeyF24, - 57388: KeyF25, - 57389: KeyF26, - 57390: KeyF27, - 57391: KeyF28, - 57392: KeyF29, - 57393: KeyF30, - 57394: KeyF31, - 57395: KeyF32, - 57396: KeyF33, - 57397: KeyF34, - 57398: KeyF35, - // TODO: KP keys +var csiUKeys = map[int]keyMap{ + 27: {Key: KeyESC}, + 9: {Key: KeyTAB}, + 13: {Key: KeyEnter}, + 127: {Key: KeyBS}, + 57358: {Key: KeyCapsLock}, + 57359: {Key: KeyScrollLock}, + 57360: {Key: KeyNumLock}, + 57361: {Key: KeyPrint}, + 57362: {Key: KeyPause}, + 57363: {Key: KeyMenu}, + 57376: {Key: KeyF13}, + 57377: {Key: KeyF14}, + 57378: {Key: KeyF15}, + 57379: {Key: KeyF16}, + 57380: {Key: KeyF17}, + 57381: {Key: KeyF18}, + 57382: {Key: KeyF19}, + 57383: {Key: KeyF20}, + 57384: {Key: KeyF21}, + 57385: {Key: KeyF22}, + 57386: {Key: KeyF23}, + 57387: {Key: KeyF24}, + 57388: {Key: KeyF25}, + 57389: {Key: KeyF26}, + 57390: {Key: KeyF27}, + 57391: {Key: KeyF28}, + 57392: {Key: KeyF29}, + 57393: {Key: KeyF30}, + 57394: {Key: KeyF31}, + 57395: {Key: KeyF32}, + 57396: {Key: KeyF33}, + 57397: {Key: KeyF34}, + 57398: {Key: KeyF35}, + 57399: {Key: KeyRune, Rune: '0'}, // KP 0 + 57400: {Key: KeyRune, Rune: '1'}, // KP 1 + 57401: {Key: KeyRune, Rune: '2'}, // KP 2 + 57402: {Key: KeyRune, Rune: '3'}, // KP 3 + 57403: {Key: KeyRune, Rune: '4'}, // KP 4 + 57404: {Key: KeyRune, Rune: '5'}, // KP 5 + 57405: {Key: KeyRune, Rune: '6'}, // KP 6 + 57406: {Key: KeyRune, Rune: '7'}, // KP 7 + 57407: {Key: KeyRune, Rune: '8'}, // KP 8 + 57408: {Key: KeyRune, Rune: '9'}, // KP 9 + 57409: {Key: KeyRune, Rune: '.'}, // KP_DECIMAL + 57410: {Key: KeyRune, Rune: '/'}, // KP_DIVIDE + 57411: {Key: KeyRune, Rune: '*'}, // KP_MULTIPLY + 57412: {Key: KeyRune, Rune: '-'}, // KP_SUBTRACT + 57413: {Key: KeyRune, Rune: '+'}, // KP_ADD + 57414: {Key: KeyEnter}, // KP_ENTER + 57415: {Key: KeyRune, Rune: '='}, // KP_EQUAL + 57416: {Key: KeyClear}, // KP_SEPARATOR + 57417: {Key: KeyLeft}, // KP_LEFT + 57418: {Key: KeyRight}, // KP_RIGHT + 57419: {Key: KeyUp}, // KP_UP + 57420: {Key: KeyDown}, // KP_DOWN + 57421: {Key: KeyPgUp}, // KP_PG_UP + 57422: {Key: KeyPgDn}, // KP_PG_DN + 57423: {Key: KeyHome}, // KP_HOME + 57424: {Key: KeyEnd}, // KP_END + 57425: {Key: KeyInsert}, // KP_INSERT + 57426: {Key: KeyDelete}, // KP_DELETE + // 57427: {Key: KeyBegin}, // KP_BEGIN + // TODO: Media keys } @@ -318,8 +349,8 @@ var winKeys = map[int]Key{ 0x03: KeyCancel, // vkCancel 0x08: KeyBackspace, // vkBackspace 0x09: KeyTab, // vkTab + 0x0c: KeyClear, // vClear 0x0d: KeyEnter, // vkReturn - 0x12: KeyClear, // vClear 0x13: KeyPause, // vkPause 0x1b: KeyEscape, // vkEscape 0x21: KeyPgUp, // vkPrior @@ -701,11 +732,22 @@ func (ip *inputProcessor) handleWinKey(P []int) { } else if chr < ' ' && P[0] >= 0x41 && P[0] <= 0x5a { key = Key(P[0]) chr = 0 - } else if key == 0x11 || key == 0x13 || key == 0x14 { + + } else if chr >= 0xD800 && chr <= 0xDBFF { + // high surrogate pair + ip.surrogate = chr + return + } else if chr >= 0xDC00 && chr <= 0xDFFF { + // low surrogate pair + chr = utf16.DecodeRune(ip.surrogate, chr) + } else if P[0] == 0x10 || P[0] == 0x11 || P[0] == 0x12 || P[0] == 0x14 { // lone modifiers + ip.surrogate = 0 return } + ip.surrogate = 0 + // Modifiers if P[4]&0x010 != 0 { mod |= ModShift @@ -791,8 +833,8 @@ func (ip *inputProcessor) handleCsi(mode rune, params []byte, intermediate []byt key := KeyRune chr := rune(0) if k1, ok := csiUKeys[P0]; ok { - key = k1 - chr = 0 + key = k1.Key + chr = k1.Rune } else { chr = rune(P0) } diff --git a/vendor/github.com/gdamore/tcell/v2/tty_win.go b/vendor/github.com/gdamore/tcell/v2/tty_win.go index a50ef5f68b2..0a6d10bb3f7 100644 --- a/vendor/github.com/gdamore/tcell/v2/tty_win.go +++ b/vendor/github.com/gdamore/tcell/v2/tty_win.go @@ -1,4 +1,4 @@ -// Copyright 2025 The TCell Authors +// Copyright 2026 The TCell Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use file except in compliance with the License. @@ -72,6 +72,7 @@ type winTty struct { oomode uint32 // original output mode oscreen consoleInfo wg sync.WaitGroup + surrogate rune sync.Mutex } @@ -126,7 +127,7 @@ func (w *winTty) Drain() error { func (w *winTty) getConsoleInput() error { // cancelFlag comes first as WaitForMultipleObjects returns the lowest index - // in the event that both events are signalled. + // in the event that both events are signaled. waitObjects := []syscall.Handle{w.cancelFlag, w.in} // As arrays are contiguous in memory, a pointer to the first object is the @@ -158,19 +159,30 @@ func (w *winTty) getConsoleInput() error { if rv == 0 { return er } + loop: for i := range nrec { ir := rec[i] switch ir.typ { case keyEvent: - chr := ir.data[10] // we only see ASCII, key down events in VT mode - - // because we use win32-input-mode, we will only - // see US-ASCII characters - (Q: will they be - // 16-bit values with possible surrogate pairs?) - select { - case w.buf <- chr: - case <-w.stopQ: - break + // we normally only expect to see ascii, but paste data may come in as UTF-16. + wc := rune(binary.LittleEndian.Uint16(ir.data[10:])) + if wc >= 0xD800 && wc <= 0xDBFF { + // if it was a high surrogate, which happens for pasted UTF-16, + // then save it until we get the low and can decode it. + w.surrogate = wc + continue + } else if wc >= 0xDC00 && wc <= 0xDFFF { + wc = utf16.DecodeRune(w.surrogate, wc) + } + w.surrogate = 0 + for _, chr := range []byte(string(wc)) { + // We normally expect only to see ASCII (win32-input-mode), + // but apparently pasted data can arrive in UTF-16 here. + select { + case w.buf <- chr: + case <-w.stopQ: + break loop + } } case resizeEvent: diff --git a/vendor/modules.txt b/vendor/modules.txt index db746300f3e..77c9716eef5 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -88,7 +88,7 @@ github.com/fatih/color # github.com/gdamore/encoding v1.0.1 ## explicit; go 1.9 github.com/gdamore/encoding -# github.com/gdamore/tcell/v2 v2.13.5 +# github.com/gdamore/tcell/v2 v2.13.7-0.20260111024317-4739cfe77a24 ## explicit; go 1.24.0 github.com/gdamore/tcell/v2 github.com/gdamore/tcell/v2/terminfo