key-encoding.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. // License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
  2. package loop
  3. import (
  4. "fmt"
  5. "strconv"
  6. "strings"
  7. "kitty"
  8. )
  9. // key encoding mappings {{{
  10. // start csi mapping (auto generated by gen-key-constants.py do not edit)
  11. var functional_key_number_to_name_map = map[int]string{57344: "ESCAPE", 57345: "ENTER", 57346: "TAB", 57347: "BACKSPACE", 57348: "INSERT", 57349: "DELETE", 57350: "LEFT", 57351: "RIGHT", 57352: "UP", 57353: "DOWN", 57354: "PAGE_UP", 57355: "PAGE_DOWN", 57356: "HOME", 57357: "END", 57358: "CAPS_LOCK", 57359: "SCROLL_LOCK", 57360: "NUM_LOCK", 57361: "PRINT_SCREEN", 57362: "PAUSE", 57363: "MENU", 57364: "F1", 57365: "F2", 57366: "F3", 57367: "F4", 57368: "F5", 57369: "F6", 57370: "F7", 57371: "F8", 57372: "F9", 57373: "F10", 57374: "F11", 57375: "F12", 57376: "F13", 57377: "F14", 57378: "F15", 57379: "F16", 57380: "F17", 57381: "F18", 57382: "F19", 57383: "F20", 57384: "F21", 57385: "F22", 57386: "F23", 57387: "F24", 57388: "F25", 57389: "F26", 57390: "F27", 57391: "F28", 57392: "F29", 57393: "F30", 57394: "F31", 57395: "F32", 57396: "F33", 57397: "F34", 57398: "F35", 57399: "KP_0", 57400: "KP_1", 57401: "KP_2", 57402: "KP_3", 57403: "KP_4", 57404: "KP_5", 57405: "KP_6", 57406: "KP_7", 57407: "KP_8", 57408: "KP_9", 57409: "KP_DECIMAL", 57410: "KP_DIVIDE", 57411: "KP_MULTIPLY", 57412: "KP_SUBTRACT", 57413: "KP_ADD", 57414: "KP_ENTER", 57415: "KP_EQUAL", 57416: "KP_SEPARATOR", 57417: "KP_LEFT", 57418: "KP_RIGHT", 57419: "KP_UP", 57420: "KP_DOWN", 57421: "KP_PAGE_UP", 57422: "KP_PAGE_DOWN", 57423: "KP_HOME", 57424: "KP_END", 57425: "KP_INSERT", 57426: "KP_DELETE", 57427: "KP_BEGIN", 57428: "MEDIA_PLAY", 57429: "MEDIA_PAUSE", 57430: "MEDIA_PLAY_PAUSE", 57431: "MEDIA_REVERSE", 57432: "MEDIA_STOP", 57433: "MEDIA_FAST_FORWARD", 57434: "MEDIA_REWIND", 57435: "MEDIA_TRACK_NEXT", 57436: "MEDIA_TRACK_PREVIOUS", 57437: "MEDIA_RECORD", 57438: "LOWER_VOLUME", 57439: "RAISE_VOLUME", 57440: "MUTE_VOLUME", 57441: "LEFT_SHIFT", 57442: "LEFT_CONTROL", 57443: "LEFT_ALT", 57444: "LEFT_SUPER", 57445: "LEFT_HYPER", 57446: "LEFT_META", 57447: "RIGHT_SHIFT", 57448: "RIGHT_CONTROL", 57449: "RIGHT_ALT", 57450: "RIGHT_SUPER", 57451: "RIGHT_HYPER", 57452: "RIGHT_META", 57453: "ISO_LEVEL3_SHIFT", 57454: "ISO_LEVEL5_SHIFT"}
  12. var csi_number_to_functional_number_map = map[int]int{2: 57348, 3: 57349, 5: 57354, 6: 57355, 7: 57356, 8: 57357, 9: 57346, 11: 57364, 12: 57365, 13: 57345, 14: 57367, 15: 57368, 17: 57369, 18: 57370, 19: 57371, 20: 57372, 21: 57373, 23: 57374, 24: 57375, 27: 57344, 127: 57347}
  13. var letter_trailer_to_csi_number_map = map[string]int{"A": 57352, "B": 57353, "C": 57351, "D": 57350, "E": 57427, "F": 8, "H": 7, "P": 11, "Q": 12, "S": 14}
  14. var tilde_trailers = map[int]bool{57348: true, 57349: true, 57354: true, 57355: true, 57366: true, 57368: true, 57369: true, 57370: true, 57371: true, 57372: true, 57373: true, 57374: true, 57375: true}
  15. // end csi mapping
  16. // }}}
  17. var name_to_functional_number_map map[string]int
  18. var functional_to_csi_number_map map[int]int
  19. var csi_number_to_letter_trailer_map map[int]string
  20. type KeyEventType uint8
  21. type KeyModifiers uint16
  22. const (
  23. PRESS KeyEventType = 1
  24. REPEAT KeyEventType = 2
  25. RELEASE KeyEventType = 4
  26. )
  27. const (
  28. SHIFT KeyModifiers = 1
  29. ALT KeyModifiers = 2
  30. CTRL KeyModifiers = 4
  31. SUPER KeyModifiers = 8
  32. HYPER KeyModifiers = 16
  33. META KeyModifiers = 32
  34. CAPS_LOCK KeyModifiers = 64
  35. NUM_LOCK KeyModifiers = 128
  36. )
  37. func (self KeyModifiers) WithoutLocks() KeyModifiers {
  38. return self & ^(CAPS_LOCK | NUM_LOCK)
  39. }
  40. func (self KeyEventType) String() string {
  41. switch self {
  42. case PRESS:
  43. return "PRESS"
  44. case REPEAT:
  45. return "REPEAT"
  46. case RELEASE:
  47. return "RELEASE"
  48. default:
  49. return fmt.Sprintf("KeyEventType:%d", int(self))
  50. }
  51. }
  52. func (self KeyModifiers) String() string {
  53. ans := make([]string, 0)
  54. if self&SHIFT != 0 {
  55. ans = append(ans, "shift")
  56. }
  57. if self&ALT != 0 {
  58. ans = append(ans, "alt")
  59. }
  60. if self&CTRL != 0 {
  61. ans = append(ans, "ctrl")
  62. }
  63. if self&SUPER != 0 {
  64. ans = append(ans, "super")
  65. }
  66. if self&HYPER != 0 {
  67. ans = append(ans, "hyper")
  68. }
  69. if self&META != 0 {
  70. ans = append(ans, "meta")
  71. }
  72. if self&CAPS_LOCK != 0 {
  73. ans = append(ans, "caps_lock")
  74. }
  75. if self&NUM_LOCK != 0 {
  76. ans = append(ans, "num_lock")
  77. }
  78. return strings.Join(ans, "+")
  79. }
  80. func (self KeyModifiers) HasCapsLock() bool {
  81. return self&CAPS_LOCK != 0
  82. }
  83. type KeyEvent struct {
  84. Type KeyEventType
  85. Mods KeyModifiers
  86. Key string
  87. ShiftedKey string
  88. AlternateKey string
  89. Text string
  90. Handled bool
  91. // The CSI string this key event was decoded from. Empty if not decoded from CSI.
  92. CSI string
  93. }
  94. func (self *KeyEvent) String() string {
  95. key := self.Key
  96. if self.Mods > 0 {
  97. key = self.Mods.String() + "+" + key
  98. }
  99. ans := fmt.Sprint(self.Type, "{ ", key, " ")
  100. if self.Text != "" {
  101. ans += "Text: " + self.Text + " "
  102. }
  103. if self.ShiftedKey != "" {
  104. ans += "ShiftedKey: " + self.ShiftedKey + " "
  105. }
  106. if self.AlternateKey != "" {
  107. ans += "AlternateKey: " + self.AlternateKey + " "
  108. }
  109. return ans + "}"
  110. }
  111. func (self *KeyEvent) HasCapsLock() bool {
  112. return self.Mods.HasCapsLock()
  113. }
  114. func KeyEventFromCSI(csi string) *KeyEvent {
  115. if len(csi) == 0 {
  116. return nil
  117. }
  118. orig_csi := csi
  119. last_char := csi[len(csi)-1:]
  120. if !strings.Contains("u~ABCDEHFPQRS", last_char) || (last_char == "~" && (csi == "200~" || csi == "201~")) {
  121. return nil
  122. }
  123. csi = csi[:len(csi)-1]
  124. sections := strings.Split(csi, ";")
  125. get_sub_sections := func(section string, missing int) []int {
  126. p := strings.Split(section, ":")
  127. ans := make([]int, len(p))
  128. for i, x := range p {
  129. if x == "" {
  130. ans[i] = missing
  131. } else {
  132. q, err := strconv.Atoi(x)
  133. if err != nil {
  134. return nil
  135. }
  136. ans[i] = q
  137. }
  138. }
  139. return ans
  140. }
  141. first_section := get_sub_sections(sections[0], 0)
  142. second_section := []int{}
  143. third_section := []int{}
  144. if len(sections) > 1 {
  145. second_section = get_sub_sections(sections[1], 1)
  146. }
  147. if len(sections) > 2 {
  148. third_section = get_sub_sections(sections[2], 0)
  149. }
  150. var ans = KeyEvent{Type: PRESS, CSI: orig_csi}
  151. var keynum int
  152. if val, ok := letter_trailer_to_csi_number_map[last_char]; ok {
  153. keynum = val
  154. } else {
  155. if len(first_section) == 0 {
  156. return nil
  157. }
  158. keynum = first_section[0]
  159. }
  160. key_name := func(keynum int) string {
  161. switch keynum {
  162. case 0:
  163. return ""
  164. case 13:
  165. if last_char == "u" {
  166. return "ENTER"
  167. }
  168. return "F3"
  169. default:
  170. if val, ok := csi_number_to_functional_number_map[keynum]; ok {
  171. keynum = val
  172. }
  173. ans := ""
  174. if val, ok := functional_key_number_to_name_map[keynum]; ok {
  175. ans = val
  176. } else {
  177. ans = string(rune(keynum))
  178. }
  179. return ans
  180. }
  181. }
  182. ans.Key = key_name(keynum)
  183. if len(first_section) > 1 {
  184. ans.ShiftedKey = key_name(first_section[1])
  185. }
  186. if len(first_section) > 2 {
  187. ans.AlternateKey = key_name(first_section[2])
  188. }
  189. if len(second_section) > 0 {
  190. ans.Mods = KeyModifiers(second_section[0] - 1)
  191. }
  192. if len(second_section) > 1 {
  193. switch second_section[1] {
  194. case 2:
  195. ans.Type = REPEAT
  196. case 3:
  197. ans.Type = RELEASE
  198. }
  199. }
  200. if len(third_section) > 0 {
  201. runes := make([]rune, len(third_section))
  202. for i, ch := range third_section {
  203. runes[i] = rune(ch)
  204. }
  205. ans.Text = string(runes)
  206. }
  207. return &ans
  208. }
  209. type ParsedShortcut struct {
  210. Mods KeyModifiers
  211. KeyName string
  212. }
  213. func (self *ParsedShortcut) String() string {
  214. ans := self.KeyName
  215. if self.Mods > 0 {
  216. ans = self.Mods.String() + "+" + ans
  217. }
  218. return ans
  219. }
  220. var parsed_shortcut_cache map[string]*ParsedShortcut
  221. func ParseShortcut(spec string) *ParsedShortcut {
  222. if parsed_shortcut_cache == nil {
  223. parsed_shortcut_cache = make(map[string]*ParsedShortcut, 128)
  224. }
  225. if val, ok := parsed_shortcut_cache[spec]; ok {
  226. return val
  227. }
  228. ospec := spec
  229. if strings.HasSuffix(spec, "+") {
  230. ospec = spec[:len(spec)-1] + "plus"
  231. }
  232. parts := strings.Split(ospec, "+")
  233. key_name := parts[len(parts)-1]
  234. if val, ok := kitty.FunctionalKeyNameAliases[strings.ToUpper(key_name)]; ok {
  235. key_name = val
  236. }
  237. if _, is_functional_key := name_to_functional_number_map[strings.ToUpper(key_name)]; is_functional_key {
  238. key_name = strings.ToUpper(key_name)
  239. } else {
  240. if val, ok := kitty.CharacterKeyNameAliases[strings.ToUpper(key_name)]; ok {
  241. key_name = val
  242. }
  243. }
  244. ans := ParsedShortcut{KeyName: key_name}
  245. if len(parts) > 1 {
  246. for _, q := range parts[:len(parts)-1] {
  247. val, ok := kitty.ConfigModMap[strings.ToUpper(q)]
  248. if ok {
  249. ans.Mods |= KeyModifiers(val)
  250. } else {
  251. ans.Mods |= META << 8
  252. }
  253. }
  254. }
  255. parsed_shortcut_cache[spec] = &ans
  256. return &ans
  257. }
  258. func (self *KeyEvent) MatchesParsedShortcut(ps *ParsedShortcut, event_type KeyEventType) bool {
  259. if self.Type&event_type == 0 {
  260. return false
  261. }
  262. mods := self.Mods.WithoutLocks()
  263. if mods == ps.Mods && self.Key == ps.KeyName {
  264. return true
  265. }
  266. if self.ShiftedKey != "" && mods&SHIFT != 0 && (mods & ^SHIFT) == ps.Mods && self.ShiftedKey == ps.KeyName {
  267. return true
  268. }
  269. return false
  270. }
  271. func (self *KeyEvent) Matches(spec string, event_type KeyEventType) bool {
  272. return self.MatchesParsedShortcut(ParseShortcut(spec), event_type)
  273. }
  274. func (self *KeyEvent) MatchesPressOrRepeat(spec string) bool {
  275. return self.MatchesParsedShortcut(ParseShortcut(spec), PRESS|REPEAT)
  276. }
  277. func (self *KeyEvent) MatchesCaseSensitiveTextOrKey(spec string) bool {
  278. if self.MatchesParsedShortcut(ParseShortcut(spec), PRESS|REPEAT) {
  279. return true
  280. }
  281. return self.Text == spec
  282. }
  283. func (self *KeyEvent) MatchesCaseInsensitiveTextOrKey(spec string) bool {
  284. if self.MatchesParsedShortcut(ParseShortcut(spec), PRESS|REPEAT) {
  285. return true
  286. }
  287. return strings.ToLower(self.Text) == strings.ToLower(spec)
  288. }
  289. func (self *KeyEvent) MatchesRelease(spec string) bool {
  290. return self.MatchesParsedShortcut(ParseShortcut(spec), RELEASE)
  291. }
  292. func (self *KeyEvent) AsCSI() string {
  293. key := csi_number_for_name(self.Key)
  294. shifted_key := csi_number_for_name(self.ShiftedKey)
  295. alternate_key := csi_number_for_name(self.AlternateKey)
  296. trailer, found := csi_number_to_letter_trailer_map[key]
  297. if !found {
  298. trailer = "u"
  299. }
  300. if self.Key == "ENTER" {
  301. trailer = "u"
  302. }
  303. if trailer != "u" {
  304. key = 1
  305. }
  306. ans := strings.Builder{}
  307. ans.Grow(32)
  308. ans.WriteString("\033[")
  309. if key != 1 || self.Mods != 0 || shifted_key != 0 || alternate_key != 0 || self.Text != "" {
  310. ans.WriteString(fmt.Sprint(key))
  311. }
  312. if shifted_key != 0 || alternate_key != 0 {
  313. ans.WriteString(":")
  314. if shifted_key != 0 {
  315. ans.WriteString(fmt.Sprint(shifted_key))
  316. }
  317. if alternate_key != 0 {
  318. ans.WriteString(fmt.Sprint(":", alternate_key))
  319. }
  320. }
  321. action := 1
  322. switch self.Type {
  323. case REPEAT:
  324. action = 2
  325. case RELEASE:
  326. action = 3
  327. }
  328. if self.Mods != 0 || action > 1 || self.Text != "" {
  329. m := uint(self.Mods)
  330. if action > 1 || m != 0 {
  331. ans.WriteString(fmt.Sprintf(";%d", m+1))
  332. if action > 1 {
  333. ans.WriteString(fmt.Sprintf(":%d", action))
  334. }
  335. } else if self.Text != "" {
  336. ans.WriteString(";")
  337. }
  338. }
  339. if self.Text != "" {
  340. runes := []rune(self.Text)
  341. codes := make([]string, len(runes))
  342. for i, r := range runes {
  343. codes[i] = strconv.Itoa(int(r))
  344. }
  345. ans.WriteString(";")
  346. ans.WriteString(strings.Join(codes, ":"))
  347. }
  348. fn, found := name_to_functional_number_map[self.Key]
  349. if found && tilde_trailers[fn] {
  350. trailer = "~"
  351. }
  352. ans.WriteString(trailer)
  353. return ans.String()
  354. }
  355. func csi_number_for_name(key_name string) int {
  356. if key_name == "" {
  357. return 0
  358. }
  359. if key_name == "F3" || key_name == "ENTER" {
  360. return 13
  361. }
  362. fn, ok := name_to_functional_number_map[key_name]
  363. if !ok {
  364. return int(rune(key_name[0]))
  365. }
  366. ans, ok := functional_to_csi_number_map[fn]
  367. if ok {
  368. return ans
  369. }
  370. return fn
  371. }
  372. func init() {
  373. name_to_functional_number_map = make(map[string]int, len(functional_key_number_to_name_map))
  374. for k, v := range functional_key_number_to_name_map {
  375. name_to_functional_number_map[v] = k
  376. }
  377. functional_to_csi_number_map = make(map[int]int, len(csi_number_to_functional_number_map))
  378. for k, v := range csi_number_to_functional_number_map {
  379. functional_to_csi_number_map[v] = k
  380. }
  381. csi_number_to_letter_trailer_map = make(map[int]string, len(letter_trailer_to_csi_number_map))
  382. for k, v := range letter_trailer_to_csi_number_map {
  383. csi_number_to_letter_trailer_map[v] = k
  384. }
  385. }