xpybind, Dan Aloni <da-x@colinux.org> (c) 2005

--------------------------------------------------------------------------------

Contents of this document:

1. Preface
2. Building and installing
3. User configuration, for starters
4. Functions and API of the xpybind module
5. Hacks and development

--------------------------------------------------------------------------------

1. Preface

Since the invention of GUI, the concept of 'hotkeys' was widely accpted as a 
method to execute functions within programs and environments. The common 
definition of hotkey is comprised of combination of key presses, that include
'function' keys named Ctrl, Alt, Meta, Super, along with 'regular' keys such
as N, R, or F4.

Desktop enviroments today, such as KDE, allow the user to define hotkeys for 
various intrinsic operations of the enviroment, such as resizing or closing 
windows, and sometimes they allow the execution of external programs. However, 
a hotkey by itself is sometimes not sufficient. The amount of combinations of 
a single hotkey in the keyboard is limited. For example, say you have bound
Ctrl-L to the operation Location, and then you decide you'd also like to
bind the Lower operation. However, Ctrl-L, Alt-L, and Ctrl-Alt-L, etc.,
are already bound, what would you do?

The developers of Emacs defined the concept of 'key sequence' that extends 
the concept of a hotkey. A key sequence is a list of hotkeys. A function is
executed only after that particular list of hotkeys have been serially 
pressed. Using this concept, you can order functions under an effective 
heirarchy. For example, find-function-other-frame is bound to 'C-x 5 l',
which means: Control-X, then 5, then l, will execute that function. Other
functions that act on frames under emacs are defined under the sub-sequence 
'C-x 5', so it is rather easy to remember how to access them.

Under conventional desktop environments such as KDE, the concept of key 
sequences doesn't exist in its pure form, probably because it is hard
to configure in GUI. However, advanced users, especially programmers and
people who have worked in emacs, would appreciate the ability to bind 
key sequences globally in X. One application, keylaunch, currently provides 
that functionality in X. However, it is limited to merely  running shell 
scripts from those sequences. 'ratpoison', the window manager, started 
to support key sequences after I contributed a patch for it. Ratpoison's 
key sequnces are bound to ratpoison commands -- then again, not flexibly, 
and forces you to use ratpoison.

XEmacs binds key sequences to its own elisp interpreter space -- of course, 
you can only access these sequences from XEmacs and not globally from X.
But unlike the other options, in XEmacs you can bind key sequences to 
complex functions written in elisp, and they all run in the same interpreter 
space, which means that you can have global variables that can be accessed 
from the various functions.

So what we need is a small utility that provides these:

 * Globally bind key sequences in X to functions.
 * The functions need to run in one scriptable interpreter space. 
 * Of course, instead of elisp, we can use a much more readble and
   widely accepted scripting language, such as Python. 

That's xpybind.


2. Building and installing

In order to build xpybind, your systems need to contains the development
libraries and include files of XFree86 and Pytohn 2.3 or above. You also
need to have GNU/make and gcc.

To build xpybind simple run:

    make

To install, run:
 
    make install

xpybind is also distributed as binary RPM and Debian packages that can
be retrieved from the xpybind site.


3. User configuration, for starters

If you don't know Python, I suggest that you surf to http://www.python.org
and start reading.

Done?

Good. After installing xpybind unto your system, create a new Python 
script as ~/.xpybind.

xpybind's configuration is quite simple. Your ~/.xpybind script needs to
contain one list of tuples, where each tuple is a key sequence definition
that contains the key sequence and the function to execute. The format 
of the tuple is (key_sequence_string, callable_object).

The most simple configuration can be as follows:

    def my_func():
        print "Hello"
    
    keyboard_maps = [
        ("C-t f", my_func),
    ]
    
But we probably want something usable:
    
    def run_mozilla():
        import os
        os.system("mozilla &")
    
    keyboard_maps = [
        ("C-t e x e c m", run_mozilla),
    ]

Defining a function for each operation can be considered code duplication. 
Instead. define a function for each *type* of operation. Consider this example:

    def run_command(command_name):
        def runner(): 
            import os
            os.system("%s &" % (command_name, ))
        return runner
    
    keyboard_maps = [
        ("C-t e x e c m", run_command("mozilla")),
        ("C-t e x e c x", run_command("xchat")),
    ]

Because it's Python we can access every Python package we would like from 
our interpreter space, for example:

    keyboard_maps = [
        ...
        ("C-t m s", xmms.stop),
        ...
    ]

That key sequence will effectively stop XMMS from playing.

We can define more types of operations:

    def killall(name):
        def wrapper():
            try:
                os.system("killall %s" % (name, ))
            except:
                from traceback import print_exc
                print_exc()
                notify_to_use("Error killing %s" % (name, ))
        return wrapper

For example, if would like our commmand to be spawned in a terminal:

    def terminal(command):
        def wrapper():
            os.system("rxvt -e %s &" % (command, ))
        return wrapper

Using the function above in a key sequence definition like this, 
("Menu e p", terminal("python")), we just bound a key sequence to a function
that runs a Python interpreter in a new rxvt terminal.

See the examples directory for more complete and useful configurations.


4. Functions and API of the xpybind module

After installing xpybind, run:

    python -c "import xpybind; help(xpybind)"

5. Hacks and development

[TBD]

--------------------------------------------------------------------------------
