diff options
Diffstat (limited to 'lib/python/qmk/keymap.py')
-rw-r--r-- | lib/python/qmk/keymap.py | 75 |
1 files changed, 61 insertions, 14 deletions
diff --git a/lib/python/qmk/keymap.py b/lib/python/qmk/keymap.py index 69cdc8d5b..70730eb4a 100644 --- a/lib/python/qmk/keymap.py +++ b/lib/python/qmk/keymap.py | |||
@@ -2,8 +2,8 @@ | |||
2 | """ | 2 | """ |
3 | from pathlib import Path | 3 | from pathlib import Path |
4 | 4 | ||
5 | import qmk.path | 5 | from qmk.path import is_keyboard |
6 | import qmk.makefile | 6 | from qmk.keyboard import rules_mk |
7 | 7 | ||
8 | # The `keymap.c` template to use when a keyboard doesn't have its own | 8 | # The `keymap.c` template to use when a keyboard doesn't have its own |
9 | DEFAULT_KEYMAP_C = """#include QMK_KEYBOARD_H | 9 | DEFAULT_KEYMAP_C = """#include QMK_KEYBOARD_H |
@@ -47,6 +47,14 @@ def _strip_any(keycode): | |||
47 | return keycode | 47 | return keycode |
48 | 48 | ||
49 | 49 | ||
50 | def is_keymap_dir(keymap): | ||
51 | """Return True if Path object `keymap` has a keymap file inside. | ||
52 | """ | ||
53 | for file in ('keymap.c', 'keymap.json'): | ||
54 | if (keymap / file).is_file(): | ||
55 | return True | ||
56 | |||
57 | |||
50 | def generate(keyboard, layout, layers): | 58 | def generate(keyboard, layout, layers): |
51 | """Returns a keymap.c for the specified keyboard, layout, and layers. | 59 | """Returns a keymap.c for the specified keyboard, layout, and layers. |
52 | 60 | ||
@@ -95,7 +103,7 @@ def write(keyboard, keymap, layout, layers): | |||
95 | An array of arrays describing the keymap. Each item in the inner array should be a string that is a valid QMK keycode. | 103 | An array of arrays describing the keymap. Each item in the inner array should be a string that is a valid QMK keycode. |
96 | """ | 104 | """ |
97 | keymap_c = generate(keyboard, layout, layers) | 105 | keymap_c = generate(keyboard, layout, layers) |
98 | keymap_file = qmk.path.keymap(keyboard) / keymap / 'keymap.c' | 106 | keymap_file = keymap(keyboard) / keymap / 'keymap.c' |
99 | 107 | ||
100 | keymap_file.parent.mkdir(parents=True, exist_ok=True) | 108 | keymap_file.parent.mkdir(parents=True, exist_ok=True) |
101 | keymap_file.write_text(keymap_c) | 109 | keymap_file.write_text(keymap_c) |
@@ -103,37 +111,76 @@ def write(keyboard, keymap, layout, layers): | |||
103 | return keymap_file | 111 | return keymap_file |
104 | 112 | ||
105 | 113 | ||
106 | def list_keymaps(keyboard_name): | 114 | def locate_keymap(keyboard, keymap): |
115 | """Returns the path to a keymap for a specific keyboard. | ||
116 | """ | ||
117 | if not is_keyboard(keyboard): | ||
118 | raise KeyError('Invalid keyboard: ' + repr(keyboard)) | ||
119 | |||
120 | # Check the keyboard folder first, last match wins | ||
121 | checked_dirs = '' | ||
122 | keymap_path = '' | ||
123 | |||
124 | for dir in keyboard.split('/'): | ||
125 | if checked_dirs: | ||
126 | checked_dirs = '/'.join((checked_dirs, dir)) | ||
127 | else: | ||
128 | checked_dirs = dir | ||
129 | |||
130 | keymap_dir = Path('keyboards') / checked_dirs / 'keymaps' | ||
131 | |||
132 | if (keymap_dir / keymap / 'keymap.c').exists(): | ||
133 | keymap_path = keymap_dir / keymap / 'keymap.c' | ||
134 | if (keymap_dir / keymap / 'keymap.json').exists(): | ||
135 | keymap_path = keymap_dir / keymap / 'keymap.json' | ||
136 | |||
137 | if keymap_path: | ||
138 | return keymap_path | ||
139 | |||
140 | # Check community layouts as a fallback | ||
141 | rules = rules_mk(keyboard) | ||
142 | |||
143 | if "LAYOUTS" in rules: | ||
144 | for layout in rules["LAYOUTS"].split(): | ||
145 | community_layout = Path('layouts/community') / layout / keymap | ||
146 | if community_layout.exists(): | ||
147 | if (community_layout / 'keymap.json').exists(): | ||
148 | return community_layout / 'keymap.json' | ||
149 | if (community_layout / 'keymap.c').exists(): | ||
150 | return community_layout / 'keymap.c' | ||
151 | |||
152 | |||
153 | def list_keymaps(keyboard): | ||
107 | """ List the available keymaps for a keyboard. | 154 | """ List the available keymaps for a keyboard. |
108 | 155 | ||
109 | Args: | 156 | Args: |
110 | keyboard_name: the keyboards full name with vendor and revision if necessary, example: clueboard/66/rev3 | 157 | keyboard: the keyboards full name with vendor and revision if necessary, example: clueboard/66/rev3 |
111 | 158 | ||
112 | Returns: | 159 | Returns: |
113 | a set with the names of the available keymaps | 160 | a set with the names of the available keymaps |
114 | """ | 161 | """ |
115 | # parse all the rules.mk files for the keyboard | 162 | # parse all the rules.mk files for the keyboard |
116 | rules_mk = qmk.makefile.get_rules_mk(keyboard_name) | 163 | rules = rules_mk(keyboard) |
117 | names = set() | 164 | names = set() |
118 | 165 | ||
119 | if rules_mk: | 166 | if rules: |
120 | # qmk_firmware/keyboards | 167 | # qmk_firmware/keyboards |
121 | keyboards_dir = Path.cwd() / "keyboards" | 168 | keyboards_dir = Path('keyboards') |
122 | # path to the keyboard's directory | 169 | # path to the keyboard's directory |
123 | kb_path = keyboards_dir / keyboard_name | 170 | kb_path = keyboards_dir / keyboard |
124 | # walk up the directory tree until keyboards_dir | 171 | # walk up the directory tree until keyboards_dir |
125 | # and collect all directories' name with keymap.c file in it | 172 | # and collect all directories' name with keymap.c file in it |
126 | while kb_path != keyboards_dir: | 173 | while kb_path != keyboards_dir: |
127 | keymaps_dir = kb_path / "keymaps" | 174 | keymaps_dir = kb_path / "keymaps" |
128 | if keymaps_dir.exists(): | 175 | if keymaps_dir.exists(): |
129 | names = names.union([keymap for keymap in keymaps_dir.iterdir() if (keymaps_dir / keymap / "keymap.c").is_file()]) | 176 | names = names.union([keymap.name for keymap in keymaps_dir.iterdir() if is_keymap_dir(keymap)]) |
130 | kb_path = kb_path.parent | 177 | kb_path = kb_path.parent |
131 | 178 | ||
132 | # if community layouts are supported, get them | 179 | # if community layouts are supported, get them |
133 | if "LAYOUTS" in rules_mk: | 180 | if "LAYOUTS" in rules: |
134 | for layout in rules_mk["LAYOUTS"].split(): | 181 | for layout in rules["LAYOUTS"].split(): |
135 | cl_path = Path.cwd() / "layouts" / "community" / layout | 182 | cl_path = Path('layouts/community') / layout |
136 | if cl_path.exists(): | 183 | if cl_path.exists(): |
137 | names = names.union([keymap for keymap in cl_path.iterdir() if (cl_path / keymap / "keymap.c").is_file()]) | 184 | names = names.union([keymap.name for keymap in cl_path.iterdir() if is_keymap_dir(keymap)]) |
138 | 185 | ||
139 | return sorted(names) | 186 | return sorted(names) |