key.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. package input
  2. import (
  3. "fmt"
  4. "strings"
  5. "unicode"
  6. "github.com/charmbracelet/x/ansi"
  7. )
  8. const (
  9. // KeyExtended is a special key code used to signify that a key event
  10. // contains multiple runes.
  11. KeyExtended = unicode.MaxRune + 1
  12. )
  13. // Special key symbols.
  14. const (
  15. // Special keys.
  16. KeyUp rune = KeyExtended + iota + 1
  17. KeyDown
  18. KeyRight
  19. KeyLeft
  20. KeyBegin
  21. KeyFind
  22. KeyInsert
  23. KeyDelete
  24. KeySelect
  25. KeyPgUp
  26. KeyPgDown
  27. KeyHome
  28. KeyEnd
  29. // Keypad keys.
  30. KeyKpEnter
  31. KeyKpEqual
  32. KeyKpMultiply
  33. KeyKpPlus
  34. KeyKpComma
  35. KeyKpMinus
  36. KeyKpDecimal
  37. KeyKpDivide
  38. KeyKp0
  39. KeyKp1
  40. KeyKp2
  41. KeyKp3
  42. KeyKp4
  43. KeyKp5
  44. KeyKp6
  45. KeyKp7
  46. KeyKp8
  47. KeyKp9
  48. //nolint:godox
  49. // The following are keys defined in the Kitty keyboard protocol.
  50. // TODO: Investigate the names of these keys.
  51. KeyKpSep
  52. KeyKpUp
  53. KeyKpDown
  54. KeyKpLeft
  55. KeyKpRight
  56. KeyKpPgUp
  57. KeyKpPgDown
  58. KeyKpHome
  59. KeyKpEnd
  60. KeyKpInsert
  61. KeyKpDelete
  62. KeyKpBegin
  63. // Function keys.
  64. KeyF1
  65. KeyF2
  66. KeyF3
  67. KeyF4
  68. KeyF5
  69. KeyF6
  70. KeyF7
  71. KeyF8
  72. KeyF9
  73. KeyF10
  74. KeyF11
  75. KeyF12
  76. KeyF13
  77. KeyF14
  78. KeyF15
  79. KeyF16
  80. KeyF17
  81. KeyF18
  82. KeyF19
  83. KeyF20
  84. KeyF21
  85. KeyF22
  86. KeyF23
  87. KeyF24
  88. KeyF25
  89. KeyF26
  90. KeyF27
  91. KeyF28
  92. KeyF29
  93. KeyF30
  94. KeyF31
  95. KeyF32
  96. KeyF33
  97. KeyF34
  98. KeyF35
  99. KeyF36
  100. KeyF37
  101. KeyF38
  102. KeyF39
  103. KeyF40
  104. KeyF41
  105. KeyF42
  106. KeyF43
  107. KeyF44
  108. KeyF45
  109. KeyF46
  110. KeyF47
  111. KeyF48
  112. KeyF49
  113. KeyF50
  114. KeyF51
  115. KeyF52
  116. KeyF53
  117. KeyF54
  118. KeyF55
  119. KeyF56
  120. KeyF57
  121. KeyF58
  122. KeyF59
  123. KeyF60
  124. KeyF61
  125. KeyF62
  126. KeyF63
  127. //nolint:godox
  128. // The following are keys defined in the Kitty keyboard protocol.
  129. // TODO: Investigate the names of these keys.
  130. KeyCapsLock
  131. KeyScrollLock
  132. KeyNumLock
  133. KeyPrintScreen
  134. KeyPause
  135. KeyMenu
  136. KeyMediaPlay
  137. KeyMediaPause
  138. KeyMediaPlayPause
  139. KeyMediaReverse
  140. KeyMediaStop
  141. KeyMediaFastForward
  142. KeyMediaRewind
  143. KeyMediaNext
  144. KeyMediaPrev
  145. KeyMediaRecord
  146. KeyLowerVol
  147. KeyRaiseVol
  148. KeyMute
  149. KeyLeftShift
  150. KeyLeftAlt
  151. KeyLeftCtrl
  152. KeyLeftSuper
  153. KeyLeftHyper
  154. KeyLeftMeta
  155. KeyRightShift
  156. KeyRightAlt
  157. KeyRightCtrl
  158. KeyRightSuper
  159. KeyRightHyper
  160. KeyRightMeta
  161. KeyIsoLevel3Shift
  162. KeyIsoLevel5Shift
  163. // Special names in C0.
  164. KeyBackspace = rune(ansi.DEL)
  165. KeyTab = rune(ansi.HT)
  166. KeyEnter = rune(ansi.CR)
  167. KeyReturn = KeyEnter
  168. KeyEscape = rune(ansi.ESC)
  169. KeyEsc = KeyEscape
  170. // Special names in G0.
  171. KeySpace = rune(ansi.SP)
  172. )
  173. // KeyPressEvent represents a key press event.
  174. type KeyPressEvent Key
  175. // String implements [fmt.Stringer] and is quite useful for matching key
  176. // events. For details, on what this returns see [Key.String].
  177. func (k KeyPressEvent) String() string {
  178. return Key(k).String()
  179. }
  180. // Keystroke returns the keystroke representation of the [Key]. While less type
  181. // safe than looking at the individual fields, it will usually be more
  182. // convenient and readable to use this method when matching against keys.
  183. //
  184. // Note that modifier keys are always printed in the following order:
  185. // - ctrl
  186. // - alt
  187. // - shift
  188. // - meta
  189. // - hyper
  190. // - super
  191. //
  192. // For example, you'll always see "ctrl+shift+alt+a" and never
  193. // "shift+ctrl+alt+a".
  194. func (k KeyPressEvent) Keystroke() string {
  195. return Key(k).Keystroke()
  196. }
  197. // Key returns the underlying key event. This is a syntactic sugar for casting
  198. // the key event to a [Key].
  199. func (k KeyPressEvent) Key() Key {
  200. return Key(k)
  201. }
  202. // KeyReleaseEvent represents a key release event.
  203. type KeyReleaseEvent Key
  204. // String implements [fmt.Stringer] and is quite useful for matching key
  205. // events. For details, on what this returns see [Key.String].
  206. func (k KeyReleaseEvent) String() string {
  207. return Key(k).String()
  208. }
  209. // Keystroke returns the keystroke representation of the [Key]. While less type
  210. // safe than looking at the individual fields, it will usually be more
  211. // convenient and readable to use this method when matching against keys.
  212. //
  213. // Note that modifier keys are always printed in the following order:
  214. // - ctrl
  215. // - alt
  216. // - shift
  217. // - meta
  218. // - hyper
  219. // - super
  220. //
  221. // For example, you'll always see "ctrl+shift+alt+a" and never
  222. // "shift+ctrl+alt+a".
  223. func (k KeyReleaseEvent) Keystroke() string {
  224. return Key(k).Keystroke()
  225. }
  226. // Key returns the underlying key event. This is a convenience method and
  227. // syntactic sugar to satisfy the [KeyEvent] interface, and cast the key event to
  228. // [Key].
  229. func (k KeyReleaseEvent) Key() Key {
  230. return Key(k)
  231. }
  232. // KeyEvent represents a key event. This can be either a key press or a key
  233. // release event.
  234. type KeyEvent interface {
  235. fmt.Stringer
  236. // Key returns the underlying key event.
  237. Key() Key
  238. }
  239. // Key represents a Key press or release event. It contains information about
  240. // the Key pressed, like the runes, the type of Key, and the modifiers pressed.
  241. // There are a couple general patterns you could use to check for key presses
  242. // or releases:
  243. //
  244. // // Switch on the string representation of the key (shorter)
  245. // switch ev := ev.(type) {
  246. // case KeyPressEvent:
  247. // switch ev.String() {
  248. // case "enter":
  249. // fmt.Println("you pressed enter!")
  250. // case "a":
  251. // fmt.Println("you pressed a!")
  252. // }
  253. // }
  254. //
  255. // // Switch on the key type (more foolproof)
  256. // switch ev := ev.(type) {
  257. // case KeyEvent:
  258. // // catch both KeyPressEvent and KeyReleaseEvent
  259. // switch key := ev.Key(); key.Code {
  260. // case KeyEnter:
  261. // fmt.Println("you pressed enter!")
  262. // default:
  263. // switch key.Text {
  264. // case "a":
  265. // fmt.Println("you pressed a!")
  266. // }
  267. // }
  268. // }
  269. //
  270. // Note that [Key.Text] will be empty for special keys like [KeyEnter],
  271. // [KeyTab], and for keys that don't represent printable characters like key
  272. // combos with modifier keys. In other words, [Key.Text] is populated only for
  273. // keys that represent printable characters shifted or unshifted (like 'a',
  274. // 'A', '1', '!', etc.).
  275. type Key struct {
  276. // Text contains the actual characters received. This usually the same as
  277. // [Key.Code]. When [Key.Text] is non-empty, it indicates that the key
  278. // pressed represents printable character(s).
  279. Text string
  280. // Mod represents modifier keys, like [ModCtrl], [ModAlt], and so on.
  281. Mod KeyMod
  282. // Code represents the key pressed. This is usually a special key like
  283. // [KeyTab], [KeyEnter], [KeyF1], or a printable character like 'a'.
  284. Code rune
  285. // ShiftedCode is the actual, shifted key pressed by the user. For example,
  286. // if the user presses shift+a, or caps lock is on, [Key.ShiftedCode] will
  287. // be 'A' and [Key.Code] will be 'a'.
  288. //
  289. // In the case of non-latin keyboards, like Arabic, [Key.ShiftedCode] is the
  290. // unshifted key on the keyboard.
  291. //
  292. // This is only available with the Kitty Keyboard Protocol or the Windows
  293. // Console API.
  294. ShiftedCode rune
  295. // BaseCode is the key pressed according to the standard PC-101 key layout.
  296. // On international keyboards, this is the key that would be pressed if the
  297. // keyboard was set to US PC-101 layout.
  298. //
  299. // For example, if the user presses 'q' on a French AZERTY keyboard,
  300. // [Key.BaseCode] will be 'q'.
  301. //
  302. // This is only available with the Kitty Keyboard Protocol or the Windows
  303. // Console API.
  304. BaseCode rune
  305. // IsRepeat indicates whether the key is being held down and sending events
  306. // repeatedly.
  307. //
  308. // This is only available with the Kitty Keyboard Protocol or the Windows
  309. // Console API.
  310. IsRepeat bool
  311. }
  312. // String implements [fmt.Stringer] and is quite useful for matching key
  313. // events. It will return the textual representation of the [Key] if there is
  314. // one, otherwise, it will fallback to [Key.Keystroke].
  315. //
  316. // For example, you'll always get "?" and instead of "shift+/" on a US ANSI
  317. // keyboard.
  318. func (k Key) String() string {
  319. if len(k.Text) > 0 && k.Text != " " {
  320. return k.Text
  321. }
  322. return k.Keystroke()
  323. }
  324. // Keystroke returns the keystroke representation of the [Key]. While less type
  325. // safe than looking at the individual fields, it will usually be more
  326. // convenient and readable to use this method when matching against keys.
  327. //
  328. // Note that modifier keys are always printed in the following order:
  329. // - ctrl
  330. // - alt
  331. // - shift
  332. // - meta
  333. // - hyper
  334. // - super
  335. //
  336. // For example, you'll always see "ctrl+shift+alt+a" and never
  337. // "shift+ctrl+alt+a".
  338. func (k Key) Keystroke() string {
  339. var sb strings.Builder
  340. if k.Mod.Contains(ModCtrl) && k.Code != KeyLeftCtrl && k.Code != KeyRightCtrl {
  341. sb.WriteString("ctrl+")
  342. }
  343. if k.Mod.Contains(ModAlt) && k.Code != KeyLeftAlt && k.Code != KeyRightAlt {
  344. sb.WriteString("alt+")
  345. }
  346. if k.Mod.Contains(ModShift) && k.Code != KeyLeftShift && k.Code != KeyRightShift {
  347. sb.WriteString("shift+")
  348. }
  349. if k.Mod.Contains(ModMeta) && k.Code != KeyLeftMeta && k.Code != KeyRightMeta {
  350. sb.WriteString("meta+")
  351. }
  352. if k.Mod.Contains(ModHyper) && k.Code != KeyLeftHyper && k.Code != KeyRightHyper {
  353. sb.WriteString("hyper+")
  354. }
  355. if k.Mod.Contains(ModSuper) && k.Code != KeyLeftSuper && k.Code != KeyRightSuper {
  356. sb.WriteString("super+")
  357. }
  358. if kt, ok := keyTypeString[k.Code]; ok {
  359. sb.WriteString(kt)
  360. } else {
  361. code := k.Code
  362. if k.BaseCode != 0 {
  363. // If a [Key.BaseCode] is present, use it to represent a key using the standard
  364. // PC-101 key layout.
  365. code = k.BaseCode
  366. }
  367. switch code {
  368. case KeySpace:
  369. // Space is the only invisible printable character.
  370. sb.WriteString("space")
  371. case KeyExtended:
  372. // Write the actual text of the key when the key contains multiple
  373. // runes.
  374. sb.WriteString(k.Text)
  375. default:
  376. sb.WriteRune(code)
  377. }
  378. }
  379. return sb.String()
  380. }
  381. var keyTypeString = map[rune]string{
  382. KeyEnter: "enter",
  383. KeyTab: "tab",
  384. KeyBackspace: "backspace",
  385. KeyEscape: "esc",
  386. KeySpace: "space",
  387. KeyUp: "up",
  388. KeyDown: "down",
  389. KeyLeft: "left",
  390. KeyRight: "right",
  391. KeyBegin: "begin",
  392. KeyFind: "find",
  393. KeyInsert: "insert",
  394. KeyDelete: "delete",
  395. KeySelect: "select",
  396. KeyPgUp: "pgup",
  397. KeyPgDown: "pgdown",
  398. KeyHome: "home",
  399. KeyEnd: "end",
  400. KeyKpEnter: "kpenter",
  401. KeyKpEqual: "kpequal",
  402. KeyKpMultiply: "kpmul",
  403. KeyKpPlus: "kpplus",
  404. KeyKpComma: "kpcomma",
  405. KeyKpMinus: "kpminus",
  406. KeyKpDecimal: "kpperiod",
  407. KeyKpDivide: "kpdiv",
  408. KeyKp0: "kp0",
  409. KeyKp1: "kp1",
  410. KeyKp2: "kp2",
  411. KeyKp3: "kp3",
  412. KeyKp4: "kp4",
  413. KeyKp5: "kp5",
  414. KeyKp6: "kp6",
  415. KeyKp7: "kp7",
  416. KeyKp8: "kp8",
  417. KeyKp9: "kp9",
  418. // Kitty keyboard extension
  419. KeyKpSep: "kpsep",
  420. KeyKpUp: "kpup",
  421. KeyKpDown: "kpdown",
  422. KeyKpLeft: "kpleft",
  423. KeyKpRight: "kpright",
  424. KeyKpPgUp: "kppgup",
  425. KeyKpPgDown: "kppgdown",
  426. KeyKpHome: "kphome",
  427. KeyKpEnd: "kpend",
  428. KeyKpInsert: "kpinsert",
  429. KeyKpDelete: "kpdelete",
  430. KeyKpBegin: "kpbegin",
  431. KeyF1: "f1",
  432. KeyF2: "f2",
  433. KeyF3: "f3",
  434. KeyF4: "f4",
  435. KeyF5: "f5",
  436. KeyF6: "f6",
  437. KeyF7: "f7",
  438. KeyF8: "f8",
  439. KeyF9: "f9",
  440. KeyF10: "f10",
  441. KeyF11: "f11",
  442. KeyF12: "f12",
  443. KeyF13: "f13",
  444. KeyF14: "f14",
  445. KeyF15: "f15",
  446. KeyF16: "f16",
  447. KeyF17: "f17",
  448. KeyF18: "f18",
  449. KeyF19: "f19",
  450. KeyF20: "f20",
  451. KeyF21: "f21",
  452. KeyF22: "f22",
  453. KeyF23: "f23",
  454. KeyF24: "f24",
  455. KeyF25: "f25",
  456. KeyF26: "f26",
  457. KeyF27: "f27",
  458. KeyF28: "f28",
  459. KeyF29: "f29",
  460. KeyF30: "f30",
  461. KeyF31: "f31",
  462. KeyF32: "f32",
  463. KeyF33: "f33",
  464. KeyF34: "f34",
  465. KeyF35: "f35",
  466. KeyF36: "f36",
  467. KeyF37: "f37",
  468. KeyF38: "f38",
  469. KeyF39: "f39",
  470. KeyF40: "f40",
  471. KeyF41: "f41",
  472. KeyF42: "f42",
  473. KeyF43: "f43",
  474. KeyF44: "f44",
  475. KeyF45: "f45",
  476. KeyF46: "f46",
  477. KeyF47: "f47",
  478. KeyF48: "f48",
  479. KeyF49: "f49",
  480. KeyF50: "f50",
  481. KeyF51: "f51",
  482. KeyF52: "f52",
  483. KeyF53: "f53",
  484. KeyF54: "f54",
  485. KeyF55: "f55",
  486. KeyF56: "f56",
  487. KeyF57: "f57",
  488. KeyF58: "f58",
  489. KeyF59: "f59",
  490. KeyF60: "f60",
  491. KeyF61: "f61",
  492. KeyF62: "f62",
  493. KeyF63: "f63",
  494. // Kitty keyboard extension
  495. KeyCapsLock: "capslock",
  496. KeyScrollLock: "scrolllock",
  497. KeyNumLock: "numlock",
  498. KeyPrintScreen: "printscreen",
  499. KeyPause: "pause",
  500. KeyMenu: "menu",
  501. KeyMediaPlay: "mediaplay",
  502. KeyMediaPause: "mediapause",
  503. KeyMediaPlayPause: "mediaplaypause",
  504. KeyMediaReverse: "mediareverse",
  505. KeyMediaStop: "mediastop",
  506. KeyMediaFastForward: "mediafastforward",
  507. KeyMediaRewind: "mediarewind",
  508. KeyMediaNext: "medianext",
  509. KeyMediaPrev: "mediaprev",
  510. KeyMediaRecord: "mediarecord",
  511. KeyLowerVol: "lowervol",
  512. KeyRaiseVol: "raisevol",
  513. KeyMute: "mute",
  514. KeyLeftShift: "leftshift",
  515. KeyLeftAlt: "leftalt",
  516. KeyLeftCtrl: "leftctrl",
  517. KeyLeftSuper: "leftsuper",
  518. KeyLeftHyper: "lefthyper",
  519. KeyLeftMeta: "leftmeta",
  520. KeyRightShift: "rightshift",
  521. KeyRightAlt: "rightalt",
  522. KeyRightCtrl: "rightctrl",
  523. KeyRightSuper: "rightsuper",
  524. KeyRightHyper: "righthyper",
  525. KeyRightMeta: "rightmeta",
  526. KeyIsoLevel3Shift: "isolevel3shift",
  527. KeyIsoLevel5Shift: "isolevel5shift",
  528. }