20

I want to hook into linux desktop key event handling.

Pressing CapsLock should enter some sort of command line.

Some of the commands I want to implement:

  • d/x: Delete from current cursor position until character x. (inspired by vi)
  • a: Goto to beginning of line, like pos1. (inspired by emacs).
  • k: Delete until end of line. (inspired by emacs).
  • ...

The commands should work in any text field: Browser, Mail Client, gnome terminal, ...

AFAIK low level xmodmap won't help me here.

Is something like this possible?

Where do I need to place the hook?

Current target platform is Ubuntu >= 14.04

Background: I want to keep my pointing fingers on F and J, and use the computer without looking at the keyboard. Works for A-Z since several years, but keys like Pos1/End are not easy to access.

Please leave a comment if you don't understand a part of this question. Thank you.

Update

This question is only about how to hook into the key event handling. The other stuff (command line) is a different topic. How can you catch for example CapsLock x?

Update2 I see there is no easy and straight forward solution. If you have no answer, but you know where I can find more help (like ask on mailing list FOO), please tell me.

Update3 Since some people do not understand what I want, I try to explain it: If I use emacs or bash I feel like being in control if the computer: it is like flying, with only very few movements I can tell the computer to do what I want. Editing text in webbrowser textarea, LibreOffice or using thunderbird makes this feeling go away. Cursor movements are cumbersome, it does not feel like flying. I want to control the desktop, not just a single application, and keep my pointing fingers on the F and J keys.

Update 4: Solution: input-remapper

I found a great solution to it: input-remapper. See my small article Ten Flying Fingers (more comfortable touch typing)

guettli
  • 25,042
  • 81
  • 346
  • 663
  • 6
    Dear down voters: Please tell me what's wrong with this question. What can I do to improve it? Two people down voted because "too broad". I don't get it. What is too broad about this question? – guettli Dec 22 '14 at 08:15
  • Should this work in no X screen is active? – Basilevs Dec 29 '14 at 15:36
  • @Basilevs No, for me it is enough if X-desktop is running. It does not need to be available if the X login screen asks for user/password or the text console (Ctrl-Alt-F1). – guettli Jan 04 '15 at 06:14

4 Answers4

12

UPDATE

Instead of telling the X server to ignore the device, you can use EVIOCGRAB ioctl, which I added to the program below.

You need to do the following things:

1.Make sure you have CONFIG_UINPUT module compiled and loaded. I believe Ubuntu already has it. If you don't see /dev/uinput device, try running modprobe -v uinput to load the module.

2.Run the following program as root and give it the path of the keyboard device, eg:

./process /dev/input/by-id/usb-Microsoft_Wired_Keyboard_600-event-kbd

The following program creates a fake input device called uinput-sample and forwards all events from a given input device to it. I adapted it from the sample given in http://thiemonge.org/getting-started-with-uinput

You can modify it to do things you want to do.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <linux/uinput.h>

#define die(str, args...) do { \
        perror(str); \
        exit(EXIT_FAILURE); \
    } while(0)

int
main(int argc, char* argv[])
{
    int                    fdo, fdi;
    struct uinput_user_dev uidev;
    struct input_event     ev;
    int                    i;

    if(argc != 2) die("error: specify input device");

    fdo = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
    if(fdo < 0) die("error: open");

    fdi = open(argv[1], O_RDONLY);
    if(fdi < 0) die("error: open");

    if(ioctl(fdi, EVIOCGRAB, 1) < 0) die("error: ioctl");

    if(ioctl(fdo, UI_SET_EVBIT, EV_SYN) < 0) die("error: ioctl");
    if(ioctl(fdo, UI_SET_EVBIT, EV_KEY) < 0) die("error: ioctl");
    if(ioctl(fdo, UI_SET_EVBIT, EV_MSC) < 0) die("error: ioctl");

    for(i = 0; i < KEY_MAX; ++i)
        if(ioctl(fdo, UI_SET_KEYBIT, i) < 0) die("error: ioctl");

    memset(&uidev, 0, sizeof(uidev));
    snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-sample");
    uidev.id.bustype = BUS_USB;
    uidev.id.vendor  = 0x1;
    uidev.id.product = 0x1;
    uidev.id.version = 1;

    if(write(fdo, &uidev, sizeof(uidev)) < 0) die("error: write");
    if(ioctl(fdo, UI_DEV_CREATE) < 0) die("error: ioctl");

    while(1)
    {
        if(read(fdi, &ev, sizeof(struct input_event)) < 0)
            die("error: read");

        ev.time.tv_sec = 0;
        ev.time.tv_usec = 0;

        if(write(fdo, &ev, sizeof(struct input_event)) < 0)
            die("error: write");
    }

    if(ioctl(fdo, UI_DEV_DESTROY) < 0) die("error: ioctl");

    close(fdi);
    close(fdo);

    return 0;
}
5

