mirror of
https://github.com/gdamore/tcell.git
synced 2025-04-24 13:48:51 +08:00
fixes #120 Support for bracketed paste mode
This adds Bracketed Paste support for terminals that have mouse support and support it. The bracketing events are EventPaste, with methods to note Start() or End() of the paste. Content comes in as normal rune events. Programs must opt-in to this by calling screen.EnablePaste().
This commit is contained in:
parent
aeb3a11948
commit
197faf3eae
@ -116,11 +116,13 @@ func main() {
|
|||||||
Foreground(tcell.ColorReset)
|
Foreground(tcell.ColorReset)
|
||||||
s.SetStyle(defStyle)
|
s.SetStyle(defStyle)
|
||||||
s.EnableMouse()
|
s.EnableMouse()
|
||||||
|
s.EnablePaste()
|
||||||
s.Clear()
|
s.Clear()
|
||||||
|
|
||||||
posfmt := "Mouse: %d, %d "
|
posfmt := "Mouse: %d, %d "
|
||||||
btnfmt := "Buttons: %s"
|
btnfmt := "Buttons: %s"
|
||||||
keyfmt := "Keys: %s"
|
keyfmt := "Keys: %s"
|
||||||
|
pastefmt := "Paste: [%d] %s"
|
||||||
white := tcell.StyleDefault.
|
white := tcell.StyleDefault.
|
||||||
Foreground(tcell.ColorWhite).Background(tcell.ColorRed)
|
Foreground(tcell.ColorWhite).Background(tcell.ColorRed)
|
||||||
|
|
||||||
@ -131,15 +133,23 @@ func main() {
|
|||||||
lchar := '*'
|
lchar := '*'
|
||||||
bstr := ""
|
bstr := ""
|
||||||
lks := ""
|
lks := ""
|
||||||
|
pstr := ""
|
||||||
ecnt := 0
|
ecnt := 0
|
||||||
|
pasting := false
|
||||||
|
|
||||||
for {
|
for {
|
||||||
drawBox(s, 1, 1, 42, 6, white, ' ')
|
drawBox(s, 1, 1, 42, 7, white, ' ')
|
||||||
emitStr(s, 2, 2, white, "Press ESC twice to exit, C to clear.")
|
emitStr(s, 2, 2, white, "Press ESC twice to exit, C to clear.")
|
||||||
emitStr(s, 2, 3, white, fmt.Sprintf(posfmt, mx, my))
|
emitStr(s, 2, 3, white, fmt.Sprintf(posfmt, mx, my))
|
||||||
emitStr(s, 2, 4, white, fmt.Sprintf(btnfmt, bstr))
|
emitStr(s, 2, 4, white, fmt.Sprintf(btnfmt, bstr))
|
||||||
emitStr(s, 2, 5, white, fmt.Sprintf(keyfmt, lks))
|
emitStr(s, 2, 5, white, fmt.Sprintf(keyfmt, lks))
|
||||||
|
|
||||||
|
ps := pstr
|
||||||
|
if len(ps) > 26 {
|
||||||
|
ps = "..." + ps[len(ps)-24:]
|
||||||
|
}
|
||||||
|
emitStr(s, 2, 6, white, fmt.Sprintf(pastefmt, len(pstr), ps))
|
||||||
|
|
||||||
s.Show()
|
s.Show()
|
||||||
bstr = ""
|
bstr = ""
|
||||||
ev := s.PollEvent()
|
ev := s.PollEvent()
|
||||||
@ -160,6 +170,17 @@ func main() {
|
|||||||
s.SetContent(w-1, h-1, 'R', nil, st)
|
s.SetContent(w-1, h-1, 'R', nil, st)
|
||||||
case *tcell.EventKey:
|
case *tcell.EventKey:
|
||||||
s.SetContent(w-2, h-2, ev.Rune(), nil, st)
|
s.SetContent(w-2, h-2, ev.Rune(), nil, st)
|
||||||
|
if pasting {
|
||||||
|
s.SetContent(w-1, h-1, 'P', nil, st)
|
||||||
|
if ev.Key() == tcell.KeyRune {
|
||||||
|
pstr = pstr + string(ev.Rune())
|
||||||
|
} else {
|
||||||
|
pstr = pstr + "\ufffd" // replacement for now
|
||||||
|
}
|
||||||
|
lks = ""
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pstr = ""
|
||||||
s.SetContent(w-1, h-1, 'K', nil, st)
|
s.SetContent(w-1, h-1, 'K', nil, st)
|
||||||
if ev.Key() == tcell.KeyEscape {
|
if ev.Key() == tcell.KeyEscape {
|
||||||
ecnt++
|
ecnt++
|
||||||
@ -176,6 +197,11 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
lks = ev.Name()
|
lks = ev.Name()
|
||||||
|
case *tcell.EventPaste:
|
||||||
|
pasting = ev.Start()
|
||||||
|
if pasting {
|
||||||
|
pstr = ""
|
||||||
|
}
|
||||||
case *tcell.EventMouse:
|
case *tcell.EventMouse:
|
||||||
x, y := ev.Position()
|
x, y := ev.Position()
|
||||||
button := ev.Buttons()
|
button := ev.Buttons()
|
||||||
@ -206,7 +232,7 @@ func main() {
|
|||||||
switch ev.Buttons() {
|
switch ev.Buttons() {
|
||||||
case tcell.ButtonNone:
|
case tcell.ButtonNone:
|
||||||
if ox >= 0 {
|
if ox >= 0 {
|
||||||
bg := tcell.Color((lchar - '0') * 2) | tcell.ColorValid
|
bg := tcell.Color((lchar-'0')*2) | tcell.ColorValid
|
||||||
drawBox(s, ox, oy, x, y,
|
drawBox(s, ox, oy, x, y,
|
||||||
up.Background(bg),
|
up.Background(bg),
|
||||||
lchar)
|
lchar)
|
||||||
|
@ -249,6 +249,10 @@ func (s *cScreen) DisableMouse() {
|
|||||||
s.setInMode(modeResizeEn | modeExtndFlg)
|
s.setInMode(modeResizeEn | modeExtndFlg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *cScreen) EnablePaste() {}
|
||||||
|
|
||||||
|
func (s *cScreen) DisablePaste() {}
|
||||||
|
|
||||||
func (s *cScreen) Fini() {
|
func (s *cScreen) Fini() {
|
||||||
s.finiOnce.Do(s.finish)
|
s.finiOnce.Do(s.finish)
|
||||||
}
|
}
|
||||||
|
6
key.go
6
key.go
@ -375,6 +375,12 @@ const (
|
|||||||
KeyF64
|
KeyF64
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// These key codes are used internally, and will never appear to applications.
|
||||||
|
keyPasteStart Key = iota + 16384
|
||||||
|
keyPasteEnd
|
||||||
|
)
|
||||||
|
|
||||||
// These are the control keys. Note that they overlap with other keys,
|
// These are the control keys. Note that they overlap with other keys,
|
||||||
// perhaps. For example, KeyCtrlH is the same as KeyBackspace.
|
// perhaps. For example, KeyCtrlH is the same as KeyBackspace.
|
||||||
const (
|
const (
|
||||||
|
48
paste.go
Normal file
48
paste.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// Copyright 2020 The TCell Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the license at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package tcell
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EventPaste is used to mark the start and end of a bracketed paste.
|
||||||
|
// An event with .Start() true will be sent to mark the start.
|
||||||
|
// Then a number of keys will be sent to indicate that the content
|
||||||
|
// is pasted in. At the end, an event with .Start() false will be sent.
|
||||||
|
type EventPaste struct {
|
||||||
|
start bool
|
||||||
|
t time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// When returns the time when this EventMouse was created.
|
||||||
|
func (ev *EventPaste) When() time.Time {
|
||||||
|
return ev.t
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start returns true if this is the start of a paste.
|
||||||
|
func (ev *EventPaste) Start() bool {
|
||||||
|
return ev.start
|
||||||
|
}
|
||||||
|
|
||||||
|
// End returns true if this is the end of a paste.
|
||||||
|
func (ev *EventPaste) End() bool {
|
||||||
|
return !ev.start
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEventPaste returns a new EventPaste.
|
||||||
|
func NewEventPaste(start bool) *EventPaste {
|
||||||
|
return &EventPaste{t: time.Now(), start: start}
|
||||||
|
}
|
@ -104,6 +104,12 @@ type Screen interface {
|
|||||||
// DisableMouse disables the mouse.
|
// DisableMouse disables the mouse.
|
||||||
DisableMouse()
|
DisableMouse()
|
||||||
|
|
||||||
|
// EnablePaste enables bracketed paste mode, if supported.
|
||||||
|
EnablePaste()
|
||||||
|
|
||||||
|
// DisablePaste() disables bracketed paste mode.
|
||||||
|
DisablePaste()
|
||||||
|
|
||||||
// HasMouse returns true if the terminal (apparently) supports a
|
// HasMouse returns true if the terminal (apparently) supports a
|
||||||
// mouse. Note that the a return value of true doesn't guarantee that
|
// mouse. Note that the a return value of true doesn't guarantee that
|
||||||
// a mouse/pointing device is present; a false return definitely
|
// a mouse/pointing device is present; a false return definitely
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2016 The TCell Authors
|
// Copyright 2020 The TCell Authors
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use file except in compliance with the License.
|
// you may not use file except in compliance with the License.
|
||||||
@ -97,6 +97,7 @@ type simscreen struct {
|
|||||||
cursory int
|
cursory int
|
||||||
cursorvis bool
|
cursorvis bool
|
||||||
mouse bool
|
mouse bool
|
||||||
|
paste bool
|
||||||
charset string
|
charset string
|
||||||
encoder transform.Transformer
|
encoder transform.Transformer
|
||||||
decoder transform.Transformer
|
decoder transform.Transformer
|
||||||
@ -321,6 +322,14 @@ func (s *simscreen) DisableMouse() {
|
|||||||
s.mouse = false
|
s.mouse = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *simscreen) EnablePaste() {
|
||||||
|
s.paste = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *simscreen) DisablePaste() {
|
||||||
|
s.paste = false
|
||||||
|
}
|
||||||
|
|
||||||
func (s *simscreen) Size() (int, int) {
|
func (s *simscreen) Size() (int, int) {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
w, h := s.back.Size()
|
w, h := s.back.Size()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2019 The TCell Authors
|
// Copyright 2020 The TCell Authors
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use file except in compliance with the License.
|
// you may not use file except in compliance with the License.
|
||||||
@ -376,6 +376,24 @@ func LoadTerminfo(name string) (*terminfo.Terminfo, string, error) {
|
|||||||
t.KeyCtrlEnd = "\x1b[8^"
|
t.KeyCtrlEnd = "\x1b[8^"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Technically the RGB flag that is provided for xterm-direct is not
|
||||||
|
// quite right. The problem is that the -direct flag that was introduced
|
||||||
|
// with ncurses 6.1 requires a parsing for the parameters that we lack.
|
||||||
|
// For this case we'll just assume it's XTerm compatible. Someday this
|
||||||
|
// may be incorrect, but right now it is correct, and nobody uses it
|
||||||
|
// anyway.
|
||||||
|
if tc.getflag("Tc") {
|
||||||
|
// This presumes XTerm 24-bit true color.
|
||||||
|
t.TrueColor = true
|
||||||
|
} else if tc.getflag("RGB") {
|
||||||
|
// This is for xterm-direct, which uses a different scheme entirely.
|
||||||
|
// (ncurses went a very different direction from everyone else, and
|
||||||
|
// so it's unlikely anything is using this definition.)
|
||||||
|
t.TrueColor = true
|
||||||
|
t.SetBg = "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m"
|
||||||
|
t.SetFg = "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m"
|
||||||
|
}
|
||||||
|
|
||||||
// If the kmous entry is present, then we need to record the
|
// If the kmous entry is present, then we need to record the
|
||||||
// the codes to enter and exit mouse mode. Sadly, this is not
|
// the codes to enter and exit mouse mode. Sadly, this is not
|
||||||
// part of the terminfo databases anywhere that I've found, but
|
// part of the terminfo databases anywhere that I've found, but
|
||||||
|
@ -213,6 +213,10 @@ type Terminfo struct {
|
|||||||
KeyAltShfEnd string
|
KeyAltShfEnd string
|
||||||
KeyMetaShfHome string
|
KeyMetaShfHome string
|
||||||
KeyMetaShfEnd string
|
KeyMetaShfEnd string
|
||||||
|
EnablePaste string // bracketed paste mode
|
||||||
|
DisablePaste string
|
||||||
|
PasteStart string
|
||||||
|
PasteEnd string
|
||||||
Modifiers int
|
Modifiers int
|
||||||
TrueColor bool // true if the terminal supports direct color
|
TrueColor bool // true if the terminal supports direct color
|
||||||
}
|
}
|
||||||
|
163
tscreen.go
163
tscreen.go
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2019 The TCell Authors
|
// Copyright 2020 The TCell Authors
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use file except in compliance with the License.
|
// you may not use file except in compliance with the License.
|
||||||
@ -33,7 +33,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewTerminfoScreen returns a Screen that uses the stock TTY interface
|
// NewTerminfoScreen returns a Screen that uses the stock TTY interface
|
||||||
// and POSIX termios, combined with a terminfo description taken from
|
// and POSIX terminal control, combined with a terminfo description taken from
|
||||||
// the $TERM environment variable. It returns an error if the terminal
|
// the $TERM environment variable. It returns an error if the terminal
|
||||||
// is not supported for any reason.
|
// is not supported for any reason.
|
||||||
//
|
//
|
||||||
@ -75,45 +75,47 @@ type tKeyCode struct {
|
|||||||
|
|
||||||
// tScreen represents a screen backed by a terminfo implementation.
|
// tScreen represents a screen backed by a terminfo implementation.
|
||||||
type tScreen struct {
|
type tScreen struct {
|
||||||
ti *terminfo.Terminfo
|
ti *terminfo.Terminfo
|
||||||
h int
|
h int
|
||||||
w int
|
w int
|
||||||
fini bool
|
fini bool
|
||||||
cells CellBuffer
|
cells CellBuffer
|
||||||
in *os.File
|
in *os.File
|
||||||
out *os.File
|
out *os.File
|
||||||
buffering bool // true if we are collecting writes to buf instead of sending directly to out
|
buffering bool // true if we are collecting writes to buf instead of sending directly to out
|
||||||
buf bytes.Buffer
|
buf bytes.Buffer
|
||||||
curstyle Style
|
curstyle Style
|
||||||
style Style
|
style Style
|
||||||
evch chan Event
|
evch chan Event
|
||||||
sigwinch chan os.Signal
|
sigwinch chan os.Signal
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
indoneq chan struct{}
|
indoneq chan struct{}
|
||||||
keyexist map[Key]bool
|
keyexist map[Key]bool
|
||||||
keycodes map[string]*tKeyCode
|
keycodes map[string]*tKeyCode
|
||||||
keychan chan []byte
|
keychan chan []byte
|
||||||
keytimer *time.Timer
|
keytimer *time.Timer
|
||||||
keyexpire time.Time
|
keyexpire time.Time
|
||||||
cx int
|
cx int
|
||||||
cy int
|
cy int
|
||||||
mouse []byte
|
mouse []byte
|
||||||
clear bool
|
clear bool
|
||||||
cursorx int
|
cursorx int
|
||||||
cursory int
|
cursory int
|
||||||
tiosp *termiosPrivate
|
tiosp *termiosPrivate
|
||||||
wasbtn bool
|
wasbtn bool
|
||||||
acs map[rune]string
|
acs map[rune]string
|
||||||
charset string
|
charset string
|
||||||
encoder transform.Transformer
|
encoder transform.Transformer
|
||||||
decoder transform.Transformer
|
decoder transform.Transformer
|
||||||
fallback map[rune]string
|
fallback map[rune]string
|
||||||
colors map[Color]Color
|
colors map[Color]Color
|
||||||
palette []Color
|
palette []Color
|
||||||
truecolor bool
|
truecolor bool
|
||||||
escaped bool
|
escaped bool
|
||||||
buttondn bool
|
buttondn bool
|
||||||
finiOnce sync.Once
|
finiOnce sync.Once
|
||||||
|
enablePaste string
|
||||||
|
disablePaste string
|
||||||
|
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
@ -279,6 +281,24 @@ func (t *tScreen) prepareXtermModifiers() {
|
|||||||
t.prepareKeyModXTerm(KeyF12, t.ti.KeyF12)
|
t.prepareKeyModXTerm(KeyF12, t.ti.KeyF12)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) prepareBracketedPaste() {
|
||||||
|
// Another workaround for lack of reporting in terminfo.
|
||||||
|
// We assume if the terminal has a mouse entry, that it
|
||||||
|
// offers bracketed paste. But we allow specific overrides
|
||||||
|
// via our terminal database.
|
||||||
|
if t.ti.EnablePaste != "" {
|
||||||
|
t.enablePaste = t.ti.EnablePaste
|
||||||
|
t.disablePaste = t.ti.DisablePaste
|
||||||
|
t.prepareKey(keyPasteStart, t.ti.PasteStart)
|
||||||
|
t.prepareKey(keyPasteEnd, t.ti.PasteEnd)
|
||||||
|
} else if t.ti.MouseMode != "" {
|
||||||
|
t.enablePaste = "\x1b[?2004h"
|
||||||
|
t.disablePaste = "\x1b[?2004l"
|
||||||
|
t.prepareKey(keyPasteStart, "\x1b[200~")
|
||||||
|
t.prepareKey(keyPasteEnd, "\x1b[201~")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (t *tScreen) prepareKey(key Key, val string) {
|
func (t *tScreen) prepareKey(key Key, val string) {
|
||||||
t.prepareKeyMod(key, ModNone, val)
|
t.prepareKeyMod(key, ModNone, val)
|
||||||
}
|
}
|
||||||
@ -414,7 +434,10 @@ func (t *tScreen) prepareKeys() {
|
|||||||
t.prepareKey(KeyHome, "\x1bOH")
|
t.prepareKey(KeyHome, "\x1bOH")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.prepareKey(keyPasteStart, ti.PasteStart)
|
||||||
|
t.prepareKey(keyPasteEnd, ti.PasteEnd)
|
||||||
t.prepareXtermModifiers()
|
t.prepareXtermModifiers()
|
||||||
|
t.prepareBracketedPaste()
|
||||||
|
|
||||||
outer:
|
outer:
|
||||||
// Add key mappings for control keys.
|
// Add key mappings for control keys.
|
||||||
@ -435,7 +458,7 @@ outer:
|
|||||||
mod := ModCtrl
|
mod := ModCtrl
|
||||||
switch Key(i) {
|
switch Key(i) {
|
||||||
case KeyBS, KeyTAB, KeyESC, KeyCR:
|
case KeyBS, KeyTAB, KeyESC, KeyCR:
|
||||||
// directly typeable- no control sequence
|
// directly type-able- no control sequence
|
||||||
mod = ModNone
|
mod = ModNone
|
||||||
}
|
}
|
||||||
t.keycodes[string(rune(i))] = &tKeyCode{key: Key(i), mod: mod}
|
t.keycodes[string(rune(i))] = &tKeyCode{key: Key(i), mod: mod}
|
||||||
@ -458,6 +481,7 @@ func (t *tScreen) finish() {
|
|||||||
t.TPuts(ti.ExitCA)
|
t.TPuts(ti.ExitCA)
|
||||||
t.TPuts(ti.ExitKeypad)
|
t.TPuts(ti.ExitKeypad)
|
||||||
t.TPuts(ti.TParm(ti.MouseMode, 0))
|
t.TPuts(ti.TParm(ti.MouseMode, 0))
|
||||||
|
t.TPuts(t.disablePaste)
|
||||||
t.curstyle = styleInvalid
|
t.curstyle = styleInvalid
|
||||||
t.clear = false
|
t.clear = false
|
||||||
t.fini = true
|
t.fini = true
|
||||||
@ -681,8 +705,6 @@ func (t *tScreen) drawCell(x, y int) int {
|
|||||||
t.cx = -1
|
t.cx = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX: check for hazeltine not being able to display ~
|
|
||||||
|
|
||||||
if x > t.w-width {
|
if x > t.w-width {
|
||||||
// too wide to fit; emit a single space instead
|
// too wide to fit; emit a single space instead
|
||||||
width = 1
|
width = 1
|
||||||
@ -731,9 +753,9 @@ func (t *tScreen) showCursor() {
|
|||||||
// write operation at some point later.
|
// write operation at some point later.
|
||||||
func (t *tScreen) writeString(s string) {
|
func (t *tScreen) writeString(s string) {
|
||||||
if t.buffering {
|
if t.buffering {
|
||||||
io.WriteString(&t.buf, s)
|
_, _ = io.WriteString(&t.buf, s)
|
||||||
} else {
|
} else {
|
||||||
io.WriteString(t.out, s)
|
_, _ = io.WriteString(t.out, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -809,7 +831,7 @@ func (t *tScreen) draw() {
|
|||||||
// restore the cursor
|
// restore the cursor
|
||||||
t.showCursor()
|
t.showCursor()
|
||||||
|
|
||||||
t.buf.WriteTo(t.out)
|
_, _ = t.buf.WriteTo(t.out)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tScreen) EnableMouse() {
|
func (t *tScreen) EnableMouse() {
|
||||||
@ -824,6 +846,14 @@ func (t *tScreen) DisableMouse() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) EnablePaste() {
|
||||||
|
t.TPuts(t.enablePaste)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tScreen) DisablePaste() {
|
||||||
|
t.TPuts(t.disablePaste)
|
||||||
|
}
|
||||||
|
|
||||||
func (t *tScreen) Size() (int, int) {
|
func (t *tScreen) Size() (int, int) {
|
||||||
t.Lock()
|
t.Lock()
|
||||||
w, h := t.w, t.h
|
w, h := t.w, t.h
|
||||||
@ -842,7 +872,7 @@ func (t *tScreen) resize() {
|
|||||||
t.h = h
|
t.h = h
|
||||||
t.w = w
|
t.w = w
|
||||||
ev := NewEventResize(w, h)
|
ev := NewEventResize(w, h)
|
||||||
t.PostEvent(ev)
|
_ = t.PostEvent(ev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1137,7 +1167,7 @@ func (t *tScreen) parseSgrMouse(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
|
|||||||
}
|
}
|
||||||
// consume the event bytes
|
// consume the event bytes
|
||||||
for i >= 0 {
|
for i >= 0 {
|
||||||
buf.ReadByte()
|
_, _ = buf.ReadByte()
|
||||||
i--
|
i--
|
||||||
}
|
}
|
||||||
*evs = append(*evs, t.buildMouseEvent(x, y, btn))
|
*evs = append(*evs, t.buildMouseEvent(x, y, btn))
|
||||||
@ -1145,7 +1175,7 @@ func (t *tScreen) parseSgrMouse(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// incomplete & inconclusve at this point
|
// incomplete & inconclusive at this point
|
||||||
return true, false
|
return true, false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1190,7 +1220,7 @@ func (t *tScreen) parseXtermMouse(buf *bytes.Buffer, evs *[]Event) (bool, bool)
|
|||||||
case 5:
|
case 5:
|
||||||
y = int(b[i]) - 32 - 1
|
y = int(b[i]) - 32 - 1
|
||||||
for i >= 0 {
|
for i >= 0 {
|
||||||
buf.ReadByte()
|
_, _ = buf.ReadByte()
|
||||||
i--
|
i--
|
||||||
}
|
}
|
||||||
*evs = append(*evs, t.buildMouseEvent(x, y, btn))
|
*evs = append(*evs, t.buildMouseEvent(x, y, btn))
|
||||||
@ -1219,9 +1249,16 @@ func (t *tScreen) parseFunctionKey(buf *bytes.Buffer, evs *[]Event) (bool, bool)
|
|||||||
mod |= ModAlt
|
mod |= ModAlt
|
||||||
t.escaped = false
|
t.escaped = false
|
||||||
}
|
}
|
||||||
*evs = append(*evs, NewEventKey(k.key, r, mod))
|
switch k.key {
|
||||||
|
case keyPasteStart:
|
||||||
|
*evs = append(*evs, NewEventPaste(true))
|
||||||
|
case keyPasteEnd:
|
||||||
|
*evs = append(*evs, NewEventPaste(false))
|
||||||
|
default:
|
||||||
|
*evs = append(*evs, NewEventKey(k.key, r, mod))
|
||||||
|
}
|
||||||
for i := 0; i < len(esc); i++ {
|
for i := 0; i < len(esc); i++ {
|
||||||
buf.ReadByte()
|
_, _ = buf.ReadByte()
|
||||||
}
|
}
|
||||||
return true, true
|
return true, true
|
||||||
}
|
}
|
||||||
@ -1242,7 +1279,7 @@ func (t *tScreen) parseRune(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
|
|||||||
t.escaped = false
|
t.escaped = false
|
||||||
}
|
}
|
||||||
*evs = append(*evs, NewEventKey(KeyRune, rune(b[0]), mod))
|
*evs = append(*evs, NewEventKey(KeyRune, rune(b[0]), mod))
|
||||||
buf.ReadByte()
|
_, _ = buf.ReadByte()
|
||||||
return true, true
|
return true, true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1251,15 +1288,15 @@ func (t *tScreen) parseRune(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
|
|||||||
return false, false
|
return false, false
|
||||||
}
|
}
|
||||||
|
|
||||||
utfb := make([]byte, 12)
|
utf := make([]byte, 12)
|
||||||
for l := 1; l <= len(b); l++ {
|
for l := 1; l <= len(b); l++ {
|
||||||
t.decoder.Reset()
|
t.decoder.Reset()
|
||||||
nout, nin, e := t.decoder.Transform(utfb, b[:l], true)
|
nOut, nIn, e := t.decoder.Transform(utf, b[:l], true)
|
||||||
if e == transform.ErrShortSrc {
|
if e == transform.ErrShortSrc {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if nout != 0 {
|
if nOut != 0 {
|
||||||
r, _ := utf8.DecodeRune(utfb[:nout])
|
r, _ := utf8.DecodeRune(utf[:nOut])
|
||||||
if r != utf8.RuneError {
|
if r != utf8.RuneError {
|
||||||
mod := ModNone
|
mod := ModNone
|
||||||
if t.escaped {
|
if t.escaped {
|
||||||
@ -1268,9 +1305,9 @@ func (t *tScreen) parseRune(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
|
|||||||
}
|
}
|
||||||
*evs = append(*evs, NewEventKey(KeyRune, r, mod))
|
*evs = append(*evs, NewEventKey(KeyRune, r, mod))
|
||||||
}
|
}
|
||||||
for nin > 0 {
|
for nIn > 0 {
|
||||||
buf.ReadByte()
|
_, _ = buf.ReadByte()
|
||||||
nin--
|
nIn--
|
||||||
}
|
}
|
||||||
return true, true
|
return true, true
|
||||||
}
|
}
|
||||||
@ -1343,7 +1380,7 @@ func (t *tScreen) collectEventsFromInput(buf *bytes.Buffer, expire bool) []Event
|
|||||||
} else {
|
} else {
|
||||||
t.escaped = true
|
t.escaped = true
|
||||||
}
|
}
|
||||||
buf.ReadByte()
|
_, _ = buf.ReadByte()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Nothing was going to match, or we timed out
|
// Nothing was going to match, or we timed out
|
||||||
@ -1430,7 +1467,7 @@ func (t *tScreen) inputLoop() {
|
|||||||
case io.EOF:
|
case io.EOF:
|
||||||
case nil:
|
case nil:
|
||||||
default:
|
default:
|
||||||
t.PostEvent(NewEventError(e))
|
_ = t.PostEvent(NewEventError(e))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t.keychan <- chunk[:n]
|
t.keychan <- chunk[:n]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user