1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package tcell
19
20 import (
21 "bytes"
22 "errors"
23 "io"
24 "os"
25 "strconv"
26 "strings"
27 "sync"
28 "time"
29 "unicode/utf8"
30
31 "golang.org/x/term"
32 "golang.org/x/text/transform"
33
34 "github.com/gdamore/tcell/v2/terminfo"
35
36
37 _ "github.com/gdamore/tcell/v2/terminfo/base"
38 )
39
40
41
42
43
44
45
46
47
48 func NewTerminfoScreen() (Screen, error) {
49 return NewTerminfoScreenFromTty(nil)
50 }
51
52
53
54 func LookupTerminfo(name string) (ti *terminfo.Terminfo, e error) {
55 ti, e = terminfo.LookupTerminfo(name)
56 if e != nil {
57 ti, e = loadDynamicTerminfo(name)
58 if e != nil {
59 return nil, e
60 }
61 terminfo.AddTerminfo(ti)
62 }
63
64 return
65 }
66
67
68
69
70
71
72
73
74 func NewTerminfoScreenFromTtyTerminfo(tty Tty, ti *terminfo.Terminfo) (s Screen, e error) {
75 if ti == nil {
76 ti, e = LookupTerminfo(os.Getenv("TERM"))
77 if e != nil {
78 return
79 }
80 }
81
82 t := &tScreen{ti: ti, tty: tty}
83
84 t.keyexist = make(map[Key]bool)
85 t.keycodes = make(map[string]*tKeyCode)
86 if len(ti.Mouse) > 0 {
87 t.mouse = []byte(ti.Mouse)
88 }
89 t.prepareKeys()
90 t.buildAcsMap()
91 t.resizeQ = make(chan bool, 1)
92 t.fallback = make(map[rune]string)
93 for k, v := range RuneFallbacks {
94 t.fallback[k] = v
95 }
96
97 return t, nil
98 }
99
100
101
102
103
104 func NewTerminfoScreenFromTty(tty Tty) (Screen, error) {
105 return NewTerminfoScreenFromTtyTerminfo(tty, nil)
106 }
107
108
109 type tKeyCode struct {
110 key Key
111 mod ModMask
112 }
113
114
115 type tScreen struct {
116 ti *terminfo.Terminfo
117 tty Tty
118 h int
119 w int
120 fini bool
121 cells CellBuffer
122 buffering bool
123 buf bytes.Buffer
124 curstyle Style
125 style Style
126 evch chan Event
127 resizeQ chan bool
128 quit chan struct{}
129 keyexist map[Key]bool
130 keycodes map[string]*tKeyCode
131 keychan chan []byte
132 keytimer *time.Timer
133 keyexpire time.Time
134 cx int
135 cy int
136 mouse []byte
137 clear bool
138 cursorx int
139 cursory int
140 acs map[rune]string
141 charset string
142 encoder transform.Transformer
143 decoder transform.Transformer
144 fallback map[rune]string
145 colors map[Color]Color
146 palette []Color
147 truecolor bool
148 escaped bool
149 buttondn bool
150 finiOnce sync.Once
151 enablePaste string
152 disablePaste string
153 enterUrl string
154 exitUrl string
155 setWinSize string
156 cursorStyles map[CursorStyle]string
157 cursorStyle CursorStyle
158 saved *term.State
159 stopQ chan struct{}
160 running bool
161 wg sync.WaitGroup
162 mouseFlags MouseFlags
163 pasteEnabled bool
164
165 sync.Mutex
166 }
167
168 func (t *tScreen) Init() error {
169 if e := t.initialize(); e != nil {
170 return e
171 }
172
173 t.evch = make(chan Event, 10)
174 t.keychan = make(chan []byte, 10)
175 t.keytimer = time.NewTimer(time.Millisecond * 50)
176 t.charset = "UTF-8"
177
178 t.charset = getCharset()
179 if enc := GetEncoding(t.charset); enc != nil {
180 t.encoder = enc.NewEncoder()
181 t.decoder = enc.NewDecoder()
182 } else {
183 return ErrNoCharset
184 }
185 ti := t.ti
186
187
188 w := ti.Columns
189 h := ti.Lines
190 if i, _ := strconv.Atoi(os.Getenv("LINES")); i != 0 {
191 h = i
192 }
193 if i, _ := strconv.Atoi(os.Getenv("COLUMNS")); i != 0 {
194 w = i
195 }
196 if t.ti.SetFgBgRGB != "" || t.ti.SetFgRGB != "" || t.ti.SetBgRGB != "" {
197 t.truecolor = true
198 }
199
200
201 if os.Getenv("TCELL_TRUECOLOR") == "disable" {
202 t.truecolor = false
203 }
204 nColors := t.nColors()
205 if nColors > 256 {
206 nColors = 256
207 }
208 t.colors = make(map[Color]Color, nColors)
209 t.palette = make([]Color, nColors)
210 for i := 0; i < nColors; i++ {
211 t.palette[i] = Color(i) | ColorValid
212
213 t.colors[Color(i)|ColorValid] = Color(i) | ColorValid
214 }
215
216 t.quit = make(chan struct{})
217
218 t.Lock()
219 t.cx = -1
220 t.cy = -1
221 t.style = StyleDefault
222 t.cells.Resize(w, h)
223 t.cursorx = -1
224 t.cursory = -1
225 t.resize()
226 t.Unlock()
227
228 if err := t.engage(); err != nil {
229 return err
230 }
231
232 return nil
233 }
234
235 func (t *tScreen) prepareKeyMod(key Key, mod ModMask, val string) {
236 if val != "" {
237
238 if _, exist := t.keycodes[val]; !exist {
239 t.keyexist[key] = true
240 t.keycodes[val] = &tKeyCode{key: key, mod: mod}
241 }
242 }
243 }
244
245 func (t *tScreen) prepareKeyModReplace(key Key, replace Key, mod ModMask, val string) {
246 if val != "" {
247
248 if old, exist := t.keycodes[val]; !exist || old.key == replace {
249 t.keyexist[key] = true
250 t.keycodes[val] = &tKeyCode{key: key, mod: mod}
251 }
252 }
253 }
254
255 func (t *tScreen) prepareKeyModXTerm(key Key, val string) {
256
257 if strings.HasPrefix(val, "\x1b[") && strings.HasSuffix(val, "~") {
258
259
260 val = val[:len(val)-1]
261
262
263
264
265 t.prepareKeyModReplace(key, key+12, ModShift, val+";2~")
266 t.prepareKeyModReplace(key, key+48, ModAlt, val+";3~")
267 t.prepareKeyModReplace(key, key+60, ModAlt|ModShift, val+";4~")
268 t.prepareKeyModReplace(key, key+24, ModCtrl, val+";5~")
269 t.prepareKeyModReplace(key, key+36, ModCtrl|ModShift, val+";6~")
270 t.prepareKeyMod(key, ModAlt|ModCtrl, val+";7~")
271 t.prepareKeyMod(key, ModShift|ModAlt|ModCtrl, val+";8~")
272 t.prepareKeyMod(key, ModMeta, val+";9~")
273 t.prepareKeyMod(key, ModMeta|ModShift, val+";10~")
274 t.prepareKeyMod(key, ModMeta|ModAlt, val+";11~")
275 t.prepareKeyMod(key, ModMeta|ModAlt|ModShift, val+";12~")
276 t.prepareKeyMod(key, ModMeta|ModCtrl, val+";13~")
277 t.prepareKeyMod(key, ModMeta|ModCtrl|ModShift, val+";14~")
278 t.prepareKeyMod(key, ModMeta|ModCtrl|ModAlt, val+";15~")
279 t.prepareKeyMod(key, ModMeta|ModCtrl|ModAlt|ModShift, val+";16~")
280 } else if strings.HasPrefix(val, "\x1bO") && len(val) == 3 {
281 val = val[2:]
282 t.prepareKeyModReplace(key, key+12, ModShift, "\x1b[1;2"+val)
283 t.prepareKeyModReplace(key, key+48, ModAlt, "\x1b[1;3"+val)
284 t.prepareKeyModReplace(key, key+24, ModCtrl, "\x1b[1;5"+val)
285 t.prepareKeyModReplace(key, key+36, ModCtrl|ModShift, "\x1b[1;6"+val)
286 t.prepareKeyModReplace(key, key+60, ModAlt|ModShift, "\x1b[1;4"+val)
287 t.prepareKeyMod(key, ModAlt|ModCtrl, "\x1b[1;7"+val)
288 t.prepareKeyMod(key, ModShift|ModAlt|ModCtrl, "\x1b[1;8"+val)
289 t.prepareKeyMod(key, ModMeta, "\x1b[1;9"+val)
290 t.prepareKeyMod(key, ModMeta|ModShift, "\x1b[1;10"+val)
291 t.prepareKeyMod(key, ModMeta|ModAlt, "\x1b[1;11"+val)
292 t.prepareKeyMod(key, ModMeta|ModAlt|ModShift, "\x1b[1;12"+val)
293 t.prepareKeyMod(key, ModMeta|ModCtrl, "\x1b[1;13"+val)
294 t.prepareKeyMod(key, ModMeta|ModCtrl|ModShift, "\x1b[1;14"+val)
295 t.prepareKeyMod(key, ModMeta|ModCtrl|ModAlt, "\x1b[1;15"+val)
296 t.prepareKeyMod(key, ModMeta|ModCtrl|ModAlt|ModShift, "\x1b[1;16"+val)
297 }
298 }
299
300 func (t *tScreen) prepareXtermModifiers() {
301 if t.ti.Modifiers != terminfo.ModifiersXTerm {
302 return
303 }
304 t.prepareKeyModXTerm(KeyRight, t.ti.KeyRight)
305 t.prepareKeyModXTerm(KeyLeft, t.ti.KeyLeft)
306 t.prepareKeyModXTerm(KeyUp, t.ti.KeyUp)
307 t.prepareKeyModXTerm(KeyDown, t.ti.KeyDown)
308 t.prepareKeyModXTerm(KeyInsert, t.ti.KeyInsert)
309 t.prepareKeyModXTerm(KeyDelete, t.ti.KeyDelete)
310 t.prepareKeyModXTerm(KeyPgUp, t.ti.KeyPgUp)
311 t.prepareKeyModXTerm(KeyPgDn, t.ti.KeyPgDn)
312 t.prepareKeyModXTerm(KeyHome, t.ti.KeyHome)
313 t.prepareKeyModXTerm(KeyEnd, t.ti.KeyEnd)
314 t.prepareKeyModXTerm(KeyF1, t.ti.KeyF1)
315 t.prepareKeyModXTerm(KeyF2, t.ti.KeyF2)
316 t.prepareKeyModXTerm(KeyF3, t.ti.KeyF3)
317 t.prepareKeyModXTerm(KeyF4, t.ti.KeyF4)
318 t.prepareKeyModXTerm(KeyF5, t.ti.KeyF5)
319 t.prepareKeyModXTerm(KeyF6, t.ti.KeyF6)
320 t.prepareKeyModXTerm(KeyF7, t.ti.KeyF7)
321 t.prepareKeyModXTerm(KeyF8, t.ti.KeyF8)
322 t.prepareKeyModXTerm(KeyF9, t.ti.KeyF9)
323 t.prepareKeyModXTerm(KeyF10, t.ti.KeyF10)
324 t.prepareKeyModXTerm(KeyF11, t.ti.KeyF11)
325 t.prepareKeyModXTerm(KeyF12, t.ti.KeyF12)
326 }
327
328 func (t *tScreen) prepareBracketedPaste() {
329
330
331
332
333 if t.ti.EnablePaste != "" {
334 t.enablePaste = t.ti.EnablePaste
335 t.disablePaste = t.ti.DisablePaste
336 t.prepareKey(keyPasteStart, t.ti.PasteStart)
337 t.prepareKey(keyPasteEnd, t.ti.PasteEnd)
338 } else if t.ti.Mouse != "" {
339 t.enablePaste = "\x1b[?2004h"
340 t.disablePaste = "\x1b[?2004l"
341 t.prepareKey(keyPasteStart, "\x1b[200~")
342 t.prepareKey(keyPasteEnd, "\x1b[201~")
343 }
344 }
345
346 func (t *tScreen) prepareExtendedOSC() {
347
348
349 if (strings.Contains(t.ti.Name, "linux")) {
350 return;
351 }
352
353
354
355
356 if t.ti.EnterUrl != "" {
357 t.enterUrl = t.ti.EnterUrl
358 t.exitUrl = t.ti.ExitUrl
359 } else if t.ti.Mouse != "" {
360 t.enterUrl = "\x1b]8;%p2%s;%p1%s\x1b\\"
361 t.exitUrl = "\x1b]8;;\x1b\\"
362 }
363
364 if t.ti.SetWindowSize != "" {
365 t.setWinSize = t.ti.SetWindowSize
366 } else if t.ti.Mouse != "" {
367 t.setWinSize = "\x1b[8;%p1%p2%d;%dt"
368 }
369 }
370
371 func (t *tScreen) prepareCursorStyles() {
372
373
374
375
376 if t.ti.CursorDefault != "" {
377 t.cursorStyles = map[CursorStyle]string{
378 CursorStyleDefault: t.ti.CursorDefault,
379 CursorStyleBlinkingBlock: t.ti.CursorBlinkingBlock,
380 CursorStyleSteadyBlock: t.ti.CursorSteadyBlock,
381 CursorStyleBlinkingUnderline: t.ti.CursorBlinkingUnderline,
382 CursorStyleSteadyUnderline: t.ti.CursorSteadyUnderline,
383 CursorStyleBlinkingBar: t.ti.CursorBlinkingBar,
384 CursorStyleSteadyBar: t.ti.CursorSteadyBar,
385 }
386 } else if t.ti.Mouse != "" {
387 t.cursorStyles = map[CursorStyle]string{
388 CursorStyleDefault: "\x1b[0 q",
389 CursorStyleBlinkingBlock: "\x1b[1 q",
390 CursorStyleSteadyBlock: "\x1b[2 q",
391 CursorStyleBlinkingUnderline: "\x1b[3 q",
392 CursorStyleSteadyUnderline: "\x1b[4 q",
393 CursorStyleBlinkingBar: "\x1b[5 q",
394 CursorStyleSteadyBar: "\x1b[6 q",
395 }
396 }
397 }
398
399 func (t *tScreen) prepareKey(key Key, val string) {
400 t.prepareKeyMod(key, ModNone, val)
401 }
402
403 func (t *tScreen) prepareKeys() {
404 ti := t.ti
405 t.prepareKey(KeyBackspace, ti.KeyBackspace)
406 t.prepareKey(KeyF1, ti.KeyF1)
407 t.prepareKey(KeyF2, ti.KeyF2)
408 t.prepareKey(KeyF3, ti.KeyF3)
409 t.prepareKey(KeyF4, ti.KeyF4)
410 t.prepareKey(KeyF5, ti.KeyF5)
411 t.prepareKey(KeyF6, ti.KeyF6)
412 t.prepareKey(KeyF7, ti.KeyF7)
413 t.prepareKey(KeyF8, ti.KeyF8)
414 t.prepareKey(KeyF9, ti.KeyF9)
415 t.prepareKey(KeyF10, ti.KeyF10)
416 t.prepareKey(KeyF11, ti.KeyF11)
417 t.prepareKey(KeyF12, ti.KeyF12)
418 t.prepareKey(KeyF13, ti.KeyF13)
419 t.prepareKey(KeyF14, ti.KeyF14)
420 t.prepareKey(KeyF15, ti.KeyF15)
421 t.prepareKey(KeyF16, ti.KeyF16)
422 t.prepareKey(KeyF17, ti.KeyF17)
423 t.prepareKey(KeyF18, ti.KeyF18)
424 t.prepareKey(KeyF19, ti.KeyF19)
425 t.prepareKey(KeyF20, ti.KeyF20)
426 t.prepareKey(KeyF21, ti.KeyF21)
427 t.prepareKey(KeyF22, ti.KeyF22)
428 t.prepareKey(KeyF23, ti.KeyF23)
429 t.prepareKey(KeyF24, ti.KeyF24)
430 t.prepareKey(KeyF25, ti.KeyF25)
431 t.prepareKey(KeyF26, ti.KeyF26)
432 t.prepareKey(KeyF27, ti.KeyF27)
433 t.prepareKey(KeyF28, ti.KeyF28)
434 t.prepareKey(KeyF29, ti.KeyF29)
435 t.prepareKey(KeyF30, ti.KeyF30)
436 t.prepareKey(KeyF31, ti.KeyF31)
437 t.prepareKey(KeyF32, ti.KeyF32)
438 t.prepareKey(KeyF33, ti.KeyF33)
439 t.prepareKey(KeyF34, ti.KeyF34)
440 t.prepareKey(KeyF35, ti.KeyF35)
441 t.prepareKey(KeyF36, ti.KeyF36)
442 t.prepareKey(KeyF37, ti.KeyF37)
443 t.prepareKey(KeyF38, ti.KeyF38)
444 t.prepareKey(KeyF39, ti.KeyF39)
445 t.prepareKey(KeyF40, ti.KeyF40)
446 t.prepareKey(KeyF41, ti.KeyF41)
447 t.prepareKey(KeyF42, ti.KeyF42)
448 t.prepareKey(KeyF43, ti.KeyF43)
449 t.prepareKey(KeyF44, ti.KeyF44)
450 t.prepareKey(KeyF45, ti.KeyF45)
451 t.prepareKey(KeyF46, ti.KeyF46)
452 t.prepareKey(KeyF47, ti.KeyF47)
453 t.prepareKey(KeyF48, ti.KeyF48)
454 t.prepareKey(KeyF49, ti.KeyF49)
455 t.prepareKey(KeyF50, ti.KeyF50)
456 t.prepareKey(KeyF51, ti.KeyF51)
457 t.prepareKey(KeyF52, ti.KeyF52)
458 t.prepareKey(KeyF53, ti.KeyF53)
459 t.prepareKey(KeyF54, ti.KeyF54)
460 t.prepareKey(KeyF55, ti.KeyF55)
461 t.prepareKey(KeyF56, ti.KeyF56)
462 t.prepareKey(KeyF57, ti.KeyF57)
463 t.prepareKey(KeyF58, ti.KeyF58)
464 t.prepareKey(KeyF59, ti.KeyF59)
465 t.prepareKey(KeyF60, ti.KeyF60)
466 t.prepareKey(KeyF61, ti.KeyF61)
467 t.prepareKey(KeyF62, ti.KeyF62)
468 t.prepareKey(KeyF63, ti.KeyF63)
469 t.prepareKey(KeyF64, ti.KeyF64)
470 t.prepareKey(KeyInsert, ti.KeyInsert)
471 t.prepareKey(KeyDelete, ti.KeyDelete)
472 t.prepareKey(KeyHome, ti.KeyHome)
473 t.prepareKey(KeyEnd, ti.KeyEnd)
474 t.prepareKey(KeyUp, ti.KeyUp)
475 t.prepareKey(KeyDown, ti.KeyDown)
476 t.prepareKey(KeyLeft, ti.KeyLeft)
477 t.prepareKey(KeyRight, ti.KeyRight)
478 t.prepareKey(KeyPgUp, ti.KeyPgUp)
479 t.prepareKey(KeyPgDn, ti.KeyPgDn)
480 t.prepareKey(KeyHelp, ti.KeyHelp)
481 t.prepareKey(KeyPrint, ti.KeyPrint)
482 t.prepareKey(KeyCancel, ti.KeyCancel)
483 t.prepareKey(KeyExit, ti.KeyExit)
484 t.prepareKey(KeyBacktab, ti.KeyBacktab)
485
486 t.prepareKeyMod(KeyRight, ModShift, ti.KeyShfRight)
487 t.prepareKeyMod(KeyLeft, ModShift, ti.KeyShfLeft)
488 t.prepareKeyMod(KeyUp, ModShift, ti.KeyShfUp)
489 t.prepareKeyMod(KeyDown, ModShift, ti.KeyShfDown)
490 t.prepareKeyMod(KeyHome, ModShift, ti.KeyShfHome)
491 t.prepareKeyMod(KeyEnd, ModShift, ti.KeyShfEnd)
492 t.prepareKeyMod(KeyPgUp, ModShift, ti.KeyShfPgUp)
493 t.prepareKeyMod(KeyPgDn, ModShift, ti.KeyShfPgDn)
494
495 t.prepareKeyMod(KeyRight, ModCtrl, ti.KeyCtrlRight)
496 t.prepareKeyMod(KeyLeft, ModCtrl, ti.KeyCtrlLeft)
497 t.prepareKeyMod(KeyUp, ModCtrl, ti.KeyCtrlUp)
498 t.prepareKeyMod(KeyDown, ModCtrl, ti.KeyCtrlDown)
499 t.prepareKeyMod(KeyHome, ModCtrl, ti.KeyCtrlHome)
500 t.prepareKeyMod(KeyEnd, ModCtrl, ti.KeyCtrlEnd)
501
502
503
504
505
506
507
508
509
510
511
512
513 if ti.EnterKeypad != "" {
514 t.prepareKey(KeyUp, "\x1b[A")
515 t.prepareKey(KeyDown, "\x1b[B")
516 t.prepareKey(KeyRight, "\x1b[C")
517 t.prepareKey(KeyLeft, "\x1b[D")
518 t.prepareKey(KeyEnd, "\x1b[F")
519 t.prepareKey(KeyHome, "\x1b[H")
520 t.prepareKey(KeyDelete, "\x1b[3~")
521 t.prepareKey(KeyHome, "\x1b[1~")
522 t.prepareKey(KeyEnd, "\x1b[4~")
523 t.prepareKey(KeyPgUp, "\x1b[5~")
524 t.prepareKey(KeyPgDn, "\x1b[6~")
525
526
527 t.prepareKey(KeyUp, "\x1bOA")
528 t.prepareKey(KeyDown, "\x1bOB")
529 t.prepareKey(KeyRight, "\x1bOC")
530 t.prepareKey(KeyLeft, "\x1bOD")
531 t.prepareKey(KeyHome, "\x1bOH")
532 }
533
534 t.prepareKey(keyPasteStart, ti.PasteStart)
535 t.prepareKey(keyPasteEnd, ti.PasteEnd)
536 t.prepareXtermModifiers()
537 t.prepareBracketedPaste()
538 t.prepareCursorStyles()
539 t.prepareExtendedOSC()
540
541 outer:
542
543 for i := 0; i < ' '; i++ {
544
545
546
547
548
549 for esc := range t.keycodes {
550 if []byte(esc)[0] == byte(i) {
551 continue outer
552 }
553 }
554
555 t.keyexist[Key(i)] = true
556
557 mod := ModCtrl
558 switch Key(i) {
559 case KeyBS, KeyTAB, KeyESC, KeyCR:
560
561 mod = ModNone
562 }
563 t.keycodes[string(rune(i))] = &tKeyCode{key: Key(i), mod: mod}
564 }
565 }
566
567 func (t *tScreen) Fini() {
568 t.finiOnce.Do(t.finish)
569 }
570
571 func (t *tScreen) finish() {
572 close(t.quit)
573 t.finalize()
574 }
575
576 func (t *tScreen) SetStyle(style Style) {
577 t.Lock()
578 if !t.fini {
579 t.style = style
580 }
581 t.Unlock()
582 }
583
584 func (t *tScreen) Clear() {
585 t.Fill(' ', t.style)
586 }
587
588 func (t *tScreen) Fill(r rune, style Style) {
589 t.Lock()
590 if !t.fini {
591 t.cells.Fill(r, style)
592 }
593 t.Unlock()
594 }
595
596 func (t *tScreen) SetContent(x, y int, mainc rune, combc []rune, style Style) {
597 t.Lock()
598 if !t.fini {
599 t.cells.SetContent(x, y, mainc, combc, style)
600 }
601 t.Unlock()
602 }
603
604 func (t *tScreen) GetContent(x, y int) (rune, []rune, Style, int) {
605 t.Lock()
606 mainc, combc, style, width := t.cells.GetContent(x, y)
607 t.Unlock()
608 return mainc, combc, style, width
609 }
610
611 func (t *tScreen) SetCell(x, y int, style Style, ch ...rune) {
612 if len(ch) > 0 {
613 t.SetContent(x, y, ch[0], ch[1:], style)
614 } else {
615 t.SetContent(x, y, ' ', nil, style)
616 }
617 }
618
619 func (t *tScreen) encodeRune(r rune, buf []byte) []byte {
620
621 nb := make([]byte, 6)
622 ob := make([]byte, 6)
623 num := utf8.EncodeRune(ob, r)
624 ob = ob[:num]
625 dst := 0
626 var err error
627 if enc := t.encoder; enc != nil {
628 enc.Reset()
629 dst, _, err = enc.Transform(nb, ob, true)
630 }
631 if err != nil || dst == 0 || nb[0] == '\x1a' {
632
633 if len(buf) == 0 {
634 if acs, ok := t.acs[r]; ok {
635 buf = append(buf, []byte(acs)...)
636 } else if fb, ok := t.fallback[r]; ok {
637 buf = append(buf, []byte(fb)...)
638 } else {
639 buf = append(buf, '?')
640 }
641 }
642 } else {
643 buf = append(buf, nb[:dst]...)
644 }
645
646 return buf
647 }
648
649 func (t *tScreen) sendFgBg(fg Color, bg Color, attr AttrMask) AttrMask {
650 ti := t.ti
651 if ti.Colors == 0 {
652
653
654 if !fg.Valid() {
655 return attr
656 }
657 v, ok := t.colors[fg]
658 if !ok {
659 v = FindColor(fg, []Color{ColorBlack, ColorWhite})
660 t.colors[fg] = v
661 }
662 switch v {
663 case ColorWhite:
664 return attr
665 case ColorBlack:
666 return attr ^ AttrReverse
667 }
668 }
669
670 if fg == ColorReset || bg == ColorReset {
671 t.TPuts(ti.ResetFgBg)
672 }
673 if t.truecolor {
674 if ti.SetFgBgRGB != "" && fg.IsRGB() && bg.IsRGB() {
675 r1, g1, b1 := fg.RGB()
676 r2, g2, b2 := bg.RGB()
677 t.TPuts(ti.TParm(ti.SetFgBgRGB,
678 int(r1), int(g1), int(b1),
679 int(r2), int(g2), int(b2)))
680 return attr
681 }
682
683 if fg.IsRGB() && ti.SetFgRGB != "" {
684 r, g, b := fg.RGB()
685 t.TPuts(ti.TParm(ti.SetFgRGB, int(r), int(g), int(b)))
686 fg = ColorDefault
687 }
688
689 if bg.IsRGB() && ti.SetBgRGB != "" {
690 r, g, b := bg.RGB()
691 t.TPuts(ti.TParm(ti.SetBgRGB,
692 int(r), int(g), int(b)))
693 bg = ColorDefault
694 }
695 }
696
697 if fg.Valid() {
698 if v, ok := t.colors[fg]; ok {
699 fg = v
700 } else {
701 v = FindColor(fg, t.palette)
702 t.colors[fg] = v
703 fg = v
704 }
705 }
706
707 if bg.Valid() {
708 if v, ok := t.colors[bg]; ok {
709 bg = v
710 } else {
711 v = FindColor(bg, t.palette)
712 t.colors[bg] = v
713 bg = v
714 }
715 }
716
717 if fg.Valid() && bg.Valid() && ti.SetFgBg != "" {
718 t.TPuts(ti.TParm(ti.SetFgBg, int(fg&0xff), int(bg&0xff)))
719 } else {
720 if fg.Valid() && ti.SetFg != "" {
721 t.TPuts(ti.TParm(ti.SetFg, int(fg&0xff)))
722 }
723 if bg.Valid() && ti.SetBg != "" {
724 t.TPuts(ti.TParm(ti.SetBg, int(bg&0xff)))
725 }
726 }
727 return attr
728 }
729
730 func (t *tScreen) drawCell(x, y int) int {
731
732 ti := t.ti
733
734 mainc, combc, style, width := t.cells.GetContent(x, y)
735 if !t.cells.Dirty(x, y) {
736 return width
737 }
738
739 if y == t.h-1 && x == t.w-1 && t.ti.AutoMargin && ti.InsertChar != "" {
740
741
742
743
744 t.TPuts(ti.TGoto(x-1, y))
745 defer func() {
746 t.TPuts(ti.TGoto(x-1, y))
747 t.TPuts(ti.InsertChar)
748 t.cy = y
749 t.cx = x - 1
750 t.cells.SetDirty(x-1, y, true)
751 _ = t.drawCell(x-1, y)
752 t.TPuts(t.ti.TGoto(0, 0))
753 t.cy = 0
754 t.cx = 0
755 }()
756 } else if t.cy != y || t.cx != x {
757 t.TPuts(ti.TGoto(x, y))
758 t.cx = x
759 t.cy = y
760 }
761
762 if style == StyleDefault {
763 style = t.style
764 }
765 if style != t.curstyle {
766 fg, bg, attrs := style.Decompose()
767
768 t.TPuts(ti.AttrOff)
769
770 attrs = t.sendFgBg(fg, bg, attrs)
771 if attrs&AttrBold != 0 {
772 t.TPuts(ti.Bold)
773 }
774 if attrs&AttrUnderline != 0 {
775 t.TPuts(ti.Underline)
776 }
777 if attrs&AttrReverse != 0 {
778 t.TPuts(ti.Reverse)
779 }
780 if attrs&AttrBlink != 0 {
781 t.TPuts(ti.Blink)
782 }
783 if attrs&AttrDim != 0 {
784 t.TPuts(ti.Dim)
785 }
786 if attrs&AttrItalic != 0 {
787 t.TPuts(ti.Italic)
788 }
789 if attrs&AttrStrikeThrough != 0 {
790 t.TPuts(ti.StrikeThrough)
791 }
792
793
794 if t.enterUrl != "" && t.curstyle != style {
795 if style.url != "" {
796 t.TPuts(ti.TParm(t.enterUrl, style.url, style.urlId))
797 } else {
798 t.TPuts(t.exitUrl)
799 }
800 }
801
802 t.curstyle = style
803 }
804
805
806
807
808
809 if width < 1 {
810 width = 1
811 }
812
813 var str string
814
815 buf := make([]byte, 0, 6)
816
817 buf = t.encodeRune(mainc, buf)
818 for _, r := range combc {
819 buf = t.encodeRune(r, buf)
820 }
821
822 str = string(buf)
823 if width > 1 && str == "?" {
824
825 str = "? "
826 t.cx = -1
827 }
828
829 if x > t.w-width {
830
831 width = 1
832 str = " "
833 }
834 t.writeString(str)
835 t.cx += width
836 t.cells.SetDirty(x, y, false)
837 if width > 1 {
838 t.cx = -1
839 }
840
841 return width
842 }
843
844 func (t *tScreen) ShowCursor(x, y int) {
845 t.Lock()
846 t.cursorx = x
847 t.cursory = y
848 t.Unlock()
849 }
850
851 func (t *tScreen) SetCursorStyle(cs CursorStyle) {
852 t.Lock()
853 t.cursorStyle = cs
854 t.Unlock()
855 }
856
857 func (t *tScreen) HideCursor() {
858 t.ShowCursor(-1, -1)
859 }
860
861 func (t *tScreen) showCursor() {
862
863 x, y := t.cursorx, t.cursory
864 w, h := t.cells.Size()
865 if x < 0 || y < 0 || x >= w || y >= h {
866 t.hideCursor()
867 return
868 }
869 t.TPuts(t.ti.TGoto(x, y))
870 t.TPuts(t.ti.ShowCursor)
871 if t.cursorStyles != nil {
872 if esc, ok := t.cursorStyles[t.cursorStyle]; ok {
873 t.TPuts(esc)
874 }
875 }
876 t.cx = x
877 t.cy = y
878 }
879
880
881
882
883
884
885
886 func (t *tScreen) writeString(s string) {
887 if t.buffering {
888 _, _ = io.WriteString(&t.buf, s)
889 } else {
890 _, _ = io.WriteString(t.tty, s)
891 }
892 }
893
894 func (t *tScreen) TPuts(s string) {
895 if t.buffering {
896 t.ti.TPuts(&t.buf, s)
897 } else {
898 t.ti.TPuts(t.tty, s)
899 }
900 }
901
902 func (t *tScreen) Show() {
903 t.Lock()
904 if !t.fini {
905 t.resize()
906 t.draw()
907 }
908 t.Unlock()
909 }
910
911 func (t *tScreen) clearScreen() {
912 t.TPuts(t.ti.AttrOff)
913 t.TPuts(t.exitUrl)
914 fg, bg, _ := t.style.Decompose()
915 _ = t.sendFgBg(fg, bg, AttrNone)
916 t.TPuts(t.ti.Clear)
917 t.clear = false
918 }
919
920 func (t *tScreen) hideCursor() {
921
922 if t.ti.HideCursor != "" {
923 t.TPuts(t.ti.HideCursor)
924 } else {
925
926
927 t.cx, t.cy = t.cells.Size()
928 t.TPuts(t.ti.TGoto(t.cx, t.cy))
929 }
930 }
931
932 func (t *tScreen) draw() {
933
934 t.cx = -1
935 t.cy = -1
936
937 t.curstyle = styleInvalid
938
939 t.buf.Reset()
940 t.buffering = true
941 defer func() {
942 t.buffering = false
943 }()
944
945
946 t.hideCursor()
947
948 if t.clear {
949 t.clearScreen()
950 }
951
952 for y := 0; y < t.h; y++ {
953 for x := 0; x < t.w; x++ {
954 width := t.drawCell(x, y)
955 if width > 1 {
956 if x+1 < t.w {
957
958
959
960 t.cells.SetDirty(x+1, y, true)
961 }
962 }
963 x += width - 1
964 }
965 }
966
967
968 t.showCursor()
969
970 _, _ = t.buf.WriteTo(t.tty)
971 }
972
973 func (t *tScreen) EnableMouse(flags ...MouseFlags) {
974 var f MouseFlags
975 flagsPresent := false
976 for _, flag := range flags {
977 f |= flag
978 flagsPresent = true
979 }
980 if !flagsPresent {
981 f = MouseMotionEvents | MouseDragEvents | MouseButtonEvents
982 }
983
984 t.Lock()
985 t.mouseFlags = f
986 t.enableMouse(f)
987 t.Unlock()
988 }
989
990 func (t *tScreen) enableMouse(f MouseFlags) {
991
992
993
994 if len(t.mouse) != 0 {
995
996 t.TPuts("\x1b[?1000l\x1b[?1002l\x1b[?1003l\x1b[?1006l")
997 if f&MouseButtonEvents != 0 {
998 t.TPuts("\x1b[?1000h")
999 }
1000 if f&MouseDragEvents != 0 {
1001 t.TPuts("\x1b[?1002h")
1002 }
1003 if f&MouseMotionEvents != 0 {
1004 t.TPuts("\x1b[?1003h")
1005 }
1006 if f&(MouseButtonEvents|MouseDragEvents|MouseMotionEvents) != 0 {
1007 t.TPuts("\x1b[?1006h")
1008 }
1009 }
1010
1011 }
1012
1013 func (t *tScreen) DisableMouse() {
1014 t.Lock()
1015 t.mouseFlags = 0
1016 t.enableMouse(0)
1017 t.Unlock()
1018 }
1019
1020 func (t *tScreen) EnablePaste() {
1021 t.Lock()
1022 t.pasteEnabled = true
1023 t.enablePasting(true)
1024 t.Unlock()
1025 }
1026
1027 func (t *tScreen) DisablePaste() {
1028 t.Lock()
1029 t.pasteEnabled = false
1030 t.enablePasting(false)
1031 t.Unlock()
1032 }
1033
1034 func (t *tScreen) enablePasting(on bool) {
1035 var s string
1036 if on {
1037 s = t.enablePaste
1038 } else {
1039 s = t.disablePaste
1040 }
1041 if s != "" {
1042 t.TPuts(s)
1043 }
1044 }
1045
1046 func (t *tScreen) Size() (int, int) {
1047 t.Lock()
1048 w, h := t.w, t.h
1049 t.Unlock()
1050 return w, h
1051 }
1052
1053 func (t *tScreen) resize() {
1054 if w, h, e := t.tty.WindowSize(); e == nil {
1055 if w != t.w || h != t.h {
1056 t.cx = -1
1057 t.cy = -1
1058
1059 t.cells.Resize(w, h)
1060 t.cells.Invalidate()
1061 t.h = h
1062 t.w = w
1063 ev := NewEventResize(w, h)
1064 _ = t.PostEvent(ev)
1065 }
1066 }
1067 }
1068
1069 func (t *tScreen) Colors() int {
1070
1071 if t.truecolor {
1072 return 1 << 24
1073 }
1074 return t.ti.Colors
1075 }
1076
1077
1078
1079
1080 func (t *tScreen) nColors() int {
1081 return t.ti.Colors
1082 }
1083
1084 func (t *tScreen) ChannelEvents(ch chan<- Event, quit <-chan struct{}) {
1085 defer close(ch)
1086 for {
1087 select {
1088 case <-quit:
1089 return
1090 case <-t.quit:
1091 return
1092 case ev := <-t.evch:
1093 select {
1094 case <-quit:
1095 return
1096 case <-t.quit:
1097 return
1098 case ch <- ev:
1099 }
1100 }
1101 }
1102 }
1103
1104 func (t *tScreen) PollEvent() Event {
1105 select {
1106 case <-t.quit:
1107 return nil
1108 case ev := <-t.evch:
1109 return ev
1110 }
1111 }
1112
1113 func (t *tScreen) HasPendingEvent() bool {
1114 return len(t.evch) > 0
1115 }
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125 var vtACSNames = map[byte]rune{
1126 '+': RuneRArrow,
1127 ',': RuneLArrow,
1128 '-': RuneUArrow,
1129 '.': RuneDArrow,
1130 '0': RuneBlock,
1131 '`': RuneDiamond,
1132 'a': RuneCkBoard,
1133 'b': '␉',
1134 'c': '␌',
1135 'd': '␋',
1136 'e': '␊',
1137 'f': RuneDegree,
1138 'g': RunePlMinus,
1139 'h': RuneBoard,
1140 'i': RuneLantern,
1141 'j': RuneLRCorner,
1142 'k': RuneURCorner,
1143 'l': RuneULCorner,
1144 'm': RuneLLCorner,
1145 'n': RunePlus,
1146 'o': RuneS1,
1147 'p': RuneS3,
1148 'q': RuneHLine,
1149 'r': RuneS7,
1150 's': RuneS9,
1151 't': RuneLTee,
1152 'u': RuneRTee,
1153 'v': RuneBTee,
1154 'w': RuneTTee,
1155 'x': RuneVLine,
1156 'y': RuneLEqual,
1157 'z': RuneGEqual,
1158 '{': RunePi,
1159 '|': RuneNEqual,
1160 '}': RuneSterling,
1161 '~': RuneBullet,
1162 }
1163
1164
1165
1166
1167
1168 func (t *tScreen) buildAcsMap() {
1169 acsstr := t.ti.AltChars
1170 t.acs = make(map[rune]string)
1171 for len(acsstr) > 2 {
1172 srcv := acsstr[0]
1173 dstv := string(acsstr[1])
1174 if r, ok := vtACSNames[srcv]; ok {
1175 t.acs[r] = t.ti.EnterAcs + dstv + t.ti.ExitAcs
1176 }
1177 acsstr = acsstr[2:]
1178 }
1179 }
1180
1181 func (t *tScreen) PostEventWait(ev Event) {
1182 t.evch <- ev
1183 }
1184
1185 func (t *tScreen) PostEvent(ev Event) error {
1186 select {
1187 case t.evch <- ev:
1188 return nil
1189 default:
1190 return ErrEventQFull
1191 }
1192 }
1193
1194 func (t *tScreen) clip(x, y int) (int, int) {
1195 w, h := t.cells.Size()
1196 if x < 0 {
1197 x = 0
1198 }
1199 if y < 0 {
1200 y = 0
1201 }
1202 if x > w-1 {
1203 x = w - 1
1204 }
1205 if y > h-1 {
1206 y = h - 1
1207 }
1208 return x, y
1209 }
1210
1211
1212
1213
1214 func (t *tScreen) buildMouseEvent(x, y, btn int) *EventMouse {
1215
1216
1217
1218
1219
1220
1221 button := ButtonNone
1222 mod := ModNone
1223
1224
1225
1226
1227
1228 switch btn & 0x43 {
1229 case 0:
1230 button = Button1
1231 case 1:
1232 button = Button3
1233 case 2:
1234 button = Button2
1235 case 3:
1236 button = ButtonNone
1237 case 0x40:
1238 button = WheelUp
1239 case 0x41:
1240 button = WheelDown
1241 }
1242
1243 if btn&0x4 != 0 {
1244 mod |= ModShift
1245 }
1246 if btn&0x8 != 0 {
1247 mod |= ModAlt
1248 }
1249 if btn&0x10 != 0 {
1250 mod |= ModCtrl
1251 }
1252
1253
1254
1255
1256 x, y = t.clip(x, y)
1257
1258 return NewEventMouse(x, y, button, mod)
1259 }
1260
1261
1262
1263
1264
1265
1266 func (t *tScreen) parseSgrMouse(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
1267
1268 b := buf.Bytes()
1269
1270 var x, y, btn, state int
1271 dig := false
1272 neg := false
1273 motion := false
1274 i := 0
1275 val := 0
1276
1277 for i = range b {
1278 switch b[i] {
1279 case '\x1b':
1280 if state != 0 {
1281 return false, false
1282 }
1283 state = 1
1284
1285 case '\x9b':
1286 if state != 0 {
1287 return false, false
1288 }
1289 state = 2
1290
1291 case '[':
1292 if state != 1 {
1293 return false, false
1294 }
1295 state = 2
1296
1297 case '<':
1298 if state != 2 {
1299 return false, false
1300 }
1301 val = 0
1302 dig = false
1303 neg = false
1304 state = 3
1305
1306 case '-':
1307 if state != 3 && state != 4 && state != 5 {
1308 return false, false
1309 }
1310 if dig || neg {
1311 return false, false
1312 }
1313 neg = true
1314
1315 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
1316 if state != 3 && state != 4 && state != 5 {
1317 return false, false
1318 }
1319 val *= 10
1320 val += int(b[i] - '0')
1321 dig = true
1322
1323 case ';':
1324 if neg {
1325 val = -val
1326 }
1327 switch state {
1328 case 3:
1329 btn, val = val, 0
1330 neg, dig, state = false, false, 4
1331 case 4:
1332 x, val = val-1, 0
1333 neg, dig, state = false, false, 5
1334 default:
1335 return false, false
1336 }
1337
1338 case 'm', 'M':
1339 if state != 5 {
1340 return false, false
1341 }
1342 if neg {
1343 val = -val
1344 }
1345 y = val - 1
1346
1347 motion = (btn & 32) != 0
1348 btn &^= 32
1349 if b[i] == 'm' {
1350
1351 btn |= 3
1352 btn &^= 0x40
1353 t.buttondn = false
1354 } else if motion {
1355
1362 if !t.buttondn {
1363 btn |= 3
1364 btn &^= 0x40
1365 }
1366 } else {
1367 t.buttondn = true
1368 }
1369
1370 for i >= 0 {
1371 _, _ = buf.ReadByte()
1372 i--
1373 }
1374 *evs = append(*evs, t.buildMouseEvent(x, y, btn))
1375 return true, true
1376 }
1377 }
1378
1379
1380 return true, false
1381 }
1382
1383
1384
1385 func (t *tScreen) parseXtermMouse(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
1386
1387 b := buf.Bytes()
1388
1389 state := 0
1390 btn := 0
1391 x := 0
1392 y := 0
1393
1394 for i := range b {
1395 switch state {
1396 case 0:
1397 switch b[i] {
1398 case '\x1b':
1399 state = 1
1400 case '\x9b':
1401 state = 2
1402 default:
1403 return false, false
1404 }
1405 case 1:
1406 if b[i] != '[' {
1407 return false, false
1408 }
1409 state = 2
1410 case 2:
1411 if b[i] != 'M' {
1412 return false, false
1413 }
1414 state++
1415 case 3:
1416 btn = int(b[i])
1417 state++
1418 case 4:
1419 x = int(b[i]) - 32 - 1
1420 state++
1421 case 5:
1422 y = int(b[i]) - 32 - 1
1423 for i >= 0 {
1424 _, _ = buf.ReadByte()
1425 i--
1426 }
1427 *evs = append(*evs, t.buildMouseEvent(x, y, btn))
1428 return true, true
1429 }
1430 }
1431 return true, false
1432 }
1433
1434 func (t *tScreen) parseFunctionKey(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
1435 b := buf.Bytes()
1436 partial := false
1437 for e, k := range t.keycodes {
1438 esc := []byte(e)
1439 if (len(esc) == 1) && (esc[0] == '\x1b') {
1440 continue
1441 }
1442 if bytes.HasPrefix(b, esc) {
1443
1444 var r rune
1445 if len(esc) == 1 {
1446 r = rune(b[0])
1447 }
1448 mod := k.mod
1449 if t.escaped {
1450 mod |= ModAlt
1451 t.escaped = false
1452 }
1453 switch k.key {
1454 case keyPasteStart:
1455 *evs = append(*evs, NewEventPaste(true))
1456 case keyPasteEnd:
1457 *evs = append(*evs, NewEventPaste(false))
1458 default:
1459 *evs = append(*evs, NewEventKey(k.key, r, mod))
1460 }
1461 for i := 0; i < len(esc); i++ {
1462 _, _ = buf.ReadByte()
1463 }
1464 return true, true
1465 }
1466 if bytes.HasPrefix(esc, b) {
1467 partial = true
1468 }
1469 }
1470 return partial, false
1471 }
1472
1473 func (t *tScreen) parseRune(buf *bytes.Buffer, evs *[]Event) (bool, bool) {
1474 b := buf.Bytes()
1475 if b[0] >= ' ' && b[0] <= 0x7F {
1476
1477 mod := ModNone
1478 if t.escaped {
1479 mod = ModAlt
1480 t.escaped = false
1481 }
1482 *evs = append(*evs, NewEventKey(KeyRune, rune(b[0]), mod))
1483 _, _ = buf.ReadByte()
1484 return true, true
1485 }
1486
1487 if b[0] < 0x80 {
1488
1489 return false, false
1490 }
1491
1492 utf := make([]byte, 12)
1493 for l := 1; l <= len(b); l++ {
1494 t.decoder.Reset()
1495 nOut, nIn, e := t.decoder.Transform(utf, b[:l], true)
1496 if e == transform.ErrShortSrc {
1497 continue
1498 }
1499 if nOut != 0 {
1500 r, _ := utf8.DecodeRune(utf[:nOut])
1501 if r != utf8.RuneError {
1502 mod := ModNone
1503 if t.escaped {
1504 mod = ModAlt
1505 t.escaped = false
1506 }
1507 *evs = append(*evs, NewEventKey(KeyRune, r, mod))
1508 }
1509 for nIn > 0 {
1510 _, _ = buf.ReadByte()
1511 nIn--
1512 }
1513 return true, true
1514 }
1515 }
1516
1517 return true, false
1518 }
1519
1520 func (t *tScreen) scanInput(buf *bytes.Buffer, expire bool) {
1521 evs := t.collectEventsFromInput(buf, expire)
1522
1523 for _, ev := range evs {
1524 t.PostEventWait(ev)
1525 }
1526 }
1527
1528
1529
1530
1531 func (t *tScreen) collectEventsFromInput(buf *bytes.Buffer, expire bool) []Event {
1532
1533 res := make([]Event, 0, 20)
1534
1535 t.Lock()
1536 defer t.Unlock()
1537
1538 for {
1539 b := buf.Bytes()
1540 if len(b) == 0 {
1541 buf.Reset()
1542 return res
1543 }
1544
1545 partials := 0
1546
1547 if part, comp := t.parseRune(buf, &res); comp {
1548 continue
1549 } else if part {
1550 partials++
1551 }
1552
1553 if part, comp := t.parseFunctionKey(buf, &res); comp {
1554 continue
1555 } else if part {
1556 partials++
1557 }
1558
1559
1560
1561
1562 if t.ti.Mouse != "" {
1563 if part, comp := t.parseXtermMouse(buf, &res); comp {
1564 continue
1565 } else if part {
1566 partials++
1567 }
1568
1569 if part, comp := t.parseSgrMouse(buf, &res); comp {
1570 continue
1571 } else if part {
1572 partials++
1573 }
1574 }
1575
1576 if partials == 0 || expire {
1577 if b[0] == '\x1b' {
1578 if len(b) == 1 {
1579 res = append(res, NewEventKey(KeyEsc, 0, ModNone))
1580 t.escaped = false
1581 } else {
1582 t.escaped = true
1583 }
1584 _, _ = buf.ReadByte()
1585 continue
1586 }
1587
1588
1589
1590
1591 by, _ := buf.ReadByte()
1592 mod := ModNone
1593 if t.escaped {
1594 t.escaped = false
1595 mod = ModAlt
1596 }
1597 res = append(res, NewEventKey(KeyRune, rune(by), mod))
1598 continue
1599 }
1600
1601
1602
1603 break
1604 }
1605
1606 return res
1607 }
1608
1609 func (t *tScreen) mainLoop(stopQ chan struct{}) {
1610 defer t.wg.Done()
1611 buf := &bytes.Buffer{}
1612 for {
1613 select {
1614 case <-stopQ:
1615 return
1616 case <-t.quit:
1617 return
1618 case <-t.resizeQ:
1619 t.Lock()
1620 t.cx = -1
1621 t.cy = -1
1622 t.resize()
1623 t.cells.Invalidate()
1624 t.draw()
1625 t.Unlock()
1626 continue
1627 case <-t.keytimer.C:
1628
1629
1630
1631
1632
1633 if buf.Len() > 0 {
1634 if time.Now().After(t.keyexpire) {
1635 t.scanInput(buf, true)
1636 }
1637 }
1638 if buf.Len() > 0 {
1639 if !t.keytimer.Stop() {
1640 select {
1641 case <-t.keytimer.C:
1642 default:
1643 }
1644 }
1645 t.keytimer.Reset(time.Millisecond * 50)
1646 }
1647 case chunk := <-t.keychan:
1648 buf.Write(chunk)
1649 t.keyexpire = time.Now().Add(time.Millisecond * 50)
1650 t.scanInput(buf, false)
1651 if !t.keytimer.Stop() {
1652 select {
1653 case <-t.keytimer.C:
1654 default:
1655 }
1656 }
1657 if buf.Len() > 0 {
1658 t.keytimer.Reset(time.Millisecond * 50)
1659 }
1660 }
1661 }
1662 }
1663
1664 func (t *tScreen) inputLoop(stopQ chan struct{}) {
1665
1666 defer t.wg.Done()
1667 for {
1668 select {
1669 case <-stopQ:
1670 return
1671 default:
1672 }
1673 chunk := make([]byte, 128)
1674 n, e := t.tty.Read(chunk)
1675 switch e {
1676 case nil:
1677 default:
1678 t.Lock()
1679 running := t.running
1680 t.Unlock()
1681 if running {
1682 _ = t.PostEvent(NewEventError(e))
1683 }
1684 return
1685 }
1686 if n > 0 {
1687 t.keychan <- chunk[:n]
1688 }
1689 }
1690 }
1691
1692 func (t *tScreen) Sync() {
1693 t.Lock()
1694 t.cx = -1
1695 t.cy = -1
1696 if !t.fini {
1697 t.resize()
1698 t.clear = true
1699 t.cells.Invalidate()
1700 t.draw()
1701 }
1702 t.Unlock()
1703 }
1704
1705 func (t *tScreen) CharacterSet() string {
1706 return t.charset
1707 }
1708
1709 func (t *tScreen) RegisterRuneFallback(orig rune, fallback string) {
1710 t.Lock()
1711 t.fallback[orig] = fallback
1712 t.Unlock()
1713 }
1714
1715 func (t *tScreen) UnregisterRuneFallback(orig rune) {
1716 t.Lock()
1717 delete(t.fallback, orig)
1718 t.Unlock()
1719 }
1720
1721 func (t *tScreen) CanDisplay(r rune, checkFallbacks bool) bool {
1722
1723 if enc := t.encoder; enc != nil {
1724 nb := make([]byte, 6)
1725 ob := make([]byte, 6)
1726 num := utf8.EncodeRune(ob, r)
1727
1728 enc.Reset()
1729 dst, _, err := enc.Transform(nb, ob[:num], true)
1730 if dst != 0 && err == nil && nb[0] != '\x1A' {
1731 return true
1732 }
1733 }
1734
1735
1736 if _, ok := t.acs[r]; ok {
1737 return true
1738 }
1739 if !checkFallbacks {
1740 return false
1741 }
1742 if _, ok := t.fallback[r]; ok {
1743 return true
1744 }
1745 return false
1746 }
1747
1748 func (t *tScreen) HasMouse() bool {
1749 return len(t.mouse) != 0
1750 }
1751
1752 func (t *tScreen) HasKey(k Key) bool {
1753 if k == KeyRune {
1754 return true
1755 }
1756 return t.keyexist[k]
1757 }
1758
1759 func (t *tScreen) SetSize(w, h int) {
1760 if t.setWinSize != "" {
1761 t.TPuts(t.ti.TParm(t.setWinSize, w, h))
1762 }
1763 t.cells.Invalidate()
1764 t.resize()
1765 }
1766
1767 func (t *tScreen) Resize(int, int, int, int) {}
1768
1769 func (t *tScreen) Suspend() error {
1770 t.disengage()
1771 return nil
1772 }
1773
1774 func (t *tScreen) Resume() error {
1775 return t.engage()
1776 }
1777
1778
1779
1780
1781 func (t *tScreen) engage() error {
1782 t.Lock()
1783 defer t.Unlock()
1784 if t.tty == nil {
1785 return ErrNoScreen
1786 }
1787 t.tty.NotifyResize(func() {
1788 select {
1789 case t.resizeQ <- true:
1790 default:
1791 }
1792 })
1793 if t.running {
1794 return errors.New("already engaged")
1795 }
1796 if err := t.tty.Start(); err != nil {
1797 return err
1798 }
1799 t.running = true
1800 if w, h, err := t.tty.WindowSize(); err == nil && w != 0 && h != 0 {
1801 t.cells.Resize(w, h)
1802 }
1803 stopQ := make(chan struct{})
1804 t.stopQ = stopQ
1805 t.enableMouse(t.mouseFlags)
1806 t.enablePasting(t.pasteEnabled)
1807
1808 ti := t.ti
1809 t.TPuts(ti.EnterCA)
1810 t.TPuts(ti.EnterKeypad)
1811 t.TPuts(ti.HideCursor)
1812 t.TPuts(ti.EnableAcs)
1813 t.TPuts(ti.Clear)
1814
1815 t.wg.Add(2)
1816 go t.inputLoop(stopQ)
1817 go t.mainLoop(stopQ)
1818 return nil
1819 }
1820
1821
1822
1823
1824
1825 func (t *tScreen) disengage() {
1826
1827 t.Lock()
1828 if !t.running {
1829 t.Unlock()
1830 return
1831 }
1832 t.running = false
1833 stopQ := t.stopQ
1834 close(stopQ)
1835 _ = t.tty.Drain()
1836 t.Unlock()
1837
1838 t.tty.NotifyResize(nil)
1839
1840 t.wg.Wait()
1841
1842
1843 ti := t.ti
1844 t.cells.Resize(0, 0)
1845 t.TPuts(ti.ShowCursor)
1846 if t.cursorStyles != nil && t.cursorStyle != CursorStyleDefault {
1847 t.TPuts(t.cursorStyles[t.cursorStyle])
1848 }
1849 t.TPuts(ti.ResetFgBg)
1850 t.TPuts(ti.AttrOff)
1851 t.TPuts(ti.Clear)
1852 t.TPuts(ti.ExitCA)
1853 t.TPuts(ti.ExitKeypad)
1854 t.enableMouse(0)
1855 t.enablePasting(false)
1856
1857 _ = t.tty.Stop()
1858 }
1859
1860
1861 func (t *tScreen) Beep() error {
1862 t.writeString(string(byte(7)))
1863 return nil
1864 }
1865
1866
1867
1868 func (t *tScreen) finalize() {
1869 t.disengage()
1870 _ = t.tty.Close()
1871 }
1872
View as plain text