simulation.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. // Copyright 2022 The TCell Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use file except in compliance with the License.
  5. // You may obtain a copy of the license at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package tcell
  15. import (
  16. "sync"
  17. "unicode/utf8"
  18. "golang.org/x/text/transform"
  19. )
  20. // NewSimulationScreen returns a SimulationScreen. Note that
  21. // SimulationScreen is also a Screen.
  22. func NewSimulationScreen(charset string) SimulationScreen {
  23. if charset == "" {
  24. charset = "UTF-8"
  25. }
  26. s := &simscreen{charset: charset}
  27. return s
  28. }
  29. // SimulationScreen represents a screen simulation. This is intended to
  30. // be a superset of normal Screens, but also adds some important interfaces
  31. // for testing.
  32. type SimulationScreen interface {
  33. // InjectKeyBytes injects a stream of bytes corresponding to
  34. // the native encoding (see charset). It turns true if the entire
  35. // set of bytes were processed and delivered as KeyEvents, false
  36. // if any bytes were not fully understood. Any bytes that are not
  37. // fully converted are discarded.
  38. InjectKeyBytes(buf []byte) bool
  39. // InjectKey injects a key event. The rune is a UTF-8 rune, post
  40. // any translation.
  41. InjectKey(key Key, r rune, mod ModMask)
  42. // InjectMouse injects a mouse event.
  43. InjectMouse(x, y int, buttons ButtonMask, mod ModMask)
  44. // GetContents returns screen contents as an array of
  45. // cells, along with the physical width & height. Note that the
  46. // physical contents will be used until the next time SetSize()
  47. // is called.
  48. GetContents() (cells []SimCell, width int, height int)
  49. // GetCursor returns the cursor details.
  50. GetCursor() (x int, y int, visible bool)
  51. Screen
  52. }
  53. // SimCell represents a simulated screen cell. The purpose of this
  54. // is to track on screen content.
  55. type SimCell struct {
  56. // Bytes is the actual character bytes. Normally this is
  57. // rune data, but it could be be data in another encoding system.
  58. Bytes []byte
  59. // Style is the style used to display the data.
  60. Style Style
  61. // Runes is the list of runes, unadulterated, in UTF-8.
  62. Runes []rune
  63. }
  64. type simscreen struct {
  65. physw int
  66. physh int
  67. fini bool
  68. style Style
  69. evch chan Event
  70. quit chan struct{}
  71. front []SimCell
  72. back CellBuffer
  73. clear bool
  74. cursorx int
  75. cursory int
  76. cursorvis bool
  77. mouse bool
  78. paste bool
  79. charset string
  80. encoder transform.Transformer
  81. decoder transform.Transformer
  82. fillchar rune
  83. fillstyle Style
  84. fallback map[rune]string
  85. sync.Mutex
  86. }
  87. func (s *simscreen) Init() error {
  88. s.evch = make(chan Event, 10)
  89. s.quit = make(chan struct{})
  90. s.fillchar = 'X'
  91. s.fillstyle = StyleDefault
  92. s.mouse = false
  93. s.physw = 80
  94. s.physh = 25
  95. s.cursorx = -1
  96. s.cursory = -1
  97. s.style = StyleDefault
  98. if enc := GetEncoding(s.charset); enc != nil {
  99. s.encoder = enc.NewEncoder()
  100. s.decoder = enc.NewDecoder()
  101. } else {
  102. return ErrNoCharset
  103. }
  104. s.front = make([]SimCell, s.physw*s.physh)
  105. s.back.Resize(80, 25)
  106. // default fallbacks
  107. s.fallback = make(map[rune]string)
  108. for k, v := range RuneFallbacks {
  109. s.fallback[k] = v
  110. }
  111. return nil
  112. }
  113. func (s *simscreen) Fini() {
  114. s.Lock()
  115. s.fini = true
  116. s.back.Resize(0, 0)
  117. s.Unlock()
  118. if s.quit != nil {
  119. close(s.quit)
  120. }
  121. s.physw = 0
  122. s.physh = 0
  123. s.front = nil
  124. }
  125. func (s *simscreen) SetStyle(style Style) {
  126. s.Lock()
  127. s.style = style
  128. s.Unlock()
  129. }
  130. func (s *simscreen) Clear() {
  131. s.Fill(' ', s.style)
  132. }
  133. func (s *simscreen) Fill(r rune, style Style) {
  134. s.Lock()
  135. s.back.Fill(r, style)
  136. s.Unlock()
  137. }
  138. func (s *simscreen) SetCell(x, y int, style Style, ch ...rune) {
  139. if len(ch) > 0 {
  140. s.SetContent(x, y, ch[0], ch[1:], style)
  141. } else {
  142. s.SetContent(x, y, ' ', nil, style)
  143. }
  144. }
  145. func (s *simscreen) SetContent(x, y int, mainc rune, combc []rune, st Style) {
  146. s.Lock()
  147. s.back.SetContent(x, y, mainc, combc, st)
  148. s.Unlock()
  149. }
  150. func (s *simscreen) GetContent(x, y int) (rune, []rune, Style, int) {
  151. var mainc rune
  152. var combc []rune
  153. var style Style
  154. var width int
  155. s.Lock()
  156. mainc, combc, style, width = s.back.GetContent(x, y)
  157. s.Unlock()
  158. return mainc, combc, style, width
  159. }
  160. func (s *simscreen) drawCell(x, y int) int {
  161. mainc, combc, style, width := s.back.GetContent(x, y)
  162. if !s.back.Dirty(x, y) {
  163. return width
  164. }
  165. if x >= s.physw || y >= s.physh || x < 0 || y < 0 {
  166. return width
  167. }
  168. simc := &s.front[(y*s.physw)+x]
  169. if style == StyleDefault {
  170. style = s.style
  171. }
  172. simc.Style = style
  173. simc.Runes = append([]rune{mainc}, combc...)
  174. // now emit runes - taking care to not overrun width with a
  175. // wide character, and to ensure that we emit exactly one regular
  176. // character followed up by any residual combing characters
  177. simc.Bytes = nil
  178. if x > s.physw-width {
  179. simc.Runes = []rune{' '}
  180. simc.Bytes = []byte{' '}
  181. return width
  182. }
  183. lbuf := make([]byte, 12)
  184. ubuf := make([]byte, 12)
  185. nout := 0
  186. for _, r := range simc.Runes {
  187. l := utf8.EncodeRune(ubuf, r)
  188. nout, _, _ = s.encoder.Transform(lbuf, ubuf[:l], true)
  189. if nout == 0 || lbuf[0] == '\x1a' {
  190. // skip combining
  191. if subst, ok := s.fallback[r]; ok {
  192. simc.Bytes = append(simc.Bytes,
  193. []byte(subst)...)
  194. } else if r >= ' ' && r <= '~' {
  195. simc.Bytes = append(simc.Bytes, byte(r))
  196. } else if simc.Bytes == nil {
  197. simc.Bytes = append(simc.Bytes, '?')
  198. }
  199. } else {
  200. simc.Bytes = append(simc.Bytes, lbuf[:nout]...)
  201. }
  202. }
  203. s.back.SetDirty(x, y, false)
  204. return width
  205. }
  206. func (s *simscreen) ShowCursor(x, y int) {
  207. s.Lock()
  208. s.cursorx, s.cursory = x, y
  209. s.showCursor()
  210. s.Unlock()
  211. }
  212. func (s *simscreen) HideCursor() {
  213. s.ShowCursor(-1, -1)
  214. }
  215. func (s *simscreen) showCursor() {
  216. x, y := s.cursorx, s.cursory
  217. if x < 0 || y < 0 || x >= s.physw || y >= s.physh {
  218. s.cursorvis = false
  219. } else {
  220. s.cursorvis = true
  221. }
  222. }
  223. func (s *simscreen) hideCursor() {
  224. // does not update cursor position
  225. s.cursorvis = false
  226. }
  227. func (s *simscreen) SetCursorStyle(CursorStyle) {}
  228. func (s *simscreen) Show() {
  229. s.Lock()
  230. s.resize()
  231. s.draw()
  232. s.Unlock()
  233. }
  234. func (s *simscreen) clearScreen() {
  235. // We emulate a hardware clear by filling with a specific pattern
  236. for i := range s.front {
  237. s.front[i].Style = s.fillstyle
  238. s.front[i].Runes = []rune{s.fillchar}
  239. s.front[i].Bytes = []byte{byte(s.fillchar)}
  240. }
  241. s.clear = false
  242. }
  243. func (s *simscreen) draw() {
  244. s.hideCursor()
  245. if s.clear {
  246. s.clearScreen()
  247. }
  248. w, h := s.back.Size()
  249. for y := 0; y < h; y++ {
  250. for x := 0; x < w; x++ {
  251. width := s.drawCell(x, y)
  252. x += width - 1
  253. }
  254. }
  255. s.showCursor()
  256. }
  257. func (s *simscreen) EnableMouse(...MouseFlags) {
  258. s.mouse = true
  259. }
  260. func (s *simscreen) DisableMouse() {
  261. s.mouse = false
  262. }
  263. func (s *simscreen) EnablePaste() {
  264. s.paste = true
  265. }
  266. func (s *simscreen) DisablePaste() {
  267. s.paste = false
  268. }
  269. func (s *simscreen) Size() (int, int) {
  270. s.Lock()
  271. w, h := s.back.Size()
  272. s.Unlock()
  273. return w, h
  274. }
  275. func (s *simscreen) resize() {
  276. w, h := s.physw, s.physh
  277. ow, oh := s.back.Size()
  278. if w != ow || h != oh {
  279. s.back.Resize(w, h)
  280. ev := NewEventResize(w, h)
  281. s.PostEvent(ev)
  282. }
  283. }
  284. func (s *simscreen) Colors() int {
  285. return 256
  286. }
  287. func (s *simscreen) ChannelEvents(ch chan<- Event, quit <-chan struct{}) {
  288. defer close(ch)
  289. for {
  290. select {
  291. case <-quit:
  292. return
  293. case <-s.quit:
  294. return
  295. case ev := <-s.evch:
  296. select {
  297. case <-quit:
  298. return
  299. case <-s.quit:
  300. return
  301. case ch <- ev:
  302. }
  303. }
  304. }
  305. }
  306. func (s *simscreen) PollEvent() Event {
  307. select {
  308. case <-s.quit:
  309. return nil
  310. case ev := <-s.evch:
  311. return ev
  312. }
  313. }
  314. func (s *simscreen) HasPendingEvent() bool {
  315. return len(s.evch) > 0
  316. }
  317. func (s *simscreen) PostEventWait(ev Event) {
  318. s.evch <- ev
  319. }
  320. func (s *simscreen) PostEvent(ev Event) error {
  321. select {
  322. case s.evch <- ev:
  323. return nil
  324. default:
  325. return ErrEventQFull
  326. }
  327. }
  328. func (s *simscreen) InjectMouse(x, y int, buttons ButtonMask, mod ModMask) {
  329. ev := NewEventMouse(x, y, buttons, mod)
  330. s.PostEvent(ev)
  331. }
  332. func (s *simscreen) InjectKey(key Key, r rune, mod ModMask) {
  333. ev := NewEventKey(key, r, mod)
  334. s.PostEvent(ev)
  335. }
  336. func (s *simscreen) InjectKeyBytes(b []byte) bool {
  337. failed := false
  338. outer:
  339. for len(b) > 0 {
  340. if b[0] >= ' ' && b[0] <= 0x7F {
  341. // printable ASCII easy to deal with -- no encodings
  342. ev := NewEventKey(KeyRune, rune(b[0]), ModNone)
  343. s.PostEvent(ev)
  344. b = b[1:]
  345. continue
  346. }
  347. if b[0] < 0x80 {
  348. mod := ModNone
  349. // No encodings start with low numbered values
  350. if Key(b[0]) >= KeyCtrlA && Key(b[0]) <= KeyCtrlZ {
  351. mod = ModCtrl
  352. }
  353. ev := NewEventKey(Key(b[0]), 0, mod)
  354. s.PostEvent(ev)
  355. b = b[1:]
  356. continue
  357. }
  358. utfb := make([]byte, len(b)*4) // worst case
  359. for l := 1; l < len(b); l++ {
  360. s.decoder.Reset()
  361. nout, nin, _ := s.decoder.Transform(utfb, b[:l], true)
  362. if nout != 0 {
  363. r, _ := utf8.DecodeRune(utfb[:nout])
  364. if r != utf8.RuneError {
  365. ev := NewEventKey(KeyRune, r, ModNone)
  366. s.PostEvent(ev)
  367. }
  368. b = b[nin:]
  369. continue outer
  370. }
  371. }
  372. failed = true
  373. b = b[1:]
  374. continue
  375. }
  376. return !failed
  377. }
  378. func (s *simscreen) Sync() {
  379. s.Lock()
  380. s.clear = true
  381. s.resize()
  382. s.back.Invalidate()
  383. s.draw()
  384. s.Unlock()
  385. }
  386. func (s *simscreen) CharacterSet() string {
  387. return s.charset
  388. }
  389. func (s *simscreen) SetSize(w, h int) {
  390. s.Lock()
  391. newc := make([]SimCell, w*h)
  392. for row := 0; row < h && row < s.physh; row++ {
  393. for col := 0; col < w && col < s.physw; col++ {
  394. newc[(row*w)+col] = s.front[(row*s.physw)+col]
  395. }
  396. }
  397. s.cursorx, s.cursory = -1, -1
  398. s.physw, s.physh = w, h
  399. s.front = newc
  400. s.back.Resize(w, h)
  401. s.Unlock()
  402. }
  403. func (s *simscreen) GetContents() ([]SimCell, int, int) {
  404. s.Lock()
  405. cells, w, h := s.front, s.physw, s.physh
  406. s.Unlock()
  407. return cells, w, h
  408. }
  409. func (s *simscreen) GetCursor() (int, int, bool) {
  410. s.Lock()
  411. x, y, vis := s.cursorx, s.cursory, s.cursorvis
  412. s.Unlock()
  413. return x, y, vis
  414. }
  415. func (s *simscreen) RegisterRuneFallback(r rune, subst string) {
  416. s.Lock()
  417. s.fallback[r] = subst
  418. s.Unlock()
  419. }
  420. func (s *simscreen) UnregisterRuneFallback(r rune) {
  421. s.Lock()
  422. delete(s.fallback, r)
  423. s.Unlock()
  424. }
  425. func (s *simscreen) CanDisplay(r rune, checkFallbacks bool) bool {
  426. if enc := s.encoder; enc != nil {
  427. nb := make([]byte, 6)
  428. ob := make([]byte, 6)
  429. num := utf8.EncodeRune(ob, r)
  430. enc.Reset()
  431. dst, _, err := enc.Transform(nb, ob[:num], true)
  432. if dst != 0 && err == nil && nb[0] != '\x1A' {
  433. return true
  434. }
  435. }
  436. if !checkFallbacks {
  437. return false
  438. }
  439. if _, ok := s.fallback[r]; ok {
  440. return true
  441. }
  442. return false
  443. }
  444. func (s *simscreen) HasMouse() bool {
  445. return false
  446. }
  447. func (s *simscreen) Resize(int, int, int, int) {}
  448. func (s *simscreen) HasKey(Key) bool {
  449. return true
  450. }
  451. func (s *simscreen) Beep() error {
  452. return nil
  453. }
  454. func (s *simscreen) Suspend() error {
  455. return nil
  456. }
  457. func (s *simscreen) Resume() error {
  458. return nil
  459. }