1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
package terminal
import "github.com/gdamore/tcell/v2"
// HandleKey sends a key press to the shell.
//
// Shift with Page Up or Page Down reads back through the history instead,
// which is where every terminal puts that. Everything else goes to the shell,
// and brings the view back to the live screen on the way — a terminal that
// stayed in its history while you typed would hide your own command.
//
// Once the program has gone, only the scrolling keys are still taken. A dead
// terminal that went on swallowing keys could never be closed with Ctrl-W: the
// write would fail silently and the key would be consumed anyway, leaving the
// mouse as the only way out of a window whose command has finished.
func (v *View) HandleKey(ev *tcell.EventKey) bool {
if !v.Focused() {
return false
}
if v.handleScrollKey(ev) {
return true
}
if v.Exited() {
return false
}
sequence := Encode(ev, v.applicationCursor())
if len(sequence) == 0 {
return false
}
v.ScrollToBottom()
// A write that fails means the shell has gone, which the reading goroutine
// is about to report; there is nothing useful to do with the error here.
_, _ = v.session.Write(sequence)
return true
}
// handleScrollKey deals with the keys that read back through the history.
func (v *View) handleScrollKey(ev *tcell.EventKey) bool {
if ev.Modifiers()&tcell.ModShift == 0 {
return false
}
page := max(v.Bounds().H-1, 1)
switch ev.Key() {
case tcell.KeyPgUp:
v.ScrollBy(page)
case tcell.KeyPgDn:
v.ScrollBy(-page)
default:
return false
}
return true
}
// applicationCursor reports the mode the program has asked for, under the lock.
func (v *View) applicationCursor() bool {
v.mu.Lock()
defer v.mu.Unlock()
return v.parser.Screen().ApplicationCursor()
}
// HandleMouse scrolls back through the history with the wheel.
//
// Clicks are not forwarded: mouse reporting is a mode this emulator does not
// implement, so a program has no reason to expect them.
func (v *View) HandleMouse(ev *tcell.EventMouse) bool {
if !v.hitTest(ev) {
return false
}
switch ev.Buttons() {
case tcell.WheelUp:
v.ScrollBy(wheelStep)
case tcell.WheelDown:
v.ScrollBy(-wheelStep)
case tcell.Button1:
// A click inside the window is claimed so that it counts as focusing
// the window rather than falling through to the desktop.
default:
return false
}
return true
}
// hitTest reports whether a mouse event landed on the view.
func (v *View) hitTest(ev *tcell.EventMouse) bool {
x, y := ev.Position()
return v.Bounds().Contains(x, y)
}
|