diff options
author | Nick Coutsos <[email protected]> | 2020-08-01 19:38:08 -0400 |
---|---|---|
committer | Nick Coutsos <[email protected]> | 2020-08-01 19:38:08 -0400 |
commit | f50c65e031cb52d0f37bb0280abdc6567412e56d (patch) | |
tree | be5cd7010f363d7e7bec1edaa96326b4c9c060f2 | |
download | keymap-editor-f50c65e031cb52d0f37bb0280abdc6567412e56d.tar.gz keymap-editor-f50c65e031cb52d0f37bb0280abdc6567412e56d.zip |
Initial commit
-rw-r--r-- | .gitignore | 80 | ||||
-rw-r--r-- | data/keycodes.json | 264 | ||||
-rw-r--r-- | data/keymap.json | 231 | ||||
-rw-r--r-- | data/layers.json | 56 | ||||
-rw-r--r-- | data/layout.json | 56 | ||||
-rw-r--r-- | index.html | 25 | ||||
-rw-r--r-- | keycodes.js | 41 | ||||
-rw-r--r-- | keymap.js | 97 | ||||
-rw-r--r-- | layers.js | 81 | ||||
-rw-r--r-- | layout.js | 43 | ||||
-rw-r--r-- | main.js | 75 | ||||
-rw-r--r-- | search.js | 109 | ||||
-rw-r--r-- | style.css | 139 |
13 files changed, 1297 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6214c43 --- /dev/null +++ b/.gitignore @@ -0,0 +1,80 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ diff --git a/data/keycodes.json b/data/keycodes.json new file mode 100644 index 0000000..c401591 --- /dev/null +++ b/data/keycodes.json @@ -0,0 +1,264 @@ +[ + { "code": "`KC_NO`", "aliases": ["`XXXXXXX`"], "description": "Ignore this key (NOOP)" }, + { "code": "`KC_TRANSPARENT`", "aliases": ["`KC_TRNS`", "`_______`"], "description": "Use the next lowest non-transparent key", "symbol": "∅" }, + { "code": "`KC_A`", "aliases": [ ], "description": "`a` and `A`" }, + { "code": "`KC_B`", "aliases": [ ], "description": "`b` and `B`" }, + { "code": "`KC_C`", "aliases": [ ], "description": "`c` and `C`" }, + { "code": "`KC_D`", "aliases": [ ], "description": "`d` and `D`" }, + { "code": "`KC_E`", "aliases": [ ], "description": "`e` and `E`" }, + { "code": "`KC_F`", "aliases": [ ], "description": "`f` and `F`" }, + { "code": "`KC_G`", "aliases": [ ], "description": "`g` and `G`" }, + { "code": "`KC_H`", "aliases": [ ], "description": "`h` and `H`" }, + { "code": "`KC_I`", "aliases": [ ], "description": "`i` and `I`" }, + { "code": "`KC_J`", "aliases": [ ], "description": "`j` and `J`" }, + { "code": "`KC_K`", "aliases": [ ], "description": "`k` and `K`" }, + { "code": "`KC_L`", "aliases": [ ], "description": "`l` and `L`" }, + { "code": "`KC_M`", "aliases": [ ], "description": "`m` and `M`" }, + { "code": "`KC_N`", "aliases": [ ], "description": "`n` and `N`" }, + { "code": "`KC_O`", "aliases": [ ], "description": "`o` and `O`" }, + { "code": "`KC_P`", "aliases": [ ], "description": "`p` and `P`" }, + { "code": "`KC_Q`", "aliases": [ ], "description": "`q` and `Q`" }, + { "code": "`KC_R`", "aliases": [ ], "description": "`r` and `R`" }, + { "code": "`KC_S`", "aliases": [ ], "description": "`s` and `S`" }, + { "code": "`KC_T`", "aliases": [ ], "description": "`t` and `T`" }, + { "code": "`KC_U`", "aliases": [ ], "description": "`u` and `U`" }, + { "code": "`KC_V`", "aliases": [ ], "description": "`v` and `V`" }, + { "code": "`KC_W`", "aliases": [ ], "description": "`w` and `W`" }, + { "code": "`KC_X`", "aliases": [ ], "description": "`x` and `X`" }, + { "code": "`KC_Y`", "aliases": [ ], "description": "`y` and `Y`" }, + { "code": "`KC_Z`", "aliases": [ ], "description": "`z` and `Z`" }, + { "code": "`KC_1`", "aliases": [ ], "description": "`1` and `!`" }, + { "code": "`KC_2`", "aliases": [ ], "description": "`2` and `@`" }, + { "code": "`KC_3`", "aliases": [ ], "description": "`3` and `#`" }, + { "code": "`KC_4`", "aliases": [ ], "description": "`4` and `$`" }, + { "code": "`KC_5`", "aliases": [ ], "description": "`5` and `%`" }, + { "code": "`KC_6`", "aliases": [ ], "description": "`6` and `^`" }, + { "code": "`KC_7`", "aliases": [ ], "description": "`7` and `&`" }, + { "code": "`KC_8`", "aliases": [ ], "description": "`8` and `*`" }, + { "code": "`KC_9`", "aliases": [ ], "description": "`9` and `(`" }, + { "code": "`KC_0`", "aliases": [ ], "description": "`0` and `)`" }, + { "code": "`KC_ENTER`", "aliases": ["`KC_ENT`"], "description": "Return (Enter)" }, + { "code": "`KC_ESCAPE`", "aliases": ["`KC_ESC`"], "description": "Escape" }, + { "code": "`KC_BSPACE`", "aliases": ["`KC_BSPC`"], "description": "Delete (Backspace)" }, + { "code": "`KC_TAB`", "aliases": [ ], "description": "Tab" }, + { "code": "`KC_SPACE`", "aliases": ["`KC_SPC`"], "description": "Spacebar" }, + { "code": "`KC_MINUS`", "aliases": ["`KC_MINS`"], "description": "`-` and `_`", "symbol": "-" }, + { "code": "`KC_EQUAL`", "aliases": ["`KC_EQL`"], "description": "`=` and `+`", "symbol": "+" }, + { "code": "`KC_LBRACKET`", "aliases": ["`KC_LBRC`"], "description": "`[` and `{`", "symbol": "[" }, + { "code": "`KC_RBRACKET`", "aliases": ["`KC_RBRC`"], "description": "`]` and `}`", "symbol": "]" }, + { "code": "`KC_BSLASH`", "aliases": ["`KC_BSLS`"], "description": "`\\` and `|`", "symbol": "\\" }, + { "code": "`KC_NONUS_HASH`", "aliases": ["`KC_NUHS`"], "description": "Non-US `#` and `~`", "symbol": "`" }, + { "code": "`KC_SCOLON`", "aliases": ["`KC_SCLN`"], "description": "`;` and `:`", "symbol": ";" }, + { "code": "`KC_QUOTE`", "aliases": ["`KC_QUOT`"], "description": "`'` and `\"`", "symbol": "'" }, + { "code": "`KC_GRAVE`", "aliases": ["`KC_GRV`", "`KC_ZKHK`"], "description": "<code>`</code> and `~`, JIS Zenkaku/Hankaku", "symbol": "~" }, + { "code": "`KC_COMMA`", "aliases": ["`KC_COMM`"], "description": "`,` and `<`", "symbol": "," }, + { "code": "`KC_DOT`", "aliases": [ ], "description": "`.` and `>`", "symbol": "." }, + { "code": "`KC_SLASH`", "aliases": ["`KC_SLSH`"], "description": "`/` and `?`", "symbol": "/" }, + { "code": "`KC_CAPSLOCK`", "aliases": ["`KC_CLCK`", "`KC_CAPS`"], "description": "Caps Lock" }, + { "code": "`KC_F1`", "aliases": [ ], "description": "F1" }, + { "code": "`KC_F2`", "aliases": [ ], "description": "F2" }, + { "code": "`KC_F3`", "aliases": [ ], "description": "F3" }, + { "code": "`KC_F4`", "aliases": [ ], "description": "F4" }, + { "code": "`KC_F5`", "aliases": [ ], "description": "F5" }, + { "code": "`KC_F6`", "aliases": [ ], "description": "F6" }, + { "code": "`KC_F7`", "aliases": [ ], "description": "F7" }, + { "code": "`KC_F8`", "aliases": [ ], "description": "F8" }, + { "code": "`KC_F9`", "aliases": [ ], "description": "F9" }, + { "code": "`KC_F10`", "aliases": [ ], "description": "F10" }, + { "code": "`KC_F11`", "aliases": [ ], "description": "F11" }, + { "code": "`KC_F12`", "aliases": [ ], "description": "F12" }, + { "code": "`KC_PSCREEN`", "aliases": ["`KC_PSCR`"], "description": "Print Screen" }, + { "code": "`KC_SCROLLLOCK`", "aliases": ["`KC_SLCK`", "`KC_BRMD`"], "description": "Scroll Lock, Brightness Down (macOS)" }, + { "code": "`KC_PAUSE`", "aliases": ["`KC_PAUS`", "`KC_BRK`", "`KC_BRMU`"], "description": "Pause, Brightness Up (macOS)" }, + { "code": "`KC_INSERT`", "aliases": ["`KC_INS`"], "description": "Insert" }, + { "code": "`KC_HOME`", "aliases": [ ], "description": "Home" }, + { "code": "`KC_PGUP`", "aliases": [ ], "description": "Page Up" }, + { "code": "`KC_DELETE`", "aliases": ["`KC_DEL`"], "description": "Forward Delete" }, + { "code": "`KC_END`", "aliases": [ ], "description": "End" }, + { "code": "`KC_PGDOWN`", "aliases": ["`KC_PGDN`"], "description": "Page Down", "symbol": "PgDn" }, + { "code": "`KC_RIGHT`", "aliases": ["`KC_RGHT`"], "description": "Right Arrow", "symbol": "►" }, + { "code": "`KC_LEFT`", "aliases": [ ], "description": "Left Arrow", "symbol": "◀︎" }, + { "code": "`KC_DOWN`", "aliases": [ ], "description": "Down Arrow", "symbol": "▼" }, + { "code": "`KC_UP`", "aliases": [ ], "description": "Up Arrow", "symbol": "▲" }, + { "code": "`KC_NUMLOCK`", "aliases": ["`KC_NLCK`"], "description": "Keypad Num Lock and Clear" }, + { "code": "`KC_KP_SLASH`", "aliases": ["`KC_PSLS`"], "description": "Keypad `/`", "symbol": "/" }, + { "code": "`KC_KP_ASTERISK`", "aliases": ["`KC_PAST`"], "description": "Keypad `*`" }, + { "code": "`KC_KP_MINUS`", "aliases": ["`KC_PMNS`"], "description": "Keypad `-`" }, + { "code": "`KC_KP_PLUS`", "aliases": ["`KC_PPLS`"], "description": "Keypad `+`" }, + { "code": "`KC_KP_ENTER`", "aliases": ["`KC_PENT`"], "description": "Keypad Enter" }, + { "code": "`KC_KP_1`", "aliases": ["`KC_P1`"], "description": "Keypad `1` and End" }, + { "code": "`KC_KP_2`", "aliases": ["`KC_P2`"], "description": "Keypad `2` and Down Arrow" }, + { "code": "`KC_KP_3`", "aliases": ["`KC_P3`"], "description": "Keypad `3` and Page Down" }, + { "code": "`KC_KP_4`", "aliases": ["`KC_P4`"], "description": "Keypad `4` and Left Arrow" }, + { "code": "`KC_KP_5`", "aliases": ["`KC_P5`"], "description": "Keypad `5`" }, + { "code": "`KC_KP_6`", "aliases": ["`KC_P6`"], "description": "Keypad `6` and Right Arrow" }, + { "code": "`KC_KP_7`", "aliases": ["`KC_P7`"], "description": "Keypad `7` and Home" }, + { "code": "`KC_KP_8`", "aliases": ["`KC_P8`"], "description": "Keypad `8` and Up Arrow" }, + { "code": "`KC_KP_9`", "aliases": ["`KC_P9`"], "description": "Keypad `9` and Page Up" }, + { "code": "`KC_KP_0`", "aliases": ["`KC_P0`"], "description": "Keypad `0` and Insert" }, + { "code": "`KC_KP_DOT`", "aliases": ["`KC_PDOT`"], "description": "Keypad `.` and Delete" }, + { "code": "`KC_NONUS_BSLASH`", "aliases": ["`KC_NUBS`"], "description": "Non-US `\\` and `|`" }, + { "code": "`KC_APPLICATION`", "aliases": ["`KC_APP`"], "description": "Application (Windows Context Menu Key)" }, + { "code": "`KC_POWER`", "aliases": [ ], "description": "System Power" }, + { "code": "`KC_KP_EQUAL`", "aliases": ["`KC_PEQL`"], "description": "Keypad `=`", "symbol": "=" }, + { "code": "`KC_F13`", "aliases": [ ], "description": "F13" }, + { "code": "`KC_F14`", "aliases": [ ], "description": "F14" }, + { "code": "`KC_F15`", "aliases": [ ], "description": "F15" }, + { "code": "`KC_F16`", "aliases": [ ], "description": "F16" }, + { "code": "`KC_F17`", "aliases": [ ], "description": "F17" }, + { "code": "`KC_F18`", "aliases": [ ], "description": "F18" }, + { "code": "`KC_F19`", "aliases": [ ], "description": "F19" }, + { "code": "`KC_F20`", "aliases": [ ], "description": "F20" }, + { "code": "`KC_F21`", "aliases": [ ], "description": "F21" }, + { "code": "`KC_F22`", "aliases": [ ], "description": "F22" }, + { "code": "`KC_F23`", "aliases": [ ], "description": "F23" }, + { "code": "`KC_F24`", "aliases": [ ], "description": "F24" }, + { "code": "`KC_EXECUTE`", "aliases": ["`KC_EXEC`"], "description": "Execute" }, + { "code": "`KC_HELP`", "aliases": [ ], "description": "Help" }, + { "code": "`KC_MENU`", "aliases": [ ], "description": "Menu" }, + { "code": "`KC_SELECT`", "aliases": ["`KC_SLCT`"], "description": "Select" }, + { "code": "`KC_STOP`", "aliases": [ ], "description": "Stop" }, + { "code": "`KC_AGAIN`", "aliases": ["`KC_AGIN`"], "description": "Again" }, + { "code": "`KC_UNDO`", "aliases": [ ], "description": "Undo" }, + { "code": "`KC_CUT`", "aliases": [ ], "description": "Cut" }, + { "code": "`KC_COPY`", "aliases": [ ], "description": "Copy" }, + { "code": "`KC_PASTE`", "aliases": ["`KC_PSTE`"], "description": "Paste" }, + { "code": "`KC_FIND`", "aliases": [ ], "description": "Find" }, + { "code": "`KC__MUTE`", "aliases": [ ], "description": "Mute" }, + { "code": "`KC__VOLUP`", "aliases": [ ], "description": "Volume Up" }, + { "code": "`KC__VOLDOWN`", "aliases": [ ], "description": "Volume Down" }, + { "code": "`KC_LOCKING_CAPS`", "aliases": ["`KC_LCAP`"], "description": "Locking Caps Lock" }, + { "code": "`KC_LOCKING_NUM`", "aliases": ["`KC_LNUM`"], "description": "Locking Num Lock" }, + { "code": "`KC_LOCKING_SCROLL`", "aliases": ["`KC_LSCR`"], "description": "Locking Scroll Lock" }, + { "code": "`KC_KP_COMMA`", "aliases": ["`KC_PCMM`"], "description": "Keypad `,`" }, + { "code": "`KC_KP_EQUAL_AS400`", "aliases": [ ], "description": "Keypad `=` on AS/400 keyboards" }, + { "code": "`KC_INT1`", "aliases": ["`KC_RO`"], "description": "JIS `\\` and `_`" }, + { "code": "`KC_INT2`", "aliases": ["`KC_KANA`"], "description": "JIS Katakana/Hiragana" }, + { "code": "`KC_INT3`", "aliases": ["`KC_JYEN`"], "description": "JIS `¥` and `|`" }, + { "code": "`KC_INT4`", "aliases": ["`KC_HENK`"], "description": "JIS Henkan" }, + { "code": "`KC_INT5`", "aliases": ["`KC_MHEN`"], "description": "JIS Muhenkan" }, + { "code": "`KC_INT6`", "aliases": [ ], "description": "JIS Numpad `,`" }, + { "code": "`KC_INT7`", "aliases": [ ], "description": "International 7" }, + { "code": "`KC_INT8`", "aliases": [ ], "description": "International 8" }, + { "code": "`KC_INT9`", "aliases": [ ], "description": "International 9" }, + { "code": "`KC_LANG1`", "aliases": ["`KC_HAEN`"], "description": "Hangul/English" }, + { "code": "`KC_LANG2`", "aliases": ["`KC_HANJ`"], "description": "Hanja" }, + { "code": "`KC_LANG3`", "aliases": [ ], "description": "JIS Katakana" }, + { "code": "`KC_LANG4`", "aliases": [ ], "description": "JIS Hiragana" }, + { "code": "`KC_LANG5`", "aliases": [ ], "description": "JIS Zenkaku/Hankaku" }, + { "code": "`KC_LANG6`", "aliases": [ ], "description": "Language 6" }, + { "code": "`KC_LANG7`", "aliases": [ ], "description": "Language 7" }, + { "code": "`KC_LANG8`", "aliases": [ ], "description": "Language 8" }, + { "code": "`KC_LANG9`", "aliases": [ ], "description": "Language 9" }, + { "code": "`KC_ALT_ERASE`", "aliases": ["`KC_ERAS`"], "description": "Alternate Erase" }, + { "code": "`KC_SYSREQ`", "aliases": [ ], "description": "SysReq/Attention" }, + { "code": "`KC_CANCEL`", "aliases": [ ], "description": "Cancel" }, + { "code": "`KC_CLEAR`", "aliases": ["`KC_CLR`"], "description": "Clear" }, + { "code": "`KC_PRIOR`", "aliases": [ ], "description": "Prior" }, + { "code": "`KC_RETURN`", "aliases": [ ], "description": "Return" }, + { "code": "`KC_SEPARATOR`", "aliases": [ ], "description": "Separator" }, + { "code": "`KC_OUT`", "aliases": [ ], "description": "Out" }, + { "code": "`KC_OPER`", "aliases": [ ], "description": "Oper" }, + { "code": "`KC_CLEAR_AGAIN`", "aliases": [ ], "description": "Clear/Again" }, + { "code": "`KC_CRSEL`", "aliases": [ ], "description": "CrSel/Props" }, + { "code": "`KC_EXSEL`", "aliases": [ ], "description": "ExSel" }, + { "code": "`KC_LCTRL`", "aliases": ["`KC_LCTL`"], "description": "Left Control", "isModifier": true }, + { "code": "`KC_LSHIFT`", "aliases": ["`KC_LSFT`"], "description": "Left Shift", "isModifier": true }, + { "code": "`KC_LALT`", "aliases": ["`KC_LOPT`"], "description": "Left Alt (Option)", "symbol": "⌥", "isModifier": true }, + { "code": "`KC_LGUI`", "aliases": ["`KC_LCMD`", "`KC_LWIN`"], "description": "Left GUI (Windows/Command/Meta key)", "symbol": "⌘", "isModifier": true }, + { "code": "`KC_RCTRL`", "aliases": ["`KC_RCTL`"], "description": "Right Control", "isModifier": true }, + { "code": "`KC_RSHIFT`", "aliases": ["`KC_RSFT`"], "description": "Right Shift", "isModifier": true }, + { "code": "`KC_RALT`", "aliases": ["`KC_ROPT`", "`KC_ALGR`"], "description": "Right Alt (Option/AltGr)", "symbol": "⌥", "isModifier": true }, + { "code": "`KC_RGUI`", "aliases": ["`KC_RCMD`", "`KC_RWIN`"], "description": "Right GUI (Windows/Command/Meta key)", "symbol": "⌘", "isModifier": true }, + { "code": "`KC_SYSTEM_POWER`", "aliases": ["`KC_PWR`"], "description": "System Power Down" }, + { "code": "`KC_SYSTEM_SLEEP`", "aliases": ["`KC_SLEP`"], "description": "System Sleep" }, + { "code": "`KC_SYSTEM_WAKE`", "aliases": ["`KC_WAKE`"], "description": "System Wake" }, + { "code": "`KC_AUDIO_MUTE`", "aliases": ["`KC_MUTE`"], "description": "Mute" }, + { "code": "`KC_AUDIO_VOL_UP`", "aliases": ["`KC_VOLU`"], "description": "Volume Up" }, + { "code": "`KC_AUDIO_VOL_DOWN`", "aliases": ["`KC_VOLD`"], "description": "Volume Down" }, + { "code": "`KC_MEDIA_NEXT_TRACK`", "aliases": ["`KC_MNXT`"], "description": "Next Track" }, + { "code": "`KC_MEDIA_PREV_TRACK`", "aliases": ["`KC_MPRV`"], "description": "Previous Track" }, + { "code": "`KC_MEDIA_STOP`", "aliases": ["`KC_MSTP`"], "description": "Stop Track" }, + { "code": "`KC_MEDIA_PLAY_PAUSE`", "aliases": ["`KC_MPLY`"], "description": "Play/Pause Track" }, + { "code": "`KC_MEDIA_SELECT`", "aliases": ["`KC_MSEL`"], "description": "Launch Media Player" }, + { "code": "`KC_MEDIA_EJECT`", "aliases": ["`KC_EJCT`"], "description": "Eject" }, + { "code": "`KC_MAIL`", "aliases": [ ], "description": "Launch Mail" }, + { "code": "`KC_CALCULATOR`", "aliases": ["`KC_CALC`"], "description": "Launch Calculator" }, + { "code": "`KC_MY_COMPUTER`", "aliases": ["`KC_MYCM`"], "description": "Launch My Computer" }, + { "code": "`KC_WWW_SEARCH`", "aliases": ["`KC_WSCH`"], "description": "Browser Search" }, + { "code": "`KC_WWW_HOME`", "aliases": ["`KC_WHOM`"], "description": "Browser Home" }, + { "code": "`KC_WWW_BACK`", "aliases": ["`KC_WBAK`"], "description": "Browser Back" }, + { "code": "`KC_WWW_FORWARD`", "aliases": ["`KC_WFWD`"], "description": "Browser Forward" }, + { "code": "`KC_WWW_STOP`", "aliases": ["`KC_WSTP`"], "description": "Browser Stop" }, + { "code": "`KC_WWW_REFRESH`", "aliases": ["`KC_WREF`"], "description": "Browser Refresh" }, + { "code": "`KC_WWW_FAVORITES`", "aliases": ["`KC_WFAV`"], "description": "Browser Favorites" }, + { "code": "`KC_MEDIA_FAST_FORWARD`", "aliases": ["`KC_MFFD`"] , "description": "Next Track" }, + { "code": "`KC_MEDIA_REWIND`", "aliases": ["`KC_MRWD`"], "description": "Previous Track" }, + { "code": "`KC_BRIGHTNESS_UP`", "aliases": ["`KC_BRIU`"], "description": "Brightness Up" }, + { "code": "`KC_BRIGHTNESS_DOWN`", "aliases": ["`KC_BRID`"], "description": "Brightness Down" }, + + { "code": "`RESET`", "aliases": [], "description": "Put the keyboard into bootloader mode for flashing" }, + { "code": "`DEBUG`", "aliases": [], "description": "Toggle debug mode" }, + { "code": "`EEPROM_RESET`", "aliases": ["`EEP_RST`"], "description": "Reinitializes the keyboard's EEPROM (persistent memory)" }, + + { "code": "`DF(layer)`", "description": "Set the base (default) layer" }, + { "code": "`MO(layer)`", "description": "Momentarily turn on `layer` when pressed (requires `KC_TRNS` on destination layer" }, + { "code": "`OSL(layer)`", "description": "Momentarily activates `layer` until a key is pressed. See [One Shot Keys](one_shot_keys.md) for details." }, + { "code": "`LM(layer, mod)`", "description": "Momentarily turn on `layer` (like MO) with `mod` active as well. Where `mod` is a mods_bit. Mods can be viewed [here](mod_tap.md). Example Implementation: `LM(LAYER_1, MOD_LALT)`" }, + { "code": "`LT(layer, kc)`", "description": "Turn on `layer` when held, `kc` when tapped" }, + { "code": "`TG(layer)`", "description": "Toggle `layer` on or off" }, + { "code": "`TO(layer)`", "description": "Turns on `layer` and turns off all other layers, except the default layer" }, + { "code": "`TT(layer)`", "description": "Normally acts like MO unless it's tapped multiple times, which toggles `layer` on" }, + + { "code": "`LCTL(kc)`", "aliases": [], "description": "Hold Left Control and press `kc`" }, + { "code": "`LSFT(kc)`", "aliases": [], "description": "Hold Left Shift and press `kc`", "symbol": "⇧" }, + { "code": "`LALT(kc)`", "aliases": ["`LOPT(kc)`"], "description": "Hold Left Alt and press `kc`" }, + { "code": "`LGUI(kc)`", "aliases": ["`LCMD(kc)`", "`LWIN(kc)`"], "description": "Hold Left GUI and press `kc`", "symbol": "⌘" }, + { "code": "`RCTL(kc)`", "description": "Hold Right Control and press `kc`" }, + { "code": "`RSFT(kc)`", "description": "Hold Right Shift and press `kc`", "symbol": "⇧" }, + { "code": "`RALT(kc)`", "aliases": ["`ROPT(kc)`", "`ALGR(kc)`"], "description": "Hold Right Alt and press `kc`" }, + { "code": "`RGUI(kc)`", "aliases": ["`RCMD(kc)`", "`LWIN(kc)`"], "description": "Hold Right GUI and press `kc`", "symbol": "⌘" }, + { "code": "`SGUI(kc)`", "aliases": ["`SCMD(kc)`", "`SWIN(kc)`"], "description": "Hold Left Shift and GUI and press `kc`" }, + { "code": "`LCA(kc)`", "description": "Hold Left Control and Alt and press `kc`" }, + { "code": "`LCAG(kc)`", "description": "Hold Left Control, Alt and GUI and press `kc`" }, + { "code": "`MEH(kc)`", "description": "Hold Left Control, Shift and Alt and press `kc`" }, + { "code": "`HYPR(kc)`", "description": "Hold Left Control, Shift, Alt and GUI and press `kc`" }, + { "code": "`KC_MEH`", "description": "Left Control, Shift and Alt" }, + { "code": "`KC_HYPR`", "description": "Left Control, Shift, Alt and GUI" }, + + { "code": "`MT(mod, kc)`", "description": "`mod` when held, `kc` when tapped" }, + { "code": "`LCTL_T(kc)`", "aliases": ["`CTL_T(kc)`"], "description": "Left Control when held, `kc` when tapped" }, + { "code": "`LSFT_T(kc)`", "aliases": ["`SFT_T(kc)`"], "description": "Left Shift when held, `kc` when tapped" }, + { "code": "`LALT_T(kc)`", "aliases": ["`LOPT_T(kc)`", "`ALT_T(kc)`", "`OPT_T(kc)`"], "description": "Left Alt when held, `kc` when tapped" }, + { "code": "`LGUI_T(kc)`", "aliases": ["`LCMD_T(kc)`", "`LWIN_T(kc)`", "`GUI_T(kc)`", "`CMD_T(kc)`", "`WIN_T(kc)`"], "description": "Left GUI when held, `kc` when tapped" }, + { "code": "`RCTL_T(kc)`", "description": "Right Control when held, `kc` when tapped" }, + { "code": "`RSFT_T(kc)`", "description": "Right Shift when held, `kc` when tapped" }, + { "code": "`RALT_T(kc)`", "aliases": ["`ROPT_T(kc)`", "`ALGR_T(kc)`"], "description": "Right Alt when held, `kc` when tapped" }, + { "code": "`RGUI_T(kc)`", "aliases": ["`RCMD_T(kc)`", "`RWIN_T(kc)`"], "description": "Right GUI when held, `kc` when tapped" }, + { "code": "`SGUI_T(kc)`", "aliases": ["`SCMD_T(kc)`", "`SWIN_T(kc)`"], "description": "Left Shift and GUI when held, `kc` when tapped" }, + { "code": "`LCA_T(kc)`", "description": "Left Control and Alt when held, `kc` when tapped" }, + { "code": "`LCAG_T(kc)`", "description": "Left Control, Alt and GUI when held, `kc` when tapped" }, + { "code": "`RCAG_T(kc)`", "description": "Right Control, Alt and GUI when held, `kc` when tapped" }, + { "code": "`C_S_T(kc)`", "description": "Left Control and Shift when held, `kc` when tapped" }, + { "code": "`MEH_T(kc)`", "description": "Left Control, Shift and Alt when held, `kc` when tapped" }, + { "code": "`HYPR_T(kc)`", "aliases": ["`ALL_T(kc)`"], "description": "Left Control, Shift, Alt and GUI when held, `kc` when tapped - more info [here](http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/)" }, + + { "code": "`RGB_TOG`", "description": "Toggle RGB lighting on or off" }, + { "code": "`RGB_MODE_FORWARD`", "aliases": ["`RGB_MOD`"], "description": "Cycle through modes, reverse direction when Shift is held" }, + { "code": "`RGB_MODE_REVERSE`", "aliases": ["`RGB_RMOD`"], "description": "Cycle through modes in reverse, forward direction when Shift is held" }, + { "code": "`RGB_HUI`", "description": "Increase hue, decrease hue when Shift is held" }, + { "code": "`RGB_HUD`", "description": "Decrease hue, increase hue when Shift is held" }, + { "code": "`RGB_SAI`", "description": "Increase saturation, decrease saturation when Shift is held" }, + { "code": "`RGB_SAD`", "description": "Decrease saturation, increase saturation when Shift is held" }, + { "code": "`RGB_VAI`", "description": "Increase value (brightness), decrease value when Shift is held" }, + { "code": "`RGB_VAD`", "description": "Decrease value (brightness), increase value when Shift is held" }, + { "code": "`RGB_SPI`", "description": "Increase effect speed (does not support eeprom yet), decrease speed when Shift is held" }, + { "code": "`RGB_SPD`", "description": "Decrease effect speed (does not support eeprom yet), increase speed when Shift is held" }, + { "code": "`KC_LCPO`", "description": "Left Control when held, `(` when tapped" }, + { "code": "`KC_RCPC`", "description": "Right Control when held, `)` when tapped" }, + { "code": "`KC_LSPO`", "description": "Left Shift when held, `(` when tapped", "symbol": "⇧/(" }, + { "code": "`KC_RSPC`", "description": "Right Shift when held, `)` when tapped", "symbol": "⇧/)" }, + { "code": "`KC_LAPO`", "description": "Left Alt when held, `(` when tapped" }, + { "code": "`KC_RAPC`", "description": "Right Alt when held, `)` when tapped" }, + { "code": "`KC_SFTENT`", "description": "Right Shift when held, Enter when tapped" } +] diff --git a/data/keymap.json b/data/keymap.json new file mode 100644 index 0000000..c8678a6 --- /dev/null +++ b/data/keymap.json @@ -0,0 +1,231 @@ +{ + "keyboard": "handwired/dactyl_reduced", + "keymap": "default", + "layout": "LAYOUT", + "layers": [ + [ + "KC_TAB", + "KC_Q", + "KC_W", + "KC_E", + "KC_R", + "KC_T", + "KC_Y", + "KC_U", + "KC_I", + "KC_O", + "KC_P", + "KC_BSLS", + "KC_CAPS", + "KC_A", + "KC_S", + "KC_D", + "KC_F", + "KC_G", + "KC_H", + "KC_J", + "KC_K", + "KC_L", + "LT(2,KC_SCLN)", + "KC_QUOT", + "KC_LSPO", + "KC_Z", + "KC_X", + "KC_C", + "KC_V", + "KC_B", + "KC_N", + "KC_M", + "KC_COMM", + "KC_DOT", + "KC_SLSH", + "KC_RSPC", + "KC_LCTL", + "KC_LEFT", + "KC_RGHT", + "KC_DOWN", + "KC_UP", + "KC_LBRC", + "KC_LCTL", + "KC_BSPC", + "KC_RALT", + "KC_ESC", + "KC_LALT", + "KC_LGUI", + "MO(1)", + "KC_PGUP", + "KC_ENT", + "KC_SPC", + "MO(2)", + "KC_PGDN" + ], + [ + "KC_TRNS", + "KC_TRNS", + "KC_GRAVE", + "KC_MINS", + "KC_EQL", + "KC_TRNS", + "KC_LBRC", + "KC_7", + "KC_8", + "KC_9", + "KC_RBRC", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_KP_PLUS", + "KC_4", + "KC_5", + "KC_6", + "KC_KP_ASTERISK", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_KP_MINUS", + "KC_1", + "KC_2", + "KC_3", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_0", + "KC_DOT", + "KC_TRNS", + "KC_TRNS", + "KC_LCMD", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_LSHIFT", + "KC_TRNS" + ], + [ + "RESET", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "LCMD(KC_LBRC)", + "LCMD(LSFT(KC_LBRC))", + "LCMD(LSFT(KC_RBRC))", + "LCMD(KC_RBRC)", + "KC_TRNS", + "KC_TRNS", + "RGB_MODE_FORWARD", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_F8", + "KC_F9", + "KC_F7", + "LCMD(LALT(KC_GRAVE))", + "KC_TRNS", + "KC_TRNS", + "RGB_HUI", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC__VOLDOWN", + "KC__VOLUP", + "KC__MUTE", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS" + ], + [ + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_F7", + "KC_F8", + "KC_F9", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_F4", + "KC_F5", + "KC_F6", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_F1", + "KC_F2", + "KC_F3", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS", + "KC_TRNS" + ] + ] +}
\ No newline at end of file diff --git a/data/layers.json b/data/layers.json new file mode 100644 index 0000000..3edf07b --- /dev/null +++ b/data/layers.json @@ -0,0 +1,56 @@ +[ + { "code": "KC_TAB" }, + { "code": "KC_Q" }, + { "code": "KC_W" }, + { "code": "KC_E" }, + { "code": "KC_R" }, + { "code": "KC_T" }, + { "code": "KC_Y" }, + { "code": "KC_U" }, + { "code": "KC_I" }, + { "code": "KC_O" }, + { "code": "KC_P" }, + { "code": "KC_BSLS" }, + { "code": "KC_CAPS" }, + { "code": "KC_A" }, + { "code": "KC_S" }, + { "code": "KC_D" }, + { "code": "KC_F" }, + { "code": "KC_G" }, + { "code": "KC_H" }, + { "code": "KC_J" }, + { "code": "KC_K" }, + { "code": "KC_L" }, + { "code": "LT(2, KC_SCLN)" }, + { "code": "KC_QUOT" }, + { "code": "KC_LSPO" }, + { "code": "KC_Z" }, + { "code": "KC_X" }, + { "code": "KC_C" }, + { "code": "KC_V" }, + { "code": "KC_B" }, + { "code": "KC_N" }, + { "code": "KC_M" }, + { "code": "KC_COMM" }, + { "code": "KC_DOT" }, + { "code": "KC_SLSH" }, + { "code": "KC_RSPC" }, + { "code": "KC_LCTL" }, + { "code": "KC_LEFT" }, + { "code": "KC_RGHT" }, + { "code": "KC_DOWN" }, + { "code": "KC_UP" }, + { "code": "KC_LBRC" }, + { "code": "KC_LCTL" }, + { "code": "KC_BSPC" }, + { "code": "KC_RALT" }, + { "code": "KC_ESC" }, + { "code": "KC_LALT" }, + { "code": "KC_LGUI" }, + { "code": "MO(1)" }, + { "code": "KC_PGUP" }, + { "code": "KC_ENT" }, + { "code": "KC_SPC" }, + { "code": "MO(2)" }, + { "code": "KC_PGDN" } +] diff --git a/data/layout.json b/data/layout.json new file mode 100644 index 0000000..8e44978 --- /dev/null +++ b/data/layout.json @@ -0,0 +1,56 @@ +[ + { "label": "L00", "x": 0, "y": 0.5 }, + { "label": "L01", "x": 1, "y": 0.5 }, + { "label": "L02", "x": 2, "y": 0.2 }, + { "label": "L03", "x": 3, "y": 0 }, + { "label": "L04", "x": 4, "y": 0.25 }, + { "label": "L05", "x": 5, "y": 0.25 }, + { "label": "R06", "x": 13, "y": 0.25 }, + { "label": "R07", "x": 14, "y": 0.25 }, + { "label": "R08", "x": 15, "y": 0 }, + { "label": "R09", "x": 16, "y": 0.2 }, + { "label": "R0A", "x": 17, "y": 0.5 }, + { "label": "R0B", "x": 18, "y": 0.5 }, + { "label": "L10", "x": 0, "y": 1.5 }, + { "label": "L11", "x": 1, "y": 1.5 }, + { "label": "L12", "x": 2, "y": 1.2 }, + { "label": "L13", "x": 3, "y": 1 }, + { "label": "L14", "x": 4, "y": 1.25 }, + { "label": "L15", "x": 5, "y": 1.25 }, + { "label": "R16", "x": 13, "y": 1.25 }, + { "label": "R17", "x": 14, "y": 1.25 }, + { "label": "R18", "x": 15, "y": 1 }, + { "label": "R19", "x": 16, "y": 1.2 }, + { "label": "R1A", "x": 17, "y": 1.5 }, + { "label": "R1B", "x": 18, "y": 1.5 }, + { "label": "L20", "x": 0, "y": 2.5 }, + { "label": "L21", "x": 1, "y": 2.5 }, + { "label": "L22", "x": 2, "y": 2.2 }, + { "label": "L23", "x": 3, "y": 2 }, + { "label": "L24", "x": 4, "y": 2.25 }, + { "label": "L25", "x": 5, "y": 2.25 }, + { "label": "R26", "x": 13, "y": 2.25 }, + { "label": "R27", "x": 14, "y": 2.25 }, + { "label": "R28", "x": 15, "y": 2 }, + { "label": "R29", "x": 16, "y": 2.2 }, + { "label": "R2A", "x": 17, "y": 2.5 }, + { "label": "R2B", "x": 18, "y": 2.5 }, + { "label": "L32", "x": 2, "y": 3.2 }, + { "label": "L33", "x": 3, "y": 3 }, + { "label": "L34", "x": 4, "y": 3.25 }, + { "label": "R37", "x": 14, "y": 3.25 }, + { "label": "R38", "x": 15, "y": 3 }, + { "label": "R39", "x": 16, "y": 3.2 }, + { "label": "L42", "x": 6.5, "y": 2, "r": 20, "rx": 4.5, "ry": 3 }, + { "label": "L43", "x": 7.5, "y": 2, "r": 20, "rx": 4.5, "ry": 3 }, + { "label": "R48", "x": 10.5, "y": 2, "r": -20, "rx": 14.5, "ry": 3 }, + { "label": "R49", "x": 11.5, "y": 2, "r": -20, "rx": 14.5, "ry": 3 }, + { "label": "L40", "x": 5.5, "y": 3, "r": 20, "rx": 4.5, "ry": 3, "h": 2 }, + { "label": "L41", "x": 6.5, "y": 3, "r": 20, "rx": 4.5, "ry": 3, "h": 2 }, + { "label": "L44", "x": 7.5, "y": 3, "r": 20, "rx": 4.5, "ry": 3 }, + { "label": "R47", "x": 10.5, "y": 3, "r": -20, "rx": 14.5, "ry": 3 }, + { "label": "R4A", "x": 11.5, "y": 3, "r": -20, "rx": 14.5, "ry": 3, "h": 2 }, + { "label": "R4B", "x": 12.5, "y": 3, "r": -20, "rx": 14.5, "ry": 3, "h": 2 }, + { "label": "L45", "x": 7.5, "y": 4, "r": 20, "rx": 4.5, "ry": 3 }, + { "label": "R46", "x": 10.5, "y": 4, "r": -20, "rx": 14.5, "ry": 3 } +] diff --git a/index.html b/index.html new file mode 100644 index 0000000..193a470 --- /dev/null +++ b/index.html @@ -0,0 +1,25 @@ +<!doctype html> +<html> +<head> + <meta charset="utf-8" /> + <link rel="stylesheet" href="style.css"> +</head> +<body> + <div id="layer-selector"> + <p>Layers:</p> + <ul></ul> + <button>Add layer</button> + </div> + <div id="layers"></div> + <div id="search" style="display: none"> + <p></p> + <input type="text" /> + <ul></ul> + </div> + + <button id="export">Export</button> + + <script src="https://rawgit.com/farzher/fuzzysort/master/fuzzysort.js"></script> + <script type="module" src="main.js"></script> +</body> +</html> diff --git a/keycodes.js b/keycodes.js new file mode 100644 index 0000000..f141c36 --- /dev/null +++ b/keycodes.js @@ -0,0 +1,41 @@ + +export function loadKeycodes () { + return fetch('data/keycodes.json') + .then(response => response.json()) + .then(normalizeKeycodes) +} + +export async function loadIndexedKeycodes() { + return loadKeycodes() + .then(keycodes => ( + keycodes.reduce((map, keycode) => Object.assign(map, { [keycode.code]: keycode }), {}) + )) +} + +function normalizeKeycodes (keycodes) { + return keycodes.map(keycode => { + keycode.params = (keycode.code.match(/\((.+?)\)/) || ['', ''])[1] + .split(',') + .map(t => t.trim()) + .filter(t => !!t) + + keycode.aliases = [keycode.code, ...(keycode.aliases || [])] + .map(code => code.replace(/`/g, '')) + .map(code => code.replace(/\(.+\)/, '')) + + keycode.symbol = keycode.symbol || ( + [...keycode.aliases] + .sort((a, b) => a.length - b.length)[0] + .replace(/^KC_/, '') + ) + + return keycode + }) + .reduce((keycodes, keycode) => { + for (let alias of keycode.aliases) { + keycodes.push(Object.assign({}, keycode, { code: alias })) + } + + return keycodes + }, []) +} diff --git a/keymap.js b/keymap.js new file mode 100644 index 0000000..1a99d40 --- /dev/null +++ b/keymap.js @@ -0,0 +1,97 @@ +import { loadIndexedKeycodes } from './keycodes.js' + +let keycodesIndex_ = loadIndexedKeycodes() + +export function loadKeymap () { + return fetch('data/keymap.json') + .then(response => response.json()) +} + +function findParentKey (element) { + const isRoot = node => node == document.body + const isKey = node => node.classList.contains('key') + let node = element + + while (!isRoot(node) && !isKey(node)) { node = node.parentNode } + + if (isRoot(node)) { + console.error('Could not find parent key for', element) + } + + return node +} + +export function recalculateDepth (element) { + function getDepth (node) { + const childDepths = Array.from(node.childNodes).map(node => getDepth(node)) + return node.nodeName !== '#text' + ? 1 + Math.max(0, ...childDepths) + : 0 + } + + const key = findParentKey(element) + key.dataset.depth = getDepth(key) - 1 +} + +export async function setKeycode(element, code) { + const keycodesIndex = await keycodesIndex_ + const paramsPattern = /\((.+)\)/ + const keycode = keycodesIndex[code.replace(paramsPattern, '')] + const params = (code.match(paramsPattern) || ['', ''])[1] + .split(',') + .map(s => s.trim()) + .filter(s => !!s) + + if (element.classList.contains('param') && element.dataset.param === 'layer') { + element.dataset.code = code + element.textContent = code + return + } + + if (!keycode) { + console.warn('wtf', code, code.replace(paramsPattern, '')) + return + } + + if (!element.classList.contains('code')) { + for (let child of [...element.childNodes]) { + element.removeChild(child) + } + + const codeElement = document.createElement('span') + codeElement.classList.add('code') + element.appendChild(codeElement) + element = codeElement + } + + element.textContent = keycode.symbol + element.dataset.code = keycode.code + element.dataset.keycode = code + + if (keycode.params.length > 0) { + const paramsElement = document.createElement('span') + element.appendChild(paramsElement) + paramsElement.classList.add('params') + + for (let i = 0; i < keycode.params.length; i++) { + const value = params[i] + + const paramElement = document.createElement('span') + paramElement.classList.add('param', 'code') + + if (value && value.match(/.+\(.+\)/)) { + setKeycode(paramElement, value) + } else { + const param = keycode.params[i] + const label = param === 'layer' ? value : ((keycodesIndex[value] || {}).symbol || value) + paramElement.textContent = label + paramElement.dataset.param = param + paramElement.dataset.code = value + } + + paramsElement.appendChild(paramElement) + } + } + + recalculateDepth(element) +} diff --git a/layers.js b/layers.js new file mode 100644 index 0000000..ef43670 --- /dev/null +++ b/layers.js @@ -0,0 +1,81 @@ +import { setKeycode } from './keymap.js' +import { renderLayout } from './layout.js' + +const layers = document.querySelector('#layers') +const layerSelector = document.querySelector('#layer-selector ul') + +export function selectLayer (index) { + const activeLayer = layers.querySelector('.layer.active') + const activeLayerTab = layerSelector.querySelector('.active') + const layer = layers.querySelector(`[data-layer="${index}"]`) + const layerTab = layerSelector.querySelector(`[data-layer="${index}"]`) + + console.log({ + activeLayer, + activeLayerTab, + layer, + layerTab + }) + + activeLayer && activeLayer.classList.remove('active') + activeLayerTab && activeLayerTab.classList.remove('active') + layer && layer.classList.add('active') + layerTab && layerTab.classList.add('active') +} + +export function addLayer (layout, layer) { + const layerElement = renderLayout(layout) + const li = document.createElement('li') + const layerIndex = layers.children.length + + layerElement.classList.add('layer') + layerElement.dataset.layer = li.dataset.layer = li.textContent = layerIndex + + layers.appendChild(layerElement) + layerSelector.appendChild(li) + selectLayer(layerIndex) + + layerSelector.addEventListener('click', event => { + if (event.target.dataset.layer !== undefined) { + selectLayer(event.target.dataset.layer) + } + }) + + for (let i = 0; i < layout.length; i++) { + // const key = layout[i] + const code = layer[i] || 'KC_TRNS' + // const keyElement = document.createElement('div') + const keyElement = layerElement.children[i] + + // const x = key.x * 65 + // const y = key.y * 65 + // const rx = (key.x - (key.rx || key.x)) * -65 + // const ry = (key.y - (key.ry || key.y)) * -65 + + setKeycode(keyElement, code) + // keyElement.classList.add('key') + // keyElement.classList.add(`key-${key.u}u`) + // keyElement.classList.add(`key-${key.h}h`) + + // keyElement.style.top = `${y}px` + // keyElement.style.left = `${x}px` + // keyElement.style.transformOrigin = `${rx}px ${ry}px` + // keyElement.style.transform = `rotate(${key.r || 0}deg)` + // keyElement.dataset.u = key.u + // keyElement.dataset.h = key.h + // layerElement.appendChild(keyElement) + // recalculateDepth(keyElement) + + keyElement.addEventListener('mouseover', event => { + const old = document.querySelector('.highlight') + old && old.classList.remove('highlight') + event.target.classList.add('highlight') + }, true) + + keyElement.addEventListener('mouseleave', event => { + event.target.classList.remove('highlight') + }, true) + } + + return layerElement +} diff --git a/layout.js b/layout.js new file mode 100644 index 0000000..8d18265 --- /dev/null +++ b/layout.js @@ -0,0 +1,43 @@ +export function loadLayout () { + return fetch('data/layout.json') + .then(response => response.json()) + .then(layout => layout.map(key => ({ + ...key, + u: key.u || 1, + h: key.h || 1 + }))) +} + +export function renderLayout (layout) { + const layerElement = document.createElement('div') + + for (let i = 0; i < layout.length; i++) { + const key = layout[i] + + const x = key.x * 65 + const y = key.y * 65 + const rx = (key.x - (key.rx || key.x)) * -65 + const ry = (key.y - (key.ry || key.y)) * -65 + + const keyElement = document.createElement('div') + keyElement.classList.add('key') + keyElement.classList.add(`key-${key.u}u`) + keyElement.classList.add(`key-${key.h}h`) + + keyElement.style.top = `${y}px` + keyElement.style.left = `${x}px` + keyElement.style.transformOrigin = `${rx}px ${ry}px` + keyElement.style.transform = `rotate(${key.r || 0}deg)` + + keyElement.dataset.label = key.label + keyElement.dataset.u = key.u + keyElement.dataset.h = key.h + + const codeElement = document.createElement('span') + codeElement.classList.add('code') + keyElement.appendChild(codeElement) + layerElement.appendChild(keyElement) + } + + return layerElement +} @@ -0,0 +1,75 @@ +import * as search from './search.js' +import { loadKeymap, setKeycode } from './keymap.js' +import { addLayer, selectLayer } from './layers.js' +import { loadLayout } from './layout.js' + + +async function main() { + // const keycodes = await loadKeycodes() + // const keycodesIndex = keycodes.reduce((map, keycode) => Object.assign(map, { [keycode.code]: keycode }), {}) + // const layout = await loadLayout() + + const layout = await loadLayout() + const keymap = await loadKeymap() + let active + + search.onSelect(code => { + if (active) { + setKeycode(active, code) + // recalculateDepth(active) + } + }) + + // addLayer(layout, keymap) + // document.getElementById('layers').appendChild(renderLayout(layout)) + for (let layer of keymap.layers) { + addLayer(layout, layer) + } + selectLayer(0) + + document.body.addEventListener('click', event => { + if (event.target.classList.contains('key') || event.target.classList.contains('code')) { + active = event.target + search.activate(event.target) + } + }) + + document.querySelector('#layer-selector button').addEventListener('click', () => { + addLayer(layout, []) + }) + + function extractCode (code) { + const paramsElement = code.querySelector('.params') + if (!paramsElement) { + return code.dataset.code + } + + const params = [...paramsElement.children].map(extractCode) + return `${code.dataset.code}(${params.join(',')})` + } + + document.querySelector('#export').addEventListener('click', () => { + const layers = [] + for (let layer of [...document.querySelectorAll('#layers .layer')]) { + const layerExport = [] + for (let key of [...layer.childNodes]) { + layerExport.push(extractCode(key.querySelector('.code'))) + } + + layers.push(layerExport) + } + + const newKeymap = Object.assign({}, keymap, { layers }) + // const blob = new Blob([JSON.stringify(newKeymap, null, 2)], { + // type: 'application/octet-stream', + // name: 'default.json' + // }) + const file = new File([JSON.stringify(newKeymap, null, 2)], 'default.json', { + type: 'application/octet-stream' + }) + + location.href = URL.createObjectURL(file) + }) +} + +main() diff --git a/search.js b/search.js new file mode 100644 index 0000000..192282d --- /dev/null +++ b/search.js @@ -0,0 +1,109 @@ +import { loadKeycodes } from './keycodes.js' + +/* global fuzzysort */ +const root = document.querySelector('#search') +export const prompt = root.querySelector('p') +export const input = root.querySelector('input') +export const results = root.querySelector('ul') +let param = null +let onSelect_ = null + +export function onSelect (callback) { + onSelect_ = callback +} + +const clear = () => { + for (let node of [...results.childNodes]) { + results.removeChild(node) + } +} + +const getOptions = (param, keycodes) => { + switch (param) { + case 'layer': + return [{code: '1' }, {code: '2' }, {code: '3' }] + case 'mod': + return keycodes.filter(keycode => keycode.isModifier) + case 'kc': + default: + return keycodes + } +} + +async function query () { + const keycodes = await loadKeycodes() + const options = getOptions(param, keycodes) + const searchResults = fuzzysort.go(input.value, options, { + key: 'code', + limit: 30 + }) + + clear() + for (let result of searchResults) { + const item = document.createElement('li') + item.innerHTML = fuzzysort.highlight(result) + item.addEventListener('click', () => { + onSelect_ && onSelect_(result.obj.code) + hide() + }) + + results.appendChild(item) + } +} + +export const hide = () => { + root.style.display = 'none' +} + +export const activate = function activate (target) { + const rect = target.getBoundingClientRect() + if (target.classList.contains('key')) { + target = target.querySelector('.code') + } + + param = target.dataset.param || 'kc' + if (target.dataset.param === 'layer') { + prompt.textContent = 'Select layer...' + } else if (target.dataset.param === 'mod') { + prompt.textContent = 'Select modifier...' + } else { + prompt.textContent = 'Select key code...' + } + + root.style.display = 'block' + root.style.top = `${window.scrollY + (rect.top + rect.bottom) / 2}px` + root.style.left = `${window.scrollX + (rect.left + rect.right) / 2}px` + input.value = target.dataset.code + + clear() + setTimeout(() => { + input.focus() + input.select() + }) +} + +function debounce(fn, limit) { + let delay = null + let delayed = null + + return function debounced(...args) { + delayed = () => fn(...args) + if (!delay) { + delay = setTimeout(() => { + delay = null + delayed() + }, limit) + } + } +} + +input.addEventListener('keypress', debounce(() => query(input.value), 250)) +document.body.addEventListener('click', (event) => { + const inactive = root.style.display === 'none' + const child = root.contains(event.target) + if (inactive || child) { + return + } + + hide() +}, true) diff --git a/style.css b/style.css new file mode 100644 index 0000000..2bceaea --- /dev/null +++ b/style.css @@ -0,0 +1,139 @@ +:root { + --dark-red: #910e0e; + --dark-blue: #6d99c6; +} + +html { font-family: avenir, sans-serif; } +html, body { + width: 100vw; + height: 100vh; + overflow: auto; + padding: 0; + margin: 0; +} + +#layer-selector * { display: inline-block; } +#layer-selector ul { + list-style-type: none; + margin: 0; + padding: 0; +} +#layer-selector li { + cursor: pointer; + background-color: lightgray; + color: darkgray; + border-radius: 5px; + padding: 5px; + margin: 2px; +} +#layer-selector li.active { + background-color: mediumseagreen; + color: white; +} + +#layers { padding-left: 20px;} +#layers .layer { + position: relative; + transition: transform 250ms linear; +} +#layers .layer:not(.active) { + transform: translate(0, -100vh); +} + +[data-u="1"] { width: 60px; } +[data-u="2"] { width: 125px; } +[data-h="1"] { height: 60px; } +[data-h="2"] { height: 125px; } + +.key { + position: absolute; + display: flex; + justify-content: center; + align-items: center; + + color: #999; + font-size: 110%; + border: 1px solid lightgray; + border-radius: 5px; +} +.key:hover { + background-color: var(--dark-red); + /*transition: 250ms;*/ + z-index: 1; +} +.key:hover .code { + background-color: var(--dark-red); + color: white; +} +.key > .code { + padding: 5px; +} + +.key[data-depth="3"] { font-size: 90%; } +.key[data-depth="5"] { font-size: 75%; } + +.code { + cursor: pointer; + display: inline-block; + box-sizing: content-box; + min-width: 0.5em; + text-align: center; + border-radius: 4px; +} +.code.highlight { + background-color: white !important; + color: var(--dark-red) !important; +} + +.params::before { content: '('; opacity: 0.4; font-weight: bold; margin: 2px; } +.params::after { content: ')'; opacity: 0.4; font-weight: bold; margin: 2px; } +.param:not(:last-child)::after { content: ','; } +.param[data-code="undefined"]::before { content: '∅'; font-size: 80%; } + +#search { + position: absolute; + transform: translate(-60px, -30px); + z-index: 2; +} +#search p { + margin: 0; + font-size: 90%; + font-weight: bold; +} +#search input { + display: block; + padding: 0; + margin: 0; + width: 120px; + height: 60px; + font-size: 120%; + border: 2px solid steelblue; + border-radius: 4px; + + text-align: center; + line-height: 60px; +} +#search ul { + font-family: monospace; + list-style-position: inside; + list-style-type: none; + padding: 4px; + background: rgba(0, 0, 0, 0.8); + border-radius: 4px; +} +#search li { + cursor: pointer; + color: white; + padding: 5px; +} +#search li:hover { + background: white; + color: black; +} +#search b { color: red; } + +#export { + position: absolute; + bottom: 20px; + right: 20px; +} |