숫자 키패드의 키를 다시 매핑하여 키를 누르는 시간에 따라 다르게 동작하도록 하고 싶습니다. 예는 다음과 같습니다.
숫자 패드 9 키를 300밀리초 미만 동안 누르고 있으면 "이전 탭" 키 명령 Ctrl+Tab
숫자 패드 키 9를 300-599ms 동안 누르고 있으면 "새 탭" 키 명령 Ctrl+T
숫자 패드 키 9를 600-899ms 동안 누르고 있으면 "탭/창 닫기" 키 명령 Ctrl+W
숫자 키패드 9를 899밀리초 이상 누르고 있으면 필요한 시간 창을 놓칠 경우를 대비해 아무 작업도 수행되지 않습니다.
Windows에서는 AutoHotKey를 사용하고 OS XI에서는 ControllerMate를 사용하여 이 작업을 수행할 수 있지만 UNIX/Linux에서는 키 보유 시간을 기반으로 키 재매핑을 허용하는 도구를 찾을 수 없습니다.
제 문제를 해결할 수 있는 도구를 알고 계시다면 위에서 설명한 조건부 키 지속 시간 동작을 보여주는 스크립트나 코드 샘플을 제공해 주시기 바랍니다. 내 예제를 해결하는 데 완전한 코드일 필요는 없지만 예제에 재사용하는 데는 충분해야 합니다.
답변1
방금 이걸 썼어요씨:
#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"'
소스 코드의 관련 키코드도 변경해야 합니다(16진수 값은 sudo showkey -a
위에서 얻을 수도 있음).
int c = 0x35;
컴파일(내 예의 출력은 /tmp/a.out
):
cc filename.c -lcurses
데모:
숫자 패드 5, 짧게 누르면 새 탭이 열리고, 중간 정도 누르면 gedit가 열리고, 길게 누르면 그놈 터미널이 열립니다.
이는 gnome 데스크탑 관리자의 모든 창에 직접 적용되지는 않지만 이를 구현하는 방법(어려운)에 대한 아이디어를 제공해야 한다고 생각합니다. 또한 가상 콘솔(Ctrl+Alt+N)과 일부 터미널 에뮬레이터(예: konsole, gnome-terminal, xterm)에서도 작동합니다.
p/s: 저는 프로그래머가 아니기 때문에 이 코드가 최적화되지 않은 경우 양해해 주시기 바랍니다.
[고쳐 쓰다]
이전 답변은 셸에서만 작동하고 포커스가 필요하므로 /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;
}
}
}
}
}
}
사용자 이름을 변경해야 합니다(멍청한 놈내 사용자 이름) 부분입니다. 이것은 또한 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
gdm에 넣고 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
" 로그를 확인할 때 수동으로 실행하는 데 문제가 없습니다.
데모:
숫자 패드 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] konsole이 gnome 테마 GUI를 사용하는지 추가 XDG_CURRENT_DESKTOP
하고 GNOME_DESKTOP_SESSION_ID
확인하십시오(gnome을 사용하지 않는 경우 변경하십시오).
Ctrl이 코드는 + 와 같은 복합 키 스트림을 처리하지 않습니다 t.
고쳐 쓰다:
여러 장치 인터페이스가 있으며 /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
위에서 사용된 "sysrq kbd leds event7" 모드가 있는 Razer 마우스에서 12자리 숫자를 클릭할 때만 이상한 출력이 인쇄됩니다 grep -P '^(?=.*sysrq)(?=.*leds)'
(모드는 다를 수 있음). sudo cat /dev/input/event6
중간 상/하 키를 클릭해야만 이상한 출력이 인쇄됩니다. sudo cat /dev/input/event5
마우스를 움직이고 휠을 스크롤 하면 이상한 출력이 인쇄됩니다.
[업데이트: 키보드 케이블을 다시 연결하고 분리하여 프로그램을 다시 로드할 수 있도록 지원]
다음은 설명이 필요합니다.
$ 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 &
답변2
특정 프로그램 세트에 대해 작동하는 도구를 찾을 수 있지만 시간 관련 동작은 윈도우 시스템이 아닌 X의 응용 프로그램 내에서 수행되므로 전체적으로 사용할 수 있는 도구는 없습니다.
답변3
Xmodmap을 확인해 보셨나요?
xmodmap은 Xorg에서 키보드 매핑과 포인터 버튼 매핑을 수정하는 유틸리티입니다.