Como remapear as teclas do teclado com base em quanto tempo você segura a tecla

9

Eu gostaria de remapear as teclas no meu teclado numérico para que elas se comportem de maneira diferente dependendo de quanto tempo a tecla é pressionada. Aqui está um exemplo:

Se eu mantiver a tecla Numpad 9 pressionada por menos de 300 ms, ela enviará o comando de tecla "tabulação anterior" Ctrl + guia

Se eu mantiver a tecla Numpad 9 pressionada por 300-599 ms, ele enviará o comando de tecla "new tab" Ctrl + T

Se eu mantiver a tecla Numpad 9 pressionada por 600-899ms, ela enviará o comando-chave "fechar guia / janela" Ctrl + W

Se eu mantiver a tecla Numpad 9 pressionada por mais de 899ms, ela não fará nada no caso de eu perder a janela de tempo que eu queria.

No Windows, eu poderia fazer isso com o AutoHotKey e, no OS X, eu poderia fazer isso com o ControllerMate, mas não consigo encontrar uma ferramenta no UNIX / Linux que permita o remapeamento de chaves com base na duração de uma chave.

Se você tiver conhecimento de uma ferramenta que possa resolver meu problema, forneça um script ou exemplo de código que demonstre o comportamento da duração da retenção de chave condicional que descrevi acima. Não precisa ser o código completo para resolver o meu exemplo, mas deve ser o suficiente para eu redirecioná-lo para o meu exemplo.

    
por kanoko 01.11.2016 / 20:14

3 respostas

5

Eu escrevi isso em C :

#include <stdio.h>
#include <curses.h>
#include <time.h> //time(0)
#include <sys/time.h>                // gettimeofday()
#include <stdlib.h>

void waitFor (unsigned int secs) {
    //credit: http://stackoverflow.com/a/3930477/1074998
    unsigned int retTime = time(0) + secs;   // Get finishing time.
    while (time(0) < retTime);               // Loop until it arrives.
}

int
main(void) {

    struct timeval t0, t1, t2, t3;
    double elapsedTime;

    clock_t elapsed_t = 0;
    int c = 0x35;

    initscr();
    cbreak();
    noecho();
    keypad(stdscr, TRUE);

    halfdelay(5); //increae the number if not working //adjust below 'if (elapsedTime <= 0.n)' if this changed
    printf("\nSTART again\n");

    elapsed_t = 0;
    gettimeofday(&t0, NULL);

    float diff;

    int first = 1;
    int atleast_one = 0;

      while( getch() == c) { //while repeating same char, else(ffff ffff in my system) break

            int atleast_one = 1;

            if (first == 1) {
                gettimeofday(&t1, NULL);
                first = 0;
            }

            //printf("DEBUG 1 %x!\n", c);
            gettimeofday(&t2, NULL);
            elapsedTime = (t2.tv_sec - t1.tv_sec) + ((t2.tv_usec - t1.tv_usec)/1000000.0); 

            if (elapsedTime > 1) { //hit max time

                printf("Hit Max, quit now. %f\n", elapsedTime);
                system("gnome-terminal");
                //waitFor(4);

                int cdd;
                while ((cdd = getch()) != '\n' && cdd != EOF);
                endwin();

                exit(0);
            }

            if(halfdelay(1) == ERR) { //increae the number if not working
                //printf("DEBUG 2\n");
                //waitFor(4);
                break; 
                }
            else {
                //printf("DEBUG 3\n");
                }
        }

    if (atleast_one == 0) {
            //gettimeofday(&t1, NULL);
            t1 = t0;
    }

    gettimeofday(&t3, NULL);
    elapsedTime = (t3.tv_sec - t1.tv_sec) + ((t3.tv_usec - t1.tv_usec)/1000000.0); 
    printf("Normal quit %f\n", elapsedTime);
    if (elapsedTime > 0.6) { //this number based on halfdelay above
        system("gedit &");
        //system("xdotool key shift+left &");
        //system("mplayer -vo caca -quiet 'video.mp4' &");
        //waitFor(4);
    }
    else if (elapsedTime <= 0.6) {
        system("xdotool key ctrl+shift+t &");
        //waitFor(4);
    }

    int cdd;
    while ( (cdd = getch() ) != '\n' && cdd != EOF);
    endwin();
    return 0; 

}

Use showkey -a para obter o código de atalho:

xb@dnxb:/tmp$ sudo showkey -a

Press any keys - Ctrl-D will terminate this program

