-
Notifications
You must be signed in to change notification settings - Fork 480
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The support is done via a class that consist of a mapping from KC to others. Such mapping are similar to what is done in QMK therefore a script is provided to bootstrap their definition. Existing doc on how to add internationla keycode is removed as those keycode are now all integrated in the base KC definition.
- Loading branch information
Showing
3 changed files
with
182 additions
and
29 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,43 @@ | ||
# International Keycodes | ||
International extension adds keys for non US layouts. It can simply be added to | ||
the extensions list. | ||
# Non QWERTY layout | ||
If your computer is not configured (at the OS level) to use the QWERTY layout, you will have a hard time making your layers as `KC.Q` will for example output an `a` on an azerty layout. | ||
|
||
To not have to deal yourself with all those translation we provide the `KeyMapConverter` class. It is intented to be subclassed for your layout, you then only have to define your mapping. | ||
|
||
The mapping is a relation: | ||
- from what you want to use in the keymap (= what you see on your keyboard key) | ||
- to what it should send as qwerty (= what your computer will print for this key if you set it up to use a QWERTY layout) | ||
|
||
|
||
## Example use | ||
For a french AZERTY layout you would have something like: | ||
|
||
file: /kmk/extensions/keymap_extras/keymap_french.py | ||
```python | ||
from kmk.extensions.international import International | ||
keyboard.extensions.append(International()) | ||
from kmk.keys import KC | ||
from kmk.extensions.keymap_extras.base import KeyMapConverter | ||
|
||
class AZERTY(KeyMapConverter): | ||
MAPPING = { | ||
'A': KC.Q, | ||
'Z': KC.W, | ||
'E': KC.E, | ||
'R': KC.R, | ||
'T': KC.T, | ||
'Y': KC.Y, | ||
... | ||
} | ||
``` | ||
|
||
## Keycodes | ||
|
||
|Key |Aliases |Description | | ||
|-----------------------|--------------------|-----------------------------------------------| | ||
|`KC.NONUS_HASH` |`KC.NUHS` |Non-US `#` and `~` | | ||
|`KC.NONUS_BSLASH` |`KC.NUBS` |Non-US `\` and <code>|</code> | | ||
|`KC.INT1` |`KC.RO` |JIS `\` and <code>|</code> | | ||
|`KC.INT2` |`KC.KANA` |JIS Katakana/Hiragana | | ||
|`KC.INT3` |`KC.JYEN` |JIS `¥` | | ||
|`KC.INT4` |`KC.HENK` |JIS Henkan | | ||
|`KC.INT5` |`KC.MHEN` |JIS Muhenkan | | ||
|`KC.INT6` | |JIS Numpad `,` | | ||
|`KC.INT7` | |International 7 | | ||
|`KC.INT8` | |International 8 | | ||
|`KC.INT9` | |International 9 | | ||
|`KC.LANG1` |`KC.HAEN` |Hangul/English | | ||
|`KC.LANG2` |`KC.HANJ` |Hanja | | ||
|`KC.LANG3` | |JIS Katakana | | ||
|`KC.LANG4` | |JIS Hiragana | | ||
|`KC.LANG5` | |JIS Zenkaku/Hankaku | | ||
|`KC.LANG6` | |Language 6 | | ||
|`KC.LANG7` | |Language 7 | | ||
|`KC.LANG8` | |Language 8 | | ||
|`KC.LANG9` | |Language 9 | | ||
file: /code.py | ||
```python | ||
from kmk.extensions.keymap_extras.keymap_french import AZERTY | ||
|
||
FR = AZERTY() | ||
keyboard.keymap = [[FR.A, FR.Z, FR.E, FR.R, FR.T, FR.Y, ...]] | ||
``` | ||
|
||
## Generating a missing layout | ||
Making such mapping is very tedious. The script in `/tools/mk_keymap.py` will generate such mapping from the existing one from the qmk repo. | ||
For the above example, you would start with the file generated by `/tools/mk_keymap.py french` | ||
|
||
Warning: The generated layout **need to be tested** and might need to be refined but that should save you quite some work. |
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,11 @@ | ||
from kmk.keys import KC | ||
|
||
|
||
class KeyMapConverter: | ||
''' Class to allow easy definition of alternative layout ''' | ||
|
||
def __getattr__(self, key): | ||
try: | ||
return self.MAPPING[key] | ||
except KeyError: | ||
return getattr(KC, key) |
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,134 @@ | ||
#!/usr/bin/env python3 | ||
|
||
import re | ||
import requests | ||
import sys | ||
from pathlib import Path | ||
|
||
try: | ||
from git import Repo | ||
|
||
repo = Repo('.', search_parent_directories=True) | ||
root = Path(repo.working_tree_dir) | ||
except ImportError: | ||
print( | ||
'could not import git (pip install gitpython). Assuming this is run from the top level of the repository' | ||
) | ||
root = Path('.') | ||
|
||
URL = 'https://github.com/qmk/qmk_firmware/file-list/master/quantum/keymap_extras' | ||
key_regexp = re.compile( | ||
r'^#define\s*(?P<slug>..)_(?P<new_keycode>\S*)\s*(?P<kc_keycode>\S*)(\s*//\s*(?P<comment>.*))?' | ||
) | ||
sep_regexp = re.compile(r'^/(/|\*)\s*(?P<comment>.*)') | ||
|
||
|
||
def list_qmk_keymap(): | ||
r = requests.get(URL) | ||
return set(re.findall(r'keymap_[^\./]*\.h', r.text)) | ||
|
||
|
||
def generate(keymap): | ||
print(f'using reference: {keymap}') | ||
r = requests.get( | ||
f'https://raw.githubusercontent.com/qmk/qmk_firmware/master/quantum/keymap_extras/{keymap}' | ||
) | ||
slug = '' | ||
content = [] | ||
seen = {} | ||
for line in r.text.split('\n'): | ||
key = re.search(key_regexp, line) | ||
sep = re.search(sep_regexp, line) | ||
if key: | ||
slug = key['slug'] | ||
kc = key['kc_keycode'] | ||
for i in range(10): | ||
kc = kc.replace(f'KC_{i}', f'KC.N{i}') | ||
kc = kc.replace('KC_', 'KC.') | ||
kc = kc.replace('S(', 'KC.LSFT(') | ||
kc = kc.replace('ALGR(', 'KC.RALT(') | ||
|
||
# expand self ref to previously defined keycode | ||
for m in re.finditer(slug + '_\w*', kc): | ||
try: | ||
kc = kc.replace(m.group(), seen[m.group()]) | ||
except KeyError: | ||
pass | ||
|
||
new = key['new_keycode'] | ||
if new.isdigit(): | ||
new = 'N' + new | ||
|
||
s = f" '{new}': {kc}," | ||
seen[slug + '_' + key['new_keycode']] = kc | ||
|
||
try: | ||
s += f" # {key['comment']}" | ||
except IndexError: | ||
pass | ||
content.append(s) | ||
|
||
elif sep and sep['comment']: | ||
if 'Copyright' in line or 'clang' in line: | ||
continue | ||
s = f" # {sep['comment']}" | ||
content.append(s) | ||
|
||
print(f'using slug: {slug}') | ||
name = re.search(r'[^_]*_(.*)\.h', keymap).group(1).upper() | ||
print( | ||
f"default class name: {name} (You might want to change it before submitting your generated file)" | ||
) | ||
|
||
layout = """from kmk.keys import KC | ||
from kmk.extensions.keymap_extras.base import KeyMapConverter | ||
class {}(KeyMapConverter): | ||
# Generated mapping from: | ||
# https://github.com/qmk/qmk_firmware/blob/master/quantum/keymap_extras/{} | ||
# might need some tweaking... | ||
MAPPING = {{ | ||
{} | ||
}} | ||
""".format( | ||
name, keymap, '\n'.join(content) | ||
) | ||
|
||
with open( | ||
root / 'kmk' / 'extensions' / 'keymap_extras' / keymap.replace('.h', '.py'), 'w' | ||
) as fp: | ||
fp.write(layout) | ||
|
||
|
||
if __name__ == '__main__': | ||
lang = sys.argv[1] if len(sys.argv) == 2 else '' | ||
|
||
if not lang: | ||
print( | ||
'You should pass an argument with a search term (probably your language abreviation), and if necessary refine it to select only one keymap.' | ||
) | ||
print( | ||
f'You can also consult {URL} to check the list and the files content first...' | ||
) | ||
sys.exit(1) | ||
|
||
choices = sorted(keymap for keymap in list_qmk_keymap() if lang in keymap) | ||
if not choices: | ||
print('Your search term is too restrictif. No keymap match it...') | ||
sys.exit(2) | ||
|
||
if lang + '.h' in choices: | ||
keymap = lang + '.h' | ||
elif 'keymap_' + lang + '.h' in choices: | ||
keymap = 'keymap_' + lang + '.h' | ||
elif len(choices) > 1: | ||
print('The following keymap match your given name:') | ||
print(choices), | ||
print('Please refine your search term.') | ||
sys.exit(0) | ||
else: | ||
keymap = choices[0] | ||
|
||
generate(keymap) |