UNPKG

rkeys

Version:

A platform for creating tablet/HTML5 virtual-keyboard apps to send keystrokes to remote X11

357 lines (300 loc) 15.8 kB
# rkeys [![Build Status][badge-travis-svg]][badge-travis-url] A platform for creating tablet/HTML5 virtual-keyboard apps to send keystrokes to remote [X11]: * [define virtual keyboards or keypads][teslapad] with a bit of [jade] and [stylus] * define [chords](#chords) and [sequences](#sequences) with delays and auto-repeat * use the built-in [mixins] and [templates] to minimise your code * enhance with [LiveScript] and [Font Awesome] icons * assign keys to dynamically switch layouts * context sensitivity - show/hide regions matching the active window title * simulate mouse buttons and run shell commands * add [sound effects](#sfx): server-side or (experimental) client-side * emit special characters using [compose-key sequences][ComposeKey] ## install globally With [node.js] installed on the target [X11] box: $ npm install -g rkeys # might need to prefix with sudo ## run examples $ rkeys then navigate your remote tablet to `http://your-rkeys-server:7000/example`: ![example screenshot](http://dizzib.github.io/rkeys/example-app.png) See this example's [jade](./site/example-app/example.jade), [stylus](./site/example-app/example.styl) and [yaml](./site/example-app/command.yaml). Also see [some real-world examples](https://github.com/dizzib/rkeys-apps). ## create your first keypad An rkeys app is a directory containing at least one jade file. Create file `bar.jade` in directory `foo` and add the following lines: extend /template/keys block layout +key('a') Host the app by passing its directory on the rkeys command line `$ rkeys foo` then navigate your tablet to `http://your-rkeys-server:7000/bar`: ![tutorial screenshot](http://dizzib.github.io/rkeys/tutorial.png) ## <a name="keys-template"></a>keys template Most of the time you'll be laying out sets of keys and this is where the [keys template] comes in handy. It extends the [base template] with the [Font Awesome] icons along with the following: ### +key mixin Generate a single key comprised of an action and some label text. The action is a [keysym] with or without the `XK_` prefix, a [chord] denoted by infix `+` symbols, a comma-delimited sequence of keysyms and/or chords, or a [command id](#command.yaml) with optional parameters. The label text is displayed inside the key unless it contains [font awesome] class names in which case an icon is displayed. Some examples: * `+key('a')`: emit a KeyPress `a` on touchstart (**down**) and KeyRelease `a` on touchend (**up**). Press and hold the key for native auto-repeat. * `+key('%')`: emit a percent symbol. Symbols are mapped to [keysyms] in the [core command.yaml]. * `+key('XK_Shift_L')`: simulate the left shift key by specifying an explicit [keysym]. * `+key('Shift_L')`: as above but with the optional `XK_` prefix dropped. * `+key('Shift_L', 'shift')`: show a user-friendly label. * `+key('Shift_L shift')`: as above using a shorter syntax. * `+key('Shift_L fa-chevron-up')`: replace label with a nice [font awesome icon](http://fortawesome.github.io/Font-Awesome/icon/chevron-up). A word starting with `fa-` is treated as a font awesome class. Multiple font awesome classes can be specified. * <a name="chords"></a>`+key('C+S+A+F12')`: a [chord] emitting the KeyPress sequence `Ctrl` `Shift` `Alt` and `F12` on touchstart, followed by KeyRelease sequence in the same order on touchend. Specify `S+` for **Shift_L**+, `C+` for **Control_L**+ and `A+` for **Alt_L**+. Press and hold for native auto-repeat. * `+key('C+S+A+F12 fold all')`: as above but with a nice label. * `+key('VBOX-HOST+m show virtualbox menu fa-navicon')`: a chord using a [custom alias](#VBOX-HOST), some descriptive text (not displayed) and an icon. * <a name="sequences"></a>`+key('a,b,3')`: emit the keystroke sequence `a` `b` `3` on touchstart with no auto-repeat. A keystroke is a KeyPress immediately followed by a KeyRelease. * `+key('a,b,3,1000')`: as above but auto-repeating every second until touchend. Integers `0` to `9` denote digits whereas longer integers denote time delay in milliseconds. Here the trailing delay indicates time to auto-repeat. * `+key('a,500,b,500,3,1000')`: as above but with interim pauses of 0.5 seconds. This might be necessary if a sequence is firing too quickly for all keystrokes to take effect, for example if a slow application needs more time to react. * `+key('C+A+F3,05,Super_L+a fa-gear')`: emit two chords separated by a 5 millisecond delay. * `+key('button:3')`: invoke the [button](#button) command with parameter `3` to simulate the right mouse button. * `+key('button:3 fa-hand-o-down fa-flip-horizontal')`: as above but with a flipped [font awesome icon](http://fortawesome.github.io/Font-Awesome/icon/hand-o-down). * `+key('button:3 right mouse button fa-hand-o-down fa-flip-horizontal')`: as above but with some descriptive text (not displayed). * `+key('layout:fn-keys')`: switch the [layout](#layout) to `fn-keys` across all connected clients on touchstart, reverting back to the default layout on touchend. ### +keys mixin Generate a set of keys by invoking `+key` multiple times. Accepts either a single space-delimited string of actions or a list of strings to apply to `+key` in order. Any classes or attributes are applied to each `+key`. Some examples: * `+keys('a b').z`: expands to `+key('a').z` `+key('b').z` * `+keys('a b c').z`: expands to `+key('a').z` `+key('b').z` `+key('c').z` * `+keys('a', 'b').z`: expands to `+key('a').z` `+key('b').z` * `+keys('a b', 'c d').z`: expands to `+key('a b').z` `+key('c d').z` * `+keys('q w e r t y')`: expands to `+key('q')` `+key('w')` `+key('e')` `+key('r')` `+key('t')` `+key('y')` * `+keys('layout:fn fn', 'Shift_R shift').w-3.latchable`: expands to `+key('layout:fn fn').w-3.latchable` `+key('Shift_R shift').w-3.latchable` ### stylus mixins and stylesheet classes The [default minimal styling](./site/ui/template/keys.styl) is easily overridden with the following mixins and classes: * key-color(*up*, *label-up*, *down*, *label-down*) : set the label-foreground and/or key-background colours when in the **up** or **down** states. If you only specify *up* and *label-up* then these colours are swapped on **down**. Call this mixin at the root level to apply to all keys or from within a selector to apply to a subset of keys. * key-size(*k*, *gap-percent*) : a mixin to override the default key size and/or gap between keys. * .key-cols-*n* : a set of adjacent keys will normally [float left] but you can apply this class to their parent to arrange them into *n* columns. *n* can be from 1 to 9, so `.key-cols-1` will produce a single vertical column of keys. * .h-*n* : apply this class to a key to multiply its height by *n* where n is from 2 to 9. For example `+key('a').h-2` will double the key's height. * .w-*n* : apply this class to a key to multiply its width by *n* where n is from 2 to 9. For example `+key('a').w-3` will triple the key's width. * .latchable : normally a key is **down** only when you're touching it, reverting back to **up** otherwise. Applying this class to a key allows it to remain **down** even when you're not touching it, by dragging your finger sideways away from the key before releasing it. Then simply tap the key to unlatch it. A latchable `shift` key behaves rather like CapsLock on a traditional keyboard. ## base template The [base template] is the foundation of rkeys apps and includes the JavaScript libraries [faye-websocket] to communicate the user's keystrokes to the server, [jquery] to dynamically manipulate the user interface and [lodash] for general purpose functions. It includes the following [jade mixins](./site/ui/mixin/base.jade): * +prevent-zoom : lock the zoom-level to prevent accidental pinch-zoom. Should be placed in the head section. * <a name="show-if"></a>+show-if(activeWindowTitle='*regexp*') : only show child content if the active window title matches the [regular expression] *regexp*. In addition the following [stylesheet classes](./site/ui/template/base.styl) are available for manipulating layouts: * .layout.*id* : only show child content when the current layout's id is *id*. The default layout's id is **default**. * .horizontal : arrange immediate children horizontally * .vertical : arrange immediate children vertically ## <a name="command.yaml"></a>command configuration yaml You can get more fancy by defining commands in a [yaml] file (typically `command.yaml`) placed in the app's directory. Each definition has format `id: command` where `id` is a unique identifier and `command` is a string specifying what to do. The first word of a command can specify a **directive** to alter the functionality: * *id*: **alias** *str* : replace occurrences of *id* with *str* in all actions and commands. The standard naming convention for an alias *id* is all capitals. * *id*: **broadcast** *msg* : send *msg* to all connected clients on rkeydown. Useful for keeping things synchronised in multi-tablet setups. * *id*: [**broadcast** *msg1*, **broadcast** *msg2*] : broadcast *msg1* on rkeydown and *msg2* on rkeyup. * *id*: **button** *n* : simulate mouse button *n* by emitting a ButtonPress on rkeydown and ButtonRelease on rkeyup. * *id*: **exec** *cmd* : execute shell command *cmd* on rkeydown. * *id*: **javascript** *script* : dynamically generate a command at runtime using [JavaScript]. The *script* must evaluate to an action or command string. * *id*: **livescript** *script* : As above but using [LiveScript]. * *id*: **nop** : no-operation. Useful as a placeholder to be redefined at runtime. Examples: * `abc: a b c`: A sequence can be delimited by spaces or commas. * `on: +c -d`: emit KeyPress `c` and KeyRelease `d` on rkeydown. Explicit KeyPress/KeyRelease events are denoted by prefixes `+` and `-` respectively. * `HelloWorld: [H e l l o, +Shift_L w -Shift_L o r l d]`: emit the keystroke sequence `H` `e` `l` `l` `o` on rkeydown and `W` `o` `r` `l` `d` on rkeyup. The square-bracket array has format **[** *rkeydown-sequence*, *rkeyup-sequence* **]**, where each sequence is delimited by spaces. * <a name="VBOX-HOST"></a>`VBOX-HOST: alias Super_R`: define an alias for the [VirtualBox] host key. * <a name="button"></a>`button: button $0`: simulate mouse button $0, where 1=left, 2=middle, 3=right, etc. This is defined in the [core command.yaml]. * <a name="layout"></a>`layout: [broadcast layout $0, broadcast layout default]`: instruct connected clients to switch to layout $0 on rkeydown, switching back to the default on rkeyup. This is defined in the [core command.yaml]. * `speakeys-onstart: exec qdbus-qt4 org.kde.simon /ActionManager triggerCommand 'Filter' 'pause' > /dev/null`: pause the [Simon] speech recognition engine. * `type: javascript '$0'.split('').join(',')`: Convert a string into a sequence of keystrokes and emit them. A more robust version is in the [core command.yaml] and is ideal for emitting short phrases and sentences. * `now: livescript (require \moment)!format 'DD/MM/YYYY_HH:mm:ss' .split '' .join ','`: Type the current date and time. ### overriding default configuration at runtime When rkeys starts, the [core command.yaml] is loaded first followed by any yaml files discovered in directories supplied on the command line in the given order. If a command-id appears multiple times then the last one takes precedence thus allowing default configuration to be overridden at runtime. For example if we launch rkeys via `$ rkeys ./app-1 ./app-2 ~/.config` then if ./app-1/cmd.yaml contains `foo: bar` and ~/.config/rkeys.yaml contains `foo: my-custom-command` then the latter definition 'wins'. ## <a name="sfx"></a>sidechaining server-side sound effects The sidechain allows secondary commands to run alongside the primary and is the best way to add low-latency server-side sound effects. Whenever a rkeydown or rkeyup occurs the command-id is checked against a sequence of `/regular-expression/: command` rules and only the first matching rule will run. Here's an example: # sidechain in command.yaml /^kde/: nop # make kde commands silent /^(button|ffx)/: PLAY-SOUND SFX-BLIP /^layout/: [ PLAY-SOUND SFX-TICK, PLAY-SOUND SFX-TOCK ] /.*/: PLAY-SOUND SFX-NOISE # everything else The built-in `SFX-` aliases are defined in the [core command.yaml] but you can always supply your own soundfiles (note that relative paths are relative to the source file). You should redefine the `PLAY-SOUND` alias to match your own system. So with [SoX] installed you could include the following to play sounds at quarter volume: PLAY-SOUND: alias exec play -V1 -q --volume 0.25 ## options $ rkeys --help Usage: rkeys [Options] [directory ...] Options: -h, --help output usage information -V, --version output the version number -g, --gen-ssl-cert generate a self-signed ssl certificate -p, --port <port> listening port (default:7000) -s, --servant-to <host[:port]> run as a servant in a guest virtual machine, forwarding active-window-changed events to the specified rkeys master host -v, --verbosity <level> verbosity 0=min 2=max (default:1) ## host over https In a new empty directory either [create a key.pem and cert.pem manually](http://stackoverflow.com/questions/10175812/how-to-create-a-self-signed-certificate-with-openssl?rq=1) or do the following: $ rkeys -g # generate using openssl. Follow the prompts. Include this directory on the `rkeys` command line to host over https on port + 1 (default 7001) at `https://your-rkeys-server:7001`. ## developer build and run $ git clone --branch=dev https://github.com/dizzib/rkeys.git $ cd rkeys $ npm install # install dependencies $ npm test # build all and run tests $ npm start # start the task runner and rkeys ## license [MIT](./LICENSE) [badge-travis-svg]: https://travis-ci.org/dizzib/rkeys.svg?branch=master [badge-travis-url]: https://travis-ci.org/dizzib/rkeys [base template]: ./site/ui/template/base.jade [ComposeKey]: https://help.ubuntu.com/community/ComposeKey#Compose%20key%20sequences [core command.yaml]: ./site/io/command.yaml [dependencies]: ./package.json.ls [Express]: http://expressjs.com [chord]: https://en.wikipedia.org/wiki/Chorded_keyboard [faye-websocket]: https://github.com/faye/faye-websocket-node [float left]: https://developer.mozilla.org/en-US/docs/Web/CSS/float [Font Awesome]: http://fortawesome.github.io/Font-Awesome/ [GCC]: https://gcc.gnu.org [jade]: http://jade-lang.com [JavaScript]: https://en.wikipedia.org/wiki/JavaScript [jquery]: http://jquery.com [keysym]: https://github.com/sidorares/node-x11/blob/master/lib/keysyms.js [keysyms]: https://github.com/sidorares/node-x11/blob/master/lib/keysyms.js [keys template]: ./site/ui/template [LiveScript]: http://livescript.net [lodash]: https://lodash.com [mixins]: ./site/ui/mixin [node.js]: http://nodejs.org [node-gyp]: https://github.com/TooTallNate/node-gyp [python]: https://www.python.org [regular expression]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions [Simon]: https://userbase.kde.org/Simon [SoX]: http://sox.sourceforge.net/Main/HomePage [stylus]: https://learnboost.github.io/stylus [templates]: ./site/ui/template [teslapad]: https://github.com/dizzib/rkeys-apps/tree/master/teslapad [VirtualBox]: https://www.virtualbox.org [X11]: https://en.wikipedia.org/wiki/X_Window_System [yaml]: https://en.wikipedia.org/wiki/YAML