console_win.go 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329
  1. //go:build windows
  2. // +build windows
  3. // Copyright 2022 The TCell Authors
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use file except in compliance with the License.
  7. // You may obtain a copy of the license at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. package tcell
  17. import (
  18. "errors"
  19. "fmt"
  20. "os"
  21. "strings"
  22. "sync"
  23. "syscall"
  24. "unicode/utf16"
  25. "unsafe"
  26. )
  27. type cScreen struct {
  28. in syscall.Handle
  29. out syscall.Handle
  30. cancelflag syscall.Handle
  31. scandone chan struct{}
  32. evch chan Event
  33. quit chan struct{}
  34. curx int
  35. cury int
  36. style Style
  37. clear bool
  38. fini bool
  39. vten bool
  40. truecolor bool
  41. running bool
  42. w int
  43. h int
  44. oscreen consoleInfo
  45. ocursor cursorInfo
  46. cursorStyle CursorStyle
  47. oimode uint32
  48. oomode uint32
  49. cells CellBuffer
  50. finiOnce sync.Once
  51. mouseEnabled bool
  52. wg sync.WaitGroup
  53. stopQ chan struct{}
  54. sync.Mutex
  55. }
  56. var winLock sync.Mutex
  57. var winPalette = []Color{
  58. ColorBlack,
  59. ColorMaroon,
  60. ColorGreen,
  61. ColorNavy,
  62. ColorOlive,
  63. ColorPurple,
  64. ColorTeal,
  65. ColorSilver,
  66. ColorGray,
  67. ColorRed,
  68. ColorLime,
  69. ColorBlue,
  70. ColorYellow,
  71. ColorFuchsia,
  72. ColorAqua,
  73. ColorWhite,
  74. }
  75. var winColors = map[Color]Color{
  76. ColorBlack: ColorBlack,
  77. ColorMaroon: ColorMaroon,
  78. ColorGreen: ColorGreen,
  79. ColorNavy: ColorNavy,
  80. ColorOlive: ColorOlive,
  81. ColorPurple: ColorPurple,
  82. ColorTeal: ColorTeal,
  83. ColorSilver: ColorSilver,
  84. ColorGray: ColorGray,
  85. ColorRed: ColorRed,
  86. ColorLime: ColorLime,
  87. ColorBlue: ColorBlue,
  88. ColorYellow: ColorYellow,
  89. ColorFuchsia: ColorFuchsia,
  90. ColorAqua: ColorAqua,
  91. ColorWhite: ColorWhite,
  92. }
  93. var (
  94. k32 = syscall.NewLazyDLL("kernel32.dll")
  95. u32 = syscall.NewLazyDLL("user32.dll")
  96. )
  97. // We have to bring in the kernel32 and user32 DLLs directly, so we can get
  98. // access to some system calls that the core Go API lacks.
  99. //
  100. // Note that Windows appends some functions with W to indicate that wide
  101. // characters (Unicode) are in use. The documentation refers to them
  102. // without this suffix, as the resolution is made via preprocessor.
  103. var (
  104. procReadConsoleInput = k32.NewProc("ReadConsoleInputW")
  105. procWaitForMultipleObjects = k32.NewProc("WaitForMultipleObjects")
  106. procCreateEvent = k32.NewProc("CreateEventW")
  107. procSetEvent = k32.NewProc("SetEvent")
  108. procGetConsoleCursorInfo = k32.NewProc("GetConsoleCursorInfo")
  109. procSetConsoleCursorInfo = k32.NewProc("SetConsoleCursorInfo")
  110. procSetConsoleCursorPosition = k32.NewProc("SetConsoleCursorPosition")
  111. procSetConsoleMode = k32.NewProc("SetConsoleMode")
  112. procGetConsoleMode = k32.NewProc("GetConsoleMode")
  113. procGetConsoleScreenBufferInfo = k32.NewProc("GetConsoleScreenBufferInfo")
  114. procFillConsoleOutputAttribute = k32.NewProc("FillConsoleOutputAttribute")
  115. procFillConsoleOutputCharacter = k32.NewProc("FillConsoleOutputCharacterW")
  116. procSetConsoleWindowInfo = k32.NewProc("SetConsoleWindowInfo")
  117. procSetConsoleScreenBufferSize = k32.NewProc("SetConsoleScreenBufferSize")
  118. procSetConsoleTextAttribute = k32.NewProc("SetConsoleTextAttribute")
  119. procGetLargestConsoleWindowSize = k32.NewProc("GetLargestConsoleWindowSize")
  120. procMessageBeep = u32.NewProc("MessageBeep")
  121. )
  122. const (
  123. w32Infinite = ^uintptr(0)
  124. w32WaitObject0 = uintptr(0)
  125. )
  126. const (
  127. // VT100/XTerm escapes understood by the console
  128. vtShowCursor = "\x1b[?25h"
  129. vtHideCursor = "\x1b[?25l"
  130. vtCursorPos = "\x1b[%d;%dH" // Note that it is Y then X
  131. vtSgr0 = "\x1b[0m"
  132. vtBold = "\x1b[1m"
  133. vtUnderline = "\x1b[4m"
  134. vtBlink = "\x1b[5m" // Not sure this is processed
  135. vtReverse = "\x1b[7m"
  136. vtSetFg = "\x1b[38;5;%dm"
  137. vtSetBg = "\x1b[48;5;%dm"
  138. vtSetFgRGB = "\x1b[38;2;%d;%d;%dm" // RGB
  139. vtSetBgRGB = "\x1b[48;2;%d;%d;%dm" // RGB
  140. vtCursorDefault = "\x1b[0 q"
  141. vtCursorBlinkingBlock = "\x1b[1 q"
  142. vtCursorSteadyBlock = "\x1b[2 q"
  143. vtCursorBlinkingUnderline = "\x1b[3 q"
  144. vtCursorSteadyUnderline = "\x1b[4 q"
  145. vtCursorBlinkingBar = "\x1b[5 q"
  146. vtCursorSteadyBar = "\x1b[6 q"
  147. )
  148. var vtCursorStyles = map[CursorStyle]string{
  149. CursorStyleDefault: vtCursorDefault,
  150. CursorStyleBlinkingBlock: vtCursorBlinkingBlock,
  151. CursorStyleSteadyBlock: vtCursorSteadyBlock,
  152. CursorStyleBlinkingUnderline: vtCursorBlinkingUnderline,
  153. CursorStyleSteadyUnderline: vtCursorSteadyUnderline,
  154. CursorStyleBlinkingBar: vtCursorBlinkingBar,
  155. CursorStyleSteadyBar: vtCursorSteadyBar,
  156. }
  157. // NewConsoleScreen returns a Screen for the Windows console associated
  158. // with the current process. The Screen makes use of the Windows Console
  159. // API to display content and read events.
  160. func NewConsoleScreen() (Screen, error) {
  161. return &cScreen{}, nil
  162. }
  163. func (s *cScreen) Init() error {
  164. s.evch = make(chan Event, 10)
  165. s.quit = make(chan struct{})
  166. s.scandone = make(chan struct{})
  167. in, e := syscall.Open("CONIN$", syscall.O_RDWR, 0)
  168. if e != nil {
  169. return e
  170. }
  171. s.in = in
  172. out, e := syscall.Open("CONOUT$", syscall.O_RDWR, 0)
  173. if e != nil {
  174. _ = syscall.Close(s.in)
  175. return e
  176. }
  177. s.out = out
  178. s.truecolor = true
  179. // ConEmu handling of colors and scrolling when in terminal
  180. // mode is extremely problematic at the best. The color
  181. // palette will scroll even though characters do not, when
  182. // emitting stuff for the last character. In the future we
  183. // might change this to look at specific versions of ConEmu
  184. // if they fix the bug.
  185. if os.Getenv("ConEmuPID") != "" {
  186. s.truecolor = false
  187. }
  188. switch os.Getenv("TCELL_TRUECOLOR") {
  189. case "disable":
  190. s.truecolor = false
  191. case "enable":
  192. s.truecolor = true
  193. }
  194. s.Lock()
  195. s.curx = -1
  196. s.cury = -1
  197. s.style = StyleDefault
  198. s.getCursorInfo(&s.ocursor)
  199. s.getConsoleInfo(&s.oscreen)
  200. s.getOutMode(&s.oomode)
  201. s.getInMode(&s.oimode)
  202. s.resize()
  203. s.fini = false
  204. s.setInMode(modeResizeEn | modeExtendFlg)
  205. // 24-bit color is opt-in for now, because we can't figure out
  206. // to make it work consistently.
  207. if s.truecolor {
  208. s.setOutMode(modeVtOutput | modeNoAutoNL | modeCookedOut)
  209. var om uint32
  210. s.getOutMode(&om)
  211. if om&modeVtOutput == modeVtOutput {
  212. s.vten = true
  213. } else {
  214. s.truecolor = false
  215. s.setOutMode(0)
  216. }
  217. } else {
  218. s.setOutMode(0)
  219. }
  220. s.Unlock()
  221. return s.engage()
  222. }
  223. func (s *cScreen) CharacterSet() string {
  224. // We are always UTF-16LE on Windows
  225. return "UTF-16LE"
  226. }
  227. func (s *cScreen) EnableMouse(...MouseFlags) {
  228. s.Lock()
  229. s.mouseEnabled = true
  230. s.enableMouse(true)
  231. s.Unlock()
  232. }
  233. func (s *cScreen) DisableMouse() {
  234. s.Lock()
  235. s.mouseEnabled = false
  236. s.enableMouse(false)
  237. s.Unlock()
  238. }
  239. func (s *cScreen) enableMouse(on bool) {
  240. if on {
  241. s.setInMode(modeResizeEn | modeMouseEn | modeExtendFlg)
  242. } else {
  243. s.setInMode(modeResizeEn | modeExtendFlg)
  244. }
  245. }
  246. // Windows lacks bracketed paste (for now)
  247. func (s *cScreen) EnablePaste() {}
  248. func (s *cScreen) DisablePaste() {}
  249. func (s *cScreen) Fini() {
  250. s.disengage()
  251. }
  252. func (s *cScreen) disengage() {
  253. s.Lock()
  254. if !s.running {
  255. s.Unlock()
  256. return
  257. }
  258. s.running = false
  259. stopQ := s.stopQ
  260. _, _, _ = procSetEvent.Call(uintptr(s.cancelflag))
  261. close(stopQ)
  262. s.Unlock()
  263. s.wg.Wait()
  264. if s.vten {
  265. s.emitVtString(vtCursorStyles[CursorStyleDefault])
  266. }
  267. s.setInMode(s.oimode)
  268. s.setOutMode(s.oomode)
  269. s.setBufferSize(int(s.oscreen.size.x), int(s.oscreen.size.y))
  270. s.clearScreen(StyleDefault, false)
  271. s.setCursorPos(0, 0, false)
  272. s.setCursorInfo(&s.ocursor)
  273. _, _, _ = procSetConsoleTextAttribute.Call(
  274. uintptr(s.out),
  275. uintptr(s.mapStyle(StyleDefault)))
  276. }
  277. func (s *cScreen) engage() error {
  278. s.Lock()
  279. defer s.Unlock()
  280. if s.running {
  281. return errors.New("already engaged")
  282. }
  283. s.stopQ = make(chan struct{})
  284. cf, _, e := procCreateEvent.Call(
  285. uintptr(0),
  286. uintptr(1),
  287. uintptr(0),
  288. uintptr(0))
  289. if cf == uintptr(0) {
  290. return e
  291. }
  292. s.running = true
  293. s.cancelflag = syscall.Handle(cf)
  294. s.enableMouse(s.mouseEnabled)
  295. if s.vten {
  296. s.setOutMode(modeVtOutput | modeNoAutoNL | modeCookedOut)
  297. } else {
  298. s.setOutMode(0)
  299. }
  300. s.clearScreen(s.style, s.vten)
  301. s.hideCursor()
  302. s.cells.Invalidate()
  303. s.hideCursor()
  304. s.resize()
  305. s.draw()
  306. s.doCursor()
  307. s.wg.Add(1)
  308. go s.scanInput(s.stopQ)
  309. return nil
  310. }
  311. func (s *cScreen) PostEventWait(ev Event) {
  312. s.evch <- ev
  313. }
  314. func (s *cScreen) PostEvent(ev Event) error {
  315. select {
  316. case s.evch <- ev:
  317. return nil
  318. default:
  319. return ErrEventQFull
  320. }
  321. }
  322. func (s *cScreen) ChannelEvents(ch chan<- Event, quit <-chan struct{}) {
  323. defer close(ch)
  324. for {
  325. select {
  326. case <-quit:
  327. return
  328. case <-s.stopQ:
  329. return
  330. case ev := <-s.evch:
  331. select {
  332. case <-quit:
  333. return
  334. case <-s.stopQ:
  335. return
  336. case ch <- ev:
  337. }
  338. }
  339. }
  340. }
  341. func (s *cScreen) PollEvent() Event {
  342. select {
  343. case <-s.stopQ:
  344. return nil
  345. case ev := <-s.evch:
  346. return ev
  347. }
  348. }
  349. func (s *cScreen) HasPendingEvent() bool {
  350. return len(s.evch) > 0
  351. }
  352. type cursorInfo struct {
  353. size uint32
  354. visible uint32
  355. }
  356. type coord struct {
  357. x int16
  358. y int16
  359. }
  360. func (c coord) uintptr() uintptr {
  361. // little endian, put x first
  362. return uintptr(c.x) | (uintptr(c.y) << 16)
  363. }
  364. type rect struct {
  365. left int16
  366. top int16
  367. right int16
  368. bottom int16
  369. }
  370. func (s *cScreen) emitVtString(vs string) {
  371. esc := utf16.Encode([]rune(vs))
  372. _ = syscall.WriteConsole(s.out, &esc[0], uint32(len(esc)), nil, nil)
  373. }
  374. func (s *cScreen) showCursor() {
  375. if s.vten {
  376. s.emitVtString(vtShowCursor)
  377. s.emitVtString(vtCursorStyles[s.cursorStyle])
  378. } else {
  379. s.setCursorInfo(&cursorInfo{size: 100, visible: 1})
  380. }
  381. }
  382. func (s *cScreen) hideCursor() {
  383. if s.vten {
  384. s.emitVtString(vtHideCursor)
  385. } else {
  386. s.setCursorInfo(&cursorInfo{size: 1, visible: 0})
  387. }
  388. }
  389. func (s *cScreen) ShowCursor(x, y int) {
  390. s.Lock()
  391. if !s.fini {
  392. s.curx = x
  393. s.cury = y
  394. }
  395. s.doCursor()
  396. s.Unlock()
  397. }
  398. func (s *cScreen) SetCursorStyle(cs CursorStyle) {
  399. s.Lock()
  400. if !s.fini {
  401. if _, ok := vtCursorStyles[cs]; ok {
  402. s.cursorStyle = cs
  403. s.doCursor()
  404. }
  405. }
  406. s.Unlock()
  407. }
  408. func (s *cScreen) doCursor() {
  409. x, y := s.curx, s.cury
  410. if x < 0 || y < 0 || x >= s.w || y >= s.h {
  411. s.hideCursor()
  412. } else {
  413. s.setCursorPos(x, y, s.vten)
  414. s.showCursor()
  415. }
  416. }
  417. func (s *cScreen) HideCursor() {
  418. s.ShowCursor(-1, -1)
  419. }
  420. type inputRecord struct {
  421. typ uint16
  422. _ uint16
  423. data [16]byte
  424. }
  425. const (
  426. keyEvent uint16 = 1
  427. mouseEvent uint16 = 2
  428. resizeEvent uint16 = 4
  429. // menuEvent uint16 = 8 // don't use
  430. // focusEvent uint16 = 16 // don't use
  431. )
  432. type mouseRecord struct {
  433. x int16
  434. y int16
  435. btns uint32
  436. mod uint32
  437. flags uint32
  438. }
  439. const (
  440. mouseHWheeled uint32 = 0x8
  441. mouseVWheeled uint32 = 0x4
  442. // mouseDoubleClick uint32 = 0x2
  443. // mouseMoved uint32 = 0x1
  444. )
  445. type resizeRecord struct {
  446. x int16
  447. y int16
  448. }
  449. type keyRecord struct {
  450. isdown int32
  451. repeat uint16
  452. kcode uint16
  453. scode uint16
  454. ch uint16
  455. mod uint32
  456. }
  457. const (
  458. // Constants per Microsoft. We don't put the modifiers
  459. // here.
  460. vkCancel = 0x03
  461. vkBack = 0x08 // Backspace
  462. vkTab = 0x09
  463. vkClear = 0x0c
  464. vkReturn = 0x0d
  465. vkPause = 0x13
  466. vkEscape = 0x1b
  467. vkSpace = 0x20
  468. vkPrior = 0x21 // PgUp
  469. vkNext = 0x22 // PgDn
  470. vkEnd = 0x23
  471. vkHome = 0x24
  472. vkLeft = 0x25
  473. vkUp = 0x26
  474. vkRight = 0x27
  475. vkDown = 0x28
  476. vkPrint = 0x2a
  477. vkPrtScr = 0x2c
  478. vkInsert = 0x2d
  479. vkDelete = 0x2e
  480. vkHelp = 0x2f
  481. vkF1 = 0x70
  482. vkF2 = 0x71
  483. vkF3 = 0x72
  484. vkF4 = 0x73
  485. vkF5 = 0x74
  486. vkF6 = 0x75
  487. vkF7 = 0x76
  488. vkF8 = 0x77
  489. vkF9 = 0x78
  490. vkF10 = 0x79
  491. vkF11 = 0x7a
  492. vkF12 = 0x7b
  493. vkF13 = 0x7c
  494. vkF14 = 0x7d
  495. vkF15 = 0x7e
  496. vkF16 = 0x7f
  497. vkF17 = 0x80
  498. vkF18 = 0x81
  499. vkF19 = 0x82
  500. vkF20 = 0x83
  501. vkF21 = 0x84
  502. vkF22 = 0x85
  503. vkF23 = 0x86
  504. vkF24 = 0x87
  505. )
  506. var vkKeys = map[uint16]Key{
  507. vkCancel: KeyCancel,
  508. vkBack: KeyBackspace,
  509. vkTab: KeyTab,
  510. vkClear: KeyClear,
  511. vkPause: KeyPause,
  512. vkPrint: KeyPrint,
  513. vkPrtScr: KeyPrint,
  514. vkPrior: KeyPgUp,
  515. vkNext: KeyPgDn,
  516. vkReturn: KeyEnter,
  517. vkEnd: KeyEnd,
  518. vkHome: KeyHome,
  519. vkLeft: KeyLeft,
  520. vkUp: KeyUp,
  521. vkRight: KeyRight,
  522. vkDown: KeyDown,
  523. vkInsert: KeyInsert,
  524. vkDelete: KeyDelete,
  525. vkHelp: KeyHelp,
  526. vkEscape: KeyEscape,
  527. vkSpace: ' ',
  528. vkF1: KeyF1,
  529. vkF2: KeyF2,
  530. vkF3: KeyF3,
  531. vkF4: KeyF4,
  532. vkF5: KeyF5,
  533. vkF6: KeyF6,
  534. vkF7: KeyF7,
  535. vkF8: KeyF8,
  536. vkF9: KeyF9,
  537. vkF10: KeyF10,
  538. vkF11: KeyF11,
  539. vkF12: KeyF12,
  540. vkF13: KeyF13,
  541. vkF14: KeyF14,
  542. vkF15: KeyF15,
  543. vkF16: KeyF16,
  544. vkF17: KeyF17,
  545. vkF18: KeyF18,
  546. vkF19: KeyF19,
  547. vkF20: KeyF20,
  548. vkF21: KeyF21,
  549. vkF22: KeyF22,
  550. vkF23: KeyF23,
  551. vkF24: KeyF24,
  552. }
  553. // NB: All Windows platforms are little endian. We assume this
  554. // never, ever change. The following code is endian safe. and does
  555. // not use unsafe pointers.
  556. func getu32(v []byte) uint32 {
  557. return uint32(v[0]) + (uint32(v[1]) << 8) + (uint32(v[2]) << 16) + (uint32(v[3]) << 24)
  558. }
  559. func geti32(v []byte) int32 {
  560. return int32(getu32(v))
  561. }
  562. func getu16(v []byte) uint16 {
  563. return uint16(v[0]) + (uint16(v[1]) << 8)
  564. }
  565. func geti16(v []byte) int16 {
  566. return int16(getu16(v))
  567. }
  568. // Convert windows dwControlKeyState to modifier mask
  569. func mod2mask(cks uint32) ModMask {
  570. mm := ModNone
  571. // Left or right control
  572. if (cks & (0x0008 | 0x0004)) != 0 {
  573. mm |= ModCtrl
  574. }
  575. // Left or right alt
  576. if (cks & (0x0002 | 0x0001)) != 0 {
  577. mm |= ModAlt
  578. }
  579. // Any shift
  580. if (cks & 0x0010) != 0 {
  581. mm |= ModShift
  582. }
  583. return mm
  584. }
  585. func mrec2btns(mbtns, flags uint32) ButtonMask {
  586. btns := ButtonNone
  587. if mbtns&0x1 != 0 {
  588. btns |= Button1
  589. }
  590. if mbtns&0x2 != 0 {
  591. btns |= Button2
  592. }
  593. if mbtns&0x4 != 0 {
  594. btns |= Button3
  595. }
  596. if mbtns&0x8 != 0 {
  597. btns |= Button4
  598. }
  599. if mbtns&0x10 != 0 {
  600. btns |= Button5
  601. }
  602. if mbtns&0x20 != 0 {
  603. btns |= Button6
  604. }
  605. if mbtns&0x40 != 0 {
  606. btns |= Button7
  607. }
  608. if mbtns&0x80 != 0 {
  609. btns |= Button8
  610. }
  611. if flags&mouseVWheeled != 0 {
  612. if mbtns&0x80000000 == 0 {
  613. btns |= WheelUp
  614. } else {
  615. btns |= WheelDown
  616. }
  617. }
  618. if flags&mouseHWheeled != 0 {
  619. if mbtns&0x80000000 == 0 {
  620. btns |= WheelRight
  621. } else {
  622. btns |= WheelLeft
  623. }
  624. }
  625. return btns
  626. }
  627. func (s *cScreen) getConsoleInput() error {
  628. // cancelFlag comes first as WaitForMultipleObjects returns the lowest index
  629. // in the event that both events are signalled.
  630. waitObjects := []syscall.Handle{s.cancelflag, s.in}
  631. // As arrays are contiguous in memory, a pointer to the first object is the
  632. // same as a pointer to the array itself.
  633. pWaitObjects := unsafe.Pointer(&waitObjects[0])
  634. rv, _, er := procWaitForMultipleObjects.Call(
  635. uintptr(len(waitObjects)),
  636. uintptr(pWaitObjects),
  637. uintptr(0),
  638. w32Infinite)
  639. // WaitForMultipleObjects returns WAIT_OBJECT_0 + the index.
  640. switch rv {
  641. case w32WaitObject0: // s.cancelFlag
  642. return errors.New("cancelled")
  643. case w32WaitObject0 + 1: // s.in
  644. rec := &inputRecord{}
  645. var nrec int32
  646. rv, _, er := procReadConsoleInput.Call(
  647. uintptr(s.in),
  648. uintptr(unsafe.Pointer(rec)),
  649. uintptr(1),
  650. uintptr(unsafe.Pointer(&nrec)))
  651. if rv == 0 {
  652. return er
  653. }
  654. if nrec != 1 {
  655. return nil
  656. }
  657. switch rec.typ {
  658. case keyEvent:
  659. krec := &keyRecord{}
  660. krec.isdown = geti32(rec.data[0:])
  661. krec.repeat = getu16(rec.data[4:])
  662. krec.kcode = getu16(rec.data[6:])
  663. krec.scode = getu16(rec.data[8:])
  664. krec.ch = getu16(rec.data[10:])
  665. krec.mod = getu32(rec.data[12:])
  666. if krec.isdown == 0 || krec.repeat < 1 {
  667. // its a key release event, ignore it
  668. return nil
  669. }
  670. if krec.ch != 0 {
  671. // synthesized key code
  672. for krec.repeat > 0 {
  673. // convert shift+tab to backtab
  674. if mod2mask(krec.mod) == ModShift && krec.ch == vkTab {
  675. s.PostEventWait(NewEventKey(KeyBacktab, 0,
  676. ModNone))
  677. } else {
  678. s.PostEventWait(NewEventKey(KeyRune, rune(krec.ch),
  679. mod2mask(krec.mod)))
  680. }
  681. krec.repeat--
  682. }
  683. return nil
  684. }
  685. key := KeyNUL // impossible on Windows
  686. ok := false
  687. if key, ok = vkKeys[krec.kcode]; !ok {
  688. return nil
  689. }
  690. for krec.repeat > 0 {
  691. s.PostEventWait(NewEventKey(key, rune(krec.ch),
  692. mod2mask(krec.mod)))
  693. krec.repeat--
  694. }
  695. case mouseEvent:
  696. var mrec mouseRecord
  697. mrec.x = geti16(rec.data[0:])
  698. mrec.y = geti16(rec.data[2:])
  699. mrec.btns = getu32(rec.data[4:])
  700. mrec.mod = getu32(rec.data[8:])
  701. mrec.flags = getu32(rec.data[12:])
  702. btns := mrec2btns(mrec.btns, mrec.flags)
  703. // we ignore double click, events are delivered normally
  704. s.PostEventWait(NewEventMouse(int(mrec.x), int(mrec.y), btns,
  705. mod2mask(mrec.mod)))
  706. case resizeEvent:
  707. var rrec resizeRecord
  708. rrec.x = geti16(rec.data[0:])
  709. rrec.y = geti16(rec.data[2:])
  710. s.PostEventWait(NewEventResize(int(rrec.x), int(rrec.y)))
  711. default:
  712. }
  713. default:
  714. return er
  715. }
  716. return nil
  717. }
  718. func (s *cScreen) scanInput(stopQ chan struct{}) {
  719. defer s.wg.Done()
  720. for {
  721. select {
  722. case <-stopQ:
  723. return
  724. default:
  725. }
  726. if e := s.getConsoleInput(); e != nil {
  727. return
  728. }
  729. }
  730. }
  731. func (s *cScreen) Colors() int {
  732. if s.vten {
  733. return 1 << 24
  734. }
  735. // Windows console can display 8 colors, in either low or high intensity
  736. return 16
  737. }
  738. var vgaColors = map[Color]uint16{
  739. ColorBlack: 0,
  740. ColorMaroon: 0x4,
  741. ColorGreen: 0x2,
  742. ColorNavy: 0x1,
  743. ColorOlive: 0x6,
  744. ColorPurple: 0x5,
  745. ColorTeal: 0x3,
  746. ColorSilver: 0x7,
  747. ColorGrey: 0x8,
  748. ColorRed: 0xc,
  749. ColorLime: 0xa,
  750. ColorBlue: 0x9,
  751. ColorYellow: 0xe,
  752. ColorFuchsia: 0xd,
  753. ColorAqua: 0xb,
  754. ColorWhite: 0xf,
  755. }
  756. // Windows uses RGB signals
  757. func mapColor2RGB(c Color) uint16 {
  758. winLock.Lock()
  759. if v, ok := winColors[c]; ok {
  760. c = v
  761. } else {
  762. v = FindColor(c, winPalette)
  763. winColors[c] = v
  764. c = v
  765. }
  766. winLock.Unlock()
  767. if vc, ok := vgaColors[c]; ok {
  768. return vc
  769. }
  770. return 0
  771. }
  772. // Map a tcell style to Windows attributes
  773. func (s *cScreen) mapStyle(style Style) uint16 {
  774. f, b, a := style.Decompose()
  775. fa := s.oscreen.attrs & 0xf
  776. ba := (s.oscreen.attrs) >> 4 & 0xf
  777. if f != ColorDefault && f != ColorReset {
  778. fa = mapColor2RGB(f)
  779. }
  780. if b != ColorDefault && b != ColorReset {
  781. ba = mapColor2RGB(b)
  782. }
  783. var attr uint16
  784. // We simulate reverse by doing the color swap ourselves.
  785. // Apparently windows cannot really do this except in DBCS
  786. // views.
  787. if a&AttrReverse != 0 {
  788. attr = ba
  789. attr |= fa << 4
  790. } else {
  791. attr = fa
  792. attr |= ba << 4
  793. }
  794. if a&AttrBold != 0 {
  795. attr |= 0x8
  796. }
  797. if a&AttrDim != 0 {
  798. attr &^= 0x8
  799. }
  800. if a&AttrUnderline != 0 {
  801. // Best effort -- doesn't seem to work though.
  802. attr |= 0x8000
  803. }
  804. // Blink is unsupported
  805. return attr
  806. }
  807. func (s *cScreen) SetCell(x, y int, style Style, ch ...rune) {
  808. if len(ch) > 0 {
  809. s.SetContent(x, y, ch[0], ch[1:], style)
  810. } else {
  811. s.SetContent(x, y, ' ', nil, style)
  812. }
  813. }
  814. func (s *cScreen) SetContent(x, y int, primary rune, combining []rune, style Style) {
  815. s.Lock()
  816. if !s.fini {
  817. s.cells.SetContent(x, y, primary, combining, style)
  818. }
  819. s.Unlock()
  820. }
  821. func (s *cScreen) GetContent(x, y int) (rune, []rune, Style, int) {
  822. s.Lock()
  823. primary, combining, style, width := s.cells.GetContent(x, y)
  824. s.Unlock()
  825. return primary, combining, style, width
  826. }
  827. func (s *cScreen) sendVtStyle(style Style) {
  828. esc := &strings.Builder{}
  829. fg, bg, attrs := style.Decompose()
  830. esc.WriteString(vtSgr0)
  831. if attrs&(AttrBold|AttrDim) == AttrBold {
  832. esc.WriteString(vtBold)
  833. }
  834. if attrs&AttrBlink != 0 {
  835. esc.WriteString(vtBlink)
  836. }
  837. if attrs&AttrUnderline != 0 {
  838. esc.WriteString(vtUnderline)
  839. }
  840. if attrs&AttrReverse != 0 {
  841. esc.WriteString(vtReverse)
  842. }
  843. if fg.IsRGB() {
  844. r, g, b := fg.RGB()
  845. _, _ = fmt.Fprintf(esc, vtSetFgRGB, r, g, b)
  846. } else if fg.Valid() {
  847. _, _ = fmt.Fprintf(esc, vtSetFg, fg&0xff)
  848. }
  849. if bg.IsRGB() {
  850. r, g, b := bg.RGB()
  851. _, _ = fmt.Fprintf(esc, vtSetBgRGB, r, g, b)
  852. } else if bg.Valid() {
  853. _, _ = fmt.Fprintf(esc, vtSetBg, bg&0xff)
  854. }
  855. s.emitVtString(esc.String())
  856. }
  857. func (s *cScreen) writeString(x, y int, style Style, ch []uint16) {
  858. // we assume the caller has hidden the cursor
  859. if len(ch) == 0 {
  860. return
  861. }
  862. s.setCursorPos(x, y, s.vten)
  863. if s.vten {
  864. s.sendVtStyle(style)
  865. } else {
  866. _, _, _ = procSetConsoleTextAttribute.Call(
  867. uintptr(s.out),
  868. uintptr(s.mapStyle(style)))
  869. }
  870. _ = syscall.WriteConsole(s.out, &ch[0], uint32(len(ch)), nil, nil)
  871. }
  872. func (s *cScreen) draw() {
  873. // allocate a scratch line bit enough for no combining chars.
  874. // if you have combining characters, you may pay for extra allocations.
  875. if s.clear {
  876. s.clearScreen(s.style, s.vten)
  877. s.clear = false
  878. s.cells.Invalidate()
  879. }
  880. buf := make([]uint16, 0, s.w)
  881. wcs := buf[:]
  882. lstyle := styleInvalid
  883. lx, ly := -1, -1
  884. ra := make([]rune, 1)
  885. for y := 0; y < s.h; y++ {
  886. for x := 0; x < s.w; x++ {
  887. mainc, combc, style, width := s.cells.GetContent(x, y)
  888. dirty := s.cells.Dirty(x, y)
  889. if style == StyleDefault {
  890. style = s.style
  891. }
  892. if !dirty || style != lstyle {
  893. // write out any data queued thus far
  894. // because we are going to skip over some
  895. // cells, or because we need to change styles
  896. s.writeString(lx, ly, lstyle, wcs)
  897. wcs = buf[0:0]
  898. lstyle = StyleDefault
  899. if !dirty {
  900. continue
  901. }
  902. }
  903. if x > s.w-width {
  904. mainc = ' '
  905. combc = nil
  906. width = 1
  907. }
  908. if len(wcs) == 0 {
  909. lstyle = style
  910. lx = x
  911. ly = y
  912. }
  913. ra[0] = mainc
  914. wcs = append(wcs, utf16.Encode(ra)...)
  915. if len(combc) != 0 {
  916. wcs = append(wcs, utf16.Encode(combc)...)
  917. }
  918. for dx := 0; dx < width; dx++ {
  919. s.cells.SetDirty(x+dx, y, false)
  920. }
  921. x += width - 1
  922. }
  923. s.writeString(lx, ly, lstyle, wcs)
  924. wcs = buf[0:0]
  925. lstyle = styleInvalid
  926. }
  927. }
  928. func (s *cScreen) Show() {
  929. s.Lock()
  930. if !s.fini {
  931. s.hideCursor()
  932. s.resize()
  933. s.draw()
  934. s.doCursor()
  935. }
  936. s.Unlock()
  937. }
  938. func (s *cScreen) Sync() {
  939. s.Lock()
  940. if !s.fini {
  941. s.cells.Invalidate()
  942. s.hideCursor()
  943. s.resize()
  944. s.draw()
  945. s.doCursor()
  946. }
  947. s.Unlock()
  948. }
  949. type consoleInfo struct {
  950. size coord
  951. pos coord
  952. attrs uint16
  953. win rect
  954. maxsz coord
  955. }
  956. func (s *cScreen) getConsoleInfo(info *consoleInfo) {
  957. _, _, _ = procGetConsoleScreenBufferInfo.Call(
  958. uintptr(s.out),
  959. uintptr(unsafe.Pointer(info)))
  960. }
  961. func (s *cScreen) getCursorInfo(info *cursorInfo) {
  962. _, _, _ = procGetConsoleCursorInfo.Call(
  963. uintptr(s.out),
  964. uintptr(unsafe.Pointer(info)))
  965. }
  966. func (s *cScreen) setCursorInfo(info *cursorInfo) {
  967. _, _, _ = procSetConsoleCursorInfo.Call(
  968. uintptr(s.out),
  969. uintptr(unsafe.Pointer(info)))
  970. }
  971. func (s *cScreen) setCursorPos(x, y int, vtEnable bool) {
  972. if vtEnable {
  973. // Note that the string is Y first. Origin is 1,1.
  974. s.emitVtString(fmt.Sprintf(vtCursorPos, y+1, x+1))
  975. } else {
  976. _, _, _ = procSetConsoleCursorPosition.Call(
  977. uintptr(s.out),
  978. coord{int16(x), int16(y)}.uintptr())
  979. }
  980. }
  981. func (s *cScreen) setBufferSize(x, y int) {
  982. _, _, _ = procSetConsoleScreenBufferSize.Call(
  983. uintptr(s.out),
  984. coord{int16(x), int16(y)}.uintptr())
  985. }
  986. func (s *cScreen) Size() (int, int) {
  987. s.Lock()
  988. w, h := s.w, s.h
  989. s.Unlock()
  990. return w, h
  991. }
  992. func (s *cScreen) SetSize(w, h int) {
  993. xy, _, _ := procGetLargestConsoleWindowSize.Call(uintptr(s.out))
  994. // xy is little endian packed
  995. y := int(xy >> 16)
  996. x := int(xy & 0xffff)
  997. if x == 0 || y == 0 {
  998. return
  999. }
  1000. // This is a hacky workaround for Windows Terminal.
  1001. // Essentially Windows Terminal (Windows 11) does not support application
  1002. // initiated resizing. To detect this, we look for an extremely large size
  1003. // for the maximum width. If it is > 500, then this is almost certainly
  1004. // Windows Terminal, and won't support this. (Note that the legacy console
  1005. // does support application resizing.)
  1006. if x >= 500 {
  1007. return
  1008. }
  1009. s.setBufferSize(x, y)
  1010. r := rect{0, 0, int16(w - 1), int16(h - 1)}
  1011. _, _, _ = procSetConsoleWindowInfo.Call(
  1012. uintptr(s.out),
  1013. uintptr(1),
  1014. uintptr(unsafe.Pointer(&r)))
  1015. s.resize()
  1016. }
  1017. func (s *cScreen) resize() {
  1018. info := consoleInfo{}
  1019. s.getConsoleInfo(&info)
  1020. w := int((info.win.right - info.win.left) + 1)
  1021. h := int((info.win.bottom - info.win.top) + 1)
  1022. if s.w == w && s.h == h {
  1023. return
  1024. }
  1025. s.cells.Resize(w, h)
  1026. s.w = w
  1027. s.h = h
  1028. s.setBufferSize(w, h)
  1029. r := rect{0, 0, int16(w - 1), int16(h - 1)}
  1030. _, _, _ = procSetConsoleWindowInfo.Call(
  1031. uintptr(s.out),
  1032. uintptr(1),
  1033. uintptr(unsafe.Pointer(&r)))
  1034. _ = s.PostEvent(NewEventResize(w, h))
  1035. }
  1036. func (s *cScreen) Clear() {
  1037. s.Fill(' ', s.style)
  1038. }
  1039. func (s *cScreen) Fill(r rune, style Style) {
  1040. s.Lock()
  1041. if !s.fini {
  1042. s.cells.Fill(r, style)
  1043. s.clear = true
  1044. }
  1045. s.Unlock()
  1046. }
  1047. func (s *cScreen) clearScreen(style Style, vtEnable bool) {
  1048. if vtEnable {
  1049. s.sendVtStyle(style)
  1050. row := strings.Repeat(" ", s.w)
  1051. for y := 0; y < s.h; y++ {
  1052. s.setCursorPos(0, y, vtEnable)
  1053. s.emitVtString(row)
  1054. }
  1055. s.setCursorPos(0, 0, vtEnable)
  1056. } else {
  1057. pos := coord{0, 0}
  1058. attr := s.mapStyle(style)
  1059. x, y := s.w, s.h
  1060. scratch := uint32(0)
  1061. count := uint32(x * y)
  1062. _, _, _ = procFillConsoleOutputAttribute.Call(
  1063. uintptr(s.out),
  1064. uintptr(attr),
  1065. uintptr(count),
  1066. pos.uintptr(),
  1067. uintptr(unsafe.Pointer(&scratch)))
  1068. _, _, _ = procFillConsoleOutputCharacter.Call(
  1069. uintptr(s.out),
  1070. uintptr(' '),
  1071. uintptr(count),
  1072. pos.uintptr(),
  1073. uintptr(unsafe.Pointer(&scratch)))
  1074. }
  1075. }
  1076. const (
  1077. // Input modes
  1078. modeExtendFlg uint32 = 0x0080
  1079. modeMouseEn = 0x0010
  1080. modeResizeEn = 0x0008
  1081. // modeCooked = 0x0001
  1082. // modeVtInput = 0x0200
  1083. // Output modes
  1084. modeCookedOut uint32 = 0x0001
  1085. modeVtOutput = 0x0004
  1086. modeNoAutoNL = 0x0008
  1087. // modeWrapEOL = 0x0002
  1088. )
  1089. func (s *cScreen) setInMode(mode uint32) {
  1090. _, _, _ = procSetConsoleMode.Call(
  1091. uintptr(s.in),
  1092. uintptr(mode))
  1093. }
  1094. func (s *cScreen) setOutMode(mode uint32) {
  1095. _, _, _ = procSetConsoleMode.Call(
  1096. uintptr(s.out),
  1097. uintptr(mode))
  1098. }
  1099. func (s *cScreen) getInMode(v *uint32) {
  1100. _, _, _ = procGetConsoleMode.Call(
  1101. uintptr(s.in),
  1102. uintptr(unsafe.Pointer(v)))
  1103. }
  1104. func (s *cScreen) getOutMode(v *uint32) {
  1105. _, _, _ = procGetConsoleMode.Call(
  1106. uintptr(s.out),
  1107. uintptr(unsafe.Pointer(v)))
  1108. }
  1109. func (s *cScreen) SetStyle(style Style) {
  1110. s.Lock()
  1111. s.style = style
  1112. s.Unlock()
  1113. }
  1114. // No fallback rune support, since we have Unicode. Yay!
  1115. func (s *cScreen) RegisterRuneFallback(_ rune, _ string) {
  1116. }
  1117. func (s *cScreen) UnregisterRuneFallback(_ rune) {
  1118. }
  1119. func (s *cScreen) CanDisplay(_ rune, _ bool) bool {
  1120. // We presume we can display anything -- we're Unicode.
  1121. // (Sadly this not precisely true. Combining characters are especially
  1122. // poorly supported under Windows.)
  1123. return true
  1124. }
  1125. func (s *cScreen) HasMouse() bool {
  1126. return true
  1127. }
  1128. func (s *cScreen) Resize(int, int, int, int) {}
  1129. func (s *cScreen) HasKey(k Key) bool {
  1130. // Microsoft has codes for some keys, but they are unusual,
  1131. // so we don't include them. We include all the typical
  1132. // 101, 105 key layout keys.
  1133. valid := map[Key]bool{
  1134. KeyBackspace: true,
  1135. KeyTab: true,
  1136. KeyEscape: true,
  1137. KeyPause: true,
  1138. KeyPrint: true,
  1139. KeyPgUp: true,
  1140. KeyPgDn: true,
  1141. KeyEnter: true,
  1142. KeyEnd: true,
  1143. KeyHome: true,
  1144. KeyLeft: true,
  1145. KeyUp: true,
  1146. KeyRight: true,
  1147. KeyDown: true,
  1148. KeyInsert: true,
  1149. KeyDelete: true,
  1150. KeyF1: true,
  1151. KeyF2: true,
  1152. KeyF3: true,
  1153. KeyF4: true,
  1154. KeyF5: true,
  1155. KeyF6: true,
  1156. KeyF7: true,
  1157. KeyF8: true,
  1158. KeyF9: true,
  1159. KeyF10: true,
  1160. KeyF11: true,
  1161. KeyF12: true,
  1162. KeyRune: true,
  1163. }
  1164. return valid[k]
  1165. }
  1166. func (s *cScreen) Beep() error {
  1167. // A simple beep. If the sound card is not available, the sound is generated
  1168. // using the speaker.
  1169. //
  1170. // Reference:
  1171. // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebeep
  1172. const simpleBeep = 0xffffffff
  1173. if rv, _, err := procMessageBeep.Call(simpleBeep); rv == 0 {
  1174. return err
  1175. }
  1176. return nil
  1177. }
  1178. func (s *cScreen) Suspend() error {
  1179. s.disengage()
  1180. return nil
  1181. }
  1182. func (s *cScreen) Resume() error {
  1183. return s.engage()
  1184. }