logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

main.go (6208B)


  1. package main
  2. import (
  3. "io/ioutil"
  4. "fmt"
  5. "encoding/json"
  6. "os"
  7. "path/filepath"
  8. "strings"
  9. "sort"
  10. "hash/crc64"
  11. //"encoding/base64"
  12. )
  13. func main() {
  14. // Show Usage
  15. if len(os.Args) < 3 {
  16. fmt.Println("Usage: ./keymap-gen src-dir out-dir")
  17. fmt.Println("Outputs c files in out-dir")
  18. fmt.Println("Make sure the dirs exist.")
  19. return
  20. }
  21. files, err := filepath.Glob(os.Args[1] + "/*.json")
  22. if err != nil {
  23. fmt.Printf("Could not open src-dir: %v\n", err)
  24. return
  25. }
  26. for _, fname := range(files) {
  27. fmt.Println("Processing: ", fname)
  28. // Read the source
  29. data, err := ioutil.ReadFile(fname)
  30. if err != nil {
  31. panic(err)
  32. }
  33. // Unbundle Data
  34. var FullDict map[string]Entry
  35. json.Unmarshal(data, &FullDict)
  36. // Loop over entries and store
  37. var output []string
  38. for i,v := range FullDict {
  39. if i == "0" {
  40. continue
  41. }
  42. // Special handling for numbermap
  43. var entry string
  44. if strings.Contains(fname, "num") {
  45. entry = v.toKeymap("NUM|")
  46. } else {
  47. entry = v.toKeymap("")
  48. }
  49. if entry != "" {
  50. output = append(output, entry)
  51. }
  52. }
  53. // Sort by length, then amount of whitespace lol
  54. sort.Slice(output, func (i,j int) bool {
  55. var maxLen int
  56. if len(output[i]) > len(output[j]) {
  57. maxLen = len(output[i])
  58. } else {
  59. maxLen = len(output[j])
  60. }
  61. return maxLen-strings.Count(output[i][:40], " ") < maxLen-strings.Count(output[j][:40], " ")
  62. })
  63. // Whack a disclaimer
  64. output = append([]string{"// This file is automatically generated. Do not edit it!\n\n"}, output...)
  65. // Write all data out
  66. outName := filepath.Base(fname)
  67. outName = os.Args[2] + outName[:len(outName)-5]+".def"
  68. fmt.Println("Saving: ", outName)
  69. ioutil.WriteFile(outName, []byte(strings.Join(output, "")), 0755)
  70. }
  71. }
  72. func (e Entry) toKeymap(prefix string) (string) {
  73. // storage for parts
  74. var command, chord, arg string
  75. wordInfo := parseWords(e)
  76. // Handle prefix
  77. if prefix != "" {
  78. chord = prefix
  79. }
  80. // Format the chord
  81. keys := []string{"AA", "AS", "AE", "AT", "AN", "AI", "AO", "AP"}
  82. for i, v := range e.Input {
  83. chord += keys[v-1]
  84. if i != len(e.Input)-1 {
  85. chord += "|"
  86. }
  87. }
  88. // Handle specials/base first
  89. var ok bool
  90. var v []string
  91. if e.Special != "" {
  92. v, ok = QMKLookup[e.Special]
  93. }
  94. if !ok && e.Base != "" {
  95. v, ok = QMKLookup[e.Base]
  96. }
  97. if ok {
  98. // Determine way to send key
  99. if len(v) == 1 {
  100. command = "PRES("
  101. } else {
  102. command = "KEYS("
  103. }
  104. }
  105. if ok {
  106. if len(v) > 1 {
  107. arg += "{"
  108. }
  109. // String together args
  110. for ii, vv := range(v) {
  111. arg += vv
  112. if ii == len(v)-1 && len(v) > 1 {
  113. arg += ", COMBO_END}"
  114. } else if ii != len(v)-1 {
  115. arg += ", "
  116. }
  117. }
  118. hash := crc64.Checksum([]byte(fmt.Sprintf("%v%v", arg, chord)), crc64.MakeTable(crc64.ECMA))
  119. hashStr := fmt.Sprintf("cmb_%x", hash)
  120. wordSpacer := strings.Repeat(" ", 42-len(arg))
  121. if command == "KEYS(" {
  122. arg = fmt.Sprintf("%v, %v %v", hashStr, wordSpacer, arg)
  123. } else {
  124. arg = fmt.Sprintf("%65v", arg)
  125. }
  126. goto Found
  127. }
  128. // Parse out word info
  129. if wordInfo.LRank == 0 && wordInfo.RRank == 0 {
  130. goto Blank
  131. }
  132. if wordInfo.LRank != 0 || wordInfo.RRank != 0 {
  133. if wordInfo.LRank != 0 && wordInfo.RRank != 0 {
  134. // Just blank the structure and recall
  135. left, right := e, e
  136. left.Trw = nil
  137. right.Tlw = nil
  138. return fmt.Sprintf("%v%v", left.toKeymap("LFT|"), right.toKeymap("RGT|"))
  139. }
  140. var word string
  141. if wordInfo.LRank > wordInfo.RRank {
  142. word = wordInfo.LWord
  143. } else {
  144. word = wordInfo.RWord
  145. }
  146. // Add in thumb
  147. chord = "AR|" + chord
  148. // generate function name
  149. hash := crc64.Checksum([]byte(word), crc64.MakeTable(crc64.ECMA))
  150. hashStr := fmt.Sprintf("str_%016X", hash)
  151. command = "SUBS("
  152. wordSpacer := strings.Repeat(" ", 40-len(word))
  153. arg = fmt.Sprintf("%v, %v \"%v \"", hashStr, wordSpacer, word)
  154. goto Found
  155. }
  156. panic(e.String())
  157. Found:
  158. chord += ","
  159. return fmt.Sprintf("%v%-35v%v)\n", command, chord, arg)
  160. Blank:
  161. return ""
  162. }
  163. type Entry struct {
  164. Input []int
  165. Base string
  166. Tlw []interface{}
  167. Trw []interface{}
  168. Special string
  169. }
  170. type Word struct {
  171. LWord string
  172. LRank float64
  173. RWord string
  174. RRank float64
  175. }
  176. func parseWords(e Entry) (ret Word) {
  177. if len(e.Tlw) > 0 {
  178. ret.LWord = e.Tlw[0].(string)
  179. ret.LRank= e.Tlw[1].(float64)
  180. }
  181. if len(e.Trw) > 0 {
  182. ret.RWord = e.Trw[0].(string)
  183. ret.RRank= e.Trw[1].(float64)
  184. }
  185. return ret
  186. }
  187. func (e Entry) String() (ret string) {
  188. ret = fmt.Sprintln("Input: ", e.Input)
  189. ret += fmt.Sprintln("Base: ", e.Base)
  190. ret += fmt.Sprintln("Left: ", e.Tlw)
  191. ret += fmt.Sprintln("Right: ", e.Trw)
  192. ret += fmt.Sprintln("Special: ", e.Special)
  193. return ret
  194. }
  195. var QMKLookup = map[string][]string {
  196. "!":[]string{"KC_LSFT", "KC_1"},
  197. "'":[]string{"KC_QUOT"},
  198. "(":[]string{"KC_LSFT", "KC_9"},
  199. ")":[]string{"KC_LSFT", "KC_0"},
  200. ",":[]string{"KC_COMM"},
  201. "-":[]string{"KC_MINS"},
  202. ".":[]string{"KC_DOT"},
  203. ";":[]string{"KC_SCLN"},
  204. "?":[]string{"KC_QUOT"},
  205. "a":[]string{"KC_A"},
  206. "b":[]string{"KC_B"},
  207. "c":[]string{"KC_C"},
  208. "d":[]string{"KC_D"},
  209. "e":[]string{"KC_E"},
  210. "f":[]string{"KC_F"},
  211. "g":[]string{"KC_G"},
  212. "h":[]string{"KC_H"},
  213. "i":[]string{"KC_I"},
  214. "j":[]string{"KC_J"},
  215. "k":[]string{"KC_K"},
  216. "l":[]string{"KC_L"},
  217. "m":[]string{"KC_M"},
  218. "n":[]string{"KC_N"},
  219. "o":[]string{"KC_O"},
  220. "p":[]string{"KC_P"},
  221. "q":[]string{"KC_Q"},
  222. "r":[]string{"KC_R"},
  223. "s":[]string{"KC_S"},
  224. "t":[]string{"KC_T"},
  225. "u":[]string{"KC_U"},
  226. "v":[]string{"KC_V"},
  227. "w":[]string{"KC_W"},
  228. "x":[]string{"KC_X"},
  229. "y":[]string{"KC_Y"},
  230. "z":[]string{"KC_Z"},
  231. //specials
  232. "bksp":[]string{"KC_BSPC"},
  233. "enter":[]string{"KC_ENT"},
  234. //"numsym":[]string{"NUM)"}, //TODO: Sticky
  235. //"LETTERS":[]string{"KC_SPC"},
  236. //symbols
  237. "[":[]string{"KC_LBRC"},
  238. "]":[]string{"KC_RBRC"},
  239. " ":[]string{"KC_SPC"},
  240. "1":[]string{"KC_1"},
  241. "2":[]string{"KC_2"},
  242. "3":[]string{"KC_3"},
  243. "4":[]string{"KC_4"},
  244. "5":[]string{"KC_5"},
  245. "6":[]string{"KC_6"},
  246. "7":[]string{"KC_7"},
  247. "8":[]string{"KC_8"},
  248. "9":[]string{"KC_9"},
  249. "0":[]string{"KC_0"},
  250. "=":[]string{"KC_EQL"},
  251. "Fn":[]string{"KC_NO"},
  252. "SPACE":[]string{"KC_SPC"},
  253. "Home":[]string{"KC_HOME"},
  254. "End":[]string{"KC_END"},
  255. " ":[]string{"KC_TAB"},
  256. " ":[]string{"KC_TAB"},
  257. "\t":[]string{"KC_TAB"},
  258. "`":[]string{"KC_GRV"},
  259. }