Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encoder Support in CLI qmk compile #8440

Closed
wants to merge 33 commits into from
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
ef946cb
initial working on python cmd
Mar 15, 2020
9e01eba
merging functions using experimental flag
Mar 15, 2020
642041b
Adding UTs
Mar 16, 2020
a37f578
Adding some cleanup
Mar 16, 2020
4784180
Deleting test files
Mar 16, 2020
635a790
Docs update. Loc needed
Mar 16, 2020
4123646
full switch
Mar 16, 2020
91d393c
Merge branch 'master' into task/lharri/encodersupport
Mar 16, 2020
f68caf7
Changing dirs so the test works correctly
Mar 17, 2020
0d5d1d4
Fixing the json
Mar 17, 2020
e587ec2
Merge branch 'master' into task/lharri/encodersupport
Mar 17, 2020
824f382
PR comments and some optimizations
Mar 19, 2020
1ffd65a
Trying to fix the weird compilation issues on the build server
Mar 19, 2020
6c08c9c
Merge branch 'master' into task/lharri/encodersupport
Mar 21, 2020
5815756
Merge branch 'master' into task/lharri/encodersupport
Mar 21, 2020
cb091b6
Removing extra newline
Mar 22, 2020
c38807a
Merge branch 'master' into task/lharri/encodersupport
Mar 22, 2020
c3787c9
Updating tap_code to tap_code16 to accomadate modifiers per fauxpark …
Mar 22, 2020
b611fff
Enforcing basic keycode usage for encoder support per fauxpark
Mar 22, 2020
190b9d1
pyformat bullshirt
Mar 22, 2020
45cc806
Merge branch 'master' into task/lharri/encodersupport
Mar 23, 2020
bba5bd4
Merge branch 'master' into task/lharri/encodersupport
Mar 28, 2020
9099337
Merge branch 'master' into task/lharri/encodersupport
Apr 5, 2020
42bbe06
Changing test folder name
Apr 5, 2020
03375b2
Merge branch 'master' into task/lharri/encodersupport
Apr 5, 2020
f6778c7
Merge branch 'master' into task/lharri/encodersupport
Apr 5, 2020
9aac181
Merge branch 'master' into task/lharri/encodersupport
Apr 10, 2020
7039ca6
Merge branch 'master' into task/lharri/encodersupport
Apr 20, 2020
c9e379e
Erovia's Latest Comments
Apr 20, 2020
7f8afc3
Merge branch 'master' into task/lharri/encodersupport
Apr 21, 2020
946b042
Removing unnecessary changes
Apr 21, 2020
433361a
Hopefully bringing this back up to master
Dec 16, 2020
2c6cd2a
Some updates
Dec 16, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions keyboards/handwired/onekey/pytest/keymap.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"keyboard": "handwired/onekey/pytest",
"keymap": "pytest",
"layout": "LAYOUT",
"layers": [
[
"KC_ENTER"
]
],
"author": "",
"notes": "",
"encoders": [
{
"index": 0,
"clockwise": "KC_UP",
"counter": "KC_DOWN"
}
]
}
14 changes: 12 additions & 2 deletions lib/python/qmk/cli/compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@
from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json


@cli.argument('filename', nargs='?', arg_only=True, type=FileType('r'), help='The configurator export to compile')
xplusplus marked this conversation as resolved.
Show resolved Hide resolved
@cli.argument('filename', nargs='?', type=FileType('r'), help='The configurator export to compile')
@cli.argument('-kb', '--keyboard', help='The keyboard to build a firmware for. Ignored when a configurator export is supplied.')
@cli.argument('-km', '--keymap', help='The keymap to build a firmware for. Ignored when a configurator export is supplied.')
@cli.argument('-x', '--experimental', action='store_true', help='True enables encoder support for configurator export files. Only enabled when a configurator export is supplied.')
xplusplus marked this conversation as resolved.
Show resolved Hide resolved
@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.")
@cli.subcommand('Compile a QMK Firmware.')
@automagic_keyboard
Expand All @@ -29,11 +30,20 @@ def compile(cli):
command = None

if cli.args.filename:

