mkeys documentation


Copyright © 2002 Andrey Volkov
Revision date 11/30/2002. You can always get the latest version from mkeys.sourceforge.net


1. Table of contents

  1. Table of contents
  2. Introduction
  3. Programming it
    1. Names and nodes
    2. Values
    3. Commands
      1. set command
      2. run command
      3. A conditional operator
      4. link command
      5. operation and key structures
      6. mount command
      7. unset command (deprecated)
    4. Modules
      1. HID input driver (HIDNode.m)
      2. OSS volume controller (OSSNode.m)
      3. LED controller (LEDNode.m)
  4. Examples
    1. A basic example
    2. A more complicated example
    3. An even more complicated example

 

2. Introduction

mkeys is a daemon that, once it is started, sits in the background and listens for user input. It does this absolutely independently from other programs that are running and handling user input. You may switch virtual consoles, start or stop X server - mkeys will behave as usual.

To run mkeys, simply type:

mkeys

To unload mkeys, type:

mkeys -u

When mkeys is started, it look at a lock file, $HOME/.mkeys/locks/lock. If it does exist, mkeys sends SIGHUP to the process that created it (another copy of mkeys), thus making shure that only one copy per user is run.

Then, if -u or --unload is specified in the command line, mkeys return control to the shell. Otherwise, it creates its own lock file and daemonize.

After it has daemonized, it begins to read config directives (which somebody can call programs). It looks for the file $HOME/.mkeys/INCLUDE. If it is found, read it line by line, assuming that each line contain name of a file that should be processed. It processes each file mentioned in INCLUDE. After all, even if INCLUDE was not found, it processes $HOME/.mkeys/config.

Then it starts serving users needs until it receives SIGHUP, when it removes a lock and terminates.

3. Programming it

3.1. Names and nodes

The basis of mkeys is its hierarchical tree where it contains all data and all actions available to user. It is in some way similar to UNIX filesystem, but uses dots instead slashes. For example, you can have somewhat like this (tree on the left, names on the right):

  +
  |-bin             bin
  | |-OSS           bin.OSS
  | | |-name        bin.OSS.name
  | | |-device      bin.OSS.device
  | | |-volume      bin.OSS.volume
  | | | |-step      bin.OSS.volume.step
  | | | |-up        bin.OSS.volume.up
  | | | |-down      bin.OSS.volume.down
  | | |-balance     bin.OSS.balance
  | |   |-step      bin.OSS.balance.step
  | |   |-left      bin.OSS.balance.left
  | |   |-right     bin.OSS.balance.right
  | |-LED           bin.LED
  |   |-name        bin.LED.name
  |   |-device      bin.LED.device
  |   |-NumLock     bin.LED.NumLock
  |   |-ScrollLock  bin.LED.ScrollLock
  |     . . .
  |-keys            keys
  | |-Keypad_Plus   keys.Keypad_Plus
  | |-KeyPad_Minus  keys.Keypad_Minus
  | |-VolumeUp      keys.VolumeUp
  | |-VolumeDown    keys.VolumeDown
  . . . . .

These names are used everywhere when programming mkeys.

Each node contains some value (or action, or both), and it can be read, written or executed. Each of these operations is permitted for every node of a tree, though may not be implemebted by a particular node.

Each node is responsible for all its subnodes. It has to maintain the activity of its subnodes. This means that, for example, node bin.OSScan fully control the behaviour of nodes bin.OSS.volume, bin.OSS.volume.step and so on.

3.2. Values

Values are used when making assignments, comparing things, running shell commands, loading modules, etc. Value is always a string. Values can be presented as:

Since every value in mkeys is a string, "false" and false are exactly the same. And "true" is exactly the same as true.

3.3. Commands

Scripts that make things running, consist of a very simple set of commands.

3.3.1. set command

Syntax:

set some.node.to.set to value

Explanation:

This will set some.node.to.set to a value value. If node some.node.to.set does not exist, it will be created.

If some.node.to.set is presented by some specific loadable module, for example, mounted on some.node, it may not behave as you wish.

Example:

set bin.OSS.device to "/dev/dsp"
set bin.OSS.volume.step to "2"

3.3.2. run command

Syntax:

run command
run some.node.to.run

Explanation:

The first will run command using default shell. For this, command should be a correct value.
The second will run action contained within some.node.to.run

Example:

run "mozilla"
run bin.OSS.volume.up

3.3.3. A conditional operator

Syntax:

if condition :
    operators
end

if condition :
    operators
else :
    operators
end

Explanation

It is a conditional operator, you know what it's like? The only condition available for now is:

some.node.to.compare is value

It refurns true if some.node.to.compare contents is exactly the same as value. If some.node.to.compare does not exist, it returns false.

Example:

if bin.OSS.name is "OSS":
    set bin.OSS.device to "/dev/dsp"
