テンキーのキーを再マップして、キーを押している時間によって動作が異なるようにしたいと思います。次に例を示します。
テンキー9キーを300ミリ秒未満押し続けると、「前のタブ」キーコマンドが送信されます。 Ctrl+Tab
テンキー9キーを300〜599ミリ秒間押し続けると、「新しいタブ」キーコマンドが送信されます。 Ctrl+T
テンキーの9キーを600〜899ミリ秒間押し続けると、「タブ/ウィンドウを閉じる」キーコマンドが送信されます Ctrl+W
テンキー9キーを899ミリ秒以上押し続けても、希望の時間枠を逃した場合でも何も起こりません。
WindowsではAutoHotKeyでこれを行うことができ、OS XではControllerMateでこれを行うことができましたが、UNIX/Linuxで、キーの保持時間に基づいてキーを再マッピングできるツールが見つかりません。
私の問題を解決できるツールをご存知の場合は、上で説明した条件付きキー保持期間の動作を示すスクリプトまたはコードサンプルを提供してください。私の例を解決するために完全なコードである必要はありませんが、私の例のためにそれを再利用するのに十分なはずです。
私はこれを[〜#〜] 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とそのコマンド(例:_/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-terminalを開く。
これは、gnomeデスクトップマネージャーのどのウィンドウにも直接適用することはできませんが、それを実装する方法(難しい)についてのアイデアが得られるはずです。仮想コンソール(Ctrl + Alt + N)でも機能し、一部のターミナルエミュレーター(konsole、gnome-terminal、xtermなど)でも機能します。
p/s:私はcプログラマーではないので、このコードが最適化されていない場合はご容赦ください。
[更新]
前の回答はシェルでのみ機能し、フォーカスが必要なので、/ 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) ) {
はテンキー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の起動時にrootとしてこのコマンドを実行します(_/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
_をチェックすると "Permission denied"が表示されますログ。手動で実行しても問題ありません。
デモンストレーション:
テンキー5、インスタントプレス(<= 0.2秒)は無視され、ショートプレス(0.2〜0.5秒)はnautilus
を開き、ミディアムプレス(0.5〜1秒)はvlc
を開きますビデオを再生し、長押し(1〜2秒)開いて_gnome-terminal
_、タイムアウト押し(2秒)開いてgedit
。
ここに完全なコード(1つのファイルのみ)をアップロードしました 。
[再度更新]
[1]複数のキーフローを追加し、_notify-send
_の定義により_DBUS_SESSION_BUS_ADDRESS
_が失敗する問題を修正しました。 [2] _XDG_CURRENT_DESKTOP
_および_GNOME_DESKTOP_SESSION_ID
_を追加して、konsoleがgnomeテーマのGUIを使用できるようにしました(gnomeを使用していない場合は変更してください)。
このコードは組み合わせキーフローを処理しないことに注意してください。 Ctrl+t。
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 &
_
_cat /proc/bus/input/devices | grep -i Razer -A 4
_からeventN抽出を試すことができます。
_$ 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
$
_
上記のこの例では、上記のgrep -P '^(?=.*sysrq)(?=.*leds)'
で使用するパターン「sysrqkbdleds event7」を持つRazerマウスで12桁をクリックすると、_Sudo cat /dev/input/event7
_のみが奇妙な出力を出力します(パターンは異なる場合があります) )。 _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 &
_
特定のプログラムセットで動作するツールを見つけるかもしれませんが、時間関連の動作はウィンドウシステムではなく、Xのアプリケーションで行われるため、グローバルに使用できるツールはありません。
xmodmapを確認しましたか?
xmodmapは、Xorgのキーマップとポインタボタンマッピングを変更するためのユーティリティです。