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

Enable linking of encoders to switch within layout macros #22264

Merged
merged 1 commit into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions data/schemas/keyboard.jsonschema
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@
"additionalProperties": false,
"required": ["x", "y"],
"properties": {
"encoder": {"$ref": "qmk.definitions.v1#/unsigned_int"},
"label": {
"type": "string",
"pattern": "^[^\\n]*$"
Expand Down
2 changes: 2 additions & 0 deletions docs/reference_info_json.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ The ISO enter key is represented by a 1.25u×2uh key. Renderers which utilize in
* `w`
* The width of the key, in key units.
* Default: `1` (1u)
* `encoder`
* The index of an encoder this key should be linked to
* Example: `{"label": "Shift", "matrix": [4, 0], "x": 0, "y": 4.25, "w": 2.25}`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Example: `{"label": "Shift", "matrix": [4, 0], "x": 0, "y": 4.25, "w": 2.25}`
* Example:
```json
{"label": "Shift", "matrix": [4, 0], "x": 0, "y": 4.25, "w": 2.25}
{"label": "Encoder", "encoder": 0, "matrix": [4, 1], "x": 2.25, "y": 4.25}
```

Added with an eye toward your "strategy on how to avoid user config errors". Since the approach seems pretty foolproof, the main way I see to try and head off user error at this point is to provide more positive examples.
Feel free to disregard.


## Leader Key :id=leader-key
Expand Down
2 changes: 1 addition & 1 deletion keyboards/drop/sense75/info.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
{"matrix": [0, 11], "label": "F11", "x": 11.75, "y": 0},
{"matrix": [0, 12], "label": "F12", "x": 12.75, "y": 0},
{"matrix": [0, 13], "label": "PrtSc", "x": 14, "y": 0},
{"matrix": [0, 14], "label": "Mute", "x": 15.25, "y": 0},
{"matrix": [0, 14], "encoder":0, "label": "Mute", "x": 15.25, "y": 0},
{"matrix": [1, 0], "label": "~", "x": 0, "y": 1.25},
{"matrix": [1, 1], "label": "!", "x": 1, "y": 1.25},
{"matrix": [1, 2], "label": "@", "x": 2, "y": 1.25},
Expand Down
28 changes: 28 additions & 0 deletions lib/python/qmk/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,29 @@ def _get_key_left_position(key):
return key['x'] - 0.25 if key.get('h', 1) == 2 and key.get('w', 1) == 1.25 else key['x']


def _find_invalid_encoder_index(info_data):
"""Perform additional validation of encoders
"""
enc_count = len(info_data.get('encoder', {}).get('rotary', []))
enc_count += len(info_data.get('split', {}).get('encoder', {}).get('right', {}).get('rotary', []))

ret = []
layouts = info_data.get('layouts', {})
for layout_name, layout_data in layouts.items():
found = set()
for key in layout_data['layout']:
if 'encoder' in key:
if enc_count == 0:
ret.append((layout_name, key['encoder'], 'non-configured'))
elif key['encoder'] >= enc_count:
ret.append((layout_name, key['encoder'], 'out of bounds'))
elif key['encoder'] in found:
ret.append((layout_name, key['encoder'], 'duplicate'))
found.add(key['encoder'])

return ret


def _additional_validation(keyboard, info_data):
"""Non schema checks
"""
Expand Down Expand Up @@ -105,6 +128,11 @@ def _additional_validation(keyboard, info_data):
if not decl.get("aliases", []):
_log_error(info_data, f'Keycode {decl["key"]} has no short form alias')

# encoder IDs in layouts must be in range and not duplicated
found = _find_invalid_encoder_index(info_data)
for layout_name, encoder_index, reason in found:
_log_error(info_data, f'Layout "{layout_name}" contains {reason} encoder index {encoder_index}.')


def _validate(keyboard, info_data):
"""Perform various validation on the provided info.json data
Expand Down
55 changes: 54 additions & 1 deletion lib/python/qmk/keyboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,28 @@
"h": "_",
},
}
ENC_DRAWING_CHARACTERS = {
"unicode": {
"tl": "╭",
"tr": "╮",
"bl": "╰",
"br": "╯",
"vl": "▲",
"vr": "▼",
"v": "│",
"h": "─",
},
"ascii": {
"tl": " ",
"tr": " ",
"bl": "\\",
"br": "/",
"v": "|",
"vl": "/",
"vr": "\\",
"h": "_",
},
}


class AllKeyboards:
Expand Down Expand Up @@ -217,7 +239,9 @@ def render_layout(layout_data, render_ascii, key_labels=None):
else:
label = key.get('label', '')

if x >= 0.25 and w == 1.25 and h == 2:
if 'encoder' in key:
render_encoder(textpad, x, y, w, h, label, style)
elif x >= 0.25 and w == 1.25 and h == 2:
render_key_isoenter(textpad, x, y, w, h, label, style)
elif w == 1.5 and h == 2:
render_key_baenter(textpad, x, y, w, h, label, style)
Expand Down Expand Up @@ -335,3 +359,32 @@ def render_key_baenter(textpad, x, y, w, h, label, style):
textpad[y + 3][x - 3:x + w] = crn_line
textpad[y + 4][x - 3:x + w] = lab_line
textpad[y + 5][x - 3:x + w] = bot_line


def render_encoder(textpad, x, y, w, h, label, style):
box_chars = ENC_DRAWING_CHARACTERS[style]
x = ceil(x * 4)
y = ceil(y * 3)
w = ceil(w * 4)
h = ceil(h * 3)

label_len = w - 2
label_leftover = label_len - len(label)

if len(label) > label_len:
label = label[:label_len]

label_blank = ' ' * label_len
label_border = box_chars['h'] * label_len
label_middle = label + ' ' * label_leftover

top_line = array('u', box_chars['tl'] + label_border + box_chars['tr'])
lab_line = array('u', box_chars['vl'] + label_middle + box_chars['vr'])
mid_line = array('u', box_chars['v'] + label_blank + box_chars['v'])
bot_line = array('u', box_chars['bl'] + label_border + box_chars['br'])

textpad[y][x:x + w] = top_line
textpad[y + 1][x:x + w] = lab_line
for i in range(h - 3):
textpad[y + i + 2][x:x + w] = mid_line
textpad[y + h - 1][x:x + w] = bot_line