├── .gitignore ├── xkb ├── WordstarKeys.desktop ├── wskeys-debug ├── experiments │ ├── wskeys-debug-test │ ├── wskeys-test │ ├── wstypes-test │ ├── wscompat-test │ └── wordstar-test ├── wskeys ├── install ├── README.md ├── wscompat └── wordstar ├── xremap ├── xremap.service ├── install ├── wordstar-simple.yml ├── README.md └── wordstar.yml ├── LICENSE.txt ├── autohotkey ├── README.md └── Wordstar Capslock.ahk └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | xkb/test/* 2 | xkb/madduck-xkb 3 | 4 | xremap/xremap 5 | -------------------------------------------------------------------------------- /xkb/WordstarKeys.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | 3 | # X desktop file to load Wordstar Keys and auto-load at startup 4 | 5 | Type=Application 6 | Exec=wskeys 7 | X-GNOME-Autostart-enabled=true 8 | NoDisplay=false 9 | Hidden=false 10 | Name[en_NZ]=Wordstar Keys 11 | Comment[en_NZ]=Load keyboard with wordstar additions when X starts 12 | X-GNOME-Autostart-Delay=0 13 | -------------------------------------------------------------------------------- /xremap/xremap.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=xremap - wordstar keys 3 | PartOf=graphical-session.target 4 | Wants=xdg-desktop-autostart.target 5 | After=xdg-desktop-autostart.target 6 | 7 | [Service] 8 | Type=simple 9 | Restart=always 10 | # prevent logging every single key to clog up the syslog 11 | StandardError=null 12 | ExecStart=xremap --watch=config %h/.config/xremap/wordstar.yml 13 | 14 | [Install] 15 | WantedBy=default.target 16 | -------------------------------------------------------------------------------- /xkb/wskeys-debug: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # run wskeys with -w10 maximum warnings, but filter out any expected warnings that are produced by the standard xkb files 3 | setxkbmap -print | xkbcomp -w10 - $DISPLAY 2>/tmp/wskeys.warnings.default 4 | ~/.local/bin/wskeys -w10 2>&1 | diff /tmp/wskeys.warnings.default - | grep "^>" | egrep -v 'Warning:.*Key "(Caps_Lock|Meta_R|Alt_R)" not found in' | egrep -v "Warning:.*Symbol map for key.*redefined|Using last definition for conflicting fields" 5 | -------------------------------------------------------------------------------- /xkb/experiments/wskeys-debug-test: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # run wskeys with -w10 maximum warnings, but filter out any expected warnings that are produced by the standard xkb files 3 | setxkbmap -print | xkbcomp -w10 - $DISPLAY 2>/tmp/wskeys.warnings.default 4 | wskeys-test -w10 2>&1 | diff /tmp/wskeys.warnings.default - | grep "^>" | egrep -v 'Warning:.*Key "(Caps_Lock|Meta_R|Alt_R)" not found in' | egrep -v "Warning:.*Symbol map for key.*redefined|Using last definition for conflicting fields" 5 | -------------------------------------------------------------------------------- /xkb/experiments/wskeys-test: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Print the current key map and reload with wordstar keys included 3 | # Note: -w1 makes xkbcomp ignore warnings that are in existing keymap files. 4 | # If you want warnings run to debug your key changes run 'wskeys -w10' 5 | # and compare differences to find new warnings 6 | setxkbmap -print \ 7 | | sed -E 's/(.*xkb_types.*".*)(".*)/\1+wstypes-test\2/g' \ 8 | | sed -E 's/(.*xkb_compat.*".*)(".*)/\1+wscompat-test\2/g' \ 9 | | sed -E 's/(.*xkb_symbols.*".*)(".*)/\1+wordstar-test\2/g' \ 10 | | xkbcomp -w1 -I$HOME/.xkb - $DISPLAY "$@" 11 | -------------------------------------------------------------------------------- /xkb/wskeys: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Print the current key map and reload with wordstar keys included 3 | # Note: -w1 makes xkbcomp ignore warnings that are in existing keymap files. 4 | # If you want warnings run to debug your key changes run 'wskeys -w10' 5 | # and compare differences to find new warnings 6 | 7 | setxkbmap -print | grep -q "xkb_symbols.*include.*:" \ 8 | && echo >&2 "Warning: It is unwise to run wskeys with more than one keyboard map loaded." \ 9 | && echo >&2 "as wskeys will clobber some of the keys in your secondary (group2) key map." \ 10 | && echo >&2 "Instead, set up hotkeys to load your different keymaps. For example, make them run:" \ 11 | && echo >&2 " setxkbmap gr && wskeys" 12 | 13 | setxkbmap -print \ 14 | | sed -E 's/(.*xkb_compat.*".*)(".*)/\1+wscompat\2/g' \ 15 | | sed -E 's/(.*xkb_symbols.*".*)(".*)/\1+wordstar\2/g' \ 16 | | xkbcomp -w1 -I$HOME/.xkb - $DISPLAY "$@" 17 | -------------------------------------------------------------------------------- /xkb/experiments/wstypes-test: -------------------------------------------------------------------------------- 1 | #!xkb //specify_lexicon_for_editor_display_style; tabsize=4 2 | 3 | // Define xkb 'types' file for wordstar cursor controls 4 | // 5 | // Modify EIGHT_LEVEL to put Ctrl on Level3 and Ctrl+Alt on Level4 6 | // so that I can redefined such keys in wskeys 7 | 8 | partial default xkb_types "default" { 9 | type "EIGHT_LEVEL_CTRL" { 10 | modifiers = Shift+LevelThree+LevelFive+Control+Alt; 11 | map[None] = Level1; 12 | map[Shift] = Level2; 13 | map[LevelThree] = Level3; 14 | map[Control+Alt] = Level4; 15 | map[LevelFive] = Level5; 16 | map[Shift+LevelFive] = Level6; 17 | map[LevelThree+LevelFive] = Level7; 18 | map[Shift+LevelThree+LevelFive] = Level8; 19 | level_name[Level1] = "Base"; 20 | level_name[Level2] = "Shift"; 21 | level_name[Level3] = "Alt Base"; 22 | level_name[Level4] = "Control Alt"; 23 | level_name[Level5] = "X"; 24 | level_name[Level6] = "X Shift"; 25 | level_name[Level7] = "X Alt Base"; 26 | level_name[Level8] = "X Shift Alt"; 27 | }; 28 | }; 29 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright 2022 Berwyn Hoyt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 7 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 8 | persons to whom the Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 13 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 14 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 15 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | -------------------------------------------------------------------------------- /xkb/install: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # install script for xkb wordstar keys 3 | # Dependencies: you must be running X Windows on Linux using xkb 4 | 5 | echo "Creating directory tree at ~/.xkb required by xkb to load files." 6 | mkdir -p ~/.xkb/symbols 7 | mkdir -p ~/.xkb/compat 8 | mkdir -p ~/.local/bin 9 | cp wordstar ~/.xkb/symbols 10 | cp wscompat ~/.xkb/compat 11 | cp wskeys wskeys-debug ~/.local/bin 12 | echo "Done." 13 | 14 | # Ask whether to make wskeys auto-load when X session starts for this user 15 | startup_file=~/.config/autostart/WordstarKeys.desktop 16 | if ! [[ -e "$startup_file" ]]; then 17 | read -p "Shall I make wskeys load with the X Windows session by adding it at "$startup_file" (y/n)? " -n1 add_at_startup 18 | echo 19 | if [[ "$add_at_startup" == "y" ]]; then 20 | cp WordstarKeys.desktop $startup_file 21 | echo "Done." 22 | fi 23 | fi 24 | 25 | # Tell the user if it needs to be added to the PATH 26 | if [[ "$PATH" != *"$HOME/.local/bin"* ]]; then 27 | echo "wskeys has been added to $HOME/.local/bin, so if you want to run 'wskeys' then" 28 | echo "you need to add ~/.local/bin to your PATH, or on some Linux distributions" 29 | echo "your default ~/.profile may automatically do so on next login." 30 | fi 31 | -------------------------------------------------------------------------------- /autohotkey/README.md: -------------------------------------------------------------------------------- 1 | # Wordstar key map for AutoHotkey (Windows) 2 | 3 | Arrow keys are the bane of keyboard life. You constantly have to lift your hands off the home keys to move around your software file. Wordstar cursor control keys are the answer. This Windows key map defines Wordstar cursor control keys using capslock as the 'control' key. It uses [AutoHotkey v1](https://www.autohotkey.com/) to do so. 4 | 5 | ### Primary key definitions 6 | 7 | * ^S/^D moves left/right; ^E/^X moves up/down; ^A/^F word left/right; ^R/^C moves page Up/Down; ^U undo 8 | * ^Q acts as a prefix, e.g. ^QS/^QD moves to Home/End of line; ^QR/^QC start/end of document 9 | * ^Y/^QY = delete/cut to end of line; ^T = delete word to the right 10 | * ^QF is find; ^L is re-find; ^QA is replace; ^QJ is goto line 11 | * ^KB/^KK turns on block marking selection mode; ^KH hides it (unmark). 12 | * ^KS save file 13 | * ^KY yank (i.e. cut) block; ^KC copy block; ^KV paste block 14 | 15 | #### Extra non-wordstar keys defined: 16 | 17 | Note: ^ is an abbreviation for CapsLock 18 | 19 | * ^N insert line break to the right 20 | * ^Y instead of delete whole line, it deletes to end of line; if pressed again, it deletes the newline 21 | * ^Backspace is delete word to the right 22 | * ^B is bold (=ctrl-B) 23 | * ^I is italic (=ctrl-I) 24 | * ^QJ goto line number (issue Ctrl-G - works in some editors) 25 | 26 | ## Implementation quirks 27 | 28 | There are several tweaks for specific applications to make this work consistently for them: OpenOffice, MSOffice, Google docs, SciTE editor, cmd, notepad, Eclipse, and the nano editor when invoked via putty. Look at the .ahk file for details. Note that due to the way AutoHotkey works, all the exceptions have to be listed first, and the main generic wordstar key bindings are defined at the end of the .ahk file. 29 | 30 | 31 | ## Installation 32 | 33 | Download and install [AutoHotkey v1](https://www.autohotkey.com/) 34 | Double-click wordstar.ahk. An icon will appear in your system tray showing that the key map is in operation. 35 | 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Wordstar key map (Linux or Windows) 2 | 3 | Arrow keys are the bane of keyboard life. You constantly have to lift your hands off the touch-typing home keys to move around your software file. Wordstar cursor control keys are the answer. They let you move your cursor all around your file using intuitive motion keys that are activated simply by holding down capslock while you press them. They were good back in the day, and they're still the best set of cursor control keys around. 4 | 5 | The great thing about this implementation is that it works for every program in your operating system. It's like defining special keyboard shortcuts in your word processor -- except they work in all your editors and even at the command line, and in web browser apps. 6 | 7 | By way of comparison, the wordstar keys have a similar purpose to the emacs editor keys, but with the following advantages: 8 | 9 | * they are more intuitive since the arrow keys are in a key pattern you'll recognise as: up, down, left, right. 10 | * basic cursor motion can all happen with your left hand, leaving your right-hand free to use the mouse (now, why use the mouse? ... but it happens.) 11 | 12 | For Linux, I recommend the [map using xremap](xremap/README.md), but there is also a [map using xkb](xkb/README.md). 13 | There is also a [version for windows using Autohotkey](autohotkey/Wordstar%20Capslock.ahk). 14 | Documentation on each of those scripts is linked above. 15 | 16 | These keyboard maps defines Wordstar cursor control keys using capslock as the 'control' key. 17 | 18 | ### Primary key definitions 19 | 20 | Note: ^ is an abbreviation for CapsLock 21 | 22 | * ^S/^D moves left/right; ^E/^X moves up/down; ^A/^F word left/right; ^R/^C moves page Up/Down 23 | * ^Q acts as a prefix, e.g. ^QS/^QD moves to Home/End of line; ^QR/^QC start/end of document 24 | * ^Y/^QY = delete/cut to end of line; ^T = delete word to the right 25 | * ^QF is find; ^L is re-find; ^QA is replace; ^QJ is goto line 26 | * ^KB/^KK turns on block marking selection mode; ^KH hides it (unmark). 27 | * ^KS save file 28 | * ^KY yank (i.e. cut) block; ^KC copy block; ^KV paste block 29 | 30 | These are the most-useful wordstar keys, though there are many others of arguable value. For a full list see this page on [wordstar.org](http://www.wordstar.org/index.php/wsemu-documentation/wsemu-commands-and-menus/1-wordstar-emulator-full-version-command-list). 31 | 32 | I have included a few other non-wordstar keys in the specific implementations for xremap, xkb, and AutoHotkey. Check their docs for specifics. 33 | 34 | ### License 35 | 36 | These scripts are released under the [MIT License](LICENSE.txt). 37 | -------------------------------------------------------------------------------- /xremap/install: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # install script for xremap wordstar keys 3 | 4 | exec_dest="/usr/local/bin/xremap" 5 | 6 | echo "Setting up user to be able to access the keyboard device." 7 | sudo gpasswd -a $(whoami) input 8 | echo "Ensuring uinput device is accessible by input group" 9 | rule='KERNEL=="uinput", GROUP="input", TAG+="uaccess"' 10 | file='/etc/udev/rules.d/99-input.rules' 11 | ! grep -qs "$rule" "$file" && echo "$rule" | sudo tee $file >/dev/null 12 | echo "User $(whoami) is now set up." 13 | echo 14 | 15 | # List latest xremap versions for optional installation 16 | installed= 17 | echo "Listing latest xremap binaries for you to install" 18 | curl -sL https://api.github.com/repos/k0kubun/xremap/releases/latest >xremaps.xml 19 | options=$(sed -nE "/name/s/.*\"(xremap.*zip)\".*/\1/p" xremaps.xml) 20 | nl <<<"$options" 21 | read -p "Which binary of xremap should I install in your system (Esc to skip)? " selection 22 | echo 23 | if [[ "$selection" =~ ^[0-9]$ ]]; then 24 | binary_name=$(sed -n ${selection}p <<<"$options") 25 | echo "Downloading and installing $binary" 26 | binary_url=$(sed -nE "s/.*browser_download_url.*(https.*$binary_name)\".*/\1/p" xremaps.xml) 27 | curl -fSLO $binary_url 28 | unzip -o $binary_name 29 | rm $binary_name 30 | 31 | echo "Copying xremap to $exec_dest" 32 | systemctl --user stop xremap &>/dev/null 33 | sudo install -D xremap "$exec_dest" 34 | installed=true 35 | else 36 | exec_dest="$(which xremap)" 37 | fi 38 | rm xremaps.xml 39 | echo 40 | echo "If you use Wayland you will also want to install this extension to enable app-specific keys:" 41 | echo " https://github.com/xremap/xremap-gnome" 42 | echo "Basic setup Complete: you should now be able to run 'xremap wordstar'" 43 | 44 | # Ask whether to install xdotool 45 | install_tool=apt-get 46 | [ -`which apt-get`- == -""- ] && install_tool=yum 47 | echo 48 | echo "Note: xdotool doesn't work on Wayland. But if you're not using Wayland you might want to install it" 49 | read -p "Shall I also '$install_tool install xdotool' so that ^W/^Z scroll keys work? (y/n)? " -n1 xdotool 50 | echo 51 | [ "$xdotool" == "y" ] && sudo $install_tool install xdotool 52 | 53 | [[ ! -f "$exec_dest" ]] && echo "Unable to install xremap" && exit 1 54 | 55 | # Ask whether to install as a user service 56 | echo 57 | read -p "Shall I also install wordstar keys as a user service to run it at login? (y/n)? " -n1 add_at_startup 58 | echo 59 | key_file=~/".config/xremap/wordstar.yml" 60 | service_file=~/".config/systemd/user/xremap.service" 61 | if [ "$add_at_startup" == "y" ]; then 62 | mkdir -p `dirname $key_file` 63 | mkdir -p `dirname $service_file` 64 | echo "Copying key file to $key_file" 65 | cp wordstar.yml "$key_file" 66 | echo "Copying service file to $service_file" 67 | sed "s|ExecStart=xremap|ExecStart=$exec_dest|" xremap.service >"$service_file" 68 | fi 69 | 70 | # Check if service is installed 71 | if [[ -f "$service_file" ]]; then 72 | systemctl --user enable xremap # for next boot 73 | systemctl --user start xremap 74 | echo 75 | echo "Service enabled. You can now start/stop/check the service by typing:" 76 | echo " systemctl --user start|stop|status xremap" 77 | echo "or view the log with:" 78 | echo " journalctl --user -fu xremap" 79 | echo "Note: changes to keymap at ~/.config/xremap/wordstar.yml will take effect immediately" 80 | fi 81 | 82 | # Warn if the xremap on the PATH is not the one I installed 83 | if [[ "$installed" != "" && "$(which xremap)" != "$exec_dest" ]]; then 84 | echo 85 | echo "*** Warning ***: The xremap on your PATH is not the same as the one I just installed in $exec_dest." 86 | echo "You may need to remove the one at $(which xremap)" 87 | fi 88 | -------------------------------------------------------------------------------- /xremap/wordstar-simple.yml: -------------------------------------------------------------------------------- 1 | # Credit Berwyn Hoyt: https://github.com/berwynhoyt/wskeys 2 | 3 | # This is a generic version of wordstar key mappings, to give you a feel for how simple this can be. 4 | # It implements only standard wordstar key mappings 5 | 6 | # For a fancier version that handles cases where some keys act differently in specific 7 | # applications, see wordstar.yml, which also adds some nice but less-standard keys mappings. 8 | 9 | # Some of these are marked as not standard wordstar keys. 10 | # See here for all standard wordstar key bindings: 11 | # http://www.wordstar.org/index.php/wsemu-documentation/wsemu-commands-and-menus/1-wordstar-emulator-full-version-command-list 12 | 13 | virtual_modifiers: 14 | - CapsLock 15 | 16 | keymap: 17 | - name: Main-Wordstar-Keys 18 | remap: 19 | # Remove mark if switching out of this app where it might cause problems 20 | Alt-tab: [Alt-tab, {set_mark: false}] 21 | 22 | # Cursor 23 | CapsLock-s: {with_mark: left} 24 | CapsLock-d: {with_mark: right} 25 | CapsLock-e: {with_mark: up} 26 | CapsLock-x: {with_mark: down} 27 | # Forward/backward word 28 | CapsLock-f: {with_mark: C-right} 29 | CapsLock-a: {with_mark: C-left} 30 | # Page up/down 31 | CapsLock-r: {with_mark: pageup} 32 | CapsLock-c: {with_mark: pagedown} 33 | 34 | # Delete 35 | CapsLock-g: [delete, {set_mark: false}] 36 | CapsLock-h: [backspace, {set_mark: false}] 37 | # Delete to end of line; then delete linebreak if pressed again. 38 | CapsLock-y: [Home, Home, Shift-end, delete, delete, {set_mark: false}] 39 | # Undo 40 | CapsLock-u: [C-z, {set_mark: false}] 41 | # Repeat-find 42 | CapsLock-l: [F3, {set_mark: false}] # re-find 43 | # Delete next word, including trailing space. 44 | # Do it this long way because, although Ctrl-Delete works, in some programs it doesn't delete the space. 45 | CapsLock-t: [{set_mark: false}, C-delete ] 46 | CapsLock-backspace: [{set_mark: false}, C-Delete ] 47 | 48 | # Scroll up/down. Most apps don't implement Ctrl-Up/Down. See wordstar.yml for an xdotool workaround 49 | CapsLock-w: C-Up 50 | CapsLock-z: C-Down 51 | 52 | CapsLock-q: 53 | remap: 54 | # Beginning/End of line 55 | CapsLock-s: {with_mark: home} 56 | CapsLock-d: {with_mark: end} 57 | # Beginning/End of file 58 | CapsLock-r: {with_mark: C-home} 59 | CapsLock-c: {with_mark: C-end} 60 | # Cut to end of line 61 | CapsLock-y: [Shift-end, C-x, {set_mark: false}] 62 | # Search 63 | CapsLock-f: [C-f, {set_mark: false}] # find 64 | CapsLock-a: [C-h, {set_mark: false}] # replace 65 | # CapsLock-q u (undo) 66 | u: [C-z, {set_mark: false}] 67 | 68 | CapsLock-k: 69 | # Block marking works slightly different than with wordstar because you can only mark 70 | # block beginning (^KB), not the end (^KK) is where the cursor is. 71 | # However, it works pretty well using the standard ^KY as cut and adding ^KV as paste. 72 | # I've also added my preferred non-standard shortcuts ^KX (cut), ^KD (copy), ^KP (paste) 73 | remap: 74 | # Block cut 75 | CapsLock-y: [C-x, {set_mark: false}] 76 | # Block copy(duplicate) 77 | CapsLock-c: [C-c, {set_mark: false}] # block copy 78 | # block paste 79 | CapsLock-v: [C-v, {set_mark: false}] # block move 80 | # Mark 81 | CapsLock-b: {set_mark: true} 82 | # Hide mark 83 | CapsLock-h: {set_mark: false} 84 | # Save 85 | CapsLock-s: C-s 86 | 87 | # Text formatting keys 88 | CapsLock-p: 89 | remap: 90 | # Bold 91 | CapsLock-b: C-b 92 | # Italic 93 | CapsLock-i: C-i 94 | # Print 95 | CapsLock-p: C-p 96 | -------------------------------------------------------------------------------- /xkb/README.md: -------------------------------------------------------------------------------- 1 | # Wordstar key map for xkb (Linux) 2 | 3 | Arrow keys are the bane of keyboard life. You constantly have to lift your hands off the home keys to move around your software file. Wordstar cursor control keys are the answer. This Linux key map defines Wordstar cursor control keys in xkb using capslock as the 'control' key. 4 | 5 | This key map is a testament to what a desperate man can achieve with xkb. But it still has serious limitations, and now that xremap has come along, the main advantage is that the xkb installation does not require root access. 6 | 7 | ### Primary key definitions 8 | 9 | Note: ^ is an abbreviation for CapsLock 10 | 11 | * ^S/^D moves left/right; ^E/^X moves up/down; ^A/^F word left/right; ^R/^C moves page Up/Down; ^U undo 12 | * ^Q acts as a prefix, e.g. ^QS/^QD moves to Home/End of line; ^QR/^QC start/end of document 13 | * ^Y/^QY = delete/cut to end of line; ^T = delete word to the right 14 | * ^QF is find; ^L is re-find; ^QA is replace; ^QJ is goto line 15 | * ^KB/^KK turns on block marking selection mode; ^KH hides it (unmark). 16 | * ^KS save file 17 | * ^KY yank (i.e. cut) block; ^KC copy block; ^KV paste block 18 | * ^PB bold; ^PI italic 19 | 20 | #### Extra non-wordstar keys defined: 21 | * ^N insert line break to the right 22 | * ^Y instead of delete whole line, it deletes to end of line 23 | * ^Backspace is delete word to the right 24 | * ^B is bold (=ctrl-B) 25 | * ^I is italic (=ctrl-I) 26 | * ^QJ goto line number 27 | 28 | 29 | ### Implementation quirks 30 | 31 | It really is a shame that xkb doesn't let me issue two keystrokes or I could do a lot better. 32 | With two keystrokes I could implement: 33 | 34 | * ^KY/^KC/^KV to automatically exit block mode. This would be much nicer to use. 35 | * ^Y (delete to end of line) performs ctrl-Shift-Delete which deletes to end of paragraph in a word processor 36 | * ^N (insert line) performs the key. There is no way to issue a second Left key afterward to make it stay on the same line like it should 37 | * ^QE/^QX (top/bottom of page): there is no standard function to do this in linux 38 | * ^W/^Z (scroll up/down) issues ctrl-Up/Down which works in my editor but in few other apps. 39 | 40 | Consequently, it's not quite perfect. But given XKB's limitations, it's pretty good. Let me know if you know how to make XKB send multiple keystrokes from one key. 41 | 42 | 43 | ## Installation 44 | 45 | ``` 46 | git clone wskeys 47 | cd xkb/wskeys 48 | ./install 49 | ``` 50 | 51 | ### Gotchas 52 | 53 | #### Wayland / Ubuntu 54 | 55 | If you use the Wayland Display Server (which I think is now the **Ubuntu** default), then wskeys will not work because Weyland does not listen to the setxkbmap or xkbcomp commands. It is possible to get xkb key layouts working with Weyland at startup, but it requires that a rules file be created to map wskeys to a key layout option, and it requires wskeys files to be installed into the xkb system folder. This has yet to be implemented. 56 | 57 | For now, you can switch to X Server instead of Wayland, or implement it yourself. To switch to X Server in Ubuntu, log out, look for the gear icon in the bottom right of the screen, and click the "Ubuntu with X" or similar option. 58 | 59 | #### Jetbrains IntelliJ issue 60 | 61 | For whatever reason IntelliJ (and related products like GoLand) take control of the keyboard at a lower level and ignore the xkb rules. To get IntelliJ to work, you have to turn on "Use national layouts for shortcuts" in Settings > Keymap ([reference](https://youtrack.jetbrains.com/issue/IDEA-263057)). 62 | 63 | 64 | ### Helpful XKB docs 65 | 66 | If things go wrong, Damiano Venturin has a great little article on [making key map changes in xkb](https://medium.com/@damko/a-simple-humble-but-comprehensive-guide-to-xkb-for-linux-6f1ad5e13450). For more detailed stuff, I'm afraid the X Keyboard file format is poorly documented in far too many places. I found the following to be most useful. 67 | 68 | Ivan Pascal's documentation is most in-depth and therefore most useful for this kind of thing. But most of it is no longer available except on the [wayback machine here](https://web.archive.org/web/20021213091011/http://www.tsu.ru/~pascal/en/xkb/). He has an introductory [article here](https://www.x.org/archive/X11R7.6/doc/xorg-docs/input/XKB-Enhancing.html); its links are rotten but you can find them again in the wayback machine link. You could also check out [Doug Palmer's docs](https://www.charvolant.org/doug/xkb/html/xkb.html) with particularly useful tables of [what can go into key action statements](https://www.charvolant.org/doug/xkb/html/node5.html#SECTION00055000000000000000) and some [Archlinux docs](https://wiki.archlinux.org/title/X_keyboard_extension), but I think they're less helpful. Martin Krafft also has a [nice article](https://www.linux.com/news/extending-x-keyboard-map-xkb/) about the process he went through to learn how to load key maps with xkbcomp, which is what got me started; but again, his [repository links](https://git.madduck.net/) have all changed (you can only track them down if you look into the git history around the same dates as the articles). 69 | -------------------------------------------------------------------------------- /xremap/README.md: -------------------------------------------------------------------------------- 1 | # Wordstar key map for xremap (Linux) 2 | 3 | Arrow keys are the bane of keyboard life. You constantly have to lift your hands off the home keys to move around your software file. Wordstar cursor control keys are the answer. This Linux key map defines Wordstar cursor control keys using capslock as the 'control' key. 4 | 5 | The advantages of this map using using **[xremap](https://github.com/k0kubun/xremap)** (as compared with xkb) are: 6 | 7 | * it lets you output multiple keystrokes for one input key 8 | * allows you to define application-specific keys 9 | * lets you run an external program on a keypress (e.g. scroll can be implemented using xdotool) 10 | * it has a simpler definition file 11 | 12 | The disadvantage is that the installation process requires root access. 13 | 14 | ### Primary key definitions 15 | 16 | Note: ^ is an abbreviation for CapsLock 17 | 18 | * ^S/^D moves left/right; ^E/^X moves up/down; ^A/^F word left/right; ^R/^C moves page Up/Down; ^U undo 19 | * ^Q acts as a prefix, e.g. ^QS/^QD moves to Home/End of line; ^QR/^QC start/end of document 20 | * ^Y/^QY = delete/cut to end of line; ^T = delete word to the right 21 | * ^QF is find; ^L is re-find; ^QA is replace; ^QJ is goto line 22 | * ^KB/^KK turns on block marking selection mode; ^KH hides it (unmark). 23 | * ^KS save file 24 | * ^KY yank (i.e. cut) block; ^KC copy block; ^KV paste block 25 | * ^PB bold; ^PI italic 26 | * ^W/^Z scroll up and down (these only work if you have xdotool installed) 27 | 28 | #### Extra non-wordstar keys defined: 29 | * ^N insert line break to the right 30 | * ^Y instead of delete whole line, it deletes to end of line; if pressed again, it deletes the newline 31 | * ^Backspace is delete word to the right 32 | * ^B is bold (=ctrl-B) 33 | * ^I is italic (=ctrl-I) 34 | * ^QJ goto line numberImplementation quirks 35 | 36 | As of September 2022 this is a generic wordstar mapping that works for all applications. I expect that some keys won't work perfectly with some applications, so throughout 2022 I will be updating this mapping with any application-specific tweaks as I come across them. 37 | 38 | ## Installation 39 | 40 | The install script will install the key dependencies, xremap and xdotool, which will let you run `xremap wordstar.yml`. Then it will offer to install wordstar keys as a service that will run whenever this user logs in. Simply start a terminal and type the following: 41 | 42 | ``` 43 | git clone https://github.com/berwynhoyt/wordstar-keys.git 44 | cd wordstar-keys/xremap 45 | ./install 46 | ``` 47 | 48 | If you do install the service as above, then changes to keymap at `~/.config/xremap/wordstar.yml` will take effect immediately. If you have trouble, see Customization below. 49 | 50 | ### Linux Support 51 | 52 | If you use Gnome Wayland (I don't), xremap may need [this extra installation step](https://github.com/k0kubun/xremap#gnome-wayland) provided in that link. 53 | 54 | I have tested this installer on Linux Mint, and I expect it will work on most desktop Linux distributions. If it doesn't work for your Linux and you can fix it, then please create a pull request. For other Linux operating systems, more settings may be required: see the installation notes at [xremap](https://github.com/k0kubun/xremap). 55 | 56 | ## Customization 57 | 58 | ### App-specific key tweaks 59 | 60 | Most of these keys will "just work" on your system. But a few keys work slightly better if xremap can detect which app you're currently typing in. You may find additional apps that need these specific tweaks. You can add your own to the wordstar.yml file. You'll see them listed near the beginning of the file. You can find the correct window title names for your own apps as [specified by xremap](https://github.com/k0kubun/xremap#x11-1). 61 | 62 | If you are using Gnome Wayland or Sway (rather than X11), your window titles might differ from mine, I'm not sure. If they are constant between systems, they could be worth contributing to my .yml file as follows. 63 | 64 | ### Hints for making your own tweaks 65 | 66 | When making changes, you might find it simpler to stop the service and run `xremap wordstar.yml` manually. This will print error messages if you make syntax errors in your definitions. To stop the service simply type `systemctl --user stop xremap`. 67 | 68 | However, if you prefer, it is possible to edit the service's yml file live at ~/.config/xremap/wordstar.yml, and your changes will take effect immediately. The only problem is that if you create a syntax error in the file, it will quietly not get re-loaded. You can see whether your live mapping file gets reloaded by looking for "Reloading Config" in the log using `systemctl --user status xremap` or by 'following' the log with `journalctl --user -f`. xremap does not currently print config load errors to the log, unfortunately. 69 | 70 | ### Send me your tweaks 71 | 72 | If you would like to contribute your own tweaks for specific apps so that others can benefit, this is relatively easy to do. Even if you're not up with git, you can contribute using github's online editor: 73 | 74 | 1. Simply sign up to github and you should see an edit pencil icon for [wordstar.yml](https://github.com/berwynhoyt/wordstar-keys/blob/main/xremap/wordstar.yml). 75 | 2. Make your changes and it will create a 'fork' of my repository in your github account. 76 | 3. Click the "Pull Requests" menu and the "New Pull Request" button. 77 | 4. Check that it looks like it's merging your fork into mine and click the "Create pull request" button. 78 | 5. I'll review your suggestions and merge them as appropriate. 79 | 80 | Please make sure you've thoroughly tested your change first. 81 | -------------------------------------------------------------------------------- /xkb/experiments/wscompat-test: -------------------------------------------------------------------------------- 1 | #!xkb #specify_lexicon_for_editor_display_style; tabsize=4 2 | // Define xkb 'compat' file key interpretations for wordstar cursor controls 3 | 4 | // Note: the hex 0x---- keysym codes used here are invented but they must match the ones used in wordstar file 5 | 6 | default partial xkb_compatibility "redirects" { 7 | // Note: keycodes are of the form for the W key: D means row D (spacebar row is row A) and key number 01 = 1 key from the left (i.e. from tab), 8 | // and function keys are ; the rest are found in /usr/share/X11/xkb/keycodes/evdev. 9 | 10 | // Implement various key redirections that could not be done with bare keys. 11 | // Redirections like these are necessary if you want to press a key with Ctrl or Shift 12 | // Note clearing Mod3 is equivalent to clearning ISO_Level5_Shift -- defined in main file 13 | interpret 0xee00 { // ^W ctrl-Up (scroll up) 14 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift+Mod3, modifiers=Control); 15 | }; 16 | interpret 0xee01 { // ^Z ctrl-Down (scroll down) 17 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift+Mod3, modifiers=Control); 18 | }; 19 | 20 | interpret 0xee02 { // ^QR ctrl-Home 21 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift+Mod3, modifiers=Control); 22 | }; 23 | interpret 0xee03 { // ^QC ctrl-End 24 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift+Mod3, modifiers=Control); 25 | }; 26 | 27 | interpret 0xee04 { // ^A ctrl-Left (word left) 28 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift+Mod3, modifiers=Control); 29 | }; 30 | interpret 0xee05 { // ^F ctrl-Left (word right) 31 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift+Mod3, modifiers=Control); 32 | }; 33 | 34 | interpret Find { // ^QF ctrl-f (find) 35 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift+Mod3, modifiers=Control); 36 | }; 37 | interpret 0xee06 { // ^QA ctrl-h (replace) 38 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift+Mod3, modifiers=Control); 39 | }; 40 | 41 | interpret 0xee07 { // ^KC ctrl-c (copy_block) 42 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift+Mod3, modifiers=Control); 43 | }; 44 | interpret 0xee08 { // ^KC ctrl-x (cut_block) 45 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift+Mod3, modifiers=Control); 46 | }; 47 | interpret 0xee09 { // ^KP ctrl-v (paste_block) 48 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift+Mod3, modifiers=Control); 49 | }; 50 | interpret 0xee0a { // ^KS ctrl-c (save) 51 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift+Mod3, modifiers=Control); 52 | }; 53 | 54 | interpret 0xee0b { // ^QY ctrl-Shift-Delete (to be used as part of delete-to-end-of-line) 55 | action = RedirectKey(keycode=, clearModifiers=AltGr+Mod3, modifiers=Shift+Control); 56 | }; 57 | 58 | interpret 0xee0c { // ^QS Home (unshifted) 59 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift+Mod3); 60 | }; 61 | interpret 0xee0d { // ^QD End (unshifted) 62 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift+Mod3); 63 | }; 64 | 65 | interpret 0xee0e { // ^P ctrl-P (print) 66 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift+Mod3, modifiers=Control); 67 | }; 68 | 69 | interpret 0xee0f { // ^QJ=>ctrl-G (jump to line) 70 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift+Mod3, modifiers=Control); 71 | }; 72 | 73 | interpret F3 { // ^L (repeat_find: remove AltGr modifier so it works even while caps held down) 74 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift+Mod3); 75 | }; 76 | 77 | // =============================================== 78 | // Now define codes needed for cursor motion in block selection mode 79 | 80 | // Define cursor keys for block mode selection 81 | interpret 0xee10 { // block-^E=>shift-Up 82 | action = RedirectKey(keycode=, clearModifiers=AltGr+Mod3, modifiers=Shift); 83 | }; 84 | interpret 0xee11 { // block-^X=>shift-Down 85 | action = RedirectKey(keycode=, clearModifiers=AltGr+Mod3, modifiers=Shift); 86 | }; 87 | 88 | interpret 0xee1a { // block-^A=>shift-ctrl-Left 89 | action = RedirectKey(keycode=, clearModifiers=AltGr+Mod3, modifiers=Shift+Control); 90 | }; 91 | interpret 0xee1b { // block-^F=>shift-ctrl-Right 92 | action = RedirectKey(keycode=, clearModifiers=AltGr+Mod3, modifiers=Shift+Control); 93 | }; 94 | 95 | interpret 0xee12 { // block-^S=>shift-Left 96 | action = RedirectKey(keycode=, clearModifiers=AltGr+Mod3, modifiers=Shift); 97 | }; 98 | interpret 0xee13 { // block-^D=>shift-Right 99 | action = RedirectKey(keycode=, clearModifiers=AltGr+Mod3, modifiers=Shift); 100 | }; 101 | 102 | interpret 0xee18 { // block-^QS=>shift-Home 103 | action = RedirectKey(keycode=, clearModifiers=AltGr+Mod3, modifiers=Shift); 104 | }; 105 | interpret 0xee19 { // block-^QD=>shift-End 106 | action = RedirectKey(keycode=, clearModifiers=AltGr+Mod3, modifiers=Shift); 107 | }; 108 | 109 | interpret 0xee14 { // block-^R=>shift-Page_Up 110 | action = RedirectKey(keycode=, clearModifiers=AltGr+Mod3, modifiers=Shift); 111 | }; 112 | interpret 0xee15 { // block-^C=>shift-Page_Down 113 | action = RedirectKey(keycode=, clearModifiers=AltGr+Mod3, modifiers=Shift); 114 | }; 115 | 116 | interpret 0xee16 { // block-^QR=>shift-ctrl-Home 117 | action = RedirectKey(keycode=, clearModifiers=AltGr+Mod3, modifiers=Shift+Control); 118 | }; 119 | interpret 0xee17 { // block-^QC=>shift-ctrl-End 120 | action = RedirectKey(keycode=, clearModifiers=AltGr+Mod3, modifiers=Shift+Control); 121 | }; 122 | 123 | interpret 0xee1c { // ^QJ=>ctrl-G (jump to line) 124 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift+Mod3, modifiers=Control); 125 | }; 126 | 127 | interpret 0xee1d { // ^Backspace=>ctrl-G (jump to line) 128 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift+Mod3, modifiers=Control); 129 | }; 130 | 131 | // =============================================== 132 | // See if we can get keys to produce scroll wheel events. 133 | 134 | // Not sure why this doesn't work. Leave it here to prove I've tried it. 135 | // Instead, I've used ctrl+Up/Down for scroll as some editors scroll that way 136 | //~ interpret Pointer_Button4 { 137 | //~ action = PointerButton(button=4); 138 | //~ }; 139 | //~ interpret Pointer_Button5 { 140 | //~ action = PointerButton(button=5); 141 | //~ }; 142 | }; 143 | -------------------------------------------------------------------------------- /xkb/wscompat: -------------------------------------------------------------------------------- 1 | #!xkb #specify_lexicon_for_editor_display_style; tabsize=4 2 | // Define xkb 'compat' file key interpretations for wordstar cursor controls 3 | 4 | // Note: the hex 0x---- keysym codes used here are invented but they must match the ones used in wordstar file 5 | 6 | default partial xkb_compatibility "redirects" { 7 | // Set up easy access to four groups; may not use them all 8 | // Be aware that any currently pressed SetGroup keys add to whatever you select here (see below) 9 | interpret 0xef01 { action = LockGroup(group=1); }; 10 | interpret 0xef02 { action = LockGroup(group=2); }; 11 | interpret 0xef03 { action = LockGroup(group=3); }; 12 | interpret 0xef04 { action = LockGroup(group=4); }; 13 | 14 | // Set up caps key to increment group 15 | // Note that SetGroup(group=2) internally actually does SetGroup(group=+1); it then subtracts 1 when the key is lifted. 16 | // So we use the syntax that shows what it actually does to avoid confusion when doing simultaneous LockGroups which this adds to 17 | interpret 0xef00 { action = SetGroup(group=+1); }; 18 | 19 | // Set up ^K to latch group3 20 | // Be aware that LatchGroup(group=n) internally translates to LatchGroup(group=+-n). 21 | // where n is set to get to the group you want, taking into account any LockGroups and any SetGroups keys currently down. 22 | // This is important to work out where a deferred group latch will land if there is a LockGroup in between. 23 | // The formula for next group is wrapped_group(new locked group +- groups added by any pending latch delta + groups added by caps key) 24 | interpret 0xef11 { action = LatchGroup(group=1); }; 25 | interpret 0xef12 { action = LatchGroup(group=2); }; 26 | interpret 0xef13 { action = LatchGroup(group=3); }; 27 | interpret 0xef14 { action = LatchGroup(group=4); }; 28 | 29 | // Note: keycodes are of the form for the W key: D means row D (spacebar row is row A) and key number 01 = 1 key from the left (i.e. from tab), 30 | // and function keys are ; the rest are found in /usr/share/X11/xkb/keycodes/evdev. 31 | 32 | // Implement various key redirections that could not be done with bare keys. 33 | // Redirections like these are necessary if you want to press a key with Ctrl or Shift 34 | interpret 0xee00 { // ^W ctrl-Up (scroll up) 35 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift, modifiers=Control); 36 | }; 37 | interpret 0xee01 { // ^Z ctrl-Down (scroll down) 38 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift, modifiers=Control); 39 | }; 40 | 41 | interpret 0xee02 { // ^QR ctrl-Home 42 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift, modifiers=Control); 43 | }; 44 | interpret 0xee03 { // ^QC ctrl-End 45 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift, modifiers=Control); 46 | }; 47 | 48 | interpret 0xee04 { // ^A ctrl-Left (word left) 49 | action = RedirectKey(keycode=, clearModifiers=AltGr, modifiers=Control); 50 | }; 51 | interpret 0xee05 { // ^F ctrl-Left (word right) 52 | action = RedirectKey(keycode=, clearModifiers=AltGr, modifiers=Control); 53 | }; 54 | 55 | interpret Find { // ^QF ctrl-f (find) 56 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift, modifiers=Control); 57 | }; 58 | interpret 0xee06 { // ^QA ctrl-h (replace) 59 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift, modifiers=Control); 60 | }; 61 | 62 | interpret 0xee07 { // ^KC ctrl-c (copy_block) 63 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift, modifiers=Control); 64 | }; 65 | interpret 0xee08 { // ^KC ctrl-x (cut_block) 66 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift, modifiers=Control); 67 | }; 68 | interpret 0xee09 { // ^KP ctrl-v (paste_block) 69 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift, modifiers=Control); 70 | }; 71 | interpret 0xee0a { // ^KS 72 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift, modifiers=Control); 73 | }; 74 | 75 | interpret 0xee0b { // ^QY ctrl-Shift-Delete (to be used as part of delete-to-end-of-line) 76 | action = RedirectKey(keycode=, clearModifiers=AltGr, modifiers=Shift+Control); 77 | }; 78 | 79 | interpret 0xee0c { // ^QS Home (unshifted) 80 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift); 81 | }; 82 | interpret 0xee0d { // ^QD End (unshifted) 83 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift); 84 | }; 85 | 86 | interpret 0xee0e { // ^P ctrl-P (print) 87 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift, modifiers=Control); 88 | }; 89 | 90 | interpret F3 { // ^L (repeat_find: remove AltGr modifier so it works even while caps held down) 91 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift); 92 | }; 93 | 94 | // =============================================== 95 | // Now define codes needed for cursor motion in block selection mode after ^KK 96 | 97 | // Define cursor keys for block mode selection 98 | interpret 0xee10 { // block-^E=>shift-Up 99 | action = RedirectKey(keycode=, clearModifiers=AltGr, modifiers=Shift); 100 | }; 101 | interpret 0xee11 { // block-^X=>shift-Down 102 | action = RedirectKey(keycode=, clearModifiers=AltGr, modifiers=Shift); 103 | }; 104 | 105 | interpret 0xee1a { // block-^A=>shift-ctrl-Left 106 | action = RedirectKey(keycode=, clearModifiers=AltGr, modifiers=Shift+Control); 107 | }; 108 | interpret 0xee1b { // block-^F=>shift-ctrl-Right 109 | action = RedirectKey(keycode=, clearModifiers=AltGr, modifiers=Shift+Control); 110 | }; 111 | 112 | interpret 0xee12 { // block-^S=>shift-Left 113 | action = RedirectKey(keycode=, clearModifiers=AltGr, modifiers=Shift); 114 | }; 115 | interpret 0xee13 { // block-^D=>shift-Right 116 | action = RedirectKey(keycode=, clearModifiers=AltGr, modifiers=Shift); 117 | }; 118 | 119 | interpret 0xee18 { // block-^QS=>shift-Home 120 | action = RedirectKey(keycode=, clearModifiers=AltGr, modifiers=Shift); 121 | }; 122 | interpret 0xee19 { // block-^QD=>shift-End 123 | action = RedirectKey(keycode=, clearModifiers=AltGr, modifiers=Shift); 124 | }; 125 | 126 | interpret 0xee14 { // block-^R=>shift-Page_Up 127 | action = RedirectKey(keycode=, clearModifiers=AltGr, modifiers=Shift); 128 | }; 129 | interpret 0xee15 { // block-^C=>shift-Page_Down 130 | action = RedirectKey(keycode=, clearModifiers=AltGr, modifiers=Shift); 131 | }; 132 | 133 | interpret 0xee16 { // block-^QR=>shift-ctrl-Home 134 | action = RedirectKey(keycode=, clearModifiers=AltGr, modifiers=Shift+Control); 135 | }; 136 | interpret 0xee17 { // block-^QC=>shift-ctrl-End 137 | action = RedirectKey(keycode=, clearModifiers=AltGr, modifiers=Shift+Control); 138 | }; 139 | 140 | interpret 0xee1c { // ^QJ=>ctrl-G (jump to line) 141 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift, modifiers=Control); 142 | }; 143 | 144 | interpret 0xee1d { // ^T or ^Backspace=>ctrl-Del (delete word to the right) 145 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift, modifiers=Control); 146 | }; 147 | 148 | interpret 0xee20 { // ^B=>ctrl-B (bold) 149 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift, modifiers=Control); 150 | }; 151 | 152 | interpret 0xee21 { // ^I=>ctrl-I (italic) 153 | action = RedirectKey(keycode=, clearModifiers=AltGr+Shift, modifiers=Control); 154 | }; 155 | 156 | // Make it so that ISO_Level2_Latch doesn't require the use of the shift key -- so we can use it for ^Q prefix which then equals shift 157 | interpret ISO_Level2_Latch { 158 | action = LatchMods(modifiers=Shift); 159 | }; 160 | 161 | // =============================================== 162 | // See if we can get keys to produce scroll wheel events. 163 | 164 | // Not sure why this doesn't work. Leave it here to prove I've tried it. 165 | // Instead, I've used ctrl+Up/Down for scroll as some editors scroll that way 166 | // ~ interpret Pointer_Button4 { 167 | // ~ action = PointerButton(button=4); 168 | // ~ }; 169 | // ~ interpret Pointer_Button5 { 170 | // ~ action = PointerButton(button=5); 171 | // ~ }; 172 | }; 173 | -------------------------------------------------------------------------------- /xkb/experiments/wordstar-test: -------------------------------------------------------------------------------- 1 | #!xkb //specify_lexicon_for_editor_display_style; tabsize=4 2 | 3 | // Define Wordstar cursor control keys using capslock as the 'control' shift key 4 | // 5 | // e.g. ^S/^D moves left/right; ^E/^X moves up/down; ^A/^F word left/right; ^R/^C moves page Up/Down 6 | // and ^Q acts as a prefix, e.g. ^QS/^QD moves to Home/End of line; ^QR/^QC start/end of document 7 | // ^Y/^QY = delete to end of line (end of paragraph in a word processor - linux quirk) 8 | // ^QF is find; ^L is re-find; ^QA is replace ^QJ is goto line 9 | // ^Backspace is delete word to the right 10 | 11 | // Implementation quirks 12 | // 13 | // All keys defined to come after ^Q will clobber their orignal 'level3' (i.e. AltGr) meaning. 14 | // and ^Q will function as an AltGr latch for the next keypress. 15 | // 16 | // It really is a shame that xkb doesn't let me issue two keystrokes or I could do a lot better. 17 | // With two keystrokes I could implement: 18 | // ^Y (delete to end of line) issues ctrl-Shift-Delete which deletes to end of paragraph in a word processor 19 | // ^N (insert line) issues key. There is no way to issue a second Left key afterward to make it stay on the saame line like it should 20 | // ^QE/^QX (top/bottom of page): there is no standard function to do this in linux 21 | // ^W/^Z (scroll up/down) issues ctrl-Up/Down which works in my editor but in few other apps. 22 | 23 | // I also tried to implement ^KK keys to define block mode in a separate keyboard group using shift-arrows for block. 24 | // It worked but was unweildy because there was no way to turn off block mode using the same key as another action, 25 | // like cut. This meant that block mode was frequently on after an operation when you didn't expect it to be, and it 26 | // often caused blocks of text to be deleted. Using groups also prevented using my greek keyboard layout as group 2 27 | // (I had to switch to it as the main keyboard group, meant that system hotkeys keys didn't fall back to english hotkeys 28 | // and so didn't work as expected). I will retain the ^KK version in a subfolder as it was done well and was a masterful 29 | // example of what can be done with xkb in a pinch. 30 | 31 | // Wordstar keys with caps-q prefix 32 | default partial modifier_keys alphanumeric_keys 33 | xkb_symbols "keys" { 34 | // Cursor motion and ^Q-prefix keys. 35 | 36 | // Empty cells or 'NoSymbol' cells in the table means leave that table entry as it was (the original key functionality). 37 | // 'VoidSymbol' cells produce no key 38 | 39 | // In xkb terminology, shift is a level-2 'shift' which means that while it is held down 40 | // it moves all key lookups right in the table by 1 level (from level 1 to 2). 41 | // I've defined capslock as a level-5 'shift' (4 levels to the right). 42 | // ^Q key prefix is a level3 'latch' which moves the *next key* lookup 2 more columns right in the table 43 | 44 | // Note1: the hex 0x---- keysym codes used here are in place of new keysym name definitions which would require 45 | // recompilation of xkb. They must match the same codes in wscompat so it can redirect to a different keyboard key. 46 | // The codes I've used are not not used by any keysyms in /usr/include/X11/keysymdef.h 47 | // Be aware that it is possible to put RedirectKey actions directly into this file without using 48 | // keysym redirections or a compat file, but it makes the table unweildy. If you wish to do this, the syntax is as follows 49 | // key { 50 | // actions[Group1] = [RedirectKey(keycode=, clearModifiers=AltGr+Shift, modifiers=Control), RedirectKey(...), ...], 51 | // actions[Group...] = [...] }; // notice lack of comma after the last [] 52 | 53 | // Note2: Beware that I tried making caps key a level3_shift, but for some reason it clears cells in google sheets -- annoying! 54 | // So it's a level 5 shift instead, but it still doesn't work in google sheets despite initial tests. What's changed since then? 55 | 56 | // Note3 keycode meanings: is the W key: D means row D (spacebar row is row A) and key number 01 = 1 key from the left (i.e. from tab). 57 | // Other specially named keys like are defined in /usr/share/X11/xkb/keycodes/evdev 58 | 59 | key.type[Group1] = "EIGHT_LEVEL"; // a modification to EIGHT_LEVEL so I can redefine BKSP and retain Terminate_Server 60 | 61 | // columns: { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, ^key, +^key, ^Qkey, +^Qkey] }; // where ^=caps 62 | // ^Q=>Level3_Latch -- create ^Q prefix key and make it look like the next key is pressed with AltGr 63 | key { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, ISO_Level3_Latch, ISO_Level3_Latch, VoidSymbol, VoidSymbol] }; 64 | // ^W=>ctrl-Up=0xee00(scroll_up) 65 | key { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, 0xee00, 0xee00] }; 66 | // ^E=>Up 67 | key { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, Up, 0xee10] }; 68 | // ^R=>Page_Up; ^QR=>0xee02(ctrl-Home 69 | key { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, Page_Up, 0xee14, 0xee02, 0xee16] }; 70 | // ^Y/^QY=>ctrl-Shift-Delete=0xee0b(delete_to_end_of_line/para) 71 | key { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, 0xee0b, VoidSymbol, 0xee0b, VoidSymbol] }; 72 | // ^A=>ctrl-Left=0xee04(word_left); ^QA=>ctrl-h=0xee06(search) 73 | key { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, 0xee04, 0xee1a, 0xee06, 0xee06] }; 74 | // ^S=>Left; ^QS=>0xee0c(Home) 75 | key { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, Left, 0xee12, 0xee0c, 0xee18] }; 76 | // ^D=>Right; ^QD=>0xee0d(End) 77 | key { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, Right, 0xee13, 0xee0d, 0xee19 ] }; 78 | // ^F=>0xee05(ctrl-Right); ^QF=>ctrl-F=Find 79 | key { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, 0xee05, 0xee1b, Find, Find] }; 80 | // ^G=>delete next char 81 | key { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, Delete, Delete, Delete, Delete] }; 82 | // ^H=>Backspace 83 | key { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, BackSpace, BackSpace, BackSpace, BackSpace] }; 84 | // ^QJ=>Jump to line 85 | key { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, 0xee1c, 0xee1c] }; 86 | // ^K=>block latch; implemented to be same as ^Q so we can define just a few common ^K sequences, not block ones since it does not work well in xkb (see notes above) 87 | key { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, ISO_Level3_Latch, ISO_Level3_Latch, VoidSymbol, VoidSymbol] }; 88 | // ^L=>F3(repeat_find) 89 | key { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, F3, F3, F3, F3] }; 90 | // ^P=>0xee0e(ctrl-p=print) 91 | key { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, 0xee0e, NoSymbol, 0xee0e, NoSymbol] }; 92 | // ^Z=>ctrl-Down=0xee01(scroll_down) 93 | key { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, 0xee01, 0xee01] }; 94 | // ^X=>Down 95 | key { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, Down, 0xee11] }; 96 | // ^C=>Page_Down; ^QC->0xee03(ctrl-End) 97 | key { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, Page_Down, 0xee15, 0xee03, 0xee17] }; 98 | // ^N=>insert_line 99 | key { [NoSymbol, NoSymbol, NoSymbol, NoSymbol, Return] }; 100 | 101 | // ^Backspace=>0xee1d(ctrl-Del) 102 | include "wordstar-test(ctrl_alt_bksp)" 103 | 104 | include "wordstar-test(level5_enable)" // see below 105 | include "level3(modifier_mapping)" // enables ISO_Level3_Latch by mapping it to a real modifier (^Q key doesn't count - quirky xkb requirement) 106 | }; 107 | 108 | partial modifier_keys 109 | xkb_symbols "ctrl_alt_bksp" { 110 | key { 111 | type="EIGHT_LEVEL_CTRL", // Put Ctrl+Alt on Level4 for this key to allow us us to reinstate terminate server. Not sure if this is a good idea. 112 | symbols[Group1] = [ NoSymbol, NoSymbol, NoSymbol, Terminate_Server, 0xee1d] 113 | }; 114 | }; 115 | 116 | // For Level5_Shift to work, must map a real (non-virtual) modifier to it. Don't know why it needs this. 117 | partial modifier_keys 118 | xkb_symbols "level5_enable" { 119 | // This code is stolen from 'include "level5(modifier_mapping)"' but with different key. 120 | // Instead of using the key (for which the compiler complains that " 121 | // is added to map for multiple modifiers" and ignores one of the definitions, making operation flakey), 122 | // I've chosen key because it's unlikely to be used 123 | // If you want a real key, say as a level 5 shift. 124 | // (But why would you want that when you have our key combo to do it?) 125 | // see /usr/share/X11/xkb/keycodes/evdev for key definitions like 126 | key { 127 | type[Group1] = "ONE_LEVEL", // must be in group 1 for Level5_Shift to work in group 1 128 | symbols[Group1] = [ISO_Level5_Shift] 129 | }; 130 | modifier_map Mod2 { }; 131 | }; 132 | -------------------------------------------------------------------------------- /xremap/wordstar.yml: -------------------------------------------------------------------------------- 1 | # Credit Berwyn Hoyt: https://github.com/berwynhoyt/wskeys 2 | 3 | # Some of these are marked as not standard wordstar keys. 4 | # See here for all standard wordstar key bindings: 5 | # http://www.wordstar.org/index.php/wsemu-documentation/wsemu-commands-and-menus/1-wordstar-emulator-full-version-command-list 6 | 7 | # To discover application names, see https://github.com/k0kubun/xremap/tree/v0.8.6#x11-1 8 | # On X11, run: wmctrl -xl 9 | 10 | # If you have problems, print keystrokes by running with: RUST_LOG=debug xremap wordstar.yml 11 | 12 | # The following makes it work in wayland and in whatsapp web in chrome/firefox/ferdium 13 | keypress_delay_ms: 20 14 | 15 | virtual_modifiers: 16 | - CapsLock 17 | 18 | shared: 19 | # Workaround if you use bouncekeys: you will need to increase the following sleep time 20 | # in ms to be larger than your bouncekeys delay in order for some mappings to work. 21 | # (In Linux Mint, bouncekeys is in accessibility/typing and each slider 'notch' is 10ms.) 22 | # This is because these key sequences output repetitions of the same keystroke (most 23 | # notably Ctrl and Shift) which bouncekeys suppresses. Note that the problem only occurs 24 | # when bouncekeys is enabled after xremap is run. 25 | sleep: &sleep {sleep: 0} # set to longer than your bouncekeys delay 26 | 27 | word_right: &word_right [{with_mark: C-right}, {with_mark: right}] 28 | # Note: to make del_next_word work the same on bash command line (to delete trailing spaces), put this in ~/.inputrc: 29 | # Make Ctrl-right (forward word) also skip space 30 | # "\e[1;5C": vi-fword 31 | # Maps ^Delete to "space,C-right,C-[-h,backspace" to make it do 'kill-word' but include subsequent spaces 32 | # Works everwhere except at end of command line: 33 | # "\e[3;5~": " \e[1;5C\e\C-h\C-?" 34 | del_next_word: &del_next_word [{set_mark: false}, C-delete] 35 | # the following version deletes trailing space even in Chrome, Firefox, google docs, etc. 36 | del_next_word2: &del_next_word2 [{set_mark: false}, C-shift-right, *sleep, C-shift-right, *sleep, C-shift-left, delete] 37 | 38 | keymap: 39 | # ~~~~ app-specific overrides must go first before the default key definitions 40 | # You can discover app names to use below using the instructions for your OS (see link above) 41 | 42 | - name: Make Zoho Mail keys more compatible with Gmail 43 | application: 44 | only: Zoho Mail - Desktop 45 | remap: 46 | C-w: C-Backslash # close tab 47 | C-Shift-8: C-dot # bullets 48 | C-Shift-7: C-slash # numbering 49 | C-q: Alt-F4 # Quit app 50 | C-rightbrace: C-m 51 | C-leftbrace: C-Shift-m 52 | 53 | - name: common-app-quirks 54 | # some apps don't properly move to the next word when pressing ctrl-right; 55 | # they only move to the end of the current word, before the space 56 | # this makes them consistent with most editors and word-processors 57 | application: 58 | only: 59 | - Google-chrome # name in both Wayland and X11 60 | - Ferdium # name in both Wayland and X11 61 | - firefox # name in both Wayland and X11 62 | - Typora # name in both Wayland and X11 63 | - Xed # name in both Wayland and X11 64 | - Zotero 65 | - Zoho Mail - Desktop 66 | remap: 67 | CapsLock-f: *word_right 68 | #Delete-next-word (incuding trailing space). 69 | # Use text marking to achieve a one-key undo 70 | CapsLock-backspace: *del_next_word2 71 | CapsLock-t: *del_next_word2 72 | 73 | - name: google-calendar 74 | window: 75 | only: [/Google Calendar -.*/] 76 | remap: 77 | CapsLock-s: p 78 | CapsLock-d: n 79 | 80 | - name: scroll-override-app-specific 81 | # Some apps implement scroll on Ctrl-Up/Down keys. Use those, if possible, to get a more controlled single-line scroll 82 | application: 83 | only: 84 | - scite.Scite 85 | - code.Code 86 | remap: 87 | # Note: the following sleep is so that keyrepeat works even with bouncekeys turned on 88 | CapsLock-w: [C-Up, *sleep] # Scroll up 89 | CapsLock-z: [C-Down, *sleep] # Scroll down 90 | 91 | - name: disable-esc-in-flameshot 92 | # disable in flameshot because it always exits accidentally. Instead make it switch to selection mode. 93 | application: 94 | only: flameshot 95 | remap: 96 | Esc: [a, s, s] # delete whole line like in windows 97 | 98 | - name: scroll-override-Gnome-terminal 99 | application: 100 | only: [gnome-terminal-server, Gnome-terminal] # names in Wayland and X11, respectively 101 | remap: 102 | CapsLock-s: C-b # bind these to emacs keys which work better than arrows in tcsh's readline 103 | CapsLock-d: C-f 104 | C-v: C-Shift-v # add Ctrl-v paste as well as gnome-terminal default of C-Shift-v 105 | C-Alt-v: C-v # but make C-Alt-v do what C-v used to do (quoted-insert) 106 | # Make Ctrl-tab and Ctrl-shift-tab switch tabs in Gnome terminal 107 | C-tab: C-pagedown 108 | C-Shift-tab: C-pageup 109 | # Gnome terminal implements scroll using Ctrl-Shift-Up/down 110 | CapsLock-w: C-Shift-Up 111 | CapsLock-z: C-Shift-Down 112 | # specific key maps that work in readline (e.g. bash) 113 | CapsLock-y: C-k # del end-of-line; (non-wordstar: in ws it deletes the whole line) 114 | Esc: [Home, C-k] # delete whole line like in windows 115 | CapsLock-k: 116 | # readline-specific (e.g. bash) block marking 117 | # NOTE: requires that you put the line 'C-h: kill-region' in your ~/.inputrc (or run 'bind C-h:kill-region') 118 | # Block marking works slightly different than with wordstar because you can only mark 119 | # block beginning (^KB or ^KK) and the end is where the cursor is. 120 | # However, it works pretty well using the standard ^KY as cut and adding ^KV as paste. 121 | # I've also added my preferred non-standard shortcuts ^KX (cut), ^KD (copy), ^KP (paste) 122 | remap: 123 | # Block cut - make it do the same as block copy since there is no cut in Gnome terminal 124 | CapsLock-y: [C-Shift-c] 125 | CapsLock-x: [C-Shift-c] # non-wordstar: in ws it exits without saving 126 | # Block copy(duplicate) - only works in bash/readline 127 | CapsLock-c: [C-Shift-c] 128 | CapsLock-d: [C-Shift-c] 129 | # block paste into Gnome terminal 130 | CapsLock-v: [C-Shift-v] # use wordstar's key for 'block move' 131 | CapsLock-p: [C-Shift-v] # non-wordstar mapping: in ws it prints. I might revert to that in future, so don't get used to it. 132 | # Mark mode - there is no keyboard-initiated mark mode in Gnome Terminal 133 | # The only reason to include ^Q keys is to bind ^Q^S and ^Q^D to a sequence works better for tcsh's readline. 134 | # But if you redefine some ^Q keys here, you have to define them all due to xremap quirk 135 | CapsLock-q: 136 | remap: 137 | # Cut to end of line doesn't work in terminal, so just do delete to end of line 138 | CapsLock-y: [{set_mark: false}, C-k] 139 | # Beginning/End of line 140 | CapsLock-s: [C-b-f, {with_mark: home}] 141 | CapsLock-d: [C-f-b, {with_mark: end}] 142 | # Beginning/End of file 143 | CapsLock-r: {with_mark: C-home} 144 | CapsLock-c: {with_mark: C-end} 145 | # Search 146 | CapsLock-f: [{set_mark: false}, C-f] # find 147 | CapsLock-a: [{set_mark: false}, C-h] # replace 148 | # CapsLock-q u (undo) 149 | u: [{set_mark: false}, C-z] 150 | # Goto line 151 | j: C-g # non-wordstar 152 | 153 | 154 | - name: repeat-search-libreoffice 155 | application: 156 | only: libreoffice-writer 157 | remap: 158 | CapsLock-l: [{set_mark: false}, Esc, C-Shift-f] # Repeat search in libreoffice 159 | Ctrl-Shift-8: [Ctrl-Alt-8] # Libreoffice doesn't recognise Ctrl-Shift-8 in Linux so assign it to some other key so that I can assign it in Libreoffice 160 | 161 | # ~~~~ Note: the following are unrelated to wordstar but included here for the author's own convenience. Feel free to remove them. 162 | 163 | - name: highlight-hotkey-in-calibre-ebook-reader 164 | application: 165 | only: calibre-ebook-viewer.calibre 166 | remap: 167 | CapsLock-h: [h, C-Enter] 168 | 169 | - name: Make ferdium quit key (^Q) perform hide (^W) 170 | application: 171 | only: Ferdium # name in both Wayland and X11 172 | remap: 173 | C-q: C-w 174 | 175 | # ~~~~ Now for the main key definitions 176 | - name: Main-Wordstar-Keys 177 | remap: 178 | # Remove mark if switching out of this app where it might cause problems 179 | Alt-tab: [{set_mark: false}, Alt-tab] 180 | 181 | # Cursor 182 | CapsLock-s: {with_mark: left} 183 | CapsLock-d: {with_mark: right} 184 | CapsLock-e: {with_mark: up} 185 | CapsLock-x: {with_mark: down} 186 | # Forward/backward word 187 | CapsLock-f: {with_mark: C-right} 188 | CapsLock-a: {with_mark: C-left} 189 | # Page up/down 190 | CapsLock-r: {with_mark: pageup} 191 | CapsLock-c: {with_mark: pagedown} 192 | # Insert newline 193 | CapsLock-n: [enter, left] # non-wordstar: does nothin in ws 194 | 195 | # Delete 196 | CapsLock-g: [delete, {set_mark: false}] 197 | CapsLock-h: [backspace, {set_mark: false}] 198 | delete: [delete, {set_mark: false}] 199 | backspace: [backspace, {set_mark: false}] 200 | 201 | # Delete to end of line; then delete linebreak if pressed again. 202 | CapsLock-y: [{set_mark: false}, Shift-end-end, delete] # non-wordstar: in ws it deletes the whole line; some apps need the repeated 'end' to 'take' 203 | # Undo 204 | CapsLock-u: [{set_mark: false}, C-z] 205 | # Repeat-find 206 | CapsLock-l: [{set_mark: false}, F3] # re-find 207 | # Delete next word, including trailing space. 208 | CapsLock-backspace: *del_next_word 209 | CapsLock-t: *del_next_word 210 | 211 | # Scroll up/down. Most apps don't implement Ctrl-Up/Down 212 | # The following complex command could be simply 'xdotool click 4' 213 | # except that operates on the window under the mouse, not the active window. 214 | # So, instead, we have to: save mouse location, move mouse to active window but under the menu bars, scroll, restore mouse 215 | CapsLock-w: {launch: ['xdotool', 'getactivewindow', 'mousemove', '0', '0', 'mousemove', '--window', '%1', '20', '130', 'click', '4', 'mousemove', 'restore']} 216 | CapsLock-z: {launch: ['xdotool', 'getactivewindow', 'mousemove', '0', '0', 'mousemove', '--window', '%1', '20', '130', 'click', '5', 'mousemove', 'restore']} 217 | 218 | # Non-wordstar extensions I like 219 | # Italic/bold 220 | CapsLock-i: C-i 221 | CapsLock-b: C-b 222 | 223 | CapsLock-q: 224 | remap: 225 | # Cut to end of line 226 | CapsLock-y: [{set_mark: false}, Shift-end-end-end, C-x] # some apps need the repeats to 'take' 227 | # Beginning/End of line 228 | CapsLock-s: {with_mark: home} 229 | CapsLock-d: {with_mark: end} 230 | # Beginning/End of file 231 | CapsLock-r: {with_mark: C-home} 232 | CapsLock-c: {with_mark: C-end} 233 | # Search 234 | CapsLock-f: [{set_mark: false}, C-f] # find 235 | CapsLock-a: [{set_mark: false}, C-h] # replace 236 | # CapsLock-q u (undo) 237 | u: [{set_mark: false}, C-z] 238 | # Goto line 239 | j: C-g # non-wordstar 240 | 241 | CapsLock-k: 242 | # Block marking works slightly different than with wordstar because you can only mark 243 | # block beginning (^KB or ^KK) and the end is where the cursor is. 244 | # However, it works pretty well using the standard ^KY as cut and adding ^KV as paste. 245 | # I've also added my preferred non-standard shortcuts ^KX (cut), ^KD (copy), ^KP (paste) 246 | remap: 247 | # Block cut 248 | CapsLock-y: [C-x, {set_mark: false}] 249 | CapsLock-x: [C-x, {set_mark: false}] # non-wordstar: in ws it exits without saving 250 | # Block copy(duplicate) 251 | CapsLock-c: [C-c, {set_mark: false}, up, down] # block copy - up/down removes the visibl mark 252 | CapsLock-d: [C-c, {set_mark: false}, up, down] # non-wordstar: in ws it does save-and-close 253 | # block paste 254 | CapsLock-v: [C-v, {set_mark: false}] # use wordstar's key for 'block move' 255 | CapsLock-p: [C-v, {set_mark: false}] # non-wordstar: in ws it prints. I might revert to that in future, so don't get used to it. 256 | # Mark 257 | CapsLock-b: {set_mark: true} 258 | CapsLock-k: {set_mark: true} # non-wordstar 259 | # Hide mark 260 | CapsLock-h: [{set_mark: false}, up, down] 261 | # Save 262 | CapsLock-s: C-s 263 | 264 | # Text formatting keys 265 | CapsLock-p: 266 | remap: 267 | # Bold 268 | CapsLock-b: C-b 269 | # Italic 270 | CapsLock-i: C-i 271 | # Print 272 | CapsLock-p: C-p 273 | -------------------------------------------------------------------------------- /xkb/wordstar: -------------------------------------------------------------------------------- 1 | #!xkb //specify_lexicon_for_editor_display_style; tabsize=4 2 | 3 | // Define Wordstar cursor control keys using capslock as the 'control' shift key 4 | // 5 | // e.g. ^S/^D moves left/right; ^E/^X moves up/down; ^A/^F word left/right; ^R/^C moves page Up/Down 6 | // and ^Q acts as a prefix, e.g. ^QS/^QD moves to Home/End of line; ^QR/^QC start/end of document 7 | // ^Y/^QY = delete to end of line (end of paragraph in a word processor - linux quirk) 8 | // ^QF is find; ^L is re-find; ^QA is replace; ^QJ is goto line 9 | // ^KB/^KK turns on block marking selection mode; ^KH hides (releases) it. 10 | // ^KS block_save file 11 | // ^KY yank_block(i.e. cut); ^KC copy block 12 | // ^KP block_paste -- not wordstar standard which doesn't have paste 13 | 14 | // Extra non-wordstar keys: 15 | // ^Backspace is delete word to the right 16 | // ^B is bold (=ctrl-B) 17 | // ^I is italic (=ctrl-I) 18 | 19 | // Implementation quirks 20 | // 21 | // It really is a shame that xkb doesn't let me issue two keystrokes or I could do a lot better. 22 | // With two keystrokes I could implement: 23 | // ^Y (delete to end of line) issues ctrl-Shift-Delete which deletes to end of paragraph in a word processor 24 | // ^N (insert line) issues key. There is no way to issue a second Left key afterward to make it stay on the same line like it should 25 | // ^QE/^QX (top/bottom of page): there is no standard function to do this in linux 26 | // ^W/^Z (scroll up/down) issues ctrl-Up/Down which works in my editor but in few other apps. 27 | // ^KX/^KC automatically exit block mode afterward 28 | 29 | // Main import: wordstar(keys) 30 | default partial modifier_keys alphanumeric_keys 31 | xkb_symbols "keys" { 32 | // when 'keys' invoked, include sub-sections from same file below 33 | replace "wordstar(qkeys)" 34 | include "wordstar(kkeys)" 35 | }; 36 | 37 | // Wordstar keys with caps-q prefix 38 | partial modifier_keys alphanumeric_keys 39 | xkb_symbols "qkeys" { 40 | // Cursor motion and ^Q-prefix keys. These can be used without kkeys below if you want simplicity 41 | 42 | // Empty cells or 'NoSymbol' cells in the table means leave that table entry as it was (the original key functionality). 43 | // 'VoidSymbol' cells produce no key 44 | 45 | // This works by making capslock a Group+1 latch in xkb terminology which means it 46 | // moves all key lookups into the second set of square brackets in table below 47 | // ^Q key prefix is a level2 'latch' (same as shift) which moves the *next key* lookup 1 column right in the table to 'level 2' 48 | 49 | // Note1: the hex 0x---- keysym codes used here are in place of new keysym name definitions which would require 50 | // recompilation of xkb. They must match the same codes in wscompat so it can redirect to a different keyboard key. 51 | // The codes I've used are not not used by any keysyms in /usr/include/X11/keysymdef.h 52 | // Be aware that it is possible to put RedirectKey actions directly into this file without using 53 | // keysym redirections or a compat file, but it makes the table unweildy. If you wish to do this, the syntax is as follows 54 | // key { 55 | // actions[Group1] = [RedirectKey(keycode=, clearModifiers=AltGr+Shift, modifiers=Control), RedirectKey(...), ...], 56 | // actions[Group...] = [...] }; // notice lack of comma after the last [] 57 | 58 | // Note2: Beware that I tried making caps key a level3_latch and a level5_latch (see 'experiments' directory), but for some reason 59 | // it clears cells in google sheets -- annoying! So it's a group_latch instead. 60 | 61 | // Note3 keycode meanings: is the W key: D means row D (spacebar row is row A) and key number 01 = 1 key from the left (i.e. from tab). 62 | // Other specially named keys like are defined in /usr/share/X11/xkb/keycodes/evdev 63 | 64 | replace "wordstar(caps_key)" // Make caps key a group2 latch 65 | 66 | name[Group2] = "wskeys"; 67 | // Note: it's really only a TWO_LEVEL table, but specify EIGHT_LEVEL for the level5 ^K stuff below. 68 | // Duplicate levels 1/2 into subsequent levels 3/4 entries to support the vestigal ^K latch (see note on 'vestigal' in kkeys below) 69 | // That way any level3 keys from a vestigal ^K latch after exiting blocking mode will perform their usual function, avoiding the confusing effects of the vestigal ^K 70 | key.type[Group2] = "EIGHT_LEVEL"; 71 | key.groupsredirect = 1; // if a key is missing in any group, revert to group 1 72 | 73 | // columns: { [], [^key, ^Qkey] }; // where ^=caps 74 | // ^Q=>Level2_Latch(=shift) -- create ^Q prefix key and make it look like the next key is pressed with shift 75 | key { [], [ISO_Level2_Latch, VoidSymbol, ISO_Level2_Latch, VoidSymbol] }; 76 | // ^W=>ctrl-Up=0xee00(scroll_up) 77 | key { [], [0xee00, VoidSymbol, 0xee00, VoidSymbol] }; 78 | // ^E=>Up 79 | key { [], [Up, VoidSymbol, Up, VoidSymbol] }; 80 | // ^R=>Page_Up; ^QR=>0xee02(ctrl-Home) 81 | key { [], [Page_Up, 0xee02, Page_Up, 0xee02] }; 82 | // ^T=0xee1d(ctrl-Del) - delete word to the right 83 | key { [], [0xee1d, VoidSymbol, 0xee1d, VoidSymbol] }; 84 | // ^Y/^QY=>ctrl-Shift-Delete=0xee0b(delete_to_end_of_line/para) 85 | key { [], [0xee0b, 0xee0b, 0xee0b, 0xee0b] }; 86 | // ^I=>0xee21(ctrl-I: italic) 87 | key { [], [0xee21] }; 88 | // ^A=>ctrl-Left=0xee04(word_left); ^QA=>ctrl-h=0xee06(search) 89 | key { [], [0xee04, 0xee06, 0xee04, 0xee06] }; 90 | // ^S=>Left; ^QS=>0xee0c(Home) 91 | key { [], [Left, 0xee0c, Left, 0xee0c] }; 92 | // ^D=>Right; ^QD=>0xee0d(End) 93 | key { [], [Right, 0xee0d, Right, 0xee0d] }; 94 | // ^F=>0xee05(ctrl-Right); ^QF=>ctrl-F=Find 95 | key { [], [0xee05, Find, 0xee05, Find] }; 96 | // ^G=>delete next char 97 | key { [], [Delete, VoidSymbol, Delete, VoidSymbol] }; 98 | // ^H=>Backspace 99 | key { [], [BackSpace, VoidSymbol, BackSpace, VoidSymbol] }; 100 | // ^QJ=>Jump to line 101 | key { [], [NoSymbol, 0xee1c, NoSymbol, 0xee1c] }; 102 | // ^L=>F3(repeat_find) 103 | key { [], [F3, VoidSymbol, F3, VoidSymbol] }; 104 | // ^P=>0xee0e(ctrl-p=print) 105 | key { [], [0xee0e, NoSymbol, 0xee0e, NoSymbol] }; 106 | // ^Z=>ctrl-Down=0xee01(scroll_down) 107 | key { [], [0xee01, VoidSymbol, 0xee01, VoidSymbol] }; 108 | // ^X=>Down 109 | key { [], [Down, VoidSymbol, Down, VoidSymbol] }; 110 | // ^C=>Page_Down; ^QC->0xee03(ctrl-End) 111 | key { [], [Page_Down, 0xee03, Page_Down, 0xee03] }; 112 | // ^B=>0xee20(ctrl-B: bold) 113 | key { [], [0xee20] }; 114 | // ^N=>insert_line 115 | key { [], [Return, VoidSymbol, Return, VoidSymbol] }; 116 | // ^Backspace=>0xee1d(ctrl-Del) 117 | key { [], [0xee1d] }; 118 | }; 119 | 120 | // Wordstar keys with caps-k prefix 121 | partial modifier_keys alphanumeric_keys 122 | xkb_symbols "kkeys" { 123 | include "wordstar(level5_enable)" // includes code below 124 | 125 | // Note on 'vestigal' ^K keys: xkb has a really annoying quirk that makes ^KB/^KH implementation difficult and messy: 126 | // a key like ^KH that does group-shift or level-shift does not get recognised as a key by xkb's 127 | // unlatching mechanism. This means, for example that the latch is still in effect after ^KH, so the next key 128 | // pressed after ^KH will be looked up with the ^K level5 latch still in effect, shifting it in the table 129 | // This is especially awkward when entering/exiting block mode. The only way to distinguish 130 | // between a fake ^K and a real one is to have the ^K latch level different in block mode and normal mode. 131 | // That is why I have made it a Level3_Latch in block mode and Level5_Latch in normal mode. 132 | // Think carefully about how to fill up the vestigal key table entries: they should contain what the non ^K entry has. 133 | 134 | //caps=group+1 135 | //^Q=Level2_Latch (i.e. Shift) 136 | //^K=Level3_Latch in block mode 137 | //^K=Level5_Latch in non-block mode -- this must be different than in block mode so we can distinguish the false carryover ^K latch 138 | //^KK=Group3_Lock (added to caps' +1 group to produce Group4. Leave Group3 array empty to revert to Group1 if user lifts caps by accident) 139 | 140 | name[Group4] = "ws-mark-keys"; 141 | key.type[Group2] = "EIGHT_LEVEL"; // see note re EIGHT_LEVEL in qkeys above 142 | key.type[Group4] = "FOUR_LEVEL"; 143 | 144 | // If a key is missing in any group, revert to group 1 145 | // Note that this does not clamp groups, only keys. SetGroup(group=+2) always wraps 146 | // (e.g. a group 4 key that does SetGroup(group=+2) wraps around to group 2 since group 4 is the last possible group) 147 | key.groupsredirect = 1; 148 | 149 | // The first 4 slots in group2 of the table below should be set to NoSymbol to inherit them from qkeys above 150 | // Note that the vestigal Level5 ^K key latch from enter block mode will correctly wraps because of FOUR_LEVEL group size 151 | // *Note (below): when ^K is pressed immediately after ^KH block exit, then both level 3 and 5 are on, adding up to level7 152 | 153 | // columns: { [], [^key, ^Qkey, vestigal-(^Kkey, +^Kkey), ^Kkey, *Note], [], block:[^key, ^Qkey, ^Kkey, +^Kkey] }; // where ^=caps; +=shift 154 | // block-^Q=>Level2_Latch(=shift) 155 | key { [], [], [], [ISO_Level2_Latch, VoidSymbol] }; 156 | // block-^W=>ctrl-Up=0xee00(scroll_up) 157 | key { [], [], [], [0xee00, VoidSymbol] }; 158 | // block-^E=>0xe10(shift-Up) 159 | key { [], [], [], [0xee10, VoidSymbol] }; 160 | // block-^R=>0xee14(shift-Page_Up) 161 | key { [], [], [], [0xee14, 0xee16] }; 162 | // ^Y/^QY=0xee0b(delete_to_end_of_line); ^KY=>ctrl-x=0xee08(cut_block); 163 | key { [], [NoSymbol, NoSymbol, NoSymbol, NoSymbol, 0xee08], [], [0xee0b, 0xee0b, 0xee08] }; 164 | // block-^I=>0xee21(ctrl-I: italic) 165 | key { [], [], [], [0xee21] }; 166 | // ^P=>0xee0e(ctrl-p=print); ^KP=>0xee09(block_paste=paste) 167 | key { [], [NoSymbol, NoSymbol, NoSymbol, NoSymbol, 0xee09], [], [0xee0e, NoSymbol, 0xee09] }; 168 | // block-^A=>shift-ctrl-Left=0xee1a(shift-ctrl-Left); block-^QA=>ctrl-h=0xee06(search) 169 | key { [], [], [], [0xee1a, 0xee06] }; 170 | // ^KS=>0xee0a(ctrl-s=save); block-^S=>0xee12(shift-Left); block-^QS=>0xee18(shift-Home); block-^KS=>0xee0a(ctrl-s=save) 171 | key { [], [NoSymbol, NoSymbol, NoSymbol, NoSymbol, 0xee0a, NoSymbol, 0xee0a], [], [0xee12, 0xee18, 0xee0a] }; 172 | // ^KD=>0xee07(copy=duplicate_block); block-^D=>0xee13(shift-End); block-^QD=>0xee19(shift-End) 173 | key { [], [NoSymbol, NoSymbol, NoSymbol, NoSymbol, 0xee07, NoSymbol, 0xee07], [], [0xee13, 0xee19, 0xee07] }; 174 | // block-^F=>0xee1b(shift-ctrl-Right); block-^QF=>ctrl-F=Find 175 | key { [], [], [], [0xee1b, Find] }; 176 | // ^G=>delete next char 177 | key { [], [], [], [Delete, VoidSymbol] }; 178 | // block-^KH=>unblock (Shift_L performs un-shiftlock); block-^H=>BackSpace; block-^KH=>un_block(hide) 179 | key { [], [], [], [ISO_Level3_Latch, VoidSymbol, 0xef01] }; 180 | // ^K=>prefix_key(Level5_Latch); ^KK=>0xef03(start_block); block-^KK=>0xef01(un_block) 181 | key { [], [ISO_Level5_Latch, VoidSymbol, ISO_Level5_Latch, NoSymbol, 0xef03], [], [ISO_Level3_Latch, VoidSymbol, 0xef01] }; 182 | // block-^L=>F3(repeat_find) 183 | key { [], [], [], [F3, VoidSymbol] }; 184 | // block-^Z=>ctrl-Down=0xee01(scroll_down) 185 | key { [], [], [], [0xee01, VoidSymbol] }; 186 | // ^KX=>ctrl-x=0xee08(block_cut); block-^X=>0xee11(shift-Down); block-^KX=>0xee08(block_cut) 187 | key { [], [NoSymbol, NoSymbol, NoSymbol, NoSymbol, 0xee08, Nosymbol, 0xee08], [], [0xee11, VoidSymbol, 0xee08] }; 188 | // ^KC=>ctrl-x=0xee07(copy_block); block-^C=>0xee15(shift-Page_Down); block-^QC=>0xee17(shift-ctrl-End); block-^KC=>0xee08(block_cut) 189 | key { [], [NoSymbol, NoSymbol, NoSymbol, NoSymbol, 0xee07, NoSymbol, 0xee07], [], [0xee15, 0xee17, 0xee07] }; 190 | // ^KV=>0xee09(block_paste=paste) 191 | key { [], [NoSymbol, NoSymbol, NoSymbol, NoSymbol, 0xee09], [], [NoSymbol, NoSymbol, 0xee09] }; 192 | // ^KB=>0xef03(start_block); block-^KB=>0xef01(hide_block) 193 | key { [], [NoSymbol, VoidSymbol, VoidSymbol, VoidSymbol, 0xef03], [], [0xee20, VoidSymbol, 0xef01] }; 194 | }; 195 | 196 | // Make capslock generate the level3 modifier 197 | partial modifier_keys 198 | xkb_symbols "caps_key" { 199 | key { 200 | type = "TWO_LEVEL", 201 | // caps=>group+1; shift-caps=>revert to group1 (in case it gets stuck in another group when ^KH isn't working) 202 | [0xef00, 0xef01], [0xef00, 0xef01], [0xef00, 0xef01], [0xef00, 0xef01] 203 | }; 204 | }; 205 | 206 | // For Level5_Shift to work, must map a real (non-virtual) modifier to it. Don't know why it needs this. 207 | partial modifier_keys 208 | xkb_symbols "level5_enable" { 209 | // This code is stolen from 'include "level5(modifier_mapping)"' but with different key. 210 | // Instead of using the key (for which the compiler complains that " 211 | // is added to map for multiple modifiers" and ignores one of the definitions, making operation flakey), 212 | // I've chosen key because it's unlikely to be used 213 | // If you want a real key, say as a level 5 shift. 214 | // (But why would you want that when you have our key combo to do it?) 215 | // see /usr/share/X11/xkb/keycodes/evdev for key definitions like 216 | key { 217 | type[Group1] = "ONE_LEVEL", // must be in group 1 for Level5_Shift to work in group 1 218 | symbols[Group1] = [ISO_Level5_Shift] 219 | }; 220 | modifier_map Mod3 { }; 221 | }; 222 | -------------------------------------------------------------------------------- /autohotkey/Wordstar Capslock.ahk: -------------------------------------------------------------------------------- 1 | ; Wordstar key map for AutoHotkey - designed by Bruce Hoyt 2 | 3 | ; Simply install Autohotkey, then double-click this file 4 | ; or put it in the windows startup folder to run it on startup 5 | ; Makes CapsLock act like WordStar 'Ctrl', but leaves Ctrl alone 6 | 7 | #MaxHotkeysPerInterval 150 ; keyboard repeat can be bigger than this otherwise 8 | 9 | ; ------------------------------- 10 | ; Define window classes for special e.g. MS Office key overrides down below 11 | ; ------------------------------- 12 | GroupAdd,MSWord,ahk_class OpusApp ; Word 13 | 14 | GroupAdd,MSOffice,ahk_group MSWord 15 | GroupAdd,MSOffice,ahk_class XLMAIN ; Excel 2007 16 | 17 | GroupAdd,WordProcessors,ahk_group MSWord 18 | 19 | GroupAdd,Eclipse,Eclipse SDK 20 | Groupadd,Eclipse,Code Composer Studio 21 | 22 | GroupAdd,Unix,ahk_class PuTTY ; putty 23 | GroupAdd,Unix,NX ahk_class cygwin/xfree86 rl ; NX Nomachine 24 | 25 | GroupAdd,kicad,Ahk_class wxWindowNR 26 | 27 | ; Chrome except Google Drive (i.e. Google Docs) 28 | GroupAdd,Chrome,ahk_class Chrome_WidgetWin_1,,,Google Drive 29 | 30 | ; ------------------------------- 31 | ; Setup 32 | ; ------------------------------- 33 | #SingleInstance force 34 | SetCapsLockState,AlwaysOff 35 | Menu, TRAY, Icon,%ProgramFiles%\AutoHotkey\AutoHotkey.exe,2,1 36 | ;#NoTrayIcon ; include if you don't want an icon in the tray 37 | SetTitleMatchMode, 2 ; match anywhere in title 38 | 39 | 40 | ; Make shift-capslock act like the old capslock 41 | ;+CapsLock:: 42 | ; GetKeyState,caps,CapsLock,T 43 | ; if caps = D 44 | ; SetCapsLockState,AlwaysOff 45 | ; else 46 | ; SetCapsLockState,On 47 | ;return 48 | 49 | ; Also make RAlt act like the old capslock 50 | RAlt:: 51 | GetKeyState,caps,CapsLock,T 52 | if caps = D 53 | SetCapsLockState,AlwaysOff 54 | else 55 | SetCapsLockState,AlwaysOn 56 | return 57 | 58 | 59 | ; ------------------------------- 60 | ;Find-Windows that get auto-closed when you push 61 | ; ------------------------------- 62 | GroupAdd,FindWindow,Find ahk_class bosa_sdm_Microsoft Office Word 12.0 ; Word 2007 find window 63 | GroupAdd,FindWindow,Find ahk_class #32770 ; Notepad find window 64 | 65 | #IfWinActive ahk_group FindWindow ; one of the find windows 66 | $Enter:: 67 | Send {Enter}{Esc} ; Escape out of find window 68 | return 69 | 70 | 71 | 72 | ; ------------------------------- 73 | ; NOTE: Put exceptions to wordstar keys under specific apps below, but above main wordstar settings at EOF 74 | ; ------------------------------- 75 | 76 | 77 | ; ------------------------------- 78 | ; For Google Chrome except Google Drive 79 | ; ------------------------------- 80 | 81 | #IfWinActive ahk_group Chrome 82 | CapsLock & BS:: 83 | Send ^+{Right}{Del} ; Delete word right 84 | k1 = 85 | Marking = 86 | return 87 | 88 | ; ------------------------------- 89 | ; For SciTE 90 | ; ------------------------------- 91 | 92 | #ifWinActive SciTE 93 | 94 | F3::^o 95 | 96 | XButton1::Send ^{F3} 97 | XButton2::Send ^+{F3} 98 | 99 | CapsLock & w:: 100 | Send ^{Up} 101 | return 102 | 103 | CapsLock & z:: 104 | Send ^{Down} 105 | return 106 | 107 | !x:: 108 | ; exit all windows 109 | Send ^w ; Window close 110 | return 111 | 112 | !n::Send !n 113 | !p::Send !p 114 | 115 | ^q::Send ^q 116 | 117 | CapsLock & j:: 118 | if A_PriorHotKey = CapsLock & q 119 | Send ^g 120 | else if k1 121 | { 122 | Send {F2} 123 | k1 = 124 | } 125 | return 126 | 127 | ; Ctrl+h does backspace and ^k^h remove marking 128 | CapsLock & m:: 129 | if k1 130 | { 131 | Send ^{F2} 132 | k1 = 133 | } 134 | return 135 | 136 | CapsLock & d:: 137 | if k1 138 | { 139 | Send ^c{Right} ; Duplicate selection 140 | Marking = 141 | } 142 | else if A_PriorHotKey = CapsLock & q 143 | { 144 | if Marking 145 | Send +{End} ; Extend selection end of line 146 | else 147 | Send {End} ; End of line 148 | } 149 | else if Marking 150 | Send +{Right} ; Extend selection right 151 | else 152 | Send {Right} ; Char right 153 | k1 = 154 | return 155 | 156 | 157 | ; ------------------------------- 158 | ; For FE, just translate CapsLock to Ctrl 159 | ; ------------------------------- 160 | #IfWinActive Edit ahk_class ConsoleWindowClass 161 | $*CapsLock::Send {LControl Down} 162 | $*CapsLock Up::Send {LControl Up} 163 | 164 | 165 | ; ------------------------------- 166 | ; Cmd.exe 167 | ; ------------------------------- 168 | #IfWinActive ahk_class ConsoleWindowClass 169 | 170 | sendn(key, times) { 171 | Loop %times% { 172 | Send %key% 173 | } 174 | } 175 | 176 | ; Scroll page up 177 | +PgUp:: 178 | sendn("{WheelUp}", 25) 179 | return 180 | 181 | ; Scroll page down 182 | +PgDn:: 183 | sendn("{WheelDown}", 25) 184 | return 185 | 186 | 187 | ; ------------------------------- 188 | ; Notepad 189 | ; ------------------------------- 190 | 191 | #IfWinActive ahk_class Notepad 192 | CapsLock & j:: 193 | if A_PriorHotKey = CapsLock & q 194 | Send ^g 195 | return 196 | 197 | 198 | ; ------------------------------- 199 | ; OpenOffice.org key mapping 200 | ; 201 | ; Some key mappings must be defined in OOo 202 | ; ^0 -> Default paragraph style 203 | ; ^+0 -> Text body paragraph style 204 | ; ------------------------------- 205 | 206 | #IfWinActive ahk_class SALFRAME ; OpenOffice.org 207 | 208 | ; caps-b=bold; caps-kb begins marking 209 | CapsLock & b:: 210 | { 211 | if k1 212 | { 213 | Marking = 1 214 | k1 = 215 | } 216 | else 217 | Send ^b{Esc} ; Bold 218 | } 219 | return 220 | 221 | !b:: 222 | Send ^+0{Esc} ; Text body style 223 | k1 = 224 | Marking = 225 | return 226 | 227 | ; Ctrl+h does backspace and ^k^h remove marking 228 | CapsLock & h:: 229 | if k1 230 | { 231 | Marking = 232 | Send {Left}{Right}{Esc} ; Esc is for open office 233 | k1 = 234 | } 235 | return 236 | 237 | CapsLock & l:: 238 | Send ^+F ; Repeat search 239 | k1 = 240 | Marking = 241 | return 242 | 243 | ; Increment leading 244 | !l:: 245 | ; There is probably a faster way to do this 246 | Send {Esc}^+o 247 | MouseGetPos xcur, ycur 248 | MouseMove 66, 36, 0 249 | Sleep 10 250 | Click 251 | Send ^{Tab} 252 | MouseMove 64, 53, 0 253 | Click 254 | MouseMove 342, 239, 0 255 | Click 256 | Click 257 | MouseMove xcur, ycur, 0 258 | Send {Enter} 259 | k1 = 260 | Marking = 261 | return 262 | 263 | ; Decrement leading 264 | !+l:: 265 | ; There is probably a faster way to do this 266 | Send {Esc}^+o 267 | MouseGetPos xcur, ycur 268 | MouseMove 66, 36, 0 269 | Click 270 | Send ^{Tab} 271 | MouseMove 64, 53, 0 272 | Click 273 | MouseMove 342, 247, 0 274 | Click 275 | Click 276 | MouseMove xcur, ycur, 0 277 | Send {Enter} 278 | k1 = 279 | Marking = 280 | return 281 | 282 | CapsLock & m:: 283 | Send {F2} 284 | return 285 | 286 | CapsLock & n:: 287 | Send {Esc}{Enter}{Home}{Left} ; New line ; Esc for open office; Home is for auto-indent editors 288 | k1 = 289 | return 290 | 291 | !n:: 292 | Send ^0{Esc} ; Default or normal style 293 | k1 = 294 | Marking = 295 | return 296 | 297 | CapsLock & t:: 298 | if GetKeyState("Shift") { 299 | Send !e!g!r 300 | } else { 301 | Send {F4}!o!a!f-1.27{Enter} ; Hanging indent 302 | k1 = 303 | Marking = 304 | } 305 | return 306 | 307 | Capslock & u:: 308 | Send ^z ; Undo 309 | k1 = 310 | Marking = 311 | return 312 | 313 | ; exit all OOo windows 314 | !x:: 315 | Send ^q 316 | k1 = 317 | return 318 | 319 | CapsLock & y:: 320 | if k1 321 | { 322 | Send +{Del} ; Edit cut 323 | Marking = 324 | } 325 | else 326 | { 327 | saveclip := ClipboardAll 328 | Clipboard = 329 | Send +{End}+{Del} ; Select to eol 330 | Sleep, 40 ; Wait for data to enter clipboard 331 | if not Clipboard 332 | Send +{Right}{Del} ; For some reason just {Del} doesn't do it 333 | Clipboard := saveclip 334 | } 335 | k1 = 336 | Marking = 337 | return 338 | 339 | $Esc:: 340 | if Marking 341 | { 342 | Marking = 343 | Send {Esc} ;Esc for open office 344 | } 345 | else 346 | Send {Esc} 347 | return 348 | 349 | 350 | ; ------------------------------- 351 | ; Eclipse IDE 352 | ; ------------------------------- 353 | 354 | #IfWinActive ahk_group Eclipse 355 | 356 | CapsLock & d:: 357 | if k1 358 | { 359 | Send ^c{Right} 360 | Marking = 361 | } 362 | else if A_PriorHotKey = CapsLock & q 363 | { 364 | if Marking 365 | Send +{End} ; Extend selection end of line 366 | else 367 | Send {End} ; End of line 368 | } 369 | else if Marking 370 | Send +{Right} ; Extend selection right 371 | else 372 | Send {Right} ; Char right 373 | k1 = 374 | return 375 | 376 | CapsLock & l:: 377 | Send ^k 378 | k1 = 379 | Marking = 380 | return 381 | 382 | $!p:: Send {Alt Down}p 383 | 384 | $Esc:: 385 | if Marking { 386 | Marking = 387 | Send {Right}{Esc} 388 | } else 389 | Send {Esc} 390 | return 391 | 392 | 393 | ; ------------------------------- 394 | ; Putty (nano) 395 | ; ------------------------------- 396 | 397 | #IfWinActive ahk_group Unix 398 | 399 | F3::Send {F5} 400 | 401 | CapsLock & a:: 402 | if A_PriorHotKey = CapsLock & q 403 | Send !r 404 | else 405 | Send !{Space} 406 | return 407 | 408 | ; caps-b begins marking 409 | CapsLock & b:: 410 | if k1 { 411 | Send !a 412 | k1 = 413 | } 414 | return 415 | 416 | CapsLock & c:: 417 | if A_PriorHotKey = CapsLock & q 418 | Send !g100000{Enter} 419 | else if k1 420 | Send ^k 421 | else 422 | Send {PgDn} 423 | k1 = 424 | return 425 | 426 | CapsLock & d:: 427 | if A_PriorHotKey = CapsLock & q 428 | Send {End} ; End of line 429 | else if k1 430 | Send ^k^u 431 | else 432 | Send {Right} ; Char right 433 | k1 = 434 | return 435 | 436 | CapsLock & f:: 437 | if A_PriorHotKey = CapsLock & q 438 | Send ^w 439 | else 440 | Send ^{Space} 441 | return 442 | 443 | CapsLock & h:: 444 | if k1 445 | Send !a 446 | else 447 | Send ^h 448 | k1 = 449 | return 450 | 451 | CapsLock & i:: 452 | if k1 453 | Send !{}} 454 | else 455 | Send ^i 456 | k1 = 457 | return 458 | 459 | CapsLock & k:: 460 | if k1 { 461 | Send !a 462 | k1 = 463 | } else { 464 | k1 = 1 465 | } 466 | return 467 | 468 | CapsLock & r:: 469 | if A_PriorHotKey = CapsLock & q 470 | Send !g1{Enter} 471 | else if k1 472 | Send ^R 473 | else 474 | Send {PgUp} 475 | k1 = 476 | return 477 | 478 | CapsLock & s:: 479 | if k1 480 | Send ^o{Enter} ; File save 481 | else if A_PriorHotKey = CapsLock & q 482 | { 483 | if Marking 484 | Send +{Home} ; Extend selection start of line 485 | else 486 | Send {Home} ; Start of line 487 | } 488 | else if Marking 489 | send +{Left} ; Extend selection left 490 | else 491 | Send {Left} ; Char left 492 | k1 = 493 | return 494 | 495 | CapsLock & j:: 496 | if A_PriorHotKey = CapsLock & q 497 | Send !g 498 | return 499 | 500 | CapsLock & l:: 501 | Send ^w{Enter} 502 | return 503 | 504 | CapsLock & p:: 505 | if k1 506 | Send ^u 507 | k1 = 508 | return 509 | 510 | CapsLock & u:: 511 | if k1 512 | Send !{{} 513 | else 514 | Send ^u 515 | k1 = 516 | return 517 | 518 | CapsLock & w:: 519 | Send !_{Down} 520 | return 521 | 522 | CapsLock & y:: 523 | if A_PriorHotKey = CapsLock & q 524 | Send !a{End}^k 525 | else if k1 526 | Send ^k 527 | else 528 | Send !a{End}{Right}^k 529 | return 530 | 531 | CapsLock & z:: 532 | Send !+={Up} 533 | return 534 | 535 | ; open file (have to then push alt-m to open in a new buffer -- no way to switch automatically once for all 536 | ^o:: 537 | Send ^r 538 | return 539 | 540 | ^s:: 541 | Send ^o{Enter} 542 | return 543 | 544 | !n:: 545 | Send !. 546 | return 547 | 548 | !x:: 549 | Send ^xy{Enter} 550 | return 551 | 552 | !q:: 553 | Send ^xn{BS} 554 | return 555 | 556 | 557 | ; ------------------------------- 558 | ; Notepad 559 | ; ------------------------------- 560 | 561 | #IfWinActive Find ahk_class #32770 ; Notepad find window 562 | $Enter:: 563 | Send {Enter}{Esc} ; Escape out of find window 564 | return 565 | 566 | 567 | ; ------------------------------- 568 | ; Microsoft Office - MS Office 569 | ; ------------------------------- 570 | 571 | #IfWinActive ahk_group MSOffice 572 | 573 | CapsLock & l:: 574 | Send +{F4} 575 | k1 = 576 | Marking = 577 | return 578 | 579 | 580 | ; ------------------------------- 581 | ; Word processors (they act slightly differently to text editors) 582 | ; ------------------------------- 583 | 584 | #ifWinActive ahk_group WordProcessors 585 | 586 | CapsLock & d:: 587 | if k1 588 | { 589 | Send ^c{Left}{Right} ; Duplicate selection 590 | Marking = 591 | } 592 | else if A_PriorHotKey = CapsLock & q 593 | { 594 | if Marking 595 | Send +{End}+{Left} ; Extend selection end of line 596 | else 597 | Send {End} ; End of line 598 | } 599 | else if Marking 600 | Send +{Right} ; Extend selection right 601 | else 602 | Send {Right} ; Char right 603 | k1 = 604 | return 605 | 606 | CapsLock & y:: 607 | if k1 608 | Send {Home}+{End}{Del} ; Delete line 609 | else 610 | Send +{End}+{Left}{Del} ; Delete to eol 611 | k1 = 612 | Marking = 613 | return 614 | 615 | 616 | ; ------------------------------- 617 | ; Kicad 618 | ; ------------------------------- 619 | 620 | #ifWinActive ahk_group kicad 621 | 622 | CapsLock & l::Send ^f{Enter}{Esc} 623 | 624 | 625 | ; ------------------------------- 626 | ; Generic Wordstar key mapping 627 | ; Note: this must go last after all overrides for specific apps 628 | ; ------------------------------- 629 | 630 | ;#IfWinActive ; For everything else 631 | #IfWinNotActive Edit ahk_class ConsoleWindowClass ; For everything except FE 632 | 633 | CapsLock & a:: 634 | if k1 635 | { 636 | Send ^a ; Select all 637 | Marking = 1 638 | } 639 | else if A_PriorHotKey = CapsLock & q 640 | Send ^h ; Replace 641 | else if Marking 642 | Send ^+{Left} ; Extend selection word left 643 | else 644 | Send ^{Left} ; Word left 645 | k1 = 646 | return 647 | 648 | ; caps-b=bold; caps-kb begins marking 649 | CapsLock & b:: 650 | { 651 | if k1 652 | { 653 | Marking = 1 654 | k1 = 655 | } 656 | else 657 | Send ^b 658 | } 659 | return 660 | 661 | CapsLock & c:: 662 | if k1 663 | { 664 | Send +{Del} ; Edit cut 665 | Marking = 666 | } 667 | else if A_PriorHotKey = CapsLock & q 668 | { 669 | if Marking 670 | Send ^+{End} ; Extend selection end of document 671 | else 672 | Send ^{End} ; End of document 673 | } 674 | else if Marking 675 | Send +{PgDn} 676 | else 677 | Send {PgDn} ; Page down 678 | k1 = 679 | return 680 | 681 | CapsLock & d:: 682 | if k1 683 | { 684 | Send ^c{Left}{Right} ; Duplicate selection 685 | Marking = 686 | } 687 | else if A_PriorHotKey = CapsLock & q 688 | { 689 | if Marking 690 | Send +{End} ; Extend selection end of line 691 | else 692 | Send {End} ; End of line 693 | } 694 | else if Marking 695 | Send +{Right} ; Extend selection right 696 | else 697 | Send {Right} ; Char right 698 | k1 = 699 | return 700 | 701 | CapsLock & e:: 702 | if A_PriorHotKey = CapsLock & q 703 | if Marking 704 | Send +^{Up} ; Extend selection line up 705 | else 706 | Send ^{Up} ; Line up 707 | else if Marking 708 | Send +{Up} ; Extend selection line up 709 | else 710 | Send {Up} ; Line up 711 | k1 = 712 | return 713 | 714 | CapsLock & f:: 715 | if A_PriorHotKey = CapsLock & q 716 | { 717 | Send ^f ; Edit find 718 | Marking = 719 | } 720 | else if Marking 721 | Send ^+{Right} ; Extend selection word right 722 | else 723 | Send ^{Right} ; Word right 724 | k1 = 725 | return 726 | 727 | CapsLock & g:: 728 | Send {Del} ; Delete char right 729 | k1 = 730 | Marking = 731 | return 732 | 733 | ; Ctrl+h does backspace and ^k^h remove marking 734 | CapsLock & h:: 735 | if k1 736 | { 737 | Marking = 738 | Send {Right} 739 | k1 = 740 | } 741 | return 742 | 743 | CapsLock & i::Send ^i 744 | 745 | ; Ctrl+k prefix, ^k^k toggles marking 746 | CapsLock & k:: 747 | if Marking 748 | { 749 | if k1 750 | { 751 | Marking = 752 | Send {Left}{Right} 753 | k1 = 754 | } 755 | else 756 | k1 = 1 757 | } 758 | else 759 | { 760 | if k1 761 | { 762 | Marking = 1 763 | k1 = 764 | } 765 | else 766 | k1 = 1 767 | } 768 | return 769 | 770 | CapsLock & l:: 771 | if GetKeyState("Shift") { 772 | Send +{F3} ; Find previous 773 | } else { 774 | Send {F3} ; Find again 775 | } 776 | k1 = 777 | Marking = 778 | return 779 | 780 | CapsLock & n:: 781 | Send {Enter}{Home}{Left} ; New line ; Home is for auto-indent editors 782 | k1 = 783 | return 784 | 785 | ; next previous window 786 | !p::Send +^{Tab} 787 | 788 | CapsLock & p:: 789 | if k1 790 | Send +{Ins} ; Edit paste 791 | else 792 | Send ^p ; Print 793 | k1 = 794 | return 795 | 796 | ; dummy hotkey so that A_PriorHotKey can detect it 797 | CapsLock & q:: 798 | return 799 | 800 | CapsLock & r:: 801 | if A_PriorHotKey = CapsLock & q 802 | { 803 | if Marking 804 | Send ^+{Home} ; Extend selection start of document 805 | else 806 | Send ^{Home} ; Start of document 807 | } 808 | else if Marking 809 | Send +{PgUp} ; Extend selection page up 810 | else 811 | Send {PgUp} ; Page up 812 | k1 = 813 | return 814 | 815 | CapsLock & s:: 816 | if k1 817 | Send ^s ; File save 818 | else if A_PriorHotKey = CapsLock & q 819 | { 820 | if Marking 821 | Send +{Home} ; Extend selection start of line 822 | else 823 | Send {Home} ; Start of line 824 | } 825 | else if Marking 826 | send +{Left} ; Extend selection left 827 | else 828 | Send {Left} ; Char left 829 | k1 = 830 | return 831 | 832 | CapsLock & t:: 833 | Send ^+{Right}{Del} ; Delete word right 834 | k1 = 835 | Marking = 836 | return 837 | 838 | Capslock & u:: 839 | Send ^z ; Undo 840 | k1 = 841 | Marking = 842 | return 843 | 844 | CapsLock & BS:: 845 | Send ^+{Right}{Del} ; Delete word right 846 | k1 = 847 | Marking = 848 | return 849 | 850 | CapsLock & w:: 851 | Send {WheelUp} ; Scroll down 852 | k1 = 853 | return 854 | 855 | CapsLock & x:: 856 | if k1 { 857 | ; Send !{F4} ; Window close 858 | } else if A_PriorHotKey = CapsLock & q 859 | if Marking 860 | Send +^{Down} ; Extend selection line down 861 | else 862 | Send ^{Down} ; Bottom of file 863 | else if Marking 864 | Send +{Down} ; Extend selection line down 865 | else 866 | Send {Down} ; Bottom of file 867 | k1 = 868 | return 869 | 870 | ; exit all windows 871 | !x:: 872 | Send !{F4} ; Window close 873 | k1 = 874 | return 875 | 876 | CapsLock & y:: 877 | if k1 878 | { 879 | Send +{Del} ; Edit cut 880 | Marking = 881 | } 882 | else 883 | Send +{End}{Del} ; Delete to eol 884 | k1 = 885 | Marking = 886 | return 887 | 888 | CapsLock & z:: 889 | Send {WheelDown} ; Scroll up 890 | k1 = 891 | return 892 | 893 | $BS:: 894 | Send {BS} ; Delete left char 895 | k1 = 896 | Marking = 897 | return 898 | 899 | !BS:: 900 | Send ^z ; Undo 901 | k1 = 902 | Marking = 903 | return 904 | 905 | !+BS:: 906 | Send ^y ; Redo 907 | k1 = 908 | Marking = 909 | return 910 | 911 | $Del:: 912 | Send {Del} ; Delete char right 913 | k1 = 914 | Marking = 915 | return 916 | 917 | $Esc:: 918 | if Marking 919 | { 920 | Marking = 921 | Send {Left}{Right}{Esc} 922 | } 923 | else 924 | Send {Esc} 925 | return 926 | --------------------------------------------------------------------------------