-
Notifications
You must be signed in to change notification settings - Fork 67
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
Add option to show key under transparent keys, and find the layer name during parsing #67
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -25,7 +25,9 @@ def __init__( | |||||||
self.columns = columns if columns is not None else 0 | ||||||||
self.layer_names: list[str] | None = layer_names | ||||||||
self.base_keymap = base_keymap | ||||||||
self.layer_activated_from: dict[int, set[int]] = {} # layer to key positions | ||||||||
self.layer_activated_from: dict[ | ||||||||
int, set[tuple[int, int]] | ||||||||
] = {} # layer to [layer index, key position] from keys | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
self.conditional_layers: dict[int, list[int]] = {} # then-layer to if-layers mapping | ||||||||
self.trans_key = LayoutKey.from_key_spec(self.cfg.trans_legend) | ||||||||
self.raw_binding_map = self.cfg.raw_binding_map.copy() | ||||||||
|
@@ -53,7 +55,9 @@ def update_layer_activated_from( | |||||||
|
||||||||
if to_layer not in self.layer_activated_from: | ||||||||
self.layer_activated_from[to_layer] = set() | ||||||||
self.layer_activated_from[to_layer] |= set(key_positions) # came here through these key(s) | ||||||||
|
||||||||
for from_layer in from_layers: | ||||||||
self.layer_activated_from[to_layer] |= set((from_layer, key_pos) for key_pos in key_positions) | ||||||||
|
||||||||
# also consider how the layer we are coming from got activated | ||||||||
for from_layer in from_layers: | ||||||||
|
@@ -69,7 +73,7 @@ def add_held_keys(self, layers: dict[str, list[LayoutKey]]) -> dict[str, list[La | |||||||
|
||||||||
# assign held keys | ||||||||
for layer_index, activating_keys in self.layer_activated_from.items(): | ||||||||
for key_idx in activating_keys: | ||||||||
for _, key_idx in activating_keys: | ||||||||
key = layers[self.layer_names[layer_index]][key_idx] | ||||||||
if key == self.trans_key: # clear legend if it is a transparent key | ||||||||
layers[self.layer_names[layer_index]][key_idx] = LayoutKey(type="held") | ||||||||
|
@@ -78,6 +82,43 @@ def add_held_keys(self, layers: dict[str, list[LayoutKey]]) -> dict[str, list[La | |||||||
|
||||||||
return layers | ||||||||
|
||||||||
def fill_trans_keys(self, layers: dict[str, list[LayoutKey]]) -> dict[str, list[LayoutKey]]: | ||||||||
"""Fill in transparent keys with the legend of the key that is underneath.""" | ||||||||
assert self.layer_names is not None | ||||||||
|
||||||||
for layer_name, keys in layers.items(): | ||||||||
layer_idx = self.layer_names.index(layer_name) | ||||||||
for key_idx, key in enumerate(keys): | ||||||||
if key == self.trans_key: | ||||||||
lower_keys = self._find_lower_keys(layer_idx, key_idx, layers) | ||||||||
# usually there should only be one lower key, but if you can get to this layer | ||||||||
# that have this key defined, show all of them from multiple different layers | ||||||||
if len(lower_keys) > 0: | ||||||||
layers[layer_name][key_idx] = LayoutKey( | ||||||||
tap="|".join(key.tap for key in lower_keys), | ||||||||
hold="|".join(key.hold for key in lower_keys), | ||||||||
shifted="|".join(key.shifted for key in lower_keys), | ||||||||
type=self.trans_key.type, | ||||||||
) | ||||||||
return layers | ||||||||
|
||||||||
def _find_lower_keys(self, layer: int, key: int, layers: dict[str, list[LayoutKey]]) -> set[LayoutKey]: | ||||||||
assert self.layer_names is not None | ||||||||
|
||||||||
lower_keys = set() | ||||||||
activated_from_keys = self.layer_activated_from.get(layer, set()) | ||||||||
|
||||||||
for layer_idx, _ in activated_from_keys: | ||||||||
layer_name = self.layer_names[layer_idx] | ||||||||
from_layer = layers[layer_name] | ||||||||
Comment on lines
+112
to
+113
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
lower_key = from_layer[key] | ||||||||
if lower_key == self.trans_key: | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this comparison why the hash function is necessary? |
||||||||
lower_keys |= self._find_lower_keys(layer_idx, key, layers) | ||||||||
else: | ||||||||
lower_keys.add(lower_key) | ||||||||
|
||||||||
return lower_keys | ||||||||
|
||||||||
def _parse(self, in_str: str, file_name: str | None = None) -> tuple[dict, KeymapData]: | ||||||||
raise NotImplementedError | ||||||||
|
||||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -17,7 +17,7 @@ class QmkJsonParser(KeymapParser): | |||||
_tog_re = re.compile(r"(TG|TO|DF)\((\d+)\)") | ||||||
_mts_re = re.compile(r"([A-Z_]+)_T\((\S+)\)") | ||||||
_mtl_re = re.compile(r"MT\((\S+), *(\S+)\)") | ||||||
_lt_re = re.compile(r"LT\((\d+), *(\S+)\)") | ||||||
_lt_re = re.compile(r"LT\((\S+), *(\S+)\)") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure I understand how this happens, can you actually have layer name defines instead of indices in keymap.json? Do you use it alongside e.g. |
||||||
_osm_re = re.compile(r"OSM\(MOD_(\S+)\)") | ||||||
_osl_re = re.compile(r"OSL\((\d+)\)") | ||||||
|
||||||
|
@@ -50,23 +50,32 @@ def mapped(key: str) -> LayoutKey: | |||||
key = self._prefix_re.sub("", key) | ||||||
return LayoutKey.from_key_spec(self.cfg.qmk_keycode_map.get(key, key.replace("_", " "))) | ||||||
|
||||||
def parse_layer(layer: str) -> int: | ||||||
assert self.layer_names is not None | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I am not wrong, the only way we know layer names is still via user input, i.e.
Suggested change
|
||||||
|
||||||
if layer.isdigit(): | ||||||
return int(layer) | ||||||
return self.layer_names.index(layer) | ||||||
|
||||||
if m := self._trans_re.fullmatch(key_str): # transparent | ||||||
return self.trans_key | ||||||
if m := self._mo_re.fullmatch(key_str): # momentary layer | ||||||
to_layer = int(m.group(1).strip()) | ||||||
to_layer = parse_layer(m.group(1).strip()) | ||||||
self.update_layer_activated_from([current_layer], to_layer, key_positions) | ||||||
return LayoutKey(tap=self.layer_names[to_layer]) | ||||||
if m := self._tog_re.fullmatch(key_str): # toggled layer | ||||||
to_layer = int(m.group(2).strip()) | ||||||
to_layer = parse_layer(m.group(2).strip()) | ||||||
return LayoutKey(tap=self.layer_names[to_layer], hold=self.cfg.toggle_label) | ||||||
if m := self._mts_re.fullmatch(key_str): # short mod-tap syntax | ||||||
tap_key = mapped(m.group(2).strip()) | ||||||
return LayoutKey(tap=tap_key.tap, hold=m.group(1), shifted=tap_key.shifted) | ||||||
hold_key = mapped(m.group(1).strip()) | ||||||
return LayoutKey(tap=tap_key.tap, hold=hold_key.tap, shifted=tap_key.shifted) | ||||||
if m := self._mtl_re.fullmatch(key_str): # long mod-tap syntax | ||||||
tap_key = mapped(m.group(2).strip()) | ||||||
return LayoutKey(tap=tap_key.tap, hold=m.group(1).strip(), shifted=tap_key.shifted) | ||||||
hold_key = mapped(m.group(1).strip()) | ||||||
return LayoutKey(tap=tap_key.tap, hold=hold_key.tap, shifted=tap_key.shifted) | ||||||
if m := self._lt_re.fullmatch(key_str): # layer-tap | ||||||
to_layer = int(m.group(1).strip()) | ||||||
to_layer = parse_layer(m.group(1).strip()) | ||||||
self.update_layer_activated_from([current_layer], to_layer, key_positions) | ||||||
tap_key = mapped(m.group(2).strip()) | ||||||
return LayoutKey(tap=tap_key.tap, hold=self.layer_names[to_layer], shifted=tap_key.shifted) | ||||||
|
@@ -109,6 +118,10 @@ def _parse(self, in_str: str, file_name: str | None = None) -> tuple[dict, Keyma | |||||
} | ||||||
|
||||||
layers = self.add_held_keys(layers) | ||||||
|
||||||
if self.cfg.trans_show_lower_key: | ||||||
layers = self.fill_trans_keys(layers) | ||||||
|
||||||
keymap_data = KeymapData(layers=layers, layout=None, config=None) | ||||||
|
||||||
return layout, keymap_data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add an item to CONFIGURATION.md as well?