# Warn the user if they are using experimental mode
if cli.args.experimental:
cli.log.info("{fg_yellow}Compiling in experimental mode! I hope you know what you're doing...")

# If a configurator JSON was provided generate a keymap and compile it
# FIXME(skullydazed): add code to check and warn if the keymap already exists when compiling a json keymap.

# Parse the configurator json
user_keymap = parse_configurator_json(cli.args.filename)
keymap_path = qmk.path.keymap(user_keymap['keyboard'])
command = compile_configurator_json(user_keymap)

# Compile the keymap
command = compile_configurator_json(user_keymap, experimental=cli.args.experimental)

cli.log.info('Wrote keymap to {fg_cyan}%s/%s/keymap.c', keymap_path, user_keymap['keymap'])

Expand Down
4 changes: 3 additions & 1 deletion lib/python/qmk/cli/flash.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ def flash(cli):
# Handle compiling a configurator JSON
user_keymap = parse_configurator_json(cli.args.filename)
keymap_path = qmk.path.keymap(user_keymap['keyboard'])
command = compile_configurator_json(user_keymap, cli.args.bootloader)

# Convert the JSON into a C file and write it to disk.
command = compile_configurator_json(user_keymap, bootloader=cli.args.bootloader)
xplusplus marked this conversation as resolved.
Show resolved Hide resolved

cli.log.info('Wrote keymap to {fg_cyan}%s/%s/keymap.c', keymap_path, user_keymap['keymap'])

Expand Down
10 changes: 8 additions & 2 deletions lib/python/qmk/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def create_make_command(keyboard, keymap, target=None):
return ['make', ':'.join(make_args)]


def compile_configurator_json(user_keymap, bootloader=None):
def compile_configurator_json(user_keymap, bootloader=None, experimental=False):
"""Convert a configurator export JSON file into a C file

Args:
Expand All @@ -42,12 +42,18 @@ def compile_configurator_json(user_keymap, bootloader=None):
bootloader
A bootloader to flash

experimental
True if the user wants to attempt compilation with encoder support.

Returns:

A command to run to compile and flash the C file.
"""
# Find the encoders, if any
encoders = None if 'encoders' not in user_keymap.keys() else user_keymap['encoders']
xplusplus marked this conversation as resolved.
Show resolved Hide resolved

# Write the keymap C file
qmk.keymap.write(user_keymap['keyboard'], user_keymap['keymap'], user_keymap['layout'], user_keymap['layers'])
qmk.keymap.write(user_keymap['keyboard'], user_keymap['keymap'], user_keymap['layout'], user_keymap['layers'], encoders, experimental)

# Return a command that can be run to make the keymap and flash if given
if bootloader is None:
Expand Down
77 changes: 71 additions & 6 deletions lib/python/qmk/keymap.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,34 @@
};
"""

DEFAULT_KEYMAP_ENCODERS_C = """#include QMK_KEYBOARD_H

def template(keyboard):
/* THIS FILE WAS GENERATED AND IS EXPERIMENTAL!
*
* This file was generated by qmk-compile-json. You may or may not want to
* edit it directly.
*/

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
__KEYMAP_GOES_HERE__
};

xplusplus marked this conversation as resolved.
Show resolved Hide resolved
void encoder_update_user(uint8_t index, bool clockwise) {
__ENCODERS_GO_HERE__
};
"""
xplusplus marked this conversation as resolved.
Show resolved Hide resolved

ENCODER_IF = """\t_ELIF_ (index == _INDEX_) {
\t\tif (clockwise) {
\t\t\ttap_code(_CLOCKWISE_);
\t\t} else {
\t\t\ttap_code(_COUNTER_);
\t\t}
\t}
"""
xplusplus marked this conversation as resolved.
Show resolved Hide resolved


def template(keyboard, experimental=False):
"""Returns the `keymap.c` template for a keyboard.

If a template exists in `keyboards/<keyboard>/templates/keymap.c` that
Expand All @@ -30,16 +56,21 @@ def template(keyboard):
Args:
keyboard
The keyboard to return a template for.