The brute-force way would be to modyfy/rebuild xserver-xorg-input-evdev package and replace /usr/lib/xorg/modules/input/evdev_drv.so. I would start by trying to modify EvdevQueueKbdEvent() function in xf86-input-evdev-2.9.0/src/evdev.c. Doesn't look very elegant solution, but I think you'll get flexibility to modify keyboard event queue.

Less intrusive solution may be possible using XGRabKey() (some details here) and/or XGrabKeyboard().

Some info, which may be helpful here (regarding XTest extension).

Community
  • 1
  • 1
kestasx
  • 1,091
  • 8
  • 15
  • 1
    Thank you very much. This is the first positive feedback I get. Modifying evdev.c looks not very flexible. My extension would need to compiled for every xserver. Maybe it is possible to replace the method at runtime... – guettli Dec 23 '14 at 19:14
  • @guettli, yes, this is kind of "feasibility analysis". Actualy I think You can build and distribute modified/renamed `evdev` driver if no beter solution is found, but it may require more work while prototyping. And I'm not sure it is the bigest problem You'll have in short term. – kestasx Dec 23 '14 at 19:26
3

Another way of looking at your question : you want some specialized window manager. Read the EWMH specs for details. Read before an overview of X11.

Or consider some existing X window manager. There are many of them. I suspect that ratpoison or xmonad (or perhaps sawfish, etc...) could be configured to suite your needs. (But I don't know these WMs well).

Think twice before implementing your window manager from scratch. It could mean years of work! AFAIU, a WM can redirect, filter, grab, or synthesize keyboard or mouse events.

Of course, with wayland things will be different.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • Yes, implementing a window manager is a lot of work. I don't want to reinvent the wheel. My solution should work for every window manager. I just want to catch and modify the keyboard events on their way from finger press to the X-application. – guettli Dec 23 '14 at 19:40
  • By definition, a window manager may (or even has to) catch such keyboard events, and may grab them. You are in need of some window manager. Choose one (or adapt one) to fit your needs. Please follow the links I gave you, they are relevant! – Basile Starynkevitch Dec 23 '14 at 20:02
  • I know that I need a window manager. But a solution which forces you to use a special window manager is not user friendly. And I think it is possible to solve this with every window manager. – guettli Dec 23 '14 at 20:11
  • What you want is not user friendly for every definition of user (it certainly won't be user friendly for me, because it would hurt my use of `emacs`). It is user friendly for your view of what a user want. So choose & customize a WM to fit your particular needs. – Basile Starynkevitch Dec 23 '14 at 20:12
  • It is interesting that you mention `emacs`. I switched from emacs to `pyCharm`. I was missing the very handy shortcuts like ctrl-a ctrl-e. Then I asked myself: Why modify pyCharm? I want basic text editing everywhere (thunderbird, Webbrowser, ...). The keys DEL, Backspace, Pos1, End exist. But they ctrl-a and ctrl-e like in emacs is much easier for touch typers. Nevertheless I guess I will try to get into the event key before the keys go to the window manager. – guettli Dec 24 '14 at 11:00
3

Here is also a python project using uinput driver:

http://hetgrotebos.org/wiki/uinput-mapper