KMonad Configuration
Table of Contents
1. Goals
1.1. It should be the most efficient keyboard layout possible.
1.1.1. Ergonomic key positions and more frequent keys closer to home row.
1.1.2. Optimize the layers in such a way where we do not need to change layer frequently
however, layers are still needed because it is sometimes more economical to switch layers rather than to reach.
2. Configuration
2.1. Initial Values
We must set our initial values for the configuration:
(defcfg input (device-file "/dev/input/by-path/platform-i8042-serio-0-event-kbd") output (uinput-sink "My KMonad output" "/usr/bin/sleep 1 && /usr/bin/setxkbmap -option compose:ralt") cmp-seq ralt ;; Set the compose key to `RightAlt' cmp-seq-delay 5 ;; 5ms delay between each compose-key sequence press fallthrough true allow-cmd true )
you need to set your input device according to your hardware.
2.2. defsrc
The defsrc block specifies the default layout that our keyboard uses. Note that when you are, for example, using a 40% keyboard, some of these keys will not be present. However, it is still syntactically valid and you will be able to use this configuration.
(defsrc grv 1 2 3 4 5 6 7 8 9 0 - = bspc tab q w e r t y u i o p [ ] \ caps a s d f g h j k l ; ' ret lsft z x c v b n m , . / rsft lctl lmet lalt spc ralt rmet cmp rctl )
Also note that the defsrc block is not used for custom key configuration. It is used only to describe the shape of the current keyboard.
2.3. defalias
defalias defines aliases for buttons. Buttons are used in deflayer blocks in order to remap the keys.
(defalias num (layer-toggle numbers) kil C-A-del )
2.4. deflayer
#| -------------------------------------------------------------------------- Necessary: at least 1 `deflayer` block It is also important to mention that the 'keymap' in KMonad is modelled as a stack of layers (just like in QMK). When an event is registered we look in the top-most layer for a handler. If we don't find one we try the next layer, and then the next. Exactly what 'evaluates-to-a-button' will be expanded on in more detail below. There are very many different specialist buttons in KMonad that we will touch upon. However, for now, these 4 are a good place to begin: 1. Any keycode evaluates to a button that, on press, emits the press of that keycode, and on release, emits the release of that keycode. Just a 'normal' button. The exception is '\', which gets used as an escape character. Use '\\' instead. Other characters that need to be escaped to match the literal character are '(', ')', and '_'. 2. An @-prefixed name evaluates to an alias lookup. We named two buttons in the `defalias` block above, we could now refer to these buttons using `@num` and `@kil`. This is also why we only use alias-names no longer than 3 characters in this tutorial. Also, note that we are already referencing some aliases that have not yet been defined, this is not an issue. 3. The '_' character evaluates to transparent. I.e. no handler for that key-event in this layer, causing this event to be handed down the layer stack to perhaps be handled by the next layer. 4. The 'XX' character evaluates to blocked. I.e. no action bound to that key-event in this layer, but do actually catch event, preventing any underlying layer from handling it. Finally, it is important to note that the *first* `deflayer` statement in a KMonad config will be the layer that is active when KMonad starts up. -------------------------------------------------------------------------- |# (deflayer qwerty grv 1 2 3 4 5 6 7 8 9 0 - = bspc tab q w e r t y u i o p [ ] \ esc a s d f g h j k l ; ' ret lsft z x c v b n m , . / rsft lctl lmet lalt spc @num rmet @sym rctl ) (deflayer numbers _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ XX / 7 8 9 - _ _ _ _ _ _ _ _ XX * 4 5 6 + _ _ _ _ \( \) . XX 0 1 2 3 _ _ _ _ _ _ _ _ _ _ )
#| -------------------------------------------------------------------------- Optional: modded buttons Let's start by exploring the various special buttons that are supported by KMonad by looking at 'modded' buttons, that is to say, buttons that activate some kind of 'mod', then perform some button, and finally release that 'mod' again. We have already seen an example of this style of button, our `kil` button is one such button. Let's look at it in more detail: C-A-del This looks like a simple declarative statement, but it's helpful to realize that is simply syntactic sugar around 2 function calls. This statement is equivalent to: (around ctl (around alt del)) This highlights a core design principle in KMonad: we try to provide very simple buttons, and then we provide rules and functions for combining them into new buttons. Although note: still very much a work in progress. So, looking at this statement: (around foo bar) Here, `around` is a function that takes two buttons and creates a new button. This new button will, on a press, first press foo, then press bar, and on a release first release bar, and then foo. Once created, this new button can be passed to anything in KMonad that expects a button. We have already seen other examples of modded buttons, \(, \), *, and +. There are no Keycodes for these buttons in KMonad, but they are buttons. They simply evaluate to `(around lsft x)`. All shifted numbers have their corresponding characters, the same is true for all capitals, and < > : ~ " | { } \_ + and ?. To wrap up 'modded-buttons', let's look back at C-A-del. We have 8 variants: C- : (around lctl X) A- : (around lalt X) M- : (around lmet X) S- : (around lsft X) Then RC-, RA-, RM-, and RS- behave exactly the same, except using the right-modifier. These can be combined however you please: C-A-M-S-x ;; Perfectly valid C-% ;; Perfectly valid: same as C-S-5 C-RC-RA-A-M-S-RS-m ;; Sure, but why would you? Also, note that although we provide special syntax for certain modifiers, these buttons are in no way 'special' in KMonad. There is no concept of 'modifier'. (around a (around b c)) ;; Perfectly valid -------------------------------------------------------------------------- |# (defalias ;; Something useful cpy C-c pst C-v cut C-x ;; Something silly md1 (around a (around b c)) ;; abc md2 (around a (around lsft b)) ;; aB md3 C-A-M-S-l md4 (around % b) ;; BEWARE: %B, not %b, do you see why? ) #| -------------------------------------------------------------------------- Optional: sticky keys KMonad also support so called "sticky keys". These are keys that will behave as if they were pressed after just tapping them. This behaviour wears off after the next button is pressed, which makes them ideal for things like a quick control or shift. For example, tapping a sticky and then pressing `abc' will result in `Abc'. You can create these keys with the `sticky-key' keyword: (defalias slc (sticky-key 500 lctl)) The number after `sticky-key' is the timeout you want, in milliseconds. If a key is tapped and that time has passed, it won't act like it's pressed down when we receive the next keypress. It is also possible to combine sticky keys. For example, to get a sticky shift+control you can do (defalias ssc (around (sticky-key 500 lsft) (sticky-key 500 lctl))) -------------------------------------------------------------------------- |# ;; Let's make both shift keys sticky (defalias sl (sticky-key 300 lsft) sr (sticky-key 300 rsft)) ;; Now we define the 'tst' button as opening and closing a bunch of layers at ;; the same time. If you understand why this works, you're starting to grok ;; KMonad. ;; ;; Explanation: we define a bunch of testing-layers with buttons to illustrate ;; the various options in KMonad. Each of these layers makes sure to have its ;; buttons not overlap with the buttons from the other layers, and specifies all ;; its other buttons as transparent. When we use the nested `around` statement, ;; whenever we push the button linked to '@tst' (check `qwerty` layer, we bind ;; it to `rctl`), any button we press when holding `rctl` will be pressed in the ;; context of those 4 layers overlayed on the stack. When we release `rctl`, all ;; these layers will be popped again. (defalias tst (around (layer-toggle macro-test) (around (layer-toggle layer-test) (around (layer-toggle around-next-test) (around (layer-toggle command-test) (layer-toggle modded-test)))))) (deflayer modded-test _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @md4 _ _ _ _ _ _ _ _ _ _ _ _ _ @md1 @md2 @md3 _ _ _ _ _ _ _ _ _ _ @cut @cpy @pst _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ) #| -------------------------------------------------------------------------- Optional: tap-macros Let's look at a button we haven't seen yet, tap-macros. `tap-macro` is a function that takes an arbitrary number of buttons and returns a new button. When this new button is pressed it rapidly taps all its stored buttons in quick succesion except for its last button, which it only presses. This last button gets released when the `tap-macro` gets released. There are two ways to define a `tap-macro`, using the `tap-macro` function directly, or through the #() syntactic sugar. Both evaluate to exactly the same button. (tap-macro K M o n a d) #(K M o n a d) If you are going to use a `tap-macro` to perform a sequence of actions inside some program you probably want to include short pauses between inputs to give the program time to register all the key-presses. Therefore we also provide the 'pause' function, which simply pauses processing for a certain amount of milliseconds. Pauses can be created like this: (pause 20) P20 You can also pause between each key stroke by specifying the `:delay' keyword, as well as a time in ms, at the end of a `tap-macro': (tap-macro K M o n a d :delay 5) #(K M o n a d :delay 5) The above would be equivalent to e.g. (tap-macro K P5 M P5 o P5 n P5 a P5 d) The `tap-macro-release` is like `tap-macro`, except that it waits to press the last button when the `tap-macro-release` gets released. It might be useful when combined with a footswitch that sends keyboard scan codes. (tap-macro-release i K M o n a d esc) WARNING: DO NOT STORE YOUR PASSWORDS IN PLAIN TEXT OR IN YOUR KEYBOARD I know it might be tempting to store your password as a macro, but there are 2 huge risks: 1. You accidentally leak your config and expose your password 2. Anyone who knows about the button can get clear-text representation of your password with any text editor, shell, or text-input field. Support for triggering shell commands directly from KMonad is described in the command buttons section below. This concludes this public service announcement. -------------------------------------------------------------------------- |# (defalias mc1 #(K M o n a d) mc2 #(C-c P50 A-tab P50 C-v) ;; Careful, this might do something mc3 #(P200 h P150 4 P100 > < P50 > < P20 0 r z 1 ! 1 ! !) mc4 (tap-macro a (pause 50) @md2 (pause 50) c) mc5 (tap-macro-release esc esc esc) mc6 #(@mc3 spc @mc3 spc @mc3) ) (deflayer macro-test _ @mc1 @mc2 @mc3 @mc4 @mc5 @mc6 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ) #| -------------------------------------------------------------------------- Optional: layer manipulation You have already seen the basics of layer-manipulation. The `layer-toggle` button. This button adds a layer to the top of KMonad's layer stack when pressed, and removes it again when released. There are a number of other ways to manipulate the layer stack, some safer than others. Let's go through all of them from safest to least safe: `layer-toggle` works as described before, 2 things to note: 1. If you are confused or worried about pressing a key, changing layers, and then releasing a key and this causing issues: don't be. KMonad handles presses and releases in very different ways. Presses get passed directly to the stacked keymap as previously described. When a KMonad button has its press-action triggered, it then registers a callback that will catch its own release before we ever touch the keymap. This guarantees that the button triggered by the press of X *will be* the button whose release is triggered by the release of X (the release of X might trigger other things as well, but that is besides the point.) 2. If `layer-toggle` can only ever add and then necessarily remove 1 layer from the stack, then it will never cause a permanent change, and is perfectly safe. `layer-delay`, once pressed, temporarily switches to some layer for some milliseconds. Just like `layer-toggle` this will never permanently mess-up the layer stack. This button was initially implemented to provide some 'leader-key' style behavior. Although I think in the future better solutions will be available. For now this will temporarily add a layer to the top of the stack: (layer-delay 500 my-layer) `layer-next`, once pressed, primes KMonad to handle the next press from some arbitrary layer. This aims to fill the same usecase as `layer-delay`: the beginnings of 'leader-key' style behavior. I think this whole button will get deleted soon, because the more general `around-next` now exists (see below) and this is nothing more than: (around-next (layer-toggle layer-name)) Until then though, use `layer-next` like this: (layer-next layer-name) `layer-switch`: change the base-layer of KMonad. As described at the top of this document, the first `deflayer` statement is the layer that is active when KMonad starts. Since `layer-toggle` can only ever add on and remove from the top of that, it can never change the base-layer. The following button will unregister the bottom-most layer of the keymap, and replace it with another layer. (layer-switch my-layer) This is where things start getting potentially dangerous (i.e. get KMonad into an unusuable state until a restart has occured). It is perfectly possible to switch into a layer that you can never get out of. Or worse, you could theoretically have a layer full of only `XX`s and switch into that, rendering your keyboard unuseable until you somehow manage to kill KMonad (without using your keyboard). However, when handled well, `layer-switch` is very useful, letting you switch between 'modes' for your keyboard. I have a tiny keyboard with a weird keymap, but I switch into a simple 'qwerty' keymap shifted 1 button to the right for gaming. Just make sure that any 'mode' you switch into has a button that allows you to switch back out of the 'mode' (or content yourself restarting KMonad somehow). `layer-add` and `layer-rem`. This is where you can very quickly cause yourself a big headache. Originally I didn't expose these operations, but someone wanted to use them, and I am not one to deny someone else a chainsaw. As the names might give away: (layer-add name) ;; Add a layer to the top of the stack (layer-rem name) ;; Remove a layer by name (noop if no such layer) To use `layer-add` and `layer-rem` well, you should take a moment to think about how to create a layout that will prevent you from getting into situations where you enter a key-configuration you cannot get out of again. These two operations together, however, are very useful for activating a permanent overlay for a while. This technique is illustrated in the tap-hold overlay a bit further down. -------------------------------------------------------------------------- |# (defalias yah (layer-toggle asking-for-trouble) ;; Completely safe nah (layer-add asking-for-trouble) ;; Completely unsafe ld1 (layer-delay 500 numbers) ;; One way to get a leader-key ld2 (layer-next numbers) ;; Another way to get a leader key ;; NOTE, this is safe because both `qwerty` and `colemak` contain the `@tst` ;; button which will get us to the `layer-test` layer, which itself contains ;; both `@qwe` and `@col`. qwe (layer-switch qwerty) ;; Set qwerty as the base layer col (layer-switch colemak) ;; Set colemak as the base layer ) (deflayer layer-test @qwe _ _ _ _ _ _ _ _ _ _ @add _ @nah @col _ _ _ _ _ _ _ _ _ _ _ _ @yah _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @ld1 @ld2 _ _ _ _ _ _ _ _ _ ) ;; Exactly like qwerty, but with the letters switched around (deflayer colemak grv 1 2 3 4 5 6 7 8 9 0 - = bspc tab q w f p g j l u y ; [ ] \ @xcp a r s t d h n e i o ' ret @sl z x c v b k m , . / @sr lctl @num lalt spc ralt rmet @sym @tst ) (defalias lol #(: - D)) ;; Contrived example (deflayer asking-for-trouble @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol @lol ) ;; One way to safely use layer-add and layer-rem: the button bound to layer-add ;; is the same button bound to layer-rem in the layer that `add` adds to the ;; stack. I.e., it becomes impossible to add or remove multiple copies of a ;; layer. (defalias add (layer-add multi-overlay) ;; multi-overlay is defined in the next rem (layer-rem multi-overlay) ;; section below this ) #| -------------------------------------------------------------------------- Optional: Multi-use buttons Perhaps one of the most useful features of KMonad, where a lot of work has gone into, but also an area with many buttons that are ever so slightly different. The naming and structuring of these buttons might change sometime soon, but for now, this is what there is. For the next section being able to talk about examples is going to be handy, so consider the following scenario and mini-language that will be the same between scenarios. - We have some button `foo` that will be different between scenarios - `foo` is bound to 'Esc' on the input keyboard - the letters a s d f are bound to themselves - Px signifies the press of button x on the keyboard - Rx signifies the release of said button - Tx signifies the sequential and near instantaneous press and release of x - 100 signifies 100ms pass So for example: Tesc Ta: tap of 'Esc' (triggering `foo`), tap of 'a' triggering `a` Pesc 100 Ta Tb Resc: press of 'Esc', 100ms pause, tap of 'a', tap of 'b', release of 'Esc' The `tap-next` button takes 2 buttons, one for tapping, one for holding, and combines them into a single button. When pressed, if the next event is its own release, we tap the 'tapping' button. In all other cases we first press the 'holding' button then we handle the event. Then when the `tap-next` gets released, we release the 'holding' button. So, using our mini-language, we set foo to: (tap-next x lsft) Then: Tesc -> x Tesc Ta -> xa Pesc Ta Resc -> A Pesc Ta Tr Resc -> AR The `tap-hold` button is very similar to `tap-next` (a theme, trust me). The difference lies in how the decision is made whether to tap or hold. A `tap-hold` waits for a particular timeout, if the `tap-hold` is released anywhere before that moment we execute a tap immediately. If the timeout occurs and the `tap-hold` is still held, we switch to holding mode. The additional feature of a `tap-hold` is that it pauses event-processing until it makes its decision and then rolls back processing when the decision has been made. So, again with the mini-language, we set foo to: (tap-hold 200 x lsft) ;; Like tap-next, but with a 200ms timeout Then: Tesc -> x Tesc Ta -> xa Pesc 300 a -> A (the moment you press a) Pesc a 300 -> A (after 200 ms) Pesc a 100 Resc -> xa (both happening immediately on Resc) The `tap-hold-next` button is a combination of the previous 2. Essentially, think of it as a `tap-next` button, but it also switches to held after a period of time. This is useful, because if you have a (tap-next ret ctl) for example, and you press it thinking you want to press C-v, but then you change your mind, you now cannot release the button without triggering a 'ret', that you then have to backspace. With the `tap-hold-next` button, you simply outwait the delay, and you're good. I see no benefit of `tap-next` over `tap-hold-next` with a decent timeout value. You can use the `:timeout-button` keyword to specify a button other than the hold button which should be held when the timeout expires. For example, we can construct a button which types one x when tapped, multiple x's when held, and yet still acts as shift when another button is pressed before the timeout expires. So, using the minilanguage and foo as: (tap-hold-next 200 x lsft :timeout-button x) Then: Tesc -> Tx Pesc 100 a -> A (the moment you press a) Pesc 5000 Resc -> xxxxxxx (some number of auto-repeated x's) Note that KMonad does not itself auto-repeat the key. In this last example, KMonad emits 200 Px 4800 Rx, and the operating system's auto-repeat feature, if any, emits multiple x's because it sees that the x key is held for 4800 ms. The `tap-next-release` is like `tap-next`, except it decides whether to tap or hold based on the next release of a key that was *not* pressed before us. This also performs rollback like `tap-hold`. So, using the minilanguage and foo as: (tap-next-release x lsft) Then: Tesc Ta -> xa Pa Pesc Ra Resc -> ax (because 'a' was already pressed when we started, so foo decides it is tapping) Pesc Pa Resc Ra -> xa (because the first release we encounter is of esc) Pesc Ta Resc -> A (because a was pressed *and* released after we started, so foo decides it is holding) `tap-next-press` is also a lot like `tap-next`, but decides whether to tap or hold based on whether another key is pressed before this one is released. Using the minilanguage: (tap-next-press x lsft) Then: Tesc Ta -> xa Pa Pesc Ra Resc -> ax (because esc is released before another key is pressed) Pesc Pa Resc Ra -> A (because a is pressed before esc is released) Pesc Ta Resc -> A (a is pressed before esc is released here as well) These increasingly stranger buttons are, I think, coming from the stubborn drive of some of my more eccentric (and I mean that in the most positive way) users to make typing with modifiers on the home-row more comfortable. Especially layouts that encourage a lot of rolling motions are nicer to use with the `release` style buttons. The `tap-hold-next-release` (notice a trend?) is just like `tap-next-release`, but it comes with an additional timeout that, just like `tap-hold-next` will jump into holding-mode after a timeout. I honestly think that `tap-hold-next-release`, although it seems the most complicated, probably is the most comfortable to use. But I've put all of them in a testing layer down below, so give them a go and see what is nice. -------------------------------------------------------------------------- |# (defalias xtn (tap-next x lsft) ;; Shift that does 'x' on tap xth (tap-hold 400 x lsft) ;; Long delay for easier testing thn (tap-hold-next 400 x lsft) tnr (tap-next-release x lsft) tnp (tap-next-press x lsft) tnh (tap-hold-next-release 2000 x lsft) ;; Used it the colemak layer xcp (tap-hold-next 400 esc ctl) ) ;; Some of the buttons used here are defined in the next section (deflayer multi-overlay @mt _ _ _ _ _ _ _ _ _ _ _ @rem _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @thn _ _ _ _ _ _ _ _ _ _ _ _ @xtn _ _ _ _ _ _ _ _ _ _ @xth @tnr @tnp _ _ _ _ _ @tnh ) #| -------------------------------------------------------------------------- Optional: Multi-tap Besides the tap-hold style buttons there is another multi-use button (with. only 1 variant, at the moment). The `multi-tap`. A `multi-tap` codes for different buttons depending on how often it is tapped. It is defined by a series of delays and buttons, followed by a last button without delay. As long as you tap the `multi-tap` within the delay specified, it will jump to the next button. Once the delay is exceeded the selected button is pressed. If the last button in the list is reached, it is immediately pressed. When another key is pressed down while we're tapping, `multi-tap' also immediately exits and taps the current button. Note that you can actually hold the button, so in the below example, going: tap-tap-hold (wait 300ms) will get you a pressed c, until you release again. -------------------------------------------------------------------------- |# (defalias mt (multi-tap 300 a 300 b 300 c 300 d e)) #| -------------------------------------------------------------------------- Optional: Around-next The `around-next` function creates a button that primes KMonad to perform the next button-press inside some context. This could be the context of 'having Shift pressed' or 'being inside some layer' or, less usefully, 'having d pressed'. It is a more general and powerful version of `layer-next`. There is also an `around-next-timeout` button that does the same thing as `around-next`, except that if some other button press is not detected within some timeout, some other button is tapped. This can be used to create a leader-key that simply times out (by passing a non-button), or a key that can still function as a normal key, but also as a leader key when used slowly. I think expansion of this button-style is probably the future of leader-key, hydra-style functionality support in KMonad. -------------------------------------------------------------------------- |# (defalias ns (around-next sft) ;; Shift the next press nnm (around-next @num) ;; Perform next press in numbers layer ntm (around-next-timeout 500 sft XX) ) (deflayer around-next-test _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ @ns _ _ _ _ _ _ _ _ _ _ _ _ @nnm _ _ _ _ _ _ _ _ _ _ _ @ntm _ _ _ _ _ _ _ ) #| -------------------------------------------------------------------------- Optional: Compose-key sequences Compose-key sequences are series of button-presses that your operating system will interpret as the insertion of a special character, like accented characters, or various special-languages. In that sense, they are just syntactic sugar for keyboard macros. To get this to work on Linux you will need to set your compose-key with a tool like `setxkbmap', as well as tell kmonad that information. See the `defcfg' block at the top of this file for a working example. Note that you need to wait ever so slightly for the keyboard to register with linux before the command gets executed, that's why the `sleep 1`. Also, note that all the `/run/current-system' stuff is because the author uses NixOS. Just find a shell-command that will: 1. Sleep a moment 2. Set the compose-key to your desired key Please be aware that what `setxkbmap' calls the `menu' key is not actually the `menu' key! If you want to use the often suggested setxkbmap -option compose:menu you will have to set your compose key within kmonad to `compose' and not `menu'. After this, this should work out of the box under Linux. Windows does not recognize the same compose-key sequences, but WinCompose will make most of the sequences line up with KMonad: http://wincompose.info/ This has not in any way been tested on Mac. In addition to hard-coded symbols, we also provide 'uncompleted' macros. Since a compose-key sequence is literally just a series of keystrokes, we can omit the last one, and enter the sequence for 'add an umlaut' and let the user then press some letter to add this umlaut to. These are created using the `+"` syntax. -------------------------------------------------------------------------- |# (defalias sym (layer-toggle symbols) ) (deflayer symbols _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ä é © _ _ _ _ _ _ _ _ _ _ _ +' +~ +` +^ _ _ _ _ _ _ _ _ _ +" +, _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _) #| -------------------------------------------------------------------------- Optional: Command buttons Currently we also provide the ability to launch arbitrary shell-commands from inside kmonad. These commands are simply handed off to the command-shell without any further checking or waiting. NOTE: currently only tested on Linux, but should work on any platform, as long as the command is valid for that platform. The `cmd-button' function takes two arguments, the second one of which is optional. These represent the commands to be executed on pressing and releasing the button respectively. BEWARE: never run anyone's configuration without looking at it. You wouldn't want to push: (cmd-button "rm -rf ~/*") ;; Delete all this user's data -------------------------------------------------------------------------- |#