**spartacon** is a Unix-style global hotkey daemon. It embraces the philosophies of "do one thing, and do it well" and "text in, text out". It allows you to capture hotkeys on X11, without having any strong opinions about what actions should happen when those keys are pressed. There are other hotkey applications out there; for example, modern desktop environments typically have a way to bind keys to actions, and there are standalone apps like [HyperKeys](https://hyperkeys.xureilab.com/). Typically, these implementations assume that the thing you want to happen when a key is hit is to launch a process. If what you really want is to just add hotkey functionality to an existing application without it needing to know how to do that, those are typically not suitable, because the tool being controlled is already running. spartacon sits in that space: when you want to control a "text in, text out"-style program with hotkeys, this is the tool for you. (And if you decide to pipe spartacon to something that launches processes, that's no skin off my teeth!) # Installation 0. Install GHC and cabal in your favorite way. [ghcup](https://www.haskell.org/ghcup/) is nice, or most package managers have them. 1. Install the development variants of your X11 libraries; it probably makes the most sense to do this through your package manager. The names of the packages that provide these vary a lot from distribution to distribution. If you don't install anything, the build process below will output some text about which library is missing that may help you search your package manager. 2. Clone the repo. `git clone https://github.com/dmwit/spartacon && cd spartacon` 3. Build and install. `cabal install` 4. If this is your first time using `cabal`, you will likely need to add its output directory to your `PATH`. # Usage spartacon accepts text on standard input in the [`config-value`](http://hackage.haskell.org/package/config-value/docs/Config.html) format. A simple example looks like this: ignore: [NL, M5] bindings: C-A-y: "foo" F11: quit The `ignore` field is modifiers that you want to be "ignored" -- that is, where you want your keybindings to fire whether those modifiers are on or not. It's optional, and the default is `[NL]` for numlock (see table below for other choices). So, for example, in the above file, spartacon will print out the string `foo` for any of the keypresses `C-A-y`, `NL-C-A-y`, `M5-C-A-y`, or `NL-M5-C-A-y`. The `ignore` field is never required to get a desired reaction from spartacon; it is only shorthand for binding many modifier variants at a time. The `bindings` field is a collection (possibly empty) of bindings and actions. It's optional, and the default has no bindings or actions. Each binding has a modifier part and a key part. The modifier part is a sequence (possibly empty), where each element of the sequence is one of the following strings followed by a `-`: | string | meaning | |--------|---------------------------------------------| | S | shift | | L | lock (usually capslock) | | C | control | | A | alt (=mod1) | | M1 | mod1 (usually alt) | | NL | numlock (=mod2) | | M2 | mod2 (usually numlock) | | M3 | mod3 | | M4 | mod4 (usually the Windows key or similar) | | M5 | mod5 | | B | no (additional) modifier; see next sentence | The `B-` prefix is required for unmodified keycodes and unmodified keysyms that do not start with a letter because `config-value` atoms must start with a letter. You may also use lower case, but the case must be consistent within each string (e.g. `nL` is not allowed). Only the presence or absence of one of these strings matters; if there are multiple appearances, all but the first are ignored. For example, `C-S-`, `C-S-C-`, `c-S-`, and `c-b-s-b-C-B-S-` all mean the same thing: for this keybinding to fire, both control and shift (and nothing else) must be held down. The key part of a binding may be either a keysym or a keycode. Keysyms are exactly those accepted by `XStringToKeysym`; you can find out exactly how to spell a keysym name with `xev` or similar. Keycodes are smallish numbers (no larger than 255); to distinguish these from keysyms, you must prepend a `.` to the number. For those among you not intimately familiar with X11 terminology, the distinction between keysym and keycode is that a keysym is the logical interpretation of a key while a keycode is the physical location of a key. For example, `y` means that to fire this keybinding, you must press the `y` key, wherever that may be in the current layout -- just to the right of T in the QWERTY layout but just to the right of P in the Dvorak layout. In some layouts, a single keysym may be available from multiple physical keys; spartacon will correctly respond to any of the physical keys for that keysym. On my computer, in the QWERTY layout, Y is associated with keycode 29, so as a second example, `.29` means the sixth letter key from the left in the top row, no matter what letter that's actually associated with in the current layout -- Y in the QWERTY layout, F in the Dvorak layout, etc. If you request a binding with a keysym, then change layout, spartacon will modify its hotkey definitions appropriately. It is possible to accidentally request multiple actions for the same key; for example, by requesting a keysym and a keycode that both correspond to the same key, or by requesting the "upper-case" and "lower-case" keysym variants associated with a single key. In this case, spartacon will print a short warning message to stderr and choose one of the proposed actions arbitrarily. A short warning will also be printed to stderr if a requested keysym is not associated with any key in the current layout. An action is one of the following things: * The literal atom `quit`. This instructs spartacon to successfully exit. * The literal atom `exit`. Ditto. * An arbitrary string. This instructs spartacon to print that string to stdout.