Tuşa ne kadar basılı tuttuğunuza göre klavye tuşlarını yeniden eşleme


9

Sayısal tuş takımımdaki tuşları yeniden tuşlamak istiyorum, böylece tuşun ne kadar basılı tutulduğuna bağlı olarak farklı davranıyorlar. İşte bir örnek:

Numpad 9 tuşunu 300ms'den daha az basılı tutarsam "önceki sekme" tuş komutunu Ctrl+Tab

Numpad 9 tuşunu 300-599ms boyunca basılı tutarsam "yeni sekme" tuş komutu Ctrl+T

Numpad 9 tuşunu 600-899ms boyunca basılı tutarsam "sekmeyi kapat / pencereyi kapat" tuşu komutu Ctrl+W

Numpad 9 tuşunu 899ms'den fazla basılı tutarsam, istediğim zaman penceresini kaçırmam durumunda hiçbir şey yapmaz.

Windows'da bunu AutoHotKey ile yapabilirim ve OS XI'de ControllerMate ile bunu yapabilirdim, ancak UNIX / Linux'ta bir anahtarın ne kadar süreyle tutulduğuna bağlı olarak anahtar yeniden eşlemesine izin veren bir araç bulamıyorum.

Sorunumu çözebilecek bir aracın farkındaysanız, lütfen yukarıda açıkladığım koşullu tuş tutma süresi davranışını gösteren bir komut dosyası veya kod örneği sağladığınızdan emin olun. Örneğimi çözmek için tam kod olması gerekmez, ancak örneğim için yeniden yerleştirmek benim için yeterli olmalıdır.


Bu çok tuhaf bir şey. 600 milisaniyelik baskı makinenizi nasıl zamanlayacaksınız? : Çılgın fikir için D +1.
Wildcard

Sadece hayatınıza biraz baharat eklemek için, bilgisayarınızı zorla kapatacak 347 ila 350 ms arasında bir zaman penceresi eklemelisiniz. ;)
Wildcard

@Wildcard Aslında bunun için Razer Naga'mdaki sayısal tuş takımını kullanıyorum ve fikri Windows'ta AutoHotKey ile ilk kez uyguladığımda 300-400ms zaman penceresi kullandım, ancak şimdi bu sistemi bir süredir kullanıyorum, zaman pencereleri yaklaşık 200 ms aralıklarla, ve zaman dilimi yaklaşık% 99 zaman alabilirim. Mors kodu ile iletişim kurma şeklinize çok benzer.
kanoko

Yanıtlar:


7

Ben sadece 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; 

}

showkey -aBağlama anahtar kodunu almak için kullanın :

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$ 

Bind anahtar kodunu 5 ve komutunu (örn. Run /tmp/.a.out) ~ / .bashrc dizinine koyun :

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

İlgili anahtar kodunun kaynak kodda da değiştirilmesi gerektiğini unutmayın (onaltılık değer sudo showkey -ayukarıdan da alabilir ):

int c = 0x35;

Derleme (örneğimde çıktı /tmp/a.out):

cc filename.c -lcurses

gösteri:

Numpad 5, kısa basış açık yeni sekme, orta basış açık gedit ve uzun basış açık gnome terminali.

resim açıklamasını buraya girin

Bu doğrudan gnome masaüstü yöneticisi herhangi bir pencerede uygulanabilir değildir, ama ben bunu (zor) nasıl uygulamak için bazı fikir vermek gerektiğini düşünüyorum. Sanal Konsolda (Ctrl + Alt + N) de çalışır ve bazı terminal emülatörlerinde (örn. Konsole, gnome-terminal, xterm) çalışır.

p / s: Ben ac programcı değilim, bu yüzden bu kod optimize değilse beni affet.

[GÜNCELLEME]

Önceki cevap sadece kabuk ve gerekli odak çalışması, bu yüzden / dev / input / eventX ayrıştırma tüm X oturumu çalışmak için çözüm olduğunu düşünüyorum.

Tekerleği yeniden icat etmek istemiyorum. Ben evtestyardımcı programı ile oynamak ve kendi kodu ile evtest.c alt kısmını değiştirdi :

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

Kullanıcı adı ( xiaobai benim kullanıcı adımdır ) bölümünü değiştirmeniz gerektiğini unutmayın . Ve aynı zamanda if ( (ev[i].code == 76) ) {benim Numpad 5 anahtar kodumdur, çift onaylamak için ev [i]. Kodunu manuel olarak yazdırmanız gerekebilir. Ve elbette video yolunu da değiştirmelisiniz :)

Doğrudan derleyin ve test edin (`` doğru olanı almak için kısımdır /dev/input/eventN):

$ 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}')" ` &

Bu /by-id/Fedora 24 çalışmıyor, bu yüzden / by-path / olarak değiştirin. Kali böyle bir sorun yok.

Masaüstü yöneticim gdm3:

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

Yani, ben bu satırı /etc/gdm3/PostLogin/Defaultgdm başlangıçta root olarak bu komutu çalıştırmak için koymak ( /etc/X11/Xsession.d/*çalışmıyor):

/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 &

Bilinmeyen bir nedenden dolayı / onay günlüğünde etc/gdm/PostLogin/Defaultbana " İzin reddedildi " veren Fedora 24 'gdm'de ​​çalışmıyor /tmp/l_gdmE. El ile olsa sorun çalıştırın.

gösteri:

Numpad 5, anında basma (<= 0,2 saniye) yok sayılır, kısa basma (0,2 ila 0,5 saniye) açık nautilus, orta basma (0,5 ila 1 saniye) vlcvideoyu oynatmak için uzun basın (1 ila 2 saniye) açın gnome-terminalve zaman aşımı düğmesine basın (2 saniye) gedit.

resim açıklamasını buraya girin

Tam kodu buraya yükledim (sadece bir dosya) .

[Tekrar GÜNCELLEME]

[1] Birden fazla tuş akışı eklendi ve notify-sendtanımlanamadı DBUS_SESSION_BUS_ADDRESS. [2] Eklendi XDG_CURRENT_DESKTOPve GNOME_DESKTOP_SESSION_IDkonsole gnome tema gui kullanın sağlamak için (gnome kullanmıyorsanız değiştirin).

Kodumu burada güncelledim .

Bu kodun, örneğin Ctrl+ gibi birleşik tuş akışı için işlemediğini unutmayın t.

GÜNCELLEME:

/ Dev / input / by-path / XXX-eventN girişleri sırasının rasgele olduğu birden çok aygıt arabirimi vardır. Bu yüzden komutu /etc/gdm3/PostLogin/Defaultaşağıdaki gibi değiştiriyorum ( Chesenbenim klavye adım, sizin durumunuz için grep Razerbunun yerine değiştirmelisiniz ):

/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 &

EventN ayıklamasını aşağıdakilerden deneyebilirsiniz 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 
$ 

Yukarıdaki bu örnekte, yalnızca yukarıda sudo cat /dev/input/event7kullanmak üzere "sysrq kbd leds event7" desenine sahip Razer fare üzerindeki 12 hane tıklandığında tuhaf çıktılar yazdırılacaktır grep -P '^(?=.*sysrq)(?=.*leds)'(deseniniz değişebilir). sudo cat /dev/input/event6tuhaf çıktıyı yalnızca orta yukarı / aşağı tuşuna tıkladığında yazdıracaktır. Süre sudo cat /dev/input/event5farenizi hareket ettirdiğinizde ve tekerleği kaydırdığınızda tuhaf çıktılar basacaktır.

[Güncelleme: Programı yeniden yüklemek için klavye kablosunu yeniden destekleyin]

Aşağıdakiler kendi kendini açıklama olmalıdır:

$ 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 &

Bu yöntem tuş presleri yaparken odakta bir terminal penceresi gerektirir varsayalım? bunun etrafında bir yol var mı?
kanoko

@kanoko Çözümü güncelledim.
Meyve

Teşekkürler, bu çabaları gerçekten takdir ediyorum. Bunu deneyeceğim. 12 farklı kısayol tuşuyla ayarladıysam bu çözümün cpu kullanımı üzerinde belirgin bir etkisi olacağını düşünüyor musunuz?
kanoko

@kanoko Birden fazla tuşla oynamak için kodu tekrar güncelledim. IMHO, cpu üzerinde fark edilebilir bir etki olduğunu düşünmüyorum çünkü 10+ if çok ince ve sadece okuduktan sonra kontrolü çalıştırıyor (fd, ev, sizeof (struct input_event) * 64); ifade, yani ben sadece if-elseher tuşa basın çalıştırmak, ben de if (currCode >= 59) && (currCode <= 81)önce aralığı sınırlamak için ekledi if-else.
Meyve

1
harikasın!!! yardımlarınız için çok teşekkür ederim. Razer Naga gibi bir MMO numpad faresiyle bunu deneme şansınız olursa, yemin ederim hayatınızı değiştirecek. İlgilendiğinizde size anahtar eşlemelerimi gösterebilirim.
kanoko

1

Belirli bir program kümesiyle çalışan bir araç bulabilirsiniz, ancak zamanla ilgili davranış pencere sisteminden ziyade X'deki uygulamalarda yapıldığından, küresel olarak kullanılabilir bir araç olmayacaktır.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.