Cách sắp xếp lại các phím bàn phím dựa trên thời gian bạn giữ phím


9

Tôi muốn sắp xếp lại các phím trên bàn phím số của mình để chúng hoạt động khác nhau tùy thuộc vào thời gian nhấn phím. Đây là một ví dụ:

Nếu tôi giữ phím Numpad 9 xuống dưới 300ms, nó sẽ gửi lệnh phím "tab trước" Ctrl+Tab

Nếu tôi giữ phím Numpad 9 xuống trong 300-599ms, nó sẽ gửi lệnh phím "tab mới" Ctrl+T

Nếu tôi giữ phím Numpad 9 xuống trong 600-899ms, nó sẽ gửi lệnh "tab đóng / cửa sổ" Ctrl+W

Nếu tôi giữ phím Numpad 9 xuống hơn 899ms, thì không có gì trong trường hợp tôi bỏ lỡ cửa sổ thời gian tôi muốn.

Trên Windows, tôi có thể thực hiện việc này với AutoHotKey và trên OS XI có thể thực hiện việc này với ControllerMate, nhưng tôi không thể tìm thấy một công cụ nào trên UNIX / Linux cho phép ánh xạ lại khóa dựa trên thời gian khóa được giữ.

Nếu bạn biết về một công cụ có thể giải quyết vấn đề của tôi, vui lòng đảm bảo cung cấp một tập lệnh hoặc mẫu mã thể hiện hành vi thời gian giữ khóa có điều kiện mà tôi đã mô tả ở trên. Nó không cần phải là mã đầy đủ để giải quyết ví dụ của tôi, nhưng nó đủ để tôi tái sử dụng nó cho ví dụ của mình.


Đây là một điều kỳ lạ để làm. Làm thế nào bạn sẽ thời gian báo chí 600 mili giây của bạn? : D +1 cho ý tưởng điên rồ.
tự đại diện

Chỉ cần thêm một chút gia vị vào cuộc sống của bạn, bạn nên thêm một cửa sổ thời gian từ 347 đến 350 ms sẽ buộc tắt máy tính của bạn. ;)
tự đại diện

@Wildcard Tôi thực sự sử dụng bàn phím số trên Razer Naga của mình cho việc này và khi lần đầu tiên tôi thực hiện ý tưởng với AutoHotKey trên Windows, tôi đã sử dụng cửa sổ thời gian 300-400ms, nhưng bây giờ tôi đã sử dụng hệ thống này một thời gian, tôi sử dụng cửa sổ thời gian cách nhau khoảng 200ms và tôi có thể có được cửa sổ thời gian mong muốn khoảng 99% thời gian. Nó rất giống với cách bạn sẽ giao tiếp với mã morse.
kanoko

Câu trả lời:


7

Tôi chỉ viết điều này trong 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; 

}

Sử dụng showkey -ađể lấy mã khóa liên kết:

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$ 

Đặt mã khóa liên kết 5 và lệnh của nó (ví dụ: chạy /tmp/.a.out) trong ~ / .bashrc:

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

Lưu ý rằng mã khóa có liên quan cũng cần thay đổi trong mã nguồn (giá trị hex cũng có thể nhận được từ sudo showkey -aphía trên):

int c = 0x35;

Biên dịch với (đầu ra /tmp/a.outtrong ví dụ của tôi):

cc filename.c -lcurses

Trình diễn:

Numpad 5, nhấn nhanh mở tab mới, nhấn gedit vừa và nhấn gnome-terminal dài.

nhập mô tả hình ảnh ở đây

Điều này không thể áp dụng trực tiếp trong bất kỳ cửa sổ nào trên trình quản lý máy tính để bàn gnome, nhưng tôi nghĩ nó sẽ cung cấp cho bạn một số ý tưởng về cách (khó) để thực hiện nó. Nó cũng hoạt động trong Bảng điều khiển ảo (Ctrl + Alt + N) và hoạt động trong một số trình giả lập thiết bị đầu cuối (ví dụ: konsole, gnome-terminal, xterm).

p / s: Tôi không phải là lập trình viên ac, vì vậy hãy tha thứ cho tôi nếu mã này không được tối ưu hóa.

[CẬP NHẬT]

Câu trả lời trước chỉ hoạt động trong shell và yêu cầu tập trung, vì vậy tôi nghĩ phân tích / dev / input / eventX là giải pháp để hoạt động trong toàn bộ phiên X.

Tôi không muốn phát minh lại bánh xe. Tôi chơi xung quanh với evtesttiện ích và sửa đổi phần dưới cùng của evtest.c bằng mã của riêng tôi:

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

Lưu ý rằng bạn nên thay đổi tên người dùng ( xiaobai là tên người dùng của tôi). Và đây cũng if ( (ev[i].code == 76) ) {là mã khóa Numpad 5 của tôi, bạn có thể cần in thủ công mã ev [i]. Để xác nhận gấp đôi. Và tất nhiên bạn cũng nên thay đổi đường dẫn video :)

Biên dịch và kiểm tra nó trực tiếp với (phần `` để có được chính xác /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}')" ` &

Lưu ý rằng /by-id/không hoạt động trong Fedora 24, vì vậy tôi thay đổi nó thành / by-path /. Kali không có vấn đề như vậy.

Trình quản lý máy tính để bàn của tôi là gdm3:

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

Vì vậy, tôi đặt dòng này /etc/gdm3/PostLogin/Defaultđể chạy lệnh này với quyền root khi khởi động gdm ( /etc/X11/Xsession.d/*không hoạt động):

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

Không rõ lý do / etc/gdm/PostLogin/Defaultkhông hoạt động trên Fedora 24 'gdm, điều này cho tôi " Quyền bị từ chối " khi kiểm tra /tmp/l_gdmEnhật ký. Chạy thủ công không có vấn đề mặc dù.

Trình diễn:

Numpad 5, bấm nhanh (<= 0,2 giây) sẽ bị bỏ qua, nhấn nhanh (0,2 đến 0,5 giây) mở nautilus, nhấn trung bình (0,5 đến 1 giây) vlcđể phát video, nhấn lâu (1 đến 2 giây) mở gnome-terminalvà hết thời gian - nhấn (2 giây) mở gedit.

nhập mô tả hình ảnh ở đây

Tôi đã tải lên mã đầy đủ (chỉ có một tệp) ở đây .

[CẬP NHẬT một lần nữa]

[1] Đã thêm nhiều luồng khóa và cố định notify-sendkhông thành công bằng cách xác định DBUS_SESSION_BUS_ADDRESS. [2] Đã thêm XDG_CURRENT_DESKTOPGNOME_DESKTOP_SESSION_IDđể đảm bảo konsole sử dụng gui theme gnome (Thay đổi nó nếu bạn không sử dụng gnome).

Tôi đã cập nhật mã của tôi ở đây .

Lưu ý rằng mã này không xử lý luồng kết hợp, ví dụ Ctrl+ t.

CẬP NHẬT:

Có nhiều giao diện thiết bị mà chuỗi mục nhập / dev / input / by-path / XXX-eventN là ngẫu nhiên. Vì vậy, tôi thay đổi lệnh /etc/gdm3/PostLogin/Defaultnhư dưới đây ( Chesenlà tên bàn phím của tôi, đối với trường hợp của bạn, bạn nên thay đổi nó thành grep Razerthay thế):

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

Bạn có thể thử trích xuất eventN từ 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 
$ 

Trong ví dụ này ở trên, sudo cat /dev/input/event7sẽ chỉ in đầu ra kỳ quái khi nhấp vào 12 chữ số trên chuột Razer, có mẫu "sysrq kbd leds event7" để sử dụng ở grep -P '^(?=.*sysrq)(?=.*leds)'trên (mẫu của bạn có thể thay đổi). sudo cat /dev/input/event6sẽ chỉ in đầu ra kỳ quái khi nhấp vào phím lên / xuống giữa. Trong khi sudo cat /dev/input/event5sẽ in đầu ra kỳ quái khi di chuyển chuột và cuộn bánh xe.

[Cập nhật: Hỗ trợ Thay thế cáp bàn phím để tải lại chương trình]

Sau đây nên tự giải thích:

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

tôi giả sử phương pháp này đòi hỏi một cửa sổ đầu cuối phải tập trung trong khi nhấn phím? Có cách nào để giái quyết vấn đề này không?
kanoko

@kanoko Tôi đã cập nhật giải pháp.
林果 4/11/2016

thx, tôi thực sự đánh giá cao những nỗ lực của bạn vào việc này. Tôi sẽ thử nó. Bạn có nghĩ rằng giải pháp này sẽ có tác động đáng chú ý đến việc sử dụng cpu nếu tôi thiết lập nó với 12 phím nóng khác nhau không?
kanoko

@kanoko Tôi đã cập nhật mã một lần nữa để chơi xung quanh với nhiều phím. IMHO tôi không nghĩ rằng nó có tác động đáng chú ý đến cpu vì 10+ if-other quá tinh tế và nó chỉ chạy kiểm tra sau khi đọc (fd, ev, sizeof (struct input_event) * 64); câu lệnh, tức là nó chỉ chạy if-elsemỗi lần nhấn phím, trong khi tôi cũng thêm vào if (currCode >= 59) && (currCode <= 81)để giới hạn phạm vi trước đó if-else.
林果皞

1
bạn thật tuyệt!!! Cảm ơn bạn rất nhiều vì tất cả sự giúp đỡ của bạn. nếu bạn từng có cơ hội thử điều này với một con chuột numpad MMO như Razer Naga, tôi thề nó sẽ thay đổi cuộc đời bạn. Tôi có thể chỉ cho bạn bản đồ chính của tôi nếu bạn quan tâm.
kanoko

1

Bạn có thể tìm thấy một công cụ hoạt động với một bộ chương trình cụ thể, nhưng sẽ không có công cụ nào có thể sử dụng toàn cầu vì hành vi liên quan đến thời gian được thực hiện trong các ứng dụng trong X, thay vì hệ thống cửa sổ.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.