วิธีทำการแมปแป้นคีย์บอร์ดใหม่ตามระยะเวลาที่คุณถือกุญแจ


9

ฉันต้องการตั้งค่าปุ่มบนแป้นตัวเลขของฉันใหม่เพื่อให้ทำงานได้แตกต่างกันไปตามระยะเวลาที่กดปุ่ม นี่คือตัวอย่าง:

ถ้าฉันกดปุ่ม Numpad 9 ค้างไว้น้อยกว่า 300ms มันจะส่งคำสั่งคีย์ "แท็บก่อนหน้า" Ctrl+Tab

ถ้าฉันกดปุ่ม Numpad 9 ค้างไว้เป็นเวลา 300-599ms มันจะส่งคำสั่ง "new tab" Ctrl+T

ถ้าฉันกดปุ่ม Numpad 9 ค้างไว้สำหรับ 600-899ms มันจะส่งคำสั่ง "ปิดแท็บ / หน้าต่าง" Ctrl+W

ถ้าฉันกดปุ่ม Numpad 9 ค้างไว้นานกว่า 899ms มันจะไม่ทำอะไรเลยในกรณีที่ฉันพลาดเวลาที่ฉันต้องการ

บน Windows ฉันสามารถทำได้ด้วย AutoHotKey และบน OS XI ทำได้ด้วย ControllerMate แต่ฉันไม่สามารถหาเครื่องมือบน UNIX / Linux ที่อนุญาตให้ทำการแมปคีย์ตามระยะเวลาที่ถือคีย์

หากคุณทราบถึงเครื่องมือที่สามารถแก้ปัญหาของฉันได้โปรดตรวจสอบให้แน่ใจว่าได้จัดทำตัวอย่างสคริปต์หรือรหัสที่แสดงให้เห็นถึงพฤติกรรมการทำงานตามระยะเวลาการเก็บกุญแจตามเงื่อนไขที่ฉันอธิบายไว้ข้างต้น มันไม่จำเป็นต้องเป็นรหัสเต็มรูปแบบในการแก้ตัวอย่างของฉัน แต่มันก็เพียงพอแล้วสำหรับฉันที่จะเปลี่ยนมันสำหรับตัวอย่างของฉัน


นี่เป็นสิ่งที่ต่างชาติจะทำ คุณจะใช้เวลา 600 มิลลิวินาทีในการกดปุ่มอย่างไร : D +1 สำหรับความคิดที่บ้า
Wildcard

เพียงเพื่อเพิ่มเครื่องเทศให้กับชีวิตของคุณคุณควรเพิ่มช่วงเวลาจาก 347 ถึง 350 ms ที่จะบังคับปิดคอมพิวเตอร์ของคุณ ;)
Wildcard

@ บัตรฉันใช้แป้นตัวเลขบน Razer Naga ของฉันจริง ๆ และเมื่อฉันนำแนวคิดนี้มาใช้กับ AutoHotKey บน Windows ฉันใช้ windows time 300-400ms แต่ตอนนี้ฉันใช้ระบบนี้มาระยะหนึ่งแล้วฉันใช้ use หน้าต่างเวลาอยู่ห่างกันประมาณ 200ms และฉันจะได้หน้าต่างเวลาที่ต้องการประมาณ 99% ของเวลา มันคล้ายกับวิธีที่คุณสื่อสารกับรหัสมอร์ส
kanoko

คำตอบ:


7

ฉันเพิ่งเขียนสิ่งนี้ใน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 -aเพื่อรับรหัสการเชื่อมโยง:

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$ 

ใส่รหัสการผูก 5 และคำสั่งของมัน (เช่น run /tmp/.a.out) ใน ~ / .bashrc:

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

โปรดทราบว่ารหัสที่เกี่ยวข้องจำเป็นต้องเปลี่ยนในซอร์สโค้ดด้วย (ค่าฐานสิบหกสามารถรับได้จากsudo showkey -aด้านบน):

int c = 0x35;

คอมไพล์ด้วย (ส่งออกไป/tmp/a.outในตัวอย่างของฉัน):

cc filename.c -lcurses

สาธิต:

