genkeys.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850
  1. // Copyright 2015 Hajime Hoshi
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this 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. //go:build ignore
  15. // The key name convention follows the Web standard: https://www.w3.org/TR/uievents-code/#code-value-tables
  16. package main
  17. import (
  18. "bufio"
  19. "log"
  20. "os"
  21. "path/filepath"
  22. "sort"
  23. "strconv"
  24. "strings"
  25. "text/template"
  26. )
  27. var (
  28. glfwKeyNameToGLFWKey map[string]int
  29. uiKeyNameToGLFWKeyName map[string]string
  30. androidKeyToUIKeyName map[int]string
  31. iosKeyToUIKeyName map[int]string
  32. uiKeyNameToJSCode map[string]string
  33. oldEbitengineKeyNameToUIKeyName map[string]string
  34. )
  35. func init() {
  36. glfwKeyNameToGLFWKey = map[string]int{
  37. "Unknown": -1,
  38. "Space": 32,
  39. "Apostrophe": 39,
  40. "Comma": 44,
  41. "Minus": 45,
  42. "Period": 46,
  43. "Slash": 47,
  44. "Semicolon": 59,
  45. "Equal": 61,
  46. "LeftBracket": 91,
  47. "Backslash": 92,
  48. "RightBracket": 93,
  49. "GraveAccent": 96,
  50. "World1": 161,
  51. "World2": 162,
  52. "Escape": 256,
  53. "Enter": 257,
  54. "Tab": 258,
  55. "Backspace": 259,
  56. "Insert": 260,
  57. "Delete": 261,
  58. "Right": 262,
  59. "Left": 263,
  60. "Down": 264,
  61. "Up": 265,
  62. "PageUp": 266,
  63. "PageDown": 267,
  64. "Home": 268,
  65. "End": 269,
  66. "CapsLock": 280,
  67. "ScrollLock": 281,
  68. "NumLock": 282,
  69. "PrintScreen": 283,
  70. "Pause": 284,
  71. "LeftShift": 340,
  72. "LeftControl": 341,
  73. "LeftAlt": 342,
  74. "LeftSuper": 343,
  75. "RightShift": 344,
  76. "RightControl": 345,
  77. "RightAlt": 346,
  78. "RightSuper": 347,
  79. "Menu": 348,
  80. "KPDecimal": 330,
  81. "KPDivide": 331,
  82. "KPMultiply": 332,
  83. "KPSubtract": 333,
  84. "KPAdd": 334,
  85. "KPEnter": 335,
  86. "KPEqual": 336,
  87. "Last": 348,
  88. }
  89. uiKeyNameToGLFWKeyName = map[string]string{
  90. "Space": "Space",
  91. "Quote": "Apostrophe",
  92. "Comma": "Comma",
  93. "Minus": "Minus",
  94. "Period": "Period",
  95. "Slash": "Slash",
  96. "Semicolon": "Semicolon",
  97. "Equal": "Equal",
  98. "BracketLeft": "LeftBracket",
  99. "Backslash": "Backslash",
  100. "BracketRight": "RightBracket",
  101. "Backquote": "GraveAccent",
  102. "Escape": "Escape",
  103. "Enter": "Enter",
  104. "Tab": "Tab",
  105. "Backspace": "Backspace",
  106. "Insert": "Insert",
  107. "Delete": "Delete",
  108. "ArrowRight": "Right",
  109. "ArrowLeft": "Left",
  110. "ArrowDown": "Down",
  111. "ArrowUp": "Up",
  112. "PageUp": "PageUp",
  113. "PageDown": "PageDown",
  114. "Home": "Home",
  115. "End": "End",
  116. "CapsLock": "CapsLock",
  117. "ScrollLock": "ScrollLock",
  118. "NumLock": "NumLock",
  119. "PrintScreen": "PrintScreen",
  120. "Pause": "Pause",
  121. "ShiftLeft": "LeftShift",
  122. "ControlLeft": "LeftControl",
  123. "AltLeft": "LeftAlt",
  124. "MetaLeft": "LeftSuper",
  125. "ShiftRight": "RightShift",
  126. "ControlRight": "RightControl",
  127. "AltRight": "RightAlt",
  128. "MetaRight": "RightSuper",
  129. "ContextMenu": "Menu",
  130. "NumpadAdd": "KPAdd",
  131. "NumpadDecimal": "KPDecimal",
  132. "NumpadDivide": "KPDivide",
  133. "NumpadMultiply": "KPMultiply",
  134. "NumpadSubtract": "KPSubtract",
  135. "NumpadEnter": "KPEnter",
  136. "NumpadEqual": "KPEqual",
  137. "IntlBackslash": "World1",
  138. }
  139. // https://developer.android.com/reference/android/view/KeyEvent
  140. //
  141. // Android doesn't distinguish these keys:
  142. // - a US backslash key (HID: 0x31),
  143. // - an international pound/tilde key (HID: 0x32), and
  144. // - an international backslash key (HID: 0x64).
  145. // These are mapped to the same key code KEYCODE_BACKSLASH (73).
  146. // See https://source.android.com/docs/core/interaction/input/keyboard-devices
  147. androidKeyToUIKeyName = map[int]string{
  148. 55: "Comma",
  149. 56: "Period",
  150. 57: "AltLeft",
  151. 58: "AltRight",
  152. 115: "CapsLock",
  153. 113: "ControlLeft",
  154. 114: "ControlRight",
  155. 59: "ShiftLeft",
  156. 60: "ShiftRight",
  157. 66: "Enter",
  158. 62: "Space",
  159. 61: "Tab",
  160. 112: "Delete", // KEYCODE_FORWARD_DEL
  161. 123: "End",
  162. 122: "Home",
  163. 124: "Insert",
  164. 93: "PageDown",
  165. 92: "PageUp",
  166. 20: "ArrowDown",
  167. 21: "ArrowLeft",
  168. 22: "ArrowRight",
  169. 19: "ArrowUp",
  170. 111: "Escape",
  171. 67: "Backspace", // KEYCODE_DEL
  172. 75: "Quote",
  173. 69: "Minus",
  174. 76: "Slash",
  175. 74: "Semicolon",
  176. 70: "Equal",
  177. 71: "BracketLeft",
  178. 73: "Backslash",
  179. 72: "BracketRight",
  180. 68: "Backquote",
  181. 143: "NumLock",
  182. 121: "Pause", // KEYCODE_BREAK
  183. 120: "PrintScreen", // KEYCODE_SYSRQ
  184. 116: "ScrollLock",
  185. 82: "ContextMenu",
  186. 157: "NumpadAdd",
  187. 158: "NumpadDecimal",
  188. 154: "NumpadDivide",
  189. 155: "NumpadMultiply",
  190. 156: "NumpadSubtract",
  191. 160: "NumpadEnter",
  192. 161: "NumpadEqual",
  193. 117: "MetaLeft",
  194. 118: "MetaRight",
  195. }
  196. // https://developer.apple.com/documentation/uikit/uikeyboardhidusage?language=objc
  197. iosKeyToUIKeyName = map[int]string{
  198. 0xE2: "AltLeft",
  199. 0xE6: "AltRight",
  200. 0x51: "ArrowDown",
  201. 0x50: "ArrowLeft",
  202. 0x4F: "ArrowRight",
  203. 0x52: "ArrowUp",
  204. 0x35: "Backquote",
  205. // These three keys are:
  206. // - US backslash-pipe key, and
  207. // - non-US hashmark key (bottom left of return; on German layout, this is the #' key).
  208. // On US layout configurations, they all map to the same characters - the backslash.
  209. //
  210. // See also: https://www.w3.org/TR/uievents-code/#keyboard-102
  211. 0x31: "Backslash", // UIKeyboardHIDUsageKeyboardBackslash
  212. 0x32: "Backslash", // UIKeyboardHIDUsageKeyboardNonUSPound
  213. 0x64: "IntlBackslash", // UIKeyboardHIDUsageKeyboardNonUSBackslash
  214. 0x2A: "Backspace",
  215. 0x2F: "BracketLeft",
  216. 0x30: "BracketRight",
  217. // Caps Lock can either be a normal key or a hardware toggle.
  218. 0x39: "CapsLock", // UIKeyboardHIDUsageKeyboardCapsLock
  219. 0x82: "CapsLock", // UIKeyboardHIDUsageKeyboardLockingCapsLock
  220. 0x36: "Comma",
  221. 0xE0: "ControlLeft",
  222. 0xE4: "ControlRight",
  223. 0x4C: "Delete",
  224. 0x4D: "End",
  225. 0x28: "Enter",
  226. 0x2E: "Equal",
  227. 0x29: "Escape",
  228. 0x4A: "Home",
  229. 0x49: "Insert",
  230. 0x76: "ContextMenu",
  231. 0xE3: "MetaLeft",
  232. 0xE7: "MetaRight",
  233. 0x2D: "Minus",
  234. // Num Lock can either be a normal key or a hardware toggle.
  235. 0x53: "NumLock", // UIKeyboardHIDUsageKeyboardNumLock
  236. 0x83: "NumLock", // UIKeyboardHIDUsageKeyboardLockingNumLock
  237. 0x57: "NumpadAdd",
  238. // Some keyboard layouts have a comma, some a period on the numeric pad.
  239. // They are the same key, though.
  240. 0x63: "NumpadDecimal", // UIKeyboardHIDUsageKeypadPeriod
  241. 0x85: "NumpadDecimal", // UIKeyboardHIDUsageKeypadComma
  242. 0x54: "NumpadDivide",
  243. 0x58: "NumpadEnter",
  244. // Some numeric keypads also have an equals sign.
  245. // There appear to be two separate keycodes for that.
  246. 0x67: "NumpadEqual", // UIKeyboardHIDUsageKeypadEqualSign
  247. 0x86: "NumpadEqual", // UIKeyboardHIDUsageKeypadEqualSignAS400
  248. 0x55: "NumpadMultiply",
  249. 0x56: "NumpadSubtract",
  250. 0x4E: "PageDown",
  251. 0x4B: "PageUp",
  252. 0x48: "Pause",
  253. 0x37: "Period",
  254. 0x46: "PrintScreen",
  255. 0x34: "Quote",
  256. // Scroll Lock can either be a normal key or a hardware toggle.
  257. 0x47: "ScrollLock", // UIKeyboardHIDUsageKeyboardScrollLock
  258. 0x84: "ScrollLock", // UIKeyboardHIDUsageKeyboardLockingScrollLock
  259. 0x33: "Semicolon",
  260. 0xE1: "ShiftLeft",
  261. 0xE5: "ShiftRight",
  262. 0x38: "Slash",
  263. 0x2C: "Space",
  264. 0x2B: "Tab",
  265. }
  266. // The UI key and JS key are almost same but very slightly different (e.g., 'A' vs 'KeyA').
  267. uiKeyNameToJSCode = map[string]string{
  268. "Comma": "Comma",
  269. "Period": "Period",
  270. "AltLeft": "AltLeft",
  271. "AltRight": "AltRight",
  272. "CapsLock": "CapsLock",
  273. "ControlLeft": "ControlLeft",
  274. "ControlRight": "ControlRight",
  275. "ShiftLeft": "ShiftLeft",
  276. "ShiftRight": "ShiftRight",
  277. "Enter": "Enter",
  278. "Space": "Space",
  279. "Tab": "Tab",
  280. "Delete": "Delete",
  281. "End": "End",
  282. "Home": "Home",
  283. "Insert": "Insert",
  284. "PageDown": "PageDown",
  285. "PageUp": "PageUp",
  286. "ArrowDown": "ArrowDown",
  287. "ArrowLeft": "ArrowLeft",
  288. "ArrowRight": "ArrowRight",
  289. "ArrowUp": "ArrowUp",
  290. "Escape": "Escape",
  291. "Backspace": "Backspace",
  292. "Quote": "Quote",
  293. "Minus": "Minus",
  294. "Slash": "Slash",
  295. "Semicolon": "Semicolon",
  296. "Equal": "Equal",
  297. "BracketLeft": "BracketLeft",
  298. "Backslash": "Backslash",
  299. "BracketRight": "BracketRight",
  300. "Backquote": "Backquote",
  301. "NumLock": "NumLock",
  302. "Pause": "Pause",
  303. "PrintScreen": "PrintScreen",
  304. "ScrollLock": "ScrollLock",
  305. "ContextMenu": "ContextMenu",
  306. "NumpadAdd": "NumpadAdd",
  307. "NumpadDecimal": "NumpadDecimal",
  308. "NumpadDivide": "NumpadDivide",
  309. "NumpadMultiply": "NumpadMultiply",
  310. "NumpadSubtract": "NumpadSubtract",
  311. "NumpadEnter": "NumpadEnter",
  312. "NumpadEqual": "NumpadEqual",
  313. "MetaLeft": "MetaLeft",
  314. "MetaRight": "MetaRight",
  315. "IntlBackslash": "IntlBackslash",
  316. }
  317. const (
  318. glfwKey0 = 48
  319. glfwKeyA = 65
  320. glfwKeyF1 = 290
  321. glfwKeyKP0 = 320
  322. )
  323. // ASCII: 0 - 9
  324. for c := '0'; c <= '9'; c++ {
  325. glfwKeyNameToGLFWKey[string(c)] = int(glfwKey0 + c - '0')
  326. name := "Digit" + string(c)
  327. uiKeyNameToGLFWKeyName[name] = string(c)
  328. androidKeyToUIKeyName[7+int(c)-'0'] = name
  329. // Gomobile's key code (= USB HID key codes) has successive key codes for 1, 2, ..., 9, 0
  330. // in this order. Same for iOS.
  331. if c == '0' {
  332. iosKeyToUIKeyName[0x27] = name
  333. } else {
  334. iosKeyToUIKeyName[0x1E+int(c)-'1'] = name
  335. }
  336. uiKeyNameToJSCode[name] = name
  337. }
  338. // ASCII: A - Z
  339. for c := 'A'; c <= 'Z'; c++ {
  340. glfwKeyNameToGLFWKey[string(c)] = int(glfwKeyA + c - 'A')
  341. uiKeyNameToGLFWKeyName[string(c)] = string(c)
  342. androidKeyToUIKeyName[29+int(c)-'A'] = string(c)
  343. iosKeyToUIKeyName[0x04+int(c)-'A'] = string(c)
  344. uiKeyNameToJSCode[string(c)] = "Key" + string(c)
  345. }
  346. // Function keys
  347. for i := 1; i <= 24; i++ {
  348. name := "F" + strconv.Itoa(i)
  349. glfwKeyNameToGLFWKey[name] = glfwKeyF1 + i - 1
  350. uiKeyNameToGLFWKeyName[name] = name
  351. // Android doesn't support F13 and more as constants of KeyEvent:
  352. // https://developer.android.com/reference/android/view/KeyEvent
  353. //
  354. // Note that F13 might be avilable if HID devices are available directly:
  355. // https://source.android.com/docs/core/interaction/input/keyboard-devices
  356. if i <= 12 {
  357. androidKeyToUIKeyName[131+i-1] = name
  358. }
  359. if i <= 12 {
  360. iosKeyToUIKeyName[0x3A+i-1] = name
  361. } else {
  362. iosKeyToUIKeyName[0x68+i-13] = name
  363. }
  364. uiKeyNameToJSCode[name] = name
  365. }
  366. // Numpad
  367. // https://www.w3.org/TR/uievents-code/#key-numpad-section
  368. for c := '0'; c <= '9'; c++ {
  369. name := "Numpad" + string(c)
  370. glfwKeyNameToGLFWKey["KP"+string(c)] = int(glfwKeyKP0 + c - '0')
  371. uiKeyNameToGLFWKeyName[name] = "KP" + string(c)
  372. androidKeyToUIKeyName[144+int(c)-'0'] = name
  373. // Gomobile's key code (= USB HID key codes) has successive key codes for 1, 2, ..., 9, 0
  374. // in this order. Same for iOS.
  375. if c == '0' {
  376. iosKeyToUIKeyName[0x62] = name
  377. } else {
  378. iosKeyToUIKeyName[0x59+int(c)-'1'] = name
  379. }
  380. uiKeyNameToJSCode[name] = name
  381. }
  382. // Keys for backward compatibility
  383. oldEbitengineKeyNameToUIKeyName = map[string]string{
  384. "0": "Digit0",
  385. "1": "Digit1",
  386. "2": "Digit2",
  387. "3": "Digit3",
  388. "4": "Digit4",
  389. "5": "Digit5",
  390. "6": "Digit6",
  391. "7": "Digit7",
  392. "8": "Digit8",
  393. "9": "Digit9",
  394. "Apostrophe": "Quote",
  395. "Down": "ArrowDown",
  396. "GraveAccent": "Backquote",
  397. "KP0": "Numpad0",
  398. "KP1": "Numpad1",
  399. "KP2": "Numpad2",
  400. "KP3": "Numpad3",
  401. "KP4": "Numpad4",
  402. "KP5": "Numpad5",
  403. "KP6": "Numpad6",
  404. "KP7": "Numpad7",
  405. "KP8": "Numpad8",
  406. "KP9": "Numpad9",
  407. "KPAdd": "NumpadAdd",
  408. "KPDecimal": "NumpadDecimal",
  409. "KPDivide": "NumpadDivide",
  410. "KPMultiply": "NumpadMultiply",
  411. "KPSubtract": "NumpadSubtract",
  412. "KPEnter": "NumpadEnter",
  413. "KPEqual": "NumpadEqual",
  414. "Left": "ArrowLeft",
  415. "LeftBracket": "BracketLeft",
  416. "Menu": "ContextMenu",
  417. "Right": "ArrowRight",
  418. "RightBracket": "BracketRight",
  419. "Up": "ArrowUp",
  420. }
  421. }
  422. const ebitengineKeysTmpl = `{{.License}}
  423. {{.DoNotEdit}}
  424. package ebiten
  425. import (
  426. "fmt"
  427. "strings"
  428. "github.com/hajimehoshi/ebiten/v2/internal/ui"
  429. )
  430. // A Key represents a keyboard key.
  431. // These keys represent physical keys of US keyboard.
  432. // For example, KeyQ represents Q key on US keyboards and ' (quote) key on Dvorak keyboards.
  433. type Key int
  434. // Keys.
  435. const (
  436. {{range $index, $name := .EbitengineKeyNamesWithoutMods}}Key{{$name}} Key = Key(ui.Key{{$name}})
  437. {{end}} KeyAlt Key = Key(ui.KeyReserved0)
  438. KeyControl Key = Key(ui.KeyReserved1)
  439. KeyShift Key = Key(ui.KeyReserved2)
  440. KeyMeta Key = Key(ui.KeyReserved3)
  441. KeyMax Key = KeyMeta
  442. // Keys for backward compatibility.
  443. // Deprecated: as of v2.1.
  444. {{range $old, $new := .OldEbitengineKeyNameToUIKeyName}}Key{{$old}} Key = Key(ui.Key{{$new}})
  445. {{end}}
  446. )
  447. func (k Key) isValid() bool {
  448. switch k {
  449. {{range $name := .EbitengineKeyNamesWithoutOld}}case Key{{$name}}:
  450. return true
  451. {{end}}
  452. default:
  453. return false
  454. }
  455. }
  456. // String returns a string representing the key.
  457. //
  458. // If k is an undefined key, String returns an empty string.
  459. func (k Key) String() string {
  460. switch k {
  461. {{range $name := .EbitengineKeyNamesWithoutOld}}case Key{{$name}}:
  462. return {{$name | printf "%q"}}
  463. {{end}}}
  464. return ""
  465. }
  466. func keyNameToKeyCode(name string) (Key, bool) {
  467. switch strings.ToLower(name) {
  468. {{range $name := .EbitengineKeyNames}}case {{$name | printf "%q" | ToLower}}:
  469. return Key{{$name}}, true
  470. {{end}}}
  471. return 0, false
  472. }
  473. // MarshalText implements encoding.TextMarshaler.
  474. func (k Key) MarshalText() ([]byte, error) {
  475. return []byte(k.String()), nil
  476. }
  477. // UnmarshalText implements encoding.TextUnmarshaler
  478. func (k *Key) UnmarshalText(text []byte) error {
  479. key, ok := keyNameToKeyCode(string(text))
  480. if !ok {
  481. return fmt.Errorf("ebiten: unexpected key name: %s", string(text))
  482. }
  483. *k = key
  484. return nil
  485. }
  486. `
  487. const uiKeysTmpl = `{{.License}}
  488. {{.DoNotEdit}}
  489. package ui
  490. import (
  491. "fmt"
  492. )
  493. type Key int
  494. const (
  495. {{range $index, $name := .UIKeyNames}}Key{{$name}}{{if eq $index 0}} Key = iota{{end}}
  496. {{end}} KeyReserved0
  497. KeyReserved1
  498. KeyReserved2
  499. KeyReserved3
  500. KeyMax = KeyReserved3
  501. )
  502. func (k Key) String() string {
  503. switch k {
  504. {{range $index, $name := .UIKeyNames}}case Key{{$name}}:
  505. return {{$name | printf "Key%s" | printf "%q"}}
  506. {{end}}}
  507. return fmt.Sprintf("Key(%d)", k)
  508. }
  509. `
  510. const eventKeysTmpl = `{{.License}}
  511. {{.DoNotEdit}}
  512. package event
  513. import (
  514. "github.com/hajimehoshi/ebiten/v2/internal/ui"
  515. )
  516. type Key = ui.Key
  517. const (
  518. {{range $index, $name := .UIKeyNames}}Key{{$name}} = ui.Key{{$name}}
  519. {{end}}
  520. )
  521. `
  522. const uiGLFWKeysTmpl = `{{.License}}
  523. {{.DoNotEdit}}
  524. {{.BuildConstraints}}
  525. package ui
  526. import (
  527. "github.com/hajimehoshi/ebiten/v2/internal/glfw"
  528. )
  529. var uiKeyToGLFWKey = map[Key]glfw.Key{
  530. {{range $dname, $gname := .UIKeyNameToGLFWKeyName}}Key{{$dname}}: glfw.Key{{$gname}},
  531. {{end}}
  532. }
  533. `
  534. const uiJSKeysTmpl = `{{.License}}
  535. {{.DoNotEdit}}
  536. {{.BuildConstraints}}
  537. package ui
  538. import (
  539. "syscall/js"
  540. )
  541. var uiKeyToJSCode = map[Key]js.Value{
  542. {{range $name, $code := .UIKeyNameToJSCode}}Key{{$name}}: js.ValueOf({{$code | printf "%q"}}),
  543. {{end}}
  544. }
  545. `
  546. const glfwKeysTmpl = `{{.License}}
  547. {{.DoNotEdit}}
  548. {{.BuildConstraints}}
  549. package glfw
  550. const (
  551. {{range $name, $key := .GLFWKeyNameToGLFWKey}}Key{{$name}} = Key({{$key}})
  552. {{end}}
  553. )
  554. `
  555. const mobileAndroidKeysTmpl = `{{.License}}
  556. {{.DoNotEdit}}
  557. {{.BuildConstraints}}
  558. package ebitenmobileview
  559. import (
  560. "github.com/hajimehoshi/ebiten/v2/internal/ui"
  561. )
  562. var androidKeyToUIKey = map[int]ui.Key{
  563. {{range $key, $name := .AndroidKeyToUIKeyName}}{{$key}}: ui.Key{{$name}},
  564. {{end}}
  565. }
  566. `
  567. const mobileIOSKeysTmpl = `{{.License}}
  568. {{.DoNotEdit}}
  569. {{.BuildConstraints}}
  570. package ebitenmobileview
  571. import (
  572. "github.com/hajimehoshi/ebiten/v2/internal/ui"
  573. )
  574. var iosKeyToUIKey = map[int]ui.Key{
  575. {{range $key, $name := .IOSKeyToUIKeyName}}{{$key}}: ui.Key{{$name}},
  576. {{end}}
  577. }
  578. `
  579. func digitKey(name string) int {
  580. if len(name) != 1 {
  581. return -1
  582. }
  583. c := name[0]
  584. if c < '0' || '9' < c {
  585. return -1
  586. }
  587. return int(c - '0')
  588. }
  589. func alphabetKey(name string) rune {
  590. if len(name) != 1 {
  591. return -1
  592. }
  593. c := rune(name[0])
  594. if c < 'A' || 'Z' < c {
  595. return -1
  596. }
  597. return c
  598. }
  599. func functionKey(name string) int {
  600. if len(name) < 2 {
  601. return -1
  602. }
  603. if name[0] != 'F' {
  604. return -1
  605. }
  606. i, err := strconv.Atoi(name[1:])
  607. if err != nil {
  608. return -1
  609. }
  610. return i
  611. }
  612. func keyNamesLess(k []string) func(i, j int) bool {
  613. return func(i, j int) bool {
  614. k0, k1 := k[i], k[j]
  615. d0, d1 := digitKey(k0), digitKey(k1)
  616. a0, a1 := alphabetKey(k0), alphabetKey(k1)
  617. f0, f1 := functionKey(k0), functionKey(k1)
  618. if d0 != -1 {
  619. if d1 != -1 {
  620. return d0 < d1
  621. }
  622. return true
  623. }
  624. if a0 != -1 {
  625. if d1 != -1 {
  626. return false
  627. }
  628. if a1 != -1 {
  629. return a0 < a1
  630. }
  631. return true
  632. }
  633. if d1 != -1 {
  634. return false
  635. }
  636. if a1 != -1 {
  637. return false
  638. }
  639. if f0 != -1 && f1 != -1 {
  640. return f0 < f1
  641. }
  642. return k0 < k1
  643. }
  644. }
  645. const license = `// Copyright 2013 The Ebitengine Authors
  646. //
  647. // Licensed under the Apache License, Version 2.0 (the "License");
  648. // you may not use this file except in compliance with the License.
  649. // You may obtain a copy of the License at
  650. //
  651. // http://www.apache.org/licenses/LICENSE-2.0
  652. //
  653. // Unless required by applicable law or agreed to in writing, software
  654. // distributed under the License is distributed on an "AS IS" BASIS,
  655. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  656. // See the License for the specific language governing permissions and
  657. // limitations under the License.
  658. `
  659. func main() {
  660. // Follow the standard comment rule (https://pkg.go.dev/cmd/go#hdr-Generate_Go_files_by_processing_source).
  661. doNotEdit := "// Code generated by genkeys.go using 'go generate'. DO NOT EDIT."
  662. ebitengineKeyNames := []string{}
  663. ebitengineKeyNamesWithoutOld := []string{}
  664. ebitengineKeyNamesWithoutMods := []string{}
  665. uiKeyNames := []string{}
  666. for name := range uiKeyNameToJSCode {
  667. uiKeyNames = append(uiKeyNames, name)
  668. ebitengineKeyNames = append(ebitengineKeyNames, name)
  669. ebitengineKeyNamesWithoutOld = append(ebitengineKeyNamesWithoutOld, name)
  670. ebitengineKeyNamesWithoutMods = append(ebitengineKeyNamesWithoutMods, name)
  671. }
  672. for old := range oldEbitengineKeyNameToUIKeyName {
  673. ebitengineKeyNames = append(ebitengineKeyNames, old)
  674. }
  675. // Keys for modifiers
  676. ebitengineKeyNames = append(ebitengineKeyNames, "Alt", "Control", "Shift", "Meta")
  677. ebitengineKeyNamesWithoutOld = append(ebitengineKeyNamesWithoutOld, "Alt", "Control", "Shift", "Meta")
  678. sort.Slice(ebitengineKeyNames, keyNamesLess(ebitengineKeyNames))
  679. sort.Slice(ebitengineKeyNamesWithoutOld, keyNamesLess(ebitengineKeyNamesWithoutOld))
  680. sort.Slice(ebitengineKeyNamesWithoutMods, keyNamesLess(ebitengineKeyNamesWithoutMods))
  681. sort.Slice(uiKeyNames, keyNamesLess(uiKeyNames))
  682. // TODO: Add this line for event package (#926).
  683. //
  684. // filepath.Join("event", "keys.go"): eventKeysTmpl,
  685. for path, tmpl := range map[string]string{
  686. filepath.Join("internal", "glfw", "keys.go"): glfwKeysTmpl,
  687. filepath.Join("internal", "ui", "keys.go"): uiKeysTmpl,
  688. filepath.Join("internal", "ui", "keys_glfw.go"): uiGLFWKeysTmpl,
  689. filepath.Join("internal", "ui", "keys_js.go"): uiJSKeysTmpl,
  690. filepath.Join("keys.go"): ebitengineKeysTmpl,
  691. filepath.Join("mobile", "ebitenmobileview", "keys_android.go"): mobileAndroidKeysTmpl,
  692. filepath.Join("mobile", "ebitenmobileview", "keys_ios.go"): mobileIOSKeysTmpl,
  693. } {
  694. f, err := os.Create(path)
  695. if err != nil {
  696. log.Fatal(err)
  697. }
  698. defer f.Close()
  699. funcs := template.FuncMap{
  700. "ToLower": strings.ToLower,
  701. }
  702. tmpl, err := template.New(path).Funcs(funcs).Parse(tmpl)
  703. if err != nil {
  704. log.Fatal(err)
  705. }
  706. // The build tag can't be included in the templates because of `go vet`.
  707. // Pass the build tag and extract this in the template to make `go vet` happy.
  708. buildConstraints := ""
  709. switch path {
  710. case filepath.Join("internal", "glfw", "keys.go"):
  711. buildConstraints = "//go:build darwin || freebsd || linux || netbsd || openbsd || windows"
  712. case filepath.Join("internal", "ui", "keys_mobile.go"):
  713. buildConstraints = "//go:build android || ios"
  714. case filepath.Join("internal", "ui", "keys_glfw.go"):
  715. buildConstraints = "//go:build !android && !ios && !js && !nintendosdk && !playstation5"
  716. }
  717. // NOTE: According to godoc, maps are automatically sorted by key.
  718. w := bufio.NewWriter(f)
  719. if err := tmpl.Execute(w, struct {
  720. License string
  721. DoNotEdit string
  722. BuildConstraints string
  723. UIKeyNameToJSCode map[string]string
  724. EbitengineKeyNames []string
  725. EbitengineKeyNamesWithoutOld []string
  726. EbitengineKeyNamesWithoutMods []string
  727. GLFWKeyNameToGLFWKey map[string]int
  728. UIKeyNames []string
  729. UIKeyNameToGLFWKeyName map[string]string
  730. AndroidKeyToUIKeyName map[int]string
  731. IOSKeyToUIKeyName map[int]string
  732. OldEbitengineKeyNameToUIKeyName map[string]string
  733. }{
  734. License: license,
  735. DoNotEdit: doNotEdit,
  736. BuildConstraints: buildConstraints,
  737. UIKeyNameToJSCode: uiKeyNameToJSCode,
  738. EbitengineKeyNames: ebitengineKeyNames,
  739. EbitengineKeyNamesWithoutOld: ebitengineKeyNamesWithoutOld,
  740. EbitengineKeyNamesWithoutMods: ebitengineKeyNamesWithoutMods,
  741. GLFWKeyNameToGLFWKey: glfwKeyNameToGLFWKey,
  742. UIKeyNames: uiKeyNames,
  743. UIKeyNameToGLFWKeyName: uiKeyNameToGLFWKeyName,
  744. AndroidKeyToUIKeyName: androidKeyToUIKeyName,
  745. IOSKeyToUIKeyName: iosKeyToUIKeyName,
  746. OldEbitengineKeyNameToUIKeyName: oldEbitengineKeyNameToUIKeyName,
  747. }); err != nil {
  748. log.Fatal(err)
  749. }
  750. if err := w.Flush(); err != nil {
  751. log.Fatal(err)
  752. }
  753. }
  754. }