keymap.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import json
  2. import logging
  3. import os
  4. from traceback import format_exc
  5. import qmk.path
  6. from qmk.errors import NoSuchKeyboardError
  7. # The `keymap.c` template to use when a keyboard doesn't have its own
  8. DEFAULT_KEYMAP_C = """#include QMK_KEYBOARD_H
  9. /* THIS FILE WAS GENERATED!
  10. *
  11. * This file was generated by qmk-compile-json. You may or may not want to
  12. * edit it directly.
  13. */
  14. const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
  15. __KEYMAP_GOES_HERE__
  16. };
  17. """
  18. # Helper Functions
  19. def template(keyboard, keymap):
  20. """Returns the `keymap.c` template for a keyboard.
  21. If a template exists in `keyboards/<keyboard>/templates/keymap.c` that
  22. text will be used instead of `DEFAULT_KEYMAP_C`.
  23. """
  24. template_name = 'keyboards/%s/templates/keymap.c' % keyboard
  25. if os.path.exists(template_name):
  26. with open(template_name, 'r') as fd:
  27. template_text = fd.read()
  28. return DEFAULT_KEYMAP_C.replace('__KEYMAP_GOES_HERE__', keymap)
  29. def generate(keyboard, layout, layers):
  30. """Generate the keymap source code.
  31. """
  32. layer_txt = []
  33. for layer_num, layer in enumerate(layers):
  34. if layer_num != 0:
  35. layer_txt[-1] = layer_txt[-1] + ','
  36. layer_keys = ', '.join(layer)
  37. layer_txt.append('\t[%s] = %s(%s)' % (layer_num, layout, layer_keys))
  38. keymap = '\n'.join(layer_txt)
  39. keymap_c = template(keyboard, keymap)
  40. return keymap_c
  41. def write(keyboard, keymap, layout, layers):
  42. """Generate the `keymap.c` and write it to disk.
  43. """
  44. keymap_c = generate(keyboard, layout, layers)
  45. keymap_path = qmk.path.keymap(keyboard)
  46. keymap_dir = os.path.join(keymap_path, keymap)
  47. keymap_file = os.path.join(keymap_dir, 'keymap.c')
  48. if not os.path.exists(keymap_dir):
  49. os.makedirs(keymap_dir)
  50. with open(keymap_file, 'w') as keymap_fd:
  51. keymap_fd.write(keymap_c)
  52. return keymap_file
  53. # Public functions
  54. def compile_firmware(keyboard, keymap, layout, layers):
  55. """Compile a firmware.
  56. """
  57. result = {
  58. 'keyboard': keyboard,
  59. 'layout': layout,
  60. 'keymap': keymap,
  61. 'command': ['make', 'COLOR=false', ':'.join((keyboard, keymap))],
  62. 'returncode': -2,
  63. 'output': '',
  64. 'firmware': None,
  65. 'firmware_filename': '',
  66. }
  67. try:
  68. job = get_current_job()
  69. result['id'] = job.id
  70. checkout_qmk()
  71. # Sanity checks
  72. if not os.path.exists('qmk_firmware/keyboards/' + keyboard):
  73. logging.error('Unknown keyboard: %s', keyboard)
  74. return {'returncode': -1, 'command': '', 'output': 'Unknown keyboard!', 'firmware': None}
  75. for pathname in (
  76. 'qmk_firmware/keyboards/%s/keymaps/%s' % (keyboard, keymap),
  77. 'qmk_firmware/keyboards/%s/../keymaps/%s' % (keyboard, keymap),
  78. ):
  79. if os.path.exists(pathname):
  80. logging.error('Name collision! %s already exists! This should not happen!', pathname)
  81. return {'returncode': -1, 'command': '', 'output': 'Keymap name collision! %s already exists!' % (pathname), 'firmware': None}
  82. # Build the keyboard firmware
  83. write_keymap(result['keyboard'], result['keymap'], layers)
  84. store_firmware_binary(result)
  85. except Exception as e:
  86. result['returncode'] = -3
  87. result['exception'] = e.__class__.__name__
  88. result['stacktrace'] = format_exc()
  89. if not result['output']:
  90. result['output'] = result['stacktrace']
  91. return result