else:
    mount "OSSNode.m" to bin.OSS
    set bin.OSS.device to "/dev/dsp"
end;

3.3.4 link command

Syntax:

link some.node.to.become.a.link to some.node.to.point.to

Explanation:

This will create a link some.node.to.become.a.link to a point to some.node.to.point.to. It is similar to hard links in the filesystem, the only difference is that when you delete some.node.to.point.to, it would be very bad to refer to it using still existing link. On the other hand, when you move some.node.to.point.to to another location, some.node.to.become.a.link will still point to it.

Example:

operation opr.print1:
    run "echo Print1 >> /tmp/testout"
end;

operation opr.print2:
    run "echo Print2 >> /tmp/testout"
end;

link prints.p1 to opr.print1
link prints.p2 to opr.print2
run prints.p1 /* prints Print1 */
run prints.p2 /* prints Print2 */

link print to prints.p1
run print /* prints Print1 */
link prints.p1 to opr.print2
run prints.p1 /* prints Print2 */
run print /* still prints Print1 */

3.3.5 operation and key structures

Syntax:

operation some.name :
    operators
end

key somekey :
    operators
end

Explanation:

operation is somewhat like procedure in Pascal. A bunch of operators are given a name some.name and placed in a tree. You can run them using a run operator.

key is a shortcut for creating keyboard actions, it creates operation with a name keys.somekey.

Example:

operation internet:
    run "mozilla"
    run "kmail"
    run "/etc/ppp/dial"
end;

key Homepage:
    run internet
end;

3.3.6. mount command

Syntax:

mount filename to some.point.to.mount.to

Explanation:

This will load a dynamically loadable (DL) module filename (filename should be a value, i.e. in almost all cases it should be quoted or doublequoted). A DL module contains a special node, that is then mounted (placed) to the some.point.to.mount.to. If filename starts with '/', it is considered to be an absolute path to the module in a local filesystem, else filename is treated as relative to $HOME/.mkeys/modules/. After mounting, you can refer to loaded node as some.point.to.mount.to.

Example:

mount "OSSNode.m" to bin.OSS
if bin.OSS.name is "OSS":
    link bin.sound to bin.OSS
    set bin.OSS.device to "/dev/dsp"
    set bin.OSS.volume.step to "1"
    set bin.OSS.balance.step to "2"
end;

3.3.7. unset command

Syntax:

unset some.unwanted.node

Explanation:

This will delete some.unwanted.node from nodetree. This is deprecated for now, is fairly untested and is still basically an unwanted feature. Do not use it. If you do need it, contact me and tell a reason why, and I will not call it deprecated and unwanted. It would be nice if you test it then.

Example:

None, since it is deprecated

3.4. Modules

Modules are loaded by the mount command. Usually they are represented by one "real" node that acts for all its subnodes. But it is not a rule, it is only a current state.

3.4.1. HID input driver (HIDNode.m)

This module acts as an input driver for devices that support event interface. It reads device files (usually /dev/input/event* ) and issues some commands. I will write more later...

3.4.2. OSS volume controller (OSSNode.m)

This module acts is for changing volume and balance (and muting sound, too). As you can guess, it is for OSS (Open Sound System). I did not test it with ALSA, but they say ALSA to be OSS-compatible, and in such an easy case I think it can. If it does work with ALSA, please, let me know. And if you can write a module for ALSA - it would be wonderful. I will write more on this later...

3.4.3. LED controller (LEDNode.m)

This module acts is by all means a toy-like module. However, I find it very useful for user interface style mkeys provide. LEDNode.m can turn LEDs on, off, it can even make them blink. I will write more on this later...

4. Examples

4.1. A basic example

Here I will show an example of a simple $HOME/.mkeys/config file. It will configure four keys on my multimedia keyboard to control xmms. Here it is:

mount "HIDNode.m" to bin.mkeys                 /* This will load an input driver for    */
set bin.mkeys.device to "/dev/input/event1"    /* multimedia keys on my keyboard, which */
                                               /* are represented as /dev/input/event1  */
set xmms_playing to false
key PlayPause:                                 /* This will be called when I press a    */
    if xmms_playing is true:                   /* play/pause key ( >/|| )               */
        run "xmms --pause"
        set xmms_playing to false
    else:
        run "xmms --play"
        set xmms_playing to true
   	end;
end;

key StopCD:                                    /* A stop key is called StopCD on my kb  */
    run "xmms --stop"
    set xmms_playing to false
end;

key NextSong:
    run "xmms --fwd"
end;

key PreviousSong:
    run "xmms --prev"
end;

That's it! Run mkeys from X, so that DISPLAY variable will be set when you first call xmms, or it will not initialize. Or run mkeys from console and load xmms manually when X starts. You will be able to handle it by pressing keys.