^[[24~   27 0033 0x1b #pressed F12
         91 0133 0x5b
         50 0062 0x32
         52 0064 0x34
        126 0176 0x7e
5        53 0065 0x35 #pressed Numpad 5, 5 is the keycode used in 'bind'
^C        3 0003 0x03
^D        4 0004 0x04
xb@dnxb:/tmp$ 

Coloque o código de chave de ligação 5 e seu comando (por exemplo, executar /tmp/.a.out ) em ~ / .bashrc:

bind '"5":"/tmp/a.out\n"'

Observe que o código de tecla relevante também precisa ser alterado no código-fonte (o valor hexadecimal também pode ser obtido de sudo showkey -a acima):

int c = 0x35;

Compile com (saída para /tmp/a.out no meu exemplo):

cc filename.c -lcurses

Demonstração:

Numpad 5, pressione rapidamente, abra a nova guia, pressione a mídia e abra o gnome-terminal.

Istonãoédiretamenteaplicávelemqualquerjanelanogerenciadordedesktopgnome,maseuachoquedeveriadarumaidéiadecomo(difícil)implementá-lo.EletambémfuncionanoVirtualConsole(Ctrl+Alt+N)efuncionaemalgumemuladordeterminal(porexemplo,konsole,gnome-terminal,xterm).

p/s:Eunãosouumprogramadorc,entãomeperdoeseestecódigonãoforotimizado.

[UPDATE]

Arespostaanteriorsófuncionanoshellenofoconecessário,entãoachoqueo/dev/input/eventXéasoluçãoparatrabalharemtodaasessãoX.

Eunãoqueroreinventararoda.Eubrincocomoutilitárioevtestemodifiqueiapartedebaixodo evtest.c com meu próprio código:

int onHold = 0;
struct timeval t0;
double elapsedTime;
int hitMax = 0;

while (1) {
    rd = read(fd, ev, sizeof(struct input_event) * 64);

    if (rd < (int) sizeof(struct input_event)) {
        perror("\nevtest: error reading");
        return 1;
    }

    system("echo 'running' >/tmp/l_is_running 2>/tmp/l_isrunning_E &");
    for (i = 0; i < rd / sizeof(struct input_event); i++) {

        //system("date >/tmp/l_date 2>/tmp/l_dateE &");

        if (ev[i].type == EV_KEY) {
            if ( (ev[i].code == 76) ) {

                if (!onHold) {
                    onHold = 1;
                    t0 = ev[i].time;
                    hitMax = 0;
                }
                if (!hitMax) { //to avoid hitMax still do the time checking instruction, you can remove hitMax checking if you think it's overkill, but still hitMax itself is necessary to avoid every (max) 2 seconds will repeatly system();
                    elapsedTime = (ev[i].time.tv_sec - t0.tv_sec) + ((ev[i].time.tv_usec - t0.tv_usec)/1000000.0);
                    printf("elapsedTime: %f\n", elapsedTime);
                    if (elapsedTime > 2) {
                        hitMax = 1;
                        printf("perform max time action\n");
                        system("su - xiaobai -c 'export DISPLAY=:0; gedit &'");
                    }
                }

                if (ev[i].value == 0)  {
                    printf("reseted ...... %d\n", ev[i].value);
                    onHold = 0;
                    if (!hitMax) {
                        if (elapsedTime > 1) { //just ensure lower than max 2 seconds
                            system("su - xiaobai -c 'export DISPLAY=:0; gnome-terminal &'");
                        } else if (elapsedTime > 0.5) { 
                            system("su - xiaobai -c \"export DISPLAY=:0; vlc '/home/xiaobai/Downloads/videos/test/Pokémon Red_Blue_Yellow Gym Leader Battle Theme Remix-CbJTkx7QUJU.mp4' &\"");
                        } else if  (elapsedTime > 0.2) {
                            system("su - xiaobai -c 'export DISPLAY=:0; nautilus &'");
                        }
                    } else { //else's max system() already perform
                        hitMax = 0;
                    }
                }
            }
        }
    }
}

Note que você deve mudar o nome de usuário ( xiaobai é o meu nome de usuário). E também o if ( (ev[i].code == 76) ) { é meu código-chave do Numpad 5, talvez seja necessário imprimir manualmente o código ev [i] para confirmar. E é claro que você deve mudar o caminho do vídeo também:)

Compile e teste diretamente com (a parte '' é para obter o /dev/input/eventN correto):

$ gcc /home/put_your_path/my_long_press.c -o /home/put_your_path/my_long_press; sudo /home/put_your_path/my_long_press 'ls -la /dev/input/by-path/* | grep kbd |  echo "/dev/input/""$(awk -F'/' '{print $NF}')" ' &

Note que /by-id/ não funciona no Fedora 24, então eu mudo para / by-path /. Kali nenhum problema desse tipo.

Meu gerenciador de área de trabalho é o gdm3:

$ cat /etc/X11/default-display-manager 
/usr/sbin/gdm3

Então, eu coloquei esta linha em /etc/gdm3/PostLogin/Default para executar este comando como root na inicialização do gdm ( /etc/X11/Xsession.d/* não funciona):

/home/put_your_path/my_long_press 'ls -la /dev/input/by-id/* | grep kbd |  echo "/dev/input/""$(awk -F'/' '{print $NF}')" 2>/tmp/l_gdm' 2>/tmp/l_gdmE &

Por motivo desconhecido / etc/gdm/PostLogin/Default não funciona no Fedora 24 'gdm que me dá " Permissão negada " quando verificar /tmp/l_gdmE log. Executar manualmente não há problema.

Demonstração:

Numpad 5, instant-press (< = 0,2 segundo) será ignorado, pressione brevemente (0,2 a 0,5 segundo) abra nautilus , pressione média (0,5 a 1 segundo) abra vlc para reproduzir vídeo , pressione e segure (1 a 2 segundos), abra gnome-terminal e tempo limite de impressão (2 segundos), abra gedit .

Carreguei o código completo (somente um arquivo) aqui .

[ATUALIZAR novamente]

[1] O fluxo de várias chaves foi adicionado e o% fixonotify-send falhou, definindo DBUS_SESSION_BUS_ADDRESS . [2] Adicionamos XDG_CURRENT_DESKTOP e GNOME_DESKTOP_SESSION_ID para garantir que o konsole use o gnome theme gui (Mude se você não estiver usando o gnome).

Eu atualizei meu código aqui .

Observe que esse código não funciona para o fluxo de chaves combinadas, por exemplo, Ctrl + t .

ATUALIZAÇÃO:

Existem várias interfaces de dispositivos nas quais a sequência de entradas / dev / input / by-path / XXX-eventN é aleatória. Então eu mudo o comando em /etc/gdm3/PostLogin/Default como abaixo ( Chesen é o nome do meu teclado, para o seu caso, você deve alterá-lo para grep Razer ):

/your_path/my_long_press "$(cat /proc/bus/input/devices | grep -i Chesen -A 4 | grep -P '^(?=.*sysrq)(?=.*leds)' |  tr ' ' '\n' | ls /dev/input/'grep event')" 2>/tmp/l_gdmE &

Você pode tentar a extração eventN de cat /proc/bus/input/devices | grep -i Razer -A 4 :

$ cat /proc/bus/input/devices | grep -i Razer -A 4
N: Name="Razer Razer Naga Chroma"
P: Phys=usb-0000:00:14.0-1.3/input0
S: Sysfs=/devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1.3/3-1.3:1.0/0003:1532:0053.0003/input/input6
U: Uniq=
H: Handlers=mouse2 event5 
--
N: Name="Razer Razer Naga Chroma"
P: Phys=usb-0000:00:14.0-1.3/input1
S: Sysfs=/devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1.3/3-1.3:1.1/0003:1532:0053.0004/input/input7
U: Uniq=
H: Handlers=sysrq kbd event6 
--
N: Name="Razer Razer Naga Chroma"
P: Phys=usb-0000:00:14.0-1.3/input2
S: Sysfs=/devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1.3/3-1.3:1.2/0003:1532:0053.0005/input/input8
U: Uniq=
H: Handlers=sysrq kbd leds event7 
$ 

Neste exemplo acima, somente sudo cat /dev/input/event7 imprimirá uma saída bizarra quando clicar nos 12 dígitos do mouse Razer, que tem o padrão "sysrq kbd leds event7" para usar em grep -P '^(?=.*sysrq)(?=.*leds)' acima (seu padrão pode variar). sudo cat /dev/input/event6 imprimirá saída bizarra somente quando clicar na tecla do meio para cima / baixo. Enquanto sudo cat /dev/input/event5 imprimirá uma saída bizarra quando mover o mouse e rolar a roda.

[Atualização: suporte ao cabo do teclado para recarregar o programa]

O seguinte deve ser auto-explicativo:

$ lsusb #to know my keyboard is idVendor 0a81 and idProduct 0101
...
Bus 001 Device 003: ID 0a81:0101 Chesen Electronics Corp. Keyboard

$ cat /etc/udev/rules.d/52-hole-keyboard.rules #add this line with your idVendor and idProduct above in custom udev rules file
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="0a81", ATTR{idProduct}=="0101", MODE="0666", GROUP="plugdev", RUN+="/bin/bash -c 'echo 1 > /tmp/chesen_plugged'"

$ cat /usr/local/bin/inotifyChesenPlugged #A long run listener script to listen for modification of /tmp/chesen_plugged #Ensures 'inotifywait' has been installed first.
touch /tmp/chesen_plugged
while inotifywait -q -e modify /tmp/chesen_plugged >/dev/null; do
        killall -9 my_long_press
        /usr/local/bin/startLongPress &
done

$ cat /usr/local/bin/startLongPress #the executable script run the long press executable #Change with your pattern as explained above.
#!/bin/bash
<YOUR_DIR>/my_long_press "$(cat /proc/bus/input/devices | grep -i Chesen -A 4 | grep -P '^(?=.*sysrq)(?=.*leds)' |  tr ' ' '\n' | ls /dev/input/'grep event')" 2>/tmp/l_gdmE) & disown

$ cat /etc/gdm3/PostLogin/Default #the executable startup script run listener and long press script
/usr/local/bin/inotifyChesenPlugged &
/usr/local/bin/startLongPress &
    
por 02.11.2016 / 06:17
1

Você pode encontrar uma ferramenta que funcione com um determinado conjunto de programas, mas não haverá uma ferramenta utilizável globalmente, pois o comportamento relacionado ao tempo é feito em aplicativos no X, e não no sistema de janelas.

    
por 02.11.2016 / 01:09
0

você verificou o Xmodmap?

xmodmap é um utilitário para modificar mapas de botões e mapeamentos de botões de ponteiro no Xorg

link

    
por 02.11.2016 / 00:39