forked from qmk/qmk_firmware
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add cli command to import keyboard|keymap|kbfirmware (qmk#16668)
- Loading branch information
1 parent
303a37a
commit e6f64ef
Showing
7 changed files
with
290 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from milc import cli | ||
|
||
from qmk.importers import import_kbfirmware as _import_kbfirmware | ||
from qmk.path import FileType | ||
from qmk.json_schema import json_load | ||
|
||
|
||
@cli.argument('filename', type=FileType('r'), nargs='+', arg_only=True, help='file') | ||
@cli.subcommand('Import kbfirmware json export') | ||
def import_kbfirmware(cli): | ||
filename = cli.args.filename[0] | ||
|
||
data = json_load(filename) | ||
|
||
cli.log.info(f'{{style_bright}}Importing {filename.name}.{{style_normal}}') | ||
cli.echo('') | ||
|
||
cli.log.warn("Support here is basic - Consider using 'qmk new-keyboard' instead") | ||
|
||
kb_name = _import_kbfirmware(data) | ||
|
||
cli.log.info(f'{{fg_green}}Imported a new keyboard named {{fg_cyan}}{kb_name}{{fg_green}}.{{fg_reset}}') | ||
cli.log.info(f'To start working on things, `cd` into {{fg_cyan}}keyboards/{kb_name}{{fg_reset}},') | ||
cli.log.info('or open the directory in your preferred text editor.') | ||
cli.log.info(f"And build with {{fg_yellow}}qmk compile -kb {kb_name} -km default{{fg_reset}}.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
from milc import cli | ||
|
||
from qmk.importers import import_keyboard as _import_keyboard | ||
from qmk.path import FileType | ||
from qmk.json_schema import json_load | ||
|
||
|
||
@cli.argument('filename', type=FileType('r'), nargs='+', arg_only=True, help='file') | ||
@cli.subcommand('Import data-driven keyboard') | ||
def import_keyboard(cli): | ||
filename = cli.args.filename[0] | ||
|
||
data = json_load(filename) | ||
|
||
cli.log.info(f'{{style_bright}}Importing {filename.name}.{{style_normal}}') | ||
cli.echo('') | ||
|
||
kb_name = _import_keyboard(data) | ||
|
||
cli.log.info(f'{{fg_green}}Imported a new keyboard named {{fg_cyan}}{kb_name}{{fg_green}}.{{fg_reset}}') | ||
cli.log.info(f'To start working on things, `cd` into {{fg_cyan}}keyboards/{kb_name}{{fg_reset}},') | ||
cli.log.info('or open the directory in your preferred text editor.') | ||
cli.log.info(f"And build with {{fg_yellow}}qmk compile -kb {kb_name} -km default{{fg_reset}}.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
from milc import cli | ||
|
||
from qmk.importers import import_keymap as _import_keymap | ||
from qmk.path import FileType | ||
from qmk.json_schema import json_load | ||
|
||
|
||
@cli.argument('filename', type=FileType('r'), nargs='+', arg_only=True, help='file') | ||
@cli.subcommand('Import data-driven keymap') | ||
def import_keymap(cli): | ||
filename = cli.args.filename[0] | ||
|
||
data = json_load(filename) | ||
|
||
cli.log.info(f'{{style_bright}}Importing {filename.name}.{{style_normal}}') | ||
cli.echo('') | ||
|
||
kb_name, km_name = _import_keymap(data) | ||
|
||
cli.log.info(f'{{fg_green}}Imported a new keymap named {{fg_cyan}}{km_name}{{fg_green}}.{{fg_reset}}') | ||
cli.log.info(f'To start working on things, `cd` into {{fg_cyan}}keyboards/{kb_name}/keymaps/{km_name}{{fg_reset}},') | ||
cli.log.info('or open the directory in your preferred text editor.') | ||
cli.log.info(f"And build with {{fg_yellow}}qmk compile -kb {kb_name} -km {km_name}{{fg_reset}}.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
from dotty_dict import dotty | ||
import json | ||
|
||
from qmk.json_schema import validate | ||
from qmk.path import keyboard, keymap | ||
from qmk.constants import MCU2BOOTLOADER | ||
from qmk.json_encoders import InfoJSONEncoder, KeymapJSONEncoder | ||
|
||
|
||
def _gen_dummy_keymap(name, info_data): | ||
# Pick the first layout macro and just dump in KC_NOs or something? | ||
(layout_name, layout_data), *_ = info_data["layouts"].items() | ||
layout_length = len(layout_data["layout"]) | ||
|
||
keymap_data = { | ||
"keyboard": name, | ||
"layout": layout_name, | ||
"layers": [["KC_NO" for _ in range(0, layout_length)]], | ||
} | ||
|
||
return json.dumps(keymap_data, cls=KeymapJSONEncoder) | ||
|
||
|
||
def import_keymap(keymap_data): | ||
# Validate to ensure we don't have to deal with bad data - handles stdin/file | ||
validate(keymap_data, 'qmk.keymap.v1') | ||
|
||
kb_name = keymap_data['keyboard'] | ||
km_name = keymap_data['keymap'] | ||
|
||
km_folder = keymap(kb_name) / km_name | ||
keyboard_keymap = km_folder / 'keymap.json' | ||
|
||
# This is the deepest folder in the expected tree | ||
keyboard_keymap.parent.mkdir(parents=True, exist_ok=True) | ||
|
||
# Dump out all those lovely files | ||
keyboard_keymap.write_text(json.dumps(keymap_data, cls=KeymapJSONEncoder)) | ||
|
||
return (kb_name, km_name) | ||
|
||
|
||
def import_keyboard(info_data): | ||
# Validate to ensure we don't have to deal with bad data - handles stdin/file | ||
validate(info_data, 'qmk.api.keyboard.v1') | ||
|
||
# And validate some more as everything is optional | ||
if not all(key in info_data for key in ['keyboard_name', 'layouts']): | ||
raise ValueError('invalid info.json') | ||
|
||
kb_name = info_data['keyboard_name'] | ||
|
||
# bail | ||
kb_folder = keyboard(kb_name) | ||
if kb_folder.exists(): | ||
raise ValueError(f'Keyboard {{fg_cyan}}{kb_name}{{fg_reset}} already exists! Please choose a different name.') | ||
|
||
keyboard_info = kb_folder / 'info.json' | ||
keyboard_rules = kb_folder / 'rules.mk' | ||
keyboard_keymap = kb_folder / 'keymaps' / 'default' / 'keymap.json' | ||
|
||
# This is the deepest folder in the expected tree | ||
keyboard_keymap.parent.mkdir(parents=True, exist_ok=True) | ||
|
||
# Dump out all those lovely files | ||
keyboard_info.write_text(json.dumps(info_data, cls=InfoJSONEncoder)) | ||
keyboard_rules.write_text("# This file intentionally left blank") | ||
keyboard_keymap.write_text(_gen_dummy_keymap(kb_name, info_data)) | ||
|
||
return kb_name | ||
|
||
|
||
def import_kbfirmware(kbfirmware_data): | ||
kbf_data = dotty(kbfirmware_data) | ||
|
||
diode_direction = ["COL2ROW", "ROW2COL"][kbf_data['keyboard.settings.diodeDirection']] | ||
mcu = ["atmega32u2", "atmega32u4", "at90usb1286"][kbf_data['keyboard.controller']] | ||
bootloader = MCU2BOOTLOADER.get(mcu, "custom") | ||
|
||
layout = [] | ||
for key in kbf_data['keyboard.keys']: | ||
layout.append({ | ||
"matrix": [key["row"], key["col"]], | ||
"x": key["state"]["x"], | ||
"y": key["state"]["y"], | ||
"w": key["state"]["w"], | ||
"h": key["state"]["h"], | ||
}) | ||
|
||
# convert to d/d info.json | ||
info_data = { | ||
"keyboard_name": kbf_data['keyboard.settings.name'].lower(), | ||
"manufacturer": "TODO", | ||
"maintainer": "TODO", | ||
"processor": mcu, | ||
"bootloader": bootloader, | ||
"diode_direction": diode_direction, | ||
"matrix_pins": { | ||
"cols": kbf_data['keyboard.pins.col'], | ||
"rows": kbf_data['keyboard.pins.row'], | ||
}, | ||
"usb": { | ||
"vid": "0xFEED", | ||
"pid": "0x0000", | ||
"device_version": "0.0.1", | ||
}, | ||
"features": { | ||
"bootmagic": True, | ||
"command": False, | ||
"console": False, | ||
"extrakey": True, | ||
"mousekey": True, | ||
"nkro": True, | ||
}, | ||
"layouts": { | ||
"LAYOUT": { | ||
"layout": layout, | ||
} | ||
} | ||
} | ||
|
||
if kbf_data['keyboard.pins.num'] or kbf_data['keyboard.pins.caps'] or kbf_data['keyboard.pins.scroll']: | ||
indicators = {} | ||
if kbf_data['keyboard.pins.num']: | ||
indicators['num_lock'] = kbf_data['keyboard.pins.num'] | ||
if kbf_data['keyboard.pins.caps']: | ||
indicators['caps_lock'] = kbf_data['keyboard.pins.caps'] | ||
if kbf_data['keyboard.pins.scroll']: | ||
indicators['scroll_lock'] = kbf_data['keyboard.pins.scroll'] | ||
info_data['indicators'] = indicators | ||
|
||
if kbf_data['keyboard.pins.rgb']: | ||
info_data['rgblight'] = { | ||
'animations': { | ||
'all': True | ||
}, | ||
'led_count': kbf_data['keyboard.settings.rgbNum'], | ||
'pin': kbf_data['keyboard.pins.rgb'], | ||
} | ||
|
||
if kbf_data['keyboard.pins.led']: | ||
info_data['backlight'] = { | ||
'levels': kbf_data['keyboard.settings.backlightLevels'], | ||
'pin': kbf_data['keyboard.pins.led'], | ||
} | ||
|
||
# delegate as if it were a regular keyboard import | ||
return import_keyboard(info_data) |