Two main difficulties in listing are the first two lines. First line loads a module "HIDNode.m" and places a node provided by it to bin.mkeys. This module provides an input driver for all this USB devices, that are controlled by event interface. The node it provides is an interface to this driver. It is used to contol the behaviour of the driver and set its parameters. The only required parameter is device, which is a filename of event device. After this parameter is set, driver tries to open this file, and then starts to poll it. Once a key press event is read, it runs keys.KeyName. Once a key release event is read, it runs keys.KeyName.release. The root for events may differ from keys, it is controlled by driver parameter key. Like this:

set bin.mkeys.key to "multimedia"

Note, that once you change root for keyboard events, you should specify actions like this:

operation multimedia.NextSong:
    run "xmms --fwd"
end;

4.2. A more complicated example

Now I would like to add volume-changing capabilities to my config, and it looks like this now:

mount "HIDNode.m" to bin.mkeys                 /* This will load an input driver for    */
set bin.mkeys.device to "/dev/input/event1"    /* multimedia keys on my keyboard, which */
                                               /* are represented as /dev/input/event1  */

mount "OSSNode.m" to bin.OSS                   /* This will load Open Sound System      */
set bin.OSS.device to "/dev/dsp"               /* driver and set some parameters        */
set bin.OSS.volume.step to "4"

set xmms_playing to false
key PlayPause:                                 /* This will be called when I press a    */
    if xmms_playing is true:                   /* play/pause key ( >/|| )               */
        run "xmms --pause"
        set xmms_playing to false
    else:
        run "xmms --play"
        set xmms_playing to true
    end;
end;

key StopCD:                                    /* A stop key is called StopCD on my kb  */
    run "xmms --stop"
    set xmms_playing to false
end;

key NextSong:
    run "xmms --fwd"
end;

key PreviousSong:
    run "xmms --prev"
end;

key VolumeUp:
    run bin.OSS.volume.up
end;

key VolumeDown:
    run bin.OSS.volume.down
end;

key Mute:
    run bin.OSS.volume.mute
end;

The only difference from previous example is in loading an additional driver for OSS (Open Sound System). I think that no comments are needed here.

4.3. An even more complicated example

Now I would like to change my volume using LeftAlt+MouseWheel. Let's see what I change:

mount "HIDNode.m" to bin.mkeys                 /* This will load an input driver for    */
set bin.mkeys.device to "/dev/input/event1"    /* multimedia keys on my keyboard, which */
                                               /* are represented as /dev/input/event1  */

mount "HIDNode.m" to bin.keyboard              /* This will load an input driver for    */
set bin.keyboard.device to "/dev/input/event0" /* the conventonal keys on keyboard,     */
                                               /* represented as /dev/input/event0      */

mount "HIDNode.m" to bin.mouse                 /* This will load an input driver for    */
set bin.mouse.device to "/dev/input/event2"    /* my wheel mouse, whish is              */
set bin.mouse.rel to mouse                     /* represented as /dev/input/event2      */

mount "OSSNode.m" to bin.OSS                   /* This will load Open Sound System      */
set bin.OSS.device to "/dev/dsp"               /* driver and set some parameters        */

set bin.OSS.volume.step to "1"                 /* Change: more precise volume steps     */

set xmms_playing to false
key PlayPause:                                 /* This will be called when I press a    */
    if xmms_playing is true:                   /* play/pause key ( >/|| )               */
        run "xmms --pause"
        set xmms_playing to false
    else:
        run "xmms --play"
        set xmms_playing to true
    end;
end;

key StopCD:                                    /* A stop key is called StopCD on my kb  */
    run "xmms --stop"
    set xmms_playing to false
end;

key NextSong:
    run "xmms --fwd"
end;

key PreviousSong:
    run "xmms --prev"
end;

key VolumeUp:
    run bin.OSS.volume.up                      /* Change: yes, that silly! The less     */
    run bin.OSS.volume.up                      /* volume step gets...                   */
    run bin.OSS.volume.up
    run bin.OSS.volume.up
end;

key VolumeDown:
    run bin.OSS.volume.down
    run bin.OSS.volume.down
    run bin.OSS.volume.down
    run bin.OSS.volume.down
end;

key Mute:
    run bin.OSS.volume.mute
end;

set AltPressed to false
key LeftAlt:
    set AltPressed to true
end;

key LeftAlt.release:
    set AltPressed to false
end;

operation mouse.WheelUp:
    if AltPressed is true:
	run bin.OSS.volume.up
    end;
end;
operation mouse.WheelDown:
    if AltPressed is true:
        run bin.OSS.volume.down
    end;
end;

The only difference from previous example is in loading more instances of a HIDNode driver. One is loaded for keyboard, one for multimedia keys, one for mouse. Note that a root for mouse events (exactly speaking, relative movements) is controlled by driver parameter rel, and I set it to mouse. All the mouse buttons (even side buttons and clicks on a wheel) still have keys as their root. The only interesting relative events from mouse are wheel movements.


SourceForge.net Logo