挂钩进入linux关键事件处理

时间:2014-12-20 15:09:42

标签: linux keyboard desktop

我想挂钩进入linux桌面键事件处理。

按CapsLock应输入某种命令行。

我想要实现的一些命令:

  • d / x:从当前光标位置删除,直到字符x。 (受vi启发)
  • a:转到行首,就像pos1一样。 (受emacs的启发)。
  • k:删除直到行尾。 (受emacs的启发)。
  • ...

命令应该适用于任何文本字段:浏览器,邮件客户端,gnome终端,......

AFAIK低级xmodmap在这里没有帮助我。

这样的事情可能吗?

我需要在哪里放置挂钩?

当前目标平台是Ubuntu> = 14.04

背景:我想把手指放在F和J上,然后在不看键盘的情况下使用电脑。几年来一直适用于A-Z,但是像Pos1 / End这样的键不容易访问。

如果您不理解这个问题的一部分,请发表评论。谢谢。

更新

这个问题只是关于如何挂钩关键事件处理。其他东西(命令行)是一个不同的主题。你怎么能抓住CapsLock x

UPDATE2 我看到没有简单直接的解决方案。如果你没有答案,但你知道我可以在哪里找到更多帮助(比如在邮件列表FOO上询问),请告诉我。

UPDATE3 由于有些人不明白我想要什么,我试着解释一下:如果我使用emacs或者bash,我觉得如果计算机控制它:它就像飞行一样,只有很少的动作我可以告诉计算机做什么我想要。在webbrowser textarea,LibreOffice或使用thunderbird编辑文本会让这种感觉消失。光标移动很麻烦,感觉不像是飞行。我想控制桌面,而不仅仅是单个应用程序,并且指着F和J键。

4 个答案:

答案 0 :(得分:10)

<强>更新

您可以使用我添加到下面程序中的EVIOCGRAB ioctl,而不是告诉X服务器忽略该设备。

您需要执行以下操作:

1.确保编译并加载了CONFIG_UINPUT模块。我相信Ubuntu已经拥有它。如果您没有看到/dev/uinput设备,请尝试运行modprobe -v uinput来加载模块。

2.以root身份运行以下程序并为其指定键盘设备的路径,例如:

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

以下程序创建一个名为uinput-sample的虚假输入设备,并将来自给定输入设备的所有事件转发给它。我根据http://thiemonge.org/getting-started-with-uinput

中给出的样本对其进行了调整

您可以修改它以执行您想要执行的操作。

#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;
}

答案 1 :(得分:5)

蛮力的方式是修改/重建xserver-xorg-input-evdev包并替换/usr/lib/xorg/modules/input/evdev_drv.so。我首先尝试修改EvdevQueueKbdEvent()中的xf86-input-evdev-2.9.0/src/evdev.c函数。看起来不是很优雅的解决方案,但我认为您可以灵活地修改键盘事件队列。

使用XGRabKey()(一些详细信息here)和/或XGrabKeyboard()可能会产生较少侵入性的解决方案。

一些可能有用的信息here(关于XTest扩展名)。

答案 2 :(得分:3)

查看问题的另一种方式:您需要一些专门的window manager。有关详细信息,请阅读EWMH规范。在概述X11之前阅读。

或者考虑一些现有的X window manager。他们中有很多人。我怀疑ratpoisonxmonad(或许sawfish等)可以配置以满足您的需求。 (但我不太了解这些WM)。

在从头开始实施窗口管理器之前,请三思而后行。这可能意味着多年的工作! AFAIU,WM可以重定向,过滤,抓取或合成键盘或鼠标事件。

当然,wayland事情会有所不同。

答案 3 :(得分:3)

这里还有一个使用uinput驱动程序的python项目:

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