experimental
True if the user wants to attempt compilation with encoder support
"""
template_file = Path('keyboards/%s/templates/keymap.c' % keyboard)

if template_file.exists():
return template_file.read_text()
xplusplus marked this conversation as resolved.
Show resolved Hide resolved

if experimental:
return DEFAULT_KEYMAP_ENCODERS_C
return DEFAULT_KEYMAP_C


def generate(keyboard, layout, layers):
def generate(keyboard, layout, layers, encoders=None, experimental=False):
"""Returns a keymap.c for the specified keyboard, layout, and layers.

Args:
Expand All @@ -51,6 +82,13 @@ def generate(keyboard, layout, layers):

layers
An array of arrays describing the keymap. Each item in the inner array should be a string that is a valid QMK keycode.

encoders
EXPERIMENTAL
An array of encoders on the keyboard. Each item includes the index and the counter- and clockwise key codes.

experimental
True if the user wants to attempt compilation with encoder support
"""
layer_txt = []
for layer_num, layer in enumerate(layers):
Expand All @@ -60,12 +98,32 @@ def generate(keyboard, layout, layers):
layer_txt.append('\t[%s] = %s(%s)' % (layer_num, layout, layer_keys))

keymap = '\n'.join(layer_txt)
keymap_c = template(keyboard)
keymap_c = template(keyboard, experimental)

return keymap_c.replace('__KEYMAP_GOES_HERE__', keymap)
keymap_c = keymap_c.replace('__KEYMAP_GOES_HERE__', keymap)

if experimental:
encoder_function = ''
if encoders is not None:
xplusplus marked this conversation as resolved.
Show resolved Hide resolved
encoders_txt = []
for encoder_set in encoders:
elif_str = "else if"
if encoder_set['index'] == 0:
elif_str = "if"
xplusplus marked this conversation as resolved.
Show resolved Hide resolved

def write(keyboard, keymap, layout, layers):
curr_encoder = ENCODER_IF.replace('_ELIF_', elif_str)
xplusplus marked this conversation as resolved.
Show resolved Hide resolved
curr_encoder = curr_encoder.replace('_INDEX_', str(encoder_set['index']))
curr_encoder = curr_encoder.replace('_CLOCKWISE_', encoder_set['clockwise'])
curr_encoder = curr_encoder.replace('_COUNTER_', encoder_set['counter'])
encoders_txt.append(curr_encoder)
encoder_function = '\n'.join(encoders_txt)

keymap_c = keymap_c.replace('__ENCODERS_GO_HERE__', encoder_function)

return keymap_c


def write(keyboard, keymap, layout, layers, encoders=None, experimental=False):
"""Generate the `keymap.c` and write it to disk.

Returns the filename written to.
Expand All @@ -82,8 +140,15 @@ def write(keyboard, keymap, layout, layers):

layers
An array of arrays describing the keymap. Each item in the inner array should be a string that is a valid QMK keycode.

encoders
EXPERIMENTAL
An array of encoders on the keyboard. Each item includes the index and the counter- and clockwise key codes.

experimental
True if the user wants to attempt compilation with encoder support
"""
keymap_c = generate(keyboard, layout, layers)
keymap_c = generate(keyboard, layout, layers, encoders, experimental)
keymap_file = qmk.path.keymap(keyboard) / keymap / 'keymap.c'

keymap_file.parent.mkdir(parents=True, exist_ok=True)
Expand Down
8 changes: 8 additions & 0 deletions lib/python/qmk/tests/test_cli_commands.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import subprocess
import os


def check_subcommand(command, *args):
Expand All @@ -13,6 +14,13 @@ def test_cformat():

def test_compile():
assert check_subcommand('compile', '-kb', 'handwired/onekey/pytest', '-km', 'default').returncode == 0
assert check_subcommand('compile', 'keyboards/handwired/onekey/pytest/keymap.json').returncode == 0
assert check_subcommand('compile', 'keyboards/handwired/onekey/pytest/keymap.json', '-x').returncode == 0

# Cleanup
test_output = 'keyboards/handwired/onekey/keymaps/pytest/keymap.c'
if os.path.exists(test_output):
os.remove(test_output)


def test_flash():
Expand Down