Numpad 5, กดสั้น ๆ เปิดแท็บใหม่, กด Medium open gedit และกดค้างที่ open gnome-terminal

ป้อนคำอธิบายรูปภาพที่นี่

นี่ไม่สามารถใช้งานได้โดยตรงในหน้าต่างใด ๆ บนตัวจัดการเดสก์ท็อปของ GNOME แต่ฉันคิดว่ามันควรจะทำให้คุณมีความคิดว่าจะใช้งานอย่างไร (ยาก) มันทำงานใน Virtual Console (Ctrl + Alt + N) ด้วยและทำงานในเทอร์มินัลอีมูเลเตอร์บางตัว (เช่น konsole, gnome-terminal, xterm)

p / s: ฉันไม่ใช่โปรแกรมเมอร์ ac ดังนั้นโปรดยกโทษให้ฉันหากรหัสนี้ไม่ได้รับการปรับปรุง

[อัปเดต]

คำตอบก่อนหน้านี้ใช้งานได้ในเชลล์และการโฟกัสที่ต้องการเท่านั้นดังนั้นฉันคิดว่าการแยกวิเคราะห์ / dev / input / eventX เป็นวิธีแก้ปัญหาในการทำงานในเซสชัน X ทั้งหมด

ฉันไม่ต้องการที่จะบูรณาการล้อ ฉันเล่นด้วยevtestยูทิลิตี้และแก้ไขส่วนล่างของevtest.cด้วยรหัสของฉันเอง:

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

โปรดทราบว่าคุณควรเปลี่ยนชื่อผู้ใช้ ( xiaobaiของฉันชื่อผู้ใช้บางส่วน) และยังif ( (ev[i].code == 76) ) {เป็นรหัส Numpad 5 ของฉันคุณอาจต้องพิมพ์ ev [i] .code ด้วยตนเองเพื่อยืนยันซ้ำ และแน่นอนคุณควรเปลี่ยนเส้นทางวิดีโอด้วย :)

รวบรวมและทดสอบโดยตรงกับ (ส่วน `` คือเพื่อให้ถูกต้อง/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}')" ` &

โปรดทราบว่า/by-id/ไม่สามารถใช้งานได้ใน Fedora 24 ดังนั้นฉันจึงเปลี่ยนเป็น / by-path / กาลีไม่มีปัญหาดังกล่าว

ผู้จัดการเดสก์ท็อปของฉันคือ gdm3:

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

ดังนั้นฉันใส่บรรทัดนี้/etc/gdm3/PostLogin/Defaultเพื่อเรียกใช้คำสั่งนี้เป็น root ในการเริ่มต้น gdm ( /etc/X11/Xsession.d/*ไม่ทำงาน):

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

ด้วยเหตุผลที่ไม่รู้จัก / etc/gdm/PostLogin/Defaultไม่ทำงานบน Fedora 24 'gdm ซึ่งให้ " ปฏิเสธการอนุญาต " เมื่อตรวจสอบ/tmp/l_gdmEบันทึก ทำงานด้วยตนเองไม่มีปัญหาแม้ว่า

สาธิต:

Numpad 5 กดทันที (<= 0.2 วินาที) จะถูกละเว้นกดสั้น ๆ (0.2 ถึง 0.5 วินาที) เปิดnautilusกดกลาง (0.5 ถึง 1 วินาที) เปิดvlcเพื่อเล่นวิดีโอกดยาว (1 ถึง 2 วินาที) เปิดgnome-terminalและหมดเวลากด (2 วินาที) geditเปิด

ป้อนคำอธิบายรูปภาพที่นี่

ฉันได้อัปโหลดโค้ดเต็มรูปแบบ (เฉพาะไฟล์เดียว) ที่นี่

[อัพเดทอีกครั้ง]

[1] หลายคีย์เพิ่มการไหลและคงล้มเหลวโดยกำหนดnotify-send DBUS_SESSION_BUS_ADDRESS[2] เพิ่มXDG_CURRENT_DESKTOPและGNOME_DESKTOP_SESSION_IDเพื่อให้แน่ใจว่า konsole ใช้ gnome theme gui (เปลี่ยนหากคุณไม่ได้ใช้ gnome)

ฉันปรับปรุงรหัสของฉันที่นี่

หมายเหตุว่ารหัสนี้ไม่ได้จัดการกับกุญแจรวมกันไหลเช่น+Ctrlt

UPDATE:

มีอินเตอร์เฟสหลายอุปกรณ์ที่ลำดับรายการ / dev / input / by-path / XXX-eventN เป็นแบบสุ่ม ดังนั้นฉันจึงเปลี่ยนคำสั่งใน/etc/gdm3/PostLogin/Defaultด้านล่าง ( Chesenเป็นชื่อแป้นพิมพ์ของคุณสำหรับกรณีของคุณคุณควรเปลี่ยนเป็น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 &

คุณสามารถลองแยก eventN จาก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 
$ 

ในตัวอย่างนี้ด้านบนsudo cat /dev/input/event7จะพิมพ์ผลลัพธ์ที่แปลกประหลาดเมื่อคลิกที่ตัวเลข 12 หลักบนเมาส์ Razer ซึ่งมีรูปแบบ "sysrq kbd leds event7" เพื่อใช้งานgrep -P '^(?=.*sysrq)(?=.*leds)'ด้านบน (รูปแบบของคุณอาจแตกต่างกัน) sudo cat /dev/input/event6จะพิมพ์ผลลัพธ์ที่แปลกประหลาดเฉพาะเมื่อคลิกปุ่มตรงกลางขึ้น / ลง ในขณะที่sudo cat /dev/input/event5จะพิมพ์ผลลัพธ์ที่แปลกประหลาดเมื่อเลื่อนเมาส์ของคุณและเลื่อนล้อ

[อัพเดต: รองรับสายคีย์บอร์ด Replug เพื่อโหลดโปรแกรมซ้ำ]

ต่อไปนี้ควรอธิบายด้วยตนเอง:

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

ฉันถือว่าวิธีนี้ต้องใช้หน้าต่างเทอร์มินัลในการโฟกัสขณะทำการกดปุ่ม? มีวิธีแก้ไขไหม
kanoko

@kanoko ฉันได้อัปเดตโซลูชันแล้ว
ผลไม้

ขอบคุณฉันซาบซึ้งในความพยายามของคุณ ฉันจะลองทำดู คุณคิดว่าวิธีนี้จะส่งผลกระทบอย่างเห็นได้ชัดต่อการใช้ cpu หรือไม่หากฉันตั้งค่า 12 ปุ่มลัดที่แตกต่าง
kanoko

@kanoko ฉันได้อัปเดตรหัสอีกครั้งเพื่อเล่นกับหลาย ๆ คีย์ IMHO ฉันไม่คิดว่ามันจะส่งผลกระทบอย่างเห็นได้ชัดต่อ cpu เนื่องจากมี 10+ if-else ที่บอบบางเกินไปและมันรันการตรวจสอบหลังจากอ่านแล้วเท่านั้น (fd, ev, sizeof (struct input_event) * 64); คำสั่งเช่นมันรันif-elseทุกกดปุ่มในขณะที่ฉันยังเพิ่มif (currCode >= 59) && (currCode <= 81)การ จำกัด if-elseช่วงก่อน
ผลไม้

1
คุณช่างน่าอัศจรรย์!!! ขอบคุณมากสำหรับความช่วยเหลือของคุณ หากคุณได้รับโอกาสลองใช้ด้วย MMO numpad mouse เช่น Razer Naga ฉันสาบานได้เลยว่ามันจะเปลี่ยนชีวิตคุณ ฉันสามารถแสดงการแมปกุญแจให้ฉันได้หากคุณสนใจ
kanoko

1

คุณอาจพบเครื่องมือที่ทำงานกับชุดของโปรแกรมเฉพาะ แต่จะไม่มีเครื่องมือที่ใช้งานได้ทั่วโลกเพราะพฤติกรรมที่เกี่ยวข้องกับเวลานั้นเกิดขึ้นในแอปพลิเคชันใน X แทนที่จะใช้ระบบหน้าต่าง


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.