keyboard.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. """Functions that help us work with keyboards.
  2. """
  3. from array import array
  4. from math import ceil
  5. from pathlib import Path
  6. from qmk.c_parse import parse_config_h_file
  7. from qmk.makefile import parse_rules_mk_file
  8. def config_h(keyboard):
  9. """Parses all the config.h files for a keyboard.
  10. Args:
  11. keyboard: name of the keyboard
  12. Returns:
  13. a dictionary representing the content of the entire config.h tree for a keyboard
  14. """
  15. config = {}
  16. cur_dir = Path('keyboards')
  17. rules = rules_mk(keyboard)
  18. keyboard = Path(rules['DEFAULT_FOLDER'] if 'DEFAULT_FOLDER' in rules else keyboard)
  19. for dir in keyboard.parts:
  20. cur_dir = cur_dir / dir
  21. config = {**config, **parse_config_h_file(cur_dir / 'config.h')}
  22. return config
  23. def rules_mk(keyboard):
  24. """Get a rules.mk for a keyboard
  25. Args:
  26. keyboard: name of the keyboard
  27. Returns:
  28. a dictionary representing the content of the entire rules.mk tree for a keyboard
  29. """
  30. keyboard = Path(keyboard)
  31. cur_dir = Path('keyboards')
  32. rules = parse_rules_mk_file(cur_dir / keyboard / 'rules.mk')
  33. if 'DEFAULT_FOLDER' in rules:
  34. keyboard = Path(rules['DEFAULT_FOLDER'])
  35. for i, dir in enumerate(keyboard.parts):
  36. cur_dir = cur_dir / dir
  37. rules = parse_rules_mk_file(cur_dir / 'rules.mk', rules)
  38. return rules
  39. def render_layout(layout_data, key_labels=None):
  40. """Renders a single layout.
  41. """
  42. textpad = [array('u', ' ' * 200) for x in range(50)]
  43. for key in layout_data:
  44. x = ceil(key.get('x', 0) * 4)
  45. y = ceil(key.get('y', 0) * 3)
  46. w = ceil(key.get('w', 1) * 4)
  47. h = ceil(key.get('h', 1) * 3)
  48. if key_labels:
  49. label = key_labels.pop(0)
  50. if label.startswith('KC_'):
  51. label = label[3:]
  52. else:
  53. label = key.get('label', '')
  54. label_len = w - 2
  55. label_leftover = label_len - len(label)
  56. if len(label) > label_len:
  57. label = label[:label_len]
  58. label_blank = ' ' * label_len
  59. label_border = '─' * label_len
  60. label_middle = label + ' '*label_leftover # noqa: yapf insists there be no whitespace around *
  61. top_line = array('u', '┌' + label_border + '┐')
  62. lab_line = array('u', '│' + label_middle + '│')
  63. mid_line = array('u', '│' + label_blank + '│')
  64. bot_line = array('u', '└' + label_border + "┘")
  65. textpad[y][x:x + w] = top_line
  66. textpad[y + 1][x:x + w] = lab_line
  67. for i in range(h - 3):
  68. textpad[y + i + 2][x:x + w] = mid_line
  69. textpad[y + h - 1][x:x + w] = bot_line
  70. lines = []
  71. for line in textpad:
  72. if line.tounicode().strip():
  73. lines.append(line.tounicode().rstrip())
  74. return '\n'.join(lines)
  75. def render_layouts(info_json):
  76. """Renders all the layouts from an `info_json` structure.
  77. """
  78. layouts = {}
  79. for layout in info_json['layouts']:
  80. layout_data = info_json['layouts'][layout]['layout']
  81. layouts[layout] = render_layout(layout_data)
  82. return layouts