key_windows.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. //go:build windows
  2. // +build windows
  3. package tea
  4. import (
  5. "context"
  6. "fmt"
  7. "io"
  8. "github.com/erikgeiser/coninput"
  9. localereader "github.com/mattn/go-localereader"
  10. "golang.org/x/sys/windows"
  11. )
  12. func readInputs(ctx context.Context, msgs chan<- Msg, input io.Reader) error {
  13. if coninReader, ok := input.(*conInputReader); ok {
  14. return readConInputs(ctx, msgs, coninReader.conin)
  15. }
  16. return readAnsiInputs(ctx, msgs, localereader.NewReader(input))
  17. }
  18. func readConInputs(ctx context.Context, msgsch chan<- Msg, con windows.Handle) error {
  19. var ps coninput.ButtonState // keep track of previous mouse state
  20. var ws coninput.WindowBufferSizeEventRecord // keep track of the last window size event
  21. for {
  22. events, err := coninput.ReadNConsoleInputs(con, 16)
  23. if err != nil {
  24. return fmt.Errorf("read coninput events: %w", err)
  25. }
  26. for _, event := range events {
  27. var msgs []Msg
  28. switch e := event.Unwrap().(type) {
  29. case coninput.KeyEventRecord:
  30. if !e.KeyDown || e.VirtualKeyCode == coninput.VK_SHIFT {
  31. continue
  32. }
  33. for i := 0; i < int(e.RepeatCount); i++ {
  34. msgs = append(msgs, KeyMsg{
  35. Type: keyType(e),
  36. Runes: []rune{e.Char},
  37. Alt: e.ControlKeyState.Contains(coninput.LEFT_ALT_PRESSED | coninput.RIGHT_ALT_PRESSED),
  38. })
  39. }
  40. case coninput.WindowBufferSizeEventRecord:
  41. if e != ws {
  42. ws = e
  43. msgs = append(msgs, WindowSizeMsg{
  44. Width: int(e.Size.X),
  45. Height: int(e.Size.Y),
  46. })
  47. }
  48. case coninput.MouseEventRecord:
  49. event := mouseEvent(ps, e)
  50. if event.Type != MouseUnknown {
  51. msgs = append(msgs, event)
  52. }
  53. ps = e.ButtonState
  54. case coninput.FocusEventRecord, coninput.MenuEventRecord:
  55. // ignore
  56. default: // unknown event
  57. continue
  58. }
  59. // Send all messages to the channel
  60. for _, msg := range msgs {
  61. select {
  62. case msgsch <- msg:
  63. case <-ctx.Done():
  64. err := ctx.Err()
  65. if err != nil {
  66. return fmt.Errorf("coninput context error: %w", err)
  67. }
  68. return err
  69. }
  70. }
  71. }
  72. }
  73. }
  74. func mouseEventButton(p, s coninput.ButtonState) (button MouseButton, action MouseAction) {
  75. btn := p ^ s
  76. action = MouseActionPress
  77. if btn&s == 0 {
  78. action = MouseActionRelease
  79. }
  80. if btn == 0 {
  81. switch {
  82. case s&coninput.FROM_LEFT_1ST_BUTTON_PRESSED > 0:
  83. button = MouseButtonLeft
  84. case s&coninput.FROM_LEFT_2ND_BUTTON_PRESSED > 0:
  85. button = MouseButtonMiddle
  86. case s&coninput.RIGHTMOST_BUTTON_PRESSED > 0:
  87. button = MouseButtonRight
  88. case s&coninput.FROM_LEFT_3RD_BUTTON_PRESSED > 0:
  89. button = MouseButtonBackward
  90. case s&coninput.FROM_LEFT_4TH_BUTTON_PRESSED > 0:
  91. button = MouseButtonForward
  92. }
  93. return
  94. }
  95. switch {
  96. case btn == coninput.FROM_LEFT_1ST_BUTTON_PRESSED: // left button
  97. button = MouseButtonLeft
  98. case btn == coninput.RIGHTMOST_BUTTON_PRESSED: // right button
  99. button = MouseButtonRight
  100. case btn == coninput.FROM_LEFT_2ND_BUTTON_PRESSED: // middle button
  101. button = MouseButtonMiddle
  102. case btn == coninput.FROM_LEFT_3RD_BUTTON_PRESSED: // unknown (possibly mouse backward)
  103. button = MouseButtonBackward
  104. case btn == coninput.FROM_LEFT_4TH_BUTTON_PRESSED: // unknown (possibly mouse forward)
  105. button = MouseButtonForward
  106. }
  107. return button, action
  108. }
  109. func mouseEvent(p coninput.ButtonState, e coninput.MouseEventRecord) MouseMsg {
  110. ev := MouseMsg{
  111. X: int(e.MousePositon.X),
  112. Y: int(e.MousePositon.Y),
  113. Alt: e.ControlKeyState.Contains(coninput.LEFT_ALT_PRESSED | coninput.RIGHT_ALT_PRESSED),
  114. Ctrl: e.ControlKeyState.Contains(coninput.LEFT_CTRL_PRESSED | coninput.RIGHT_CTRL_PRESSED),
  115. Shift: e.ControlKeyState.Contains(coninput.SHIFT_PRESSED),
  116. }
  117. switch e.EventFlags {
  118. case coninput.CLICK, coninput.DOUBLE_CLICK:
  119. ev.Button, ev.Action = mouseEventButton(p, e.ButtonState)
  120. if ev.Action == MouseActionRelease {
  121. ev.Type = MouseRelease
  122. }
  123. switch ev.Button {
  124. case MouseButtonLeft:
  125. ev.Type = MouseLeft
  126. case MouseButtonMiddle:
  127. ev.Type = MouseMiddle
  128. case MouseButtonRight:
  129. ev.Type = MouseRight
  130. case MouseButtonBackward:
  131. ev.Type = MouseBackward
  132. case MouseButtonForward:
  133. ev.Type = MouseForward
  134. }
  135. case coninput.MOUSE_WHEELED:
  136. if e.WheelDirection > 0 {
  137. ev.Button = MouseButtonWheelUp
  138. ev.Type = MouseWheelUp
  139. } else {
  140. ev.Button = MouseButtonWheelDown
  141. ev.Type = MouseWheelDown
  142. }
  143. case coninput.MOUSE_HWHEELED:
  144. if e.WheelDirection > 0 {
  145. ev.Button = MouseButtonWheelRight
  146. ev.Type = MouseWheelRight
  147. } else {
  148. ev.Button = MouseButtonWheelLeft
  149. ev.Type = MouseWheelLeft
  150. }
  151. case coninput.MOUSE_MOVED:
  152. ev.Button, _ = mouseEventButton(p, e.ButtonState)
  153. ev.Action = MouseActionMotion
  154. ev.Type = MouseMotion
  155. }
  156. return ev
  157. }
  158. func keyType(e coninput.KeyEventRecord) KeyType {
  159. code := e.VirtualKeyCode
  160. shiftPressed := e.ControlKeyState.Contains(coninput.SHIFT_PRESSED)
  161. ctrlPressed := e.ControlKeyState.Contains(coninput.LEFT_CTRL_PRESSED | coninput.RIGHT_CTRL_PRESSED)
  162. switch code {
  163. case coninput.VK_RETURN:
  164. return KeyEnter
  165. case coninput.VK_BACK:
  166. return KeyBackspace
  167. case coninput.VK_TAB:
  168. if shiftPressed {
  169. return KeyShiftTab
  170. }
  171. return KeyTab
  172. case coninput.VK_SPACE:
  173. return KeyRunes // this could be KeySpace but on unix space also produces KeyRunes
  174. case coninput.VK_ESCAPE:
  175. return KeyEscape
  176. case coninput.VK_UP:
  177. switch {
  178. case shiftPressed && ctrlPressed:
  179. return KeyCtrlShiftUp
  180. case shiftPressed:
  181. return KeyShiftUp
  182. case ctrlPressed:
  183. return KeyCtrlUp
  184. default:
  185. return KeyUp
  186. }
  187. case coninput.VK_DOWN:
  188. switch {
  189. case shiftPressed && ctrlPressed:
  190. return KeyCtrlShiftDown
  191. case shiftPressed:
  192. return KeyShiftDown
  193. case ctrlPressed:
  194. return KeyCtrlDown
  195. default:
  196. return KeyDown
  197. }
  198. case coninput.VK_RIGHT:
  199. switch {
  200. case shiftPressed && ctrlPressed:
  201. return KeyCtrlShiftRight
  202. case shiftPressed:
  203. return KeyShiftRight
  204. case ctrlPressed:
  205. return KeyCtrlRight
  206. default:
  207. return KeyRight
  208. }
  209. case coninput.VK_LEFT:
  210. switch {
  211. case shiftPressed && ctrlPressed:
  212. return KeyCtrlShiftLeft
  213. case shiftPressed:
  214. return KeyShiftLeft
  215. case ctrlPressed:
  216. return KeyCtrlLeft
  217. default:
  218. return KeyLeft
  219. }
  220. case coninput.VK_HOME:
  221. switch {
  222. case shiftPressed && ctrlPressed:
  223. return KeyCtrlShiftHome
  224. case shiftPressed:
  225. return KeyShiftHome
  226. case ctrlPressed:
  227. return KeyCtrlHome
  228. default:
  229. return KeyHome
  230. }
  231. case coninput.VK_END:
  232. switch {
  233. case shiftPressed && ctrlPressed:
  234. return KeyCtrlShiftEnd
  235. case shiftPressed:
  236. return KeyShiftEnd
  237. case ctrlPressed:
  238. return KeyCtrlEnd
  239. default:
  240. return KeyEnd
  241. }
  242. case coninput.VK_PRIOR:
  243. return KeyPgUp
  244. case coninput.VK_NEXT:
  245. return KeyPgDown
  246. case coninput.VK_DELETE:
  247. return KeyDelete
  248. default:
  249. if e.ControlKeyState&(coninput.LEFT_CTRL_PRESSED|coninput.RIGHT_CTRL_PRESSED) == 0 {
  250. return KeyRunes
  251. }
  252. switch e.Char {
  253. case '@':
  254. return KeyCtrlAt
  255. case '\x01':
  256. return KeyCtrlA
  257. case '\x02':
  258. return KeyCtrlB
  259. case '\x03':
  260. return KeyCtrlC
  261. case '\x04':
  262. return KeyCtrlD
  263. case '\x05':
  264. return KeyCtrlE
  265. case '\x06':
  266. return KeyCtrlF
  267. case '\a':
  268. return KeyCtrlG
  269. case '\b':
  270. return KeyCtrlH
  271. case '\t':
  272. return KeyCtrlI
  273. case '\n':
  274. return KeyCtrlJ
  275. case '\v':
  276. return KeyCtrlK
  277. case '\f':
  278. return KeyCtrlL
  279. case '\r':
  280. return KeyCtrlM
  281. case '\x0e':
  282. return KeyCtrlN
  283. case '\x0f':
  284. return KeyCtrlO
  285. case '\x10':
  286. return KeyCtrlP
  287. case '\x11':
  288. return KeyCtrlQ
  289. case '\x12':
  290. return KeyCtrlR
  291. case '\x13':
  292. return KeyCtrlS
  293. case '\x14':
  294. return KeyCtrlT
  295. case '\x15':
  296. return KeyCtrlU
  297. case '\x16':
  298. return KeyCtrlV
  299. case '\x17':
  300. return KeyCtrlW
  301. case '\x18':
  302. return KeyCtrlX
  303. case '\x19':
  304. return KeyCtrlY
  305. case '\x1a':
  306. return KeyCtrlZ
  307. case '\x1b':
  308. return KeyCtrlCloseBracket
  309. case '\x1c':
  310. return KeyCtrlBackslash
  311. case '\x1f':
  312. return KeyCtrlUnderscore
  313. }
  314. switch code {
  315. case coninput.VK_OEM_4:
  316. return KeyCtrlOpenBracket
  317. }
  318. return KeyRunes
  319. }
  320. }