rkremap 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +90 -0
- data/example/henkan-alt.rb +93 -0
- data/example/keylogger.rb +16 -0
- data/example/mac-shortcut.rb +74 -0
- data/example/tmtms.rb +180 -0
- data/lib/rkremap/keycode.rb +509 -0
- data/lib/rkremap/version.rb +5 -0
- data/lib/rkremap/winattr.rb +95 -0
- data/lib/rkremap.rb +176 -0
- metadata +70 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 945483dcd11240d5c54b359a15055219532f2f311275633503e7d485aa68917b
|
4
|
+
data.tar.gz: d594c9b549696f964cde750094169ba7198c0ac9ab5f5dfc59a7936d9610a09d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a1412a373a0673172a9eba0449613ab9a76debf400b622977887031c294f8381a58a7c060ef6451e6264703690974aeddb305ce35619c07958a2b5a1239ecf12
|
7
|
+
data.tar.gz: 619ee1de0814c2542c2a4f347dca7c48e640590a01ff58f2b7362ed80ef447acaf1576df2a2a659eaac95c9a7ec0a8f52d732d8024356613fbef43f055b16dd2
|
data/README.md
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# Rkremap
|
2
|
+
|
3
|
+
Linux でキー割り当てを変更するプログラムを作るためのライブラリ。
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
```
|
8
|
+
% gem install rkremap
|
9
|
+
```
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
ライブラリなのでプログラムを自分で作る必要がある。具体的な使い方は `example/*.rb` を見ればよい。
|
14
|
+
|
15
|
+
`/dev/input/event*` と `/dev/uinput` に対する権限が必要。`sudo` 等で `root` 権限で動かすのが良いかも。
|
16
|
+
|
17
|
+
ユーザーを `input` グループに所属させると `/dev/input/event*` を読み取る権限をつけられるけど、そのユーザーはすべての入力デバイスの入力を読み取ることができるようになってしまうので、セキュリティ的にはビミョーなところ。
|
18
|
+
|
19
|
+
`input` グループでも `/dev/uinput` に権限はないけど、`/etc/udev/rules.d/input.rules` ファイルを
|
20
|
+
```
|
21
|
+
KERNEL=="uinput", GROUP="input"
|
22
|
+
```
|
23
|
+
という内容で作れば `/dev/uinput` のグループを `input` にできるっぽい。
|
24
|
+
|
25
|
+
|
26
|
+
### `Rkremap.new`
|
27
|
+
|
28
|
+
引数に `/dev/input/event*` を指定する。キーボードデバイス以外を指定してもたぶん無意味。
|
29
|
+
キーボードのデバイスファイル名を調べるには
|
30
|
+
```
|
31
|
+
cat /proc/bus/input/devices
|
32
|
+
```
|
33
|
+
とかすればわかるかもしれない。または
|
34
|
+
```
|
35
|
+
sudo evtest /dev/input/eventX
|
36
|
+
```
|
37
|
+
とかして何かキーを押して出力があればそれ。
|
38
|
+
|
39
|
+
ThinkPad 本体のキーボードは `/dev/input/event3` だった。
|
40
|
+
|
41
|
+
### Rkremap#grab
|
42
|
+
|
43
|
+
`true` に設定するとキーイベントを奪う。キーイベントを見るだけでいいなら `false` を設定する。
|
44
|
+
|
45
|
+
### Rkremap#x11
|
46
|
+
|
47
|
+
`true` に設定すると X のアプリ名等を取得できる。X 環境下でないなら `false` を設定する。
|
48
|
+
|
49
|
+
### Rkremap#start
|
50
|
+
|
51
|
+
なにかキーを押されたらブロックを実行する。修飾キー単体ではブロックは実行されない。
|
52
|
+
ブロックの引数はキーコード(`Integer`)と修飾キー(`Hash`)と `Rkremap::App`。
|
53
|
+
`Rkremap::App#class_name` でアプリのクラス名、`Rkremap::App#title` でアプリのタイトルを取得できる。
|
54
|
+
|
55
|
+
### Rkremap#match
|
56
|
+
|
57
|
+
キーイベントが引数に適合するとブロックを実行する。ブロック引数は Event オブジェクト。
|
58
|
+
`Event#skip` するとこのイベントはスキップされる。
|
59
|
+
|
60
|
+
### Rkremap#key
|
61
|
+
|
62
|
+
キーを押したことにする。引数はキーコード(`Integer`)と修飾キー(`Hash`)。
|
63
|
+
|
64
|
+
### Rkremap#event
|
65
|
+
|
66
|
+
キーイベントを発生させる。`code` 引数はキーコード(`Integer`)。`type` 引数はイベントタイプ(`Symbol`)で `:press`, `:release`。
|
67
|
+
|
68
|
+
### Rkremap#synchronize
|
69
|
+
|
70
|
+
`start` や `match` のブロックは同時に実行されないようにするため Mutex を使用している。このメソッドで同じ Mutex を用いた排他制御を行う。
|
71
|
+
|
72
|
+
### Rkremap::CODE_KEY
|
73
|
+
|
74
|
+
コードからキー名のシンボルに変換するための Hash。
|
75
|
+
|
76
|
+
## 参考
|
77
|
+
|
78
|
+
* [mooz/xkeysnail: Yet another keyboard remapping tool for X environment](https://github.com/mooz/xkeysnail)
|
79
|
+
* [xkeysnail - もうひとつの Linux 向けキーリマッパ - Qiita](https://qiita.com/mooz@github/items/c5f25f27847333dd0b37)
|
80
|
+
* [k0kubun/xremap: Dynamic key remapper for X11 and Wayland](https://github.com/k0kubun/xremap)
|
81
|
+
* [Linux向けの最強のキーリマッパーを作った - k0kubun's blog](https://k0kubun.hatenablog.com/entry/xkremap)
|
82
|
+
* [kui/rbindkeys: key remap with ruby](https://github.com/kui/rbindkeys)
|
83
|
+
* [Ruby で設定できる Linux 環境向けキーリマッパー作った — 電卓片手に](http://k-ui.jp/blog/2012/06/06/rbindkeys-configurable-key-remapper-in-ruby/)
|
84
|
+
* [Linux の入力デバイスをカスタマイズ - Qiita](https://qiita.com/propella/items/a73fc333c95d14d06835)
|
85
|
+
* [Linux Input Subsystemの使い方](http://www.tatapa.org/~takuo/input_subsystem/input_subsystem.html)
|
86
|
+
* [1. Linux Input Subsystem userspace API — The Linux Kernel documentation](https://www.kernel.org/doc/html/v4.12/input/input_uapi.html)
|
87
|
+
|
88
|
+
## License
|
89
|
+
|
90
|
+
MIT license
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# 変換/無変換キーを0.5秒以上押してるとALTキーとして扱う。
|
2
|
+
# 0.5秒以内でも変換/無変換キーを押しながら他のキーを押すとALTキーとして扱う。
|
3
|
+
|
4
|
+
require 'rkremap'
|
5
|
+
include Rkremap::KeyCode
|
6
|
+
|
7
|
+
rk = Rkremap.new('/dev/input/event3')
|
8
|
+
rk.grab = true
|
9
|
+
|
10
|
+
class State
|
11
|
+
attr_accessor :converted
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@press = nil
|
15
|
+
@converted = false
|
16
|
+
@thread = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def press(thread)
|
20
|
+
@press = true
|
21
|
+
@converted = false
|
22
|
+
@thread = thread
|
23
|
+
end
|
24
|
+
|
25
|
+
def release
|
26
|
+
@press = false
|
27
|
+
@converted = false
|
28
|
+
@thread.kill
|
29
|
+
@thread = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def pressed?
|
33
|
+
@press
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
state = {
|
38
|
+
KEY_HENKAN => State.new,
|
39
|
+
KEY_MUHENKAN => State.new,
|
40
|
+
}
|
41
|
+
|
42
|
+
MAP = {
|
43
|
+
KEY_HENKAN => KEY_RIGHTALT,
|
44
|
+
KEY_MUHENKAN => KEY_LEFTALT,
|
45
|
+
}
|
46
|
+
|
47
|
+
rk.match(code: [KEY_HENKAN, KEY_MUHENKAN], type: :press) do |event|
|
48
|
+
thr = Thread.new(event.code) do |code|
|
49
|
+
sleep 0.5
|
50
|
+
rk.synchronize do
|
51
|
+
if state[code].pressed?
|
52
|
+
rk.event(code: MAP[code], type: :press)
|
53
|
+
state[code].converted = true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
state[event.code].press(thr)
|
58
|
+
event.skip
|
59
|
+
end
|
60
|
+
|
61
|
+
rk.match(code: [KEY_HENKAN, KEY_MUHENKAN], type: :release) do |event|
|
62
|
+
if state[event.code].converted
|
63
|
+
rk.event(code: MAP[event.code], type: :release)
|
64
|
+
event.skip
|
65
|
+
else
|
66
|
+
rk.event(code: event.code, type: :press)
|
67
|
+
rk.event(code: event.code, type: :release)
|
68
|
+
end
|
69
|
+
state[event.code].release
|
70
|
+
end
|
71
|
+
|
72
|
+
rk.match(code: [KEY_HENKAN, KEY_MUHENKAN], type: :repeat) do |event|
|
73
|
+
event.skip
|
74
|
+
end
|
75
|
+
|
76
|
+
rk.match(type: :press) do
|
77
|
+
[KEY_HENKAN, KEY_MUHENKAN].each do |code|
|
78
|
+
if state[code].pressed?
|
79
|
+
rk.event(code: MAP[code], type: :press)
|
80
|
+
state[code].converted = true
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def code2key(code)
|
86
|
+
Rkremap::CODE_KEY[code].to_s.sub(/\AKEY_/, '')
|
87
|
+
end
|
88
|
+
|
89
|
+
rk.start do |code, mod|
|
90
|
+
key = (mod.select{|_, v| v}.keys + [code]).map{|c| code2key(c)}.join('-')
|
91
|
+
puts key
|
92
|
+
rk.key(code, mod)
|
93
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# 押されたキーを記録
|
2
|
+
|
3
|
+
require 'rkremap'
|
4
|
+
|
5
|
+
def code2key(code)
|
6
|
+
Rkremap::CODE_KEY[code].to_s.sub(/\AKEY_/, '')
|
7
|
+
end
|
8
|
+
|
9
|
+
rk = Rkremap.new('/dev/input/event3')
|
10
|
+
rk.grab = false
|
11
|
+
rk.x11 = true
|
12
|
+
rk.start do |code, mod, app|
|
13
|
+
key = (mod.select{|_, v| v}.keys + [code]).map{|c| code2key(c)}.join('-')
|
14
|
+
key << " at #{app.title} [#{app.class_name}]" if rk.x11
|
15
|
+
puts key
|
16
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# Mac のショートカット風
|
2
|
+
|
3
|
+
require 'rkremap'
|
4
|
+
|
5
|
+
include Rkremap::KeyCode
|
6
|
+
|
7
|
+
ctrl_map = {
|
8
|
+
KEY_A => KEY_HOME,
|
9
|
+
KEY_E => KEY_END,
|
10
|
+
KEY_B => KEY_LEFT,
|
11
|
+
KEY_F => KEY_RIGHT,
|
12
|
+
KEY_N => KEY_DOWN,
|
13
|
+
KEY_P => KEY_UP,
|
14
|
+
KEY_D => KEY_DELETE,
|
15
|
+
KEY_H => KEY_BACKSPACE,
|
16
|
+
KEY_I => KEY_TAB,
|
17
|
+
}
|
18
|
+
mod_disable_ctrl = {
|
19
|
+
KEY_LEFTCTRL => false,
|
20
|
+
KEY_RIGHTCTRL => false,
|
21
|
+
}
|
22
|
+
mod_disable_shift = {
|
23
|
+
KEY_LEFTSHIFT => false,
|
24
|
+
KEY_RIGHTSHIFT => false,
|
25
|
+
}
|
26
|
+
mod_disable_alt = {
|
27
|
+
KEY_LEFTALT => false,
|
28
|
+
KEY_RIGHTALT => false,
|
29
|
+
}
|
30
|
+
mod_disable_meta = {
|
31
|
+
KEY_LEFTMETA => false,
|
32
|
+
KEY_RIGHTMETA => false,
|
33
|
+
}
|
34
|
+
mod_disable_all = {}.merge(mod_disable_ctrl, mod_disable_shift, mod_disable_alt, mod_disable_meta)
|
35
|
+
|
36
|
+
rk = Rkremap.new("/dev/input/event3")
|
37
|
+
rk.grab = true
|
38
|
+
rk.x11 = true
|
39
|
+
rk.start do |code, mod, app|
|
40
|
+
# Emacs や端末等ではそのまま
|
41
|
+
if app.class_name == 'Emacs' || app.class_name =~ /terminal/i || app.class_name == 'VirtualBox Machine'
|
42
|
+
rk.key(code, mod)
|
43
|
+
next
|
44
|
+
end
|
45
|
+
|
46
|
+
# ALT+[A-Z]/Enter を Ctrl+[A-Z]/Enter に変換
|
47
|
+
if (mod[KEY_LEFTALT] || mod[KEY_RIGHTALT]) && (Rkremap::CODE_KEY[code] =~ /\AKEY_[A-Z]\z/ || code == KEY_ENTER)
|
48
|
+
mod.merge!(mod_disable_alt, {KEY_LEFTCTRL => true})
|
49
|
+
mod[KEY_LEFTCTRL] = true
|
50
|
+
rk.key(code, mod)
|
51
|
+
next
|
52
|
+
end
|
53
|
+
|
54
|
+
# Ctrl は他のキーに変換
|
55
|
+
if mod[KEY_LEFTCTRL] || mod[KEY_RIGHTCTRL]
|
56
|
+
# Ctrl+K は行末まで削除
|
57
|
+
if code == KEY_K
|
58
|
+
rk.key(KEY_END, mod_disable_all.merge({KEY_LEFTSHIFT => true}))
|
59
|
+
rk.key(KEY_X, mod_disable_all.merge({KEY_LEFTCTRL => true}))
|
60
|
+
next
|
61
|
+
end
|
62
|
+
# 単純な変換
|
63
|
+
if ctrl_map[code]
|
64
|
+
rk.key(ctrl_map[code], mod_disable_ctrl)
|
65
|
+
next
|
66
|
+
end
|
67
|
+
# その他の Ctrl+[A-Z] は無視
|
68
|
+
if Rkremap::CODE_KEY[code] =~ /\AKEY_[A-Z]\z/
|
69
|
+
next
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
rk.key(code, mod)
|
74
|
+
end
|
data/example/tmtms.rb
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
# tmtms 用
|
2
|
+
#
|
3
|
+
# fcitx が有効な場合に /tmp/fcitx-enabled ファイルを作るスクリプトを動かしておく:
|
4
|
+
# while :; do
|
5
|
+
# if [ $(fcitx-remote) -eq 2 ]; then
|
6
|
+
# touch /tmp/fcitx-enabled
|
7
|
+
# else
|
8
|
+
# rm -f /tmp/fcitx-enabled
|
9
|
+
# fi
|
10
|
+
# sleep 0.1
|
11
|
+
# done
|
12
|
+
|
13
|
+
require 'rkremap'
|
14
|
+
include Rkremap::KeyCode
|
15
|
+
|
16
|
+
class State
|
17
|
+
attr_accessor :converted
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@press = nil
|
21
|
+
@converted = false
|
22
|
+
@thread = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def press(thread)
|
26
|
+
@press = true
|
27
|
+
@converted = false
|
28
|
+
@thread = thread
|
29
|
+
end
|
30
|
+
|
31
|
+
def release
|
32
|
+
@press = false
|
33
|
+
@converted = false
|
34
|
+
@thread.kill
|
35
|
+
@thread = nil
|
36
|
+
end
|
37
|
+
|
38
|
+
def pressed?
|
39
|
+
@press
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
rk = Rkremap.new("/dev/input/event3")
|
44
|
+
rk.grab = true
|
45
|
+
rk.x11 = true
|
46
|
+
|
47
|
+
# 変換/無変換キーを0.5秒以上押してるとALTキーとして扱う。
|
48
|
+
# 0.5秒以内でも変換/無変換キーを押しながら他のキーを押すとALTキーとして扱う。
|
49
|
+
|
50
|
+
state = {
|
51
|
+
KEY_HENKAN => State.new,
|
52
|
+
KEY_MUHENKAN => State.new,
|
53
|
+
}
|
54
|
+
|
55
|
+
henkan_map = {
|
56
|
+
KEY_HENKAN => KEY_RIGHTALT,
|
57
|
+
KEY_MUHENKAN => KEY_LEFTALT,
|
58
|
+
}
|
59
|
+
|
60
|
+
rk.match(code: [KEY_HENKAN, KEY_MUHENKAN], type: :press) do |event|
|
61
|
+
thr = Thread.new(event.code) do |code|
|
62
|
+
sleep 0.5
|
63
|
+
rk.synchronize do
|
64
|
+
if state[code].pressed?
|
65
|
+
rk.event(code: henkan_map[code], type: :press)
|
66
|
+
state[code].converted = true
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
state[event.code].press(thr)
|
71
|
+
event.skip
|
72
|
+
end
|
73
|
+
|
74
|
+
rk.match(code: [KEY_HENKAN, KEY_MUHENKAN], type: :release) do |event|
|
75
|
+
if state[event.code].converted
|
76
|
+
rk.event(code: henkan_map[event.code], type: :release)
|
77
|
+
event.skip
|
78
|
+
else
|
79
|
+
rk.event(code: event.code, type: :press)
|
80
|
+
rk.event(code: event.code, type: :release)
|
81
|
+
end
|
82
|
+
state[event.code].release
|
83
|
+
end
|
84
|
+
|
85
|
+
rk.match(code: [KEY_HENKAN, KEY_MUHENKAN], type: :repeat) do |event|
|
86
|
+
event.skip
|
87
|
+
end
|
88
|
+
|
89
|
+
rk.match(type: :press) do
|
90
|
+
[KEY_HENKAN, KEY_MUHENKAN].each do |code|
|
91
|
+
if state[code].pressed?
|
92
|
+
rk.event(code: henkan_map[code], type: :press)
|
93
|
+
state[code].converted = true
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# CAPSLOCK は CTRL に変換
|
99
|
+
rk.match(code: KEY_CAPSLOCK) do |event|
|
100
|
+
rk.event(code: KEY_LEFTCTRL, type: event.type)
|
101
|
+
event.skip
|
102
|
+
end
|
103
|
+
|
104
|
+
ctrl_map = {
|
105
|
+
KEY_A => KEY_HOME,
|
106
|
+
KEY_E => KEY_END,
|
107
|
+
KEY_B => KEY_LEFT,
|
108
|
+
KEY_F => KEY_RIGHT,
|
109
|
+
KEY_N => KEY_DOWN,
|
110
|
+
KEY_P => KEY_UP,
|
111
|
+
KEY_D => KEY_DELETE,
|
112
|
+
KEY_H => KEY_BACKSPACE,
|
113
|
+
KEY_I => KEY_TAB,
|
114
|
+
}
|
115
|
+
mod_disable_ctrl = {
|
116
|
+
KEY_LEFTCTRL => false,
|
117
|
+
KEY_RIGHTCTRL => false,
|
118
|
+
}
|
119
|
+
mod_disable_shift = {
|
120
|
+
KEY_LEFTSHIFT => false,
|
121
|
+
KEY_RIGHTSHIFT => false,
|
122
|
+
}
|
123
|
+
mod_disable_alt = {
|
124
|
+
KEY_LEFTALT => false,
|
125
|
+
KEY_RIGHTALT => false,
|
126
|
+
}
|
127
|
+
mod_disable_meta = {
|
128
|
+
KEY_LEFTMETA => false,
|
129
|
+
KEY_RIGHTMETA => false,
|
130
|
+
}
|
131
|
+
mod_disable_all = {}.merge(mod_disable_ctrl, mod_disable_shift, mod_disable_alt, mod_disable_meta)
|
132
|
+
|
133
|
+
key_map = {
|
134
|
+
KEY_YEN => KEY_BACKSLASH,
|
135
|
+
KEY_BACKSLASH => KEY_GRAVE,
|
136
|
+
KEY_GRAVE => KEY_ESC,
|
137
|
+
}
|
138
|
+
|
139
|
+
rk.start do |code, mod, app|
|
140
|
+
# JISキーボードを英語配列にしたときに一部キーを変える
|
141
|
+
code = key_map[code] || code
|
142
|
+
if code == KEY_RO
|
143
|
+
code = mod[KEY_LEFTSHIFT] || mod[KEY_RIGHTSHIFT] ? KEY_MINUS : KEY_BACKSLASH
|
144
|
+
end
|
145
|
+
|
146
|
+
# Emacs や端末等ではそのまま
|
147
|
+
if app.class_name == 'Emacs' || app.class_name =~ /terminal/i || app.class_name == 'VirtualBox Machine'
|
148
|
+
rk.key(code, mod)
|
149
|
+
next
|
150
|
+
end
|
151
|
+
|
152
|
+
# ALT+[A-Z]/Enter を Ctrl+[A-Z]/Enter に変換
|
153
|
+
if (mod[KEY_LEFTALT] || mod[KEY_RIGHTALT]) && (Rkremap::CODE_KEY[code] =~ /\AKEY_[A-Z]\z/ || code == KEY_ENTER)
|
154
|
+
mod.merge!(mod_disable_alt, {KEY_LEFTCTRL => true})
|
155
|
+
mod[KEY_LEFTCTRL] = true
|
156
|
+
rk.key(code, mod)
|
157
|
+
next
|
158
|
+
end
|
159
|
+
|
160
|
+
# Ctrl は他のキーに変換
|
161
|
+
if mod[KEY_LEFTCTRL] || mod[KEY_RIGHTCTRL]
|
162
|
+
# Ctrl+K は行末まで削除 (日本語変換時はそのまま)
|
163
|
+
if code == KEY_K && !File.exist?('/tmp/fcitx-enabled')
|
164
|
+
rk.key(KEY_END, mod_disable_all.merge({KEY_LEFTSHIFT => true}))
|
165
|
+
rk.key(KEY_X, mod_disable_all.merge({KEY_LEFTCTRL => true}))
|
166
|
+
next
|
167
|
+
end
|
168
|
+
# 単純な変換
|
169
|
+
if ctrl_map[code]
|
170
|
+
rk.key(ctrl_map[code], mod_disable_ctrl)
|
171
|
+
next
|
172
|
+
end
|
173
|
+
# その他の Ctrl+[A-Z] は無視
|
174
|
+
if Rkremap::CODE_KEY[code] =~ /\AKEY_[A-Z]\z/
|
175
|
+
next
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
rk.key(code, mod)
|
180
|
+
end
|
@@ -0,0 +1,509 @@
|
|
1
|
+
class Rkremap
|
2
|
+
module KeyCode
|
3
|
+
# generated from /usr/include/linux/input-event-codes.h
|
4
|
+
KEY_RESERVED = 0
|
5
|
+
KEY_ESC = 1
|
6
|
+
KEY_1 = 2
|
7
|
+
KEY_2 = 3
|
8
|
+
KEY_3 = 4
|
9
|
+
KEY_4 = 5
|
10
|
+
KEY_5 = 6
|
11
|
+
KEY_6 = 7
|
12
|
+
KEY_7 = 8
|
13
|
+
KEY_8 = 9
|
14
|
+
KEY_9 = 10
|
15
|
+
KEY_0 = 11
|
16
|
+
KEY_MINUS = 12
|
17
|
+
KEY_EQUAL = 13
|
18
|
+
KEY_BACKSPACE = 14
|
19
|
+
KEY_TAB = 15
|
20
|
+
KEY_Q = 16
|
21
|
+
KEY_W = 17
|
22
|
+
KEY_E = 18
|
23
|
+
KEY_R = 19
|
24
|
+
KEY_T = 20
|
25
|
+
KEY_Y = 21
|
26
|
+
KEY_U = 22
|
27
|
+
KEY_I = 23
|
28
|
+
KEY_O = 24
|
29
|
+
KEY_P = 25
|
30
|
+
KEY_LEFTBRACE = 26
|
31
|
+
KEY_RIGHTBRACE = 27
|
32
|
+
KEY_ENTER = 28
|
33
|
+
KEY_LEFTCTRL = 29
|
34
|
+
KEY_A = 30
|
35
|
+
KEY_S = 31
|
36
|
+
KEY_D = 32
|
37
|
+
KEY_F = 33
|
38
|
+
KEY_G = 34
|
39
|
+
KEY_H = 35
|
40
|
+
KEY_J = 36
|
41
|
+
KEY_K = 37
|
42
|
+
KEY_L = 38
|
43
|
+
KEY_SEMICOLON = 39
|
44
|
+
KEY_APOSTROPHE = 40
|
45
|
+
KEY_GRAVE = 41
|
46
|
+
KEY_LEFTSHIFT = 42
|
47
|
+
KEY_BACKSLASH = 43
|
48
|
+
KEY_Z = 44
|
49
|
+
KEY_X = 45
|
50
|
+
KEY_C = 46
|
51
|
+
KEY_V = 47
|
52
|
+
KEY_B = 48
|
53
|
+
KEY_N = 49
|
54
|
+
KEY_M = 50
|
55
|
+
KEY_COMMA = 51
|
56
|
+
KEY_DOT = 52
|
57
|
+
KEY_SLASH = 53
|
58
|
+
KEY_RIGHTSHIFT = 54
|
59
|
+
KEY_KPASTERISK = 55
|
60
|
+
KEY_LEFTALT = 56
|
61
|
+
KEY_SPACE = 57
|
62
|
+
KEY_CAPSLOCK = 58
|
63
|
+
KEY_F1 = 59
|
64
|
+
KEY_F2 = 60
|
65
|
+
KEY_F3 = 61
|
66
|
+
KEY_F4 = 62
|
67
|
+
KEY_F5 = 63
|
68
|
+
KEY_F6 = 64
|
69
|
+
KEY_F7 = 65
|
70
|
+
KEY_F8 = 66
|
71
|
+
KEY_F9 = 67
|
72
|
+
KEY_F10 = 68
|
73
|
+
KEY_NUMLOCK = 69
|
74
|
+
KEY_SCROLLLOCK = 70
|
75
|
+
KEY_KP7 = 71
|
76
|
+
KEY_KP8 = 72
|
77
|
+
KEY_KP9 = 73
|
78
|
+
KEY_KPMINUS = 74
|
79
|
+
KEY_KP4 = 75
|
80
|
+
KEY_KP5 = 76
|
81
|
+
KEY_KP6 = 77
|
82
|
+
KEY_KPPLUS = 78
|
83
|
+
KEY_KP1 = 79
|
84
|
+
KEY_KP2 = 80
|
85
|
+
KEY_KP3 = 81
|
86
|
+
KEY_KP0 = 82
|
87
|
+
KEY_KPDOT = 83
|
88
|
+
KEY_ZENKAKUHANKAKU = 85
|
89
|
+
KEY_102ND = 86
|
90
|
+
KEY_F11 = 87
|
91
|
+
KEY_F12 = 88
|
92
|
+
KEY_RO = 89
|
93
|
+
KEY_KATAKANA = 90
|
94
|
+
KEY_HIRAGANA = 91
|
95
|
+
KEY_HENKAN = 92
|
96
|
+
KEY_KATAKANAHIRAGANA = 93
|
97
|
+
KEY_MUHENKAN = 94
|
98
|
+
KEY_KPJPCOMMA = 95
|
99
|
+
KEY_KPENTER = 96
|
100
|
+
KEY_RIGHTCTRL = 97
|
101
|
+
KEY_KPSLASH = 98
|
102
|
+
KEY_SYSRQ = 99
|
103
|
+
KEY_RIGHTALT = 100
|
104
|
+
KEY_LINEFEED = 101
|
105
|
+
KEY_HOME = 102
|
106
|
+
KEY_UP = 103
|
107
|
+
KEY_PAGEUP = 104
|
108
|
+
KEY_LEFT = 105
|
109
|
+
KEY_RIGHT = 106
|
110
|
+
KEY_END = 107
|
111
|
+
KEY_DOWN = 108
|
112
|
+
KEY_PAGEDOWN = 109
|
113
|
+
KEY_INSERT = 110
|
114
|
+
KEY_DELETE = 111
|
115
|
+
KEY_MACRO = 112
|
116
|
+
KEY_MUTE = 113
|
117
|
+
KEY_VOLUMEDOWN = 114
|
118
|
+
KEY_VOLUMEUP = 115
|
119
|
+
KEY_POWER = 116 # SC System Power Down
|
120
|
+
KEY_KPEQUAL = 117
|
121
|
+
KEY_KPPLUSMINUS = 118
|
122
|
+
KEY_PAUSE = 119
|
123
|
+
KEY_SCALE = 120 # AL Compiz Scale (Expose)
|
124
|
+
KEY_KPCOMMA = 121
|
125
|
+
KEY_HANGEUL = 122
|
126
|
+
KEY_HANGUEL = KEY_HANGEUL
|
127
|
+
KEY_HANJA = 123
|
128
|
+
KEY_YEN = 124
|
129
|
+
KEY_LEFTMETA = 125
|
130
|
+
KEY_RIGHTMETA = 126
|
131
|
+
KEY_COMPOSE = 127
|
132
|
+
KEY_STOP = 128 # AC Stop
|
133
|
+
KEY_AGAIN = 129
|
134
|
+
KEY_PROPS = 130 # AC Properties
|
135
|
+
KEY_UNDO = 131 # AC Undo
|
136
|
+
KEY_FRONT = 132
|
137
|
+
KEY_COPY = 133 # AC Copy
|
138
|
+
KEY_OPEN = 134 # AC Open
|
139
|
+
KEY_PASTE = 135 # AC Paste
|
140
|
+
KEY_FIND = 136 # AC Search
|
141
|
+
KEY_CUT = 137 # AC Cut
|
142
|
+
KEY_HELP = 138 # AL Integrated Help Center
|
143
|
+
KEY_MENU = 139 # Menu (show menu)
|
144
|
+
KEY_CALC = 140 # AL Calculator
|
145
|
+
KEY_SETUP = 141
|
146
|
+
KEY_SLEEP = 142 # SC System Sleep
|
147
|
+
KEY_WAKEUP = 143 # System Wake Up
|
148
|
+
KEY_FILE = 144 # AL Local Machine Browser
|
149
|
+
KEY_SENDFILE = 145
|
150
|
+
KEY_DELETEFILE = 146
|
151
|
+
KEY_XFER = 147
|
152
|
+
KEY_PROG1 = 148
|
153
|
+
KEY_PROG2 = 149
|
154
|
+
KEY_WWW = 150 # AL Internet Browser
|
155
|
+
KEY_MSDOS = 151
|
156
|
+
KEY_COFFEE = 152 # AL Terminal Lock/Screensaver
|
157
|
+
KEY_SCREENLOCK = KEY_COFFEE
|
158
|
+
KEY_ROTATE_DISPLAY = 153 # Display orientation for e.g. tablets
|
159
|
+
KEY_DIRECTION = KEY_ROTATE_DISPLAY
|
160
|
+
KEY_CYCLEWINDOWS = 154
|
161
|
+
KEY_MAIL = 155
|
162
|
+
KEY_BOOKMARKS = 156 # AC Bookmarks
|
163
|
+
KEY_COMPUTER = 157
|
164
|
+
KEY_BACK = 158 # AC Back
|
165
|
+
KEY_FORWARD = 159 # AC Forward
|
166
|
+
KEY_CLOSECD = 160
|
167
|
+
KEY_EJECTCD = 161
|
168
|
+
KEY_EJECTCLOSECD = 162
|
169
|
+
KEY_NEXTSONG = 163
|
170
|
+
KEY_PLAYPAUSE = 164
|
171
|
+
KEY_PREVIOUSSONG = 165
|
172
|
+
KEY_STOPCD = 166
|
173
|
+
KEY_RECORD = 167
|
174
|
+
KEY_REWIND = 168
|
175
|
+
KEY_PHONE = 169 # Media Select Telephone
|
176
|
+
KEY_ISO = 170
|
177
|
+
KEY_CONFIG = 171 # AL Consumer Control Configuration
|
178
|
+
KEY_HOMEPAGE = 172 # AC Home
|
179
|
+
KEY_REFRESH = 173 # AC Refresh
|
180
|
+
KEY_EXIT = 174 # AC Exit
|
181
|
+
KEY_MOVE = 175
|
182
|
+
KEY_EDIT = 176
|
183
|
+
KEY_SCROLLUP = 177
|
184
|
+
KEY_SCROLLDOWN = 178
|
185
|
+
KEY_KPLEFTPAREN = 179
|
186
|
+
KEY_KPRIGHTPAREN = 180
|
187
|
+
KEY_NEW = 181 # AC New
|
188
|
+
KEY_REDO = 182 # AC Redo/Repeat
|
189
|
+
KEY_F13 = 183
|
190
|
+
KEY_F14 = 184
|
191
|
+
KEY_F15 = 185
|
192
|
+
KEY_F16 = 186
|
193
|
+
KEY_F17 = 187
|
194
|
+
KEY_F18 = 188
|
195
|
+
KEY_F19 = 189
|
196
|
+
KEY_F20 = 190
|
197
|
+
KEY_F21 = 191
|
198
|
+
KEY_F22 = 192
|
199
|
+
KEY_F23 = 193
|
200
|
+
KEY_F24 = 194
|
201
|
+
KEY_PLAYCD = 200
|
202
|
+
KEY_PAUSECD = 201
|
203
|
+
KEY_PROG3 = 202
|
204
|
+
KEY_PROG4 = 203
|
205
|
+
KEY_DASHBOARD = 204 # AL Dashboard
|
206
|
+
KEY_SUSPEND = 205
|
207
|
+
KEY_CLOSE = 206 # AC Close
|
208
|
+
KEY_PLAY = 207
|
209
|
+
KEY_FASTFORWARD = 208
|
210
|
+
KEY_BASSBOOST = 209
|
211
|
+
KEY_PRINT = 210 # AC Print
|
212
|
+
KEY_HP = 211
|
213
|
+
KEY_CAMERA = 212
|
214
|
+
KEY_SOUND = 213
|
215
|
+
KEY_QUESTION = 214
|
216
|
+
KEY_EMAIL = 215
|
217
|
+
KEY_CHAT = 216
|
218
|
+
KEY_SEARCH = 217
|
219
|
+
KEY_CONNECT = 218
|
220
|
+
KEY_FINANCE = 219 # AL Checkbook/Finance
|
221
|
+
KEY_SPORT = 220
|
222
|
+
KEY_SHOP = 221
|
223
|
+
KEY_ALTERASE = 222
|
224
|
+
KEY_CANCEL = 223 # AC Cancel
|
225
|
+
KEY_BRIGHTNESSDOWN = 224
|
226
|
+
KEY_BRIGHTNESSUP = 225
|
227
|
+
KEY_MEDIA = 226
|
228
|
+
KEY_SWITCHVIDEOMODE = 227 # Cycle between available video
|
229
|
+
KEY_KBDILLUMTOGGLE = 228
|
230
|
+
KEY_KBDILLUMDOWN = 229
|
231
|
+
KEY_KBDILLUMUP = 230
|
232
|
+
KEY_SEND = 231 # AC Send
|
233
|
+
KEY_REPLY = 232 # AC Reply
|
234
|
+
KEY_FORWARDMAIL = 233 # AC Forward Msg
|
235
|
+
KEY_SAVE = 234 # AC Save
|
236
|
+
KEY_DOCUMENTS = 235
|
237
|
+
KEY_BATTERY = 236
|
238
|
+
KEY_BLUETOOTH = 237
|
239
|
+
KEY_WLAN = 238
|
240
|
+
KEY_UWB = 239
|
241
|
+
KEY_UNKNOWN = 240
|
242
|
+
KEY_VIDEO_NEXT = 241 # drive next video source
|
243
|
+
KEY_VIDEO_PREV = 242 # drive previous video source
|
244
|
+
KEY_BRIGHTNESS_CYCLE = 243 # brightness up, after max is min
|
245
|
+
KEY_BRIGHTNESS_AUTO = 244 # Set Auto Brightness: manual
|
246
|
+
KEY_BRIGHTNESS_ZERO = KEY_BRIGHTNESS_AUTO
|
247
|
+
KEY_DISPLAY_OFF = 245 # display device to off state
|
248
|
+
KEY_WWAN = 246 # Wireless WAN (LTE, UMTS, GSM, etc.)
|
249
|
+
KEY_WIMAX = KEY_WWAN
|
250
|
+
KEY_RFKILL = 247 # Key that controls all radios
|
251
|
+
KEY_MICMUTE = 248 # Mute / unmute the microphone
|
252
|
+
KEY_OK = 0x160
|
253
|
+
KEY_SELECT = 0x161
|
254
|
+
KEY_GOTO = 0x162
|
255
|
+
KEY_CLEAR = 0x163
|
256
|
+
KEY_POWER2 = 0x164
|
257
|
+
KEY_OPTION = 0x165
|
258
|
+
KEY_INFO = 0x166 # AL OEM Features/Tips/Tutorial
|
259
|
+
KEY_TIME = 0x167
|
260
|
+
KEY_VENDOR = 0x168
|
261
|
+
KEY_ARCHIVE = 0x169
|
262
|
+
KEY_PROGRAM = 0x16a # Media Select Program Guide
|
263
|
+
KEY_CHANNEL = 0x16b
|
264
|
+
KEY_FAVORITES = 0x16c
|
265
|
+
KEY_EPG = 0x16d
|
266
|
+
KEY_PVR = 0x16e # Media Select Home
|
267
|
+
KEY_MHP = 0x16f
|
268
|
+
KEY_LANGUAGE = 0x170
|
269
|
+
KEY_TITLE = 0x171
|
270
|
+
KEY_SUBTITLE = 0x172
|
271
|
+
KEY_ANGLE = 0x173
|
272
|
+
KEY_FULL_SCREEN = 0x174 # AC View Toggle
|
273
|
+
KEY_ZOOM = KEY_FULL_SCREEN
|
274
|
+
KEY_MODE = 0x175
|
275
|
+
KEY_KEYBOARD = 0x176
|
276
|
+
KEY_ASPECT_RATIO = 0x177 # HUTRR37: Aspect
|
277
|
+
KEY_SCREEN = KEY_ASPECT_RATIO
|
278
|
+
KEY_PC = 0x178 # Media Select Computer
|
279
|
+
KEY_TV = 0x179 # Media Select TV
|
280
|
+
KEY_TV2 = 0x17a # Media Select Cable
|
281
|
+
KEY_VCR = 0x17b # Media Select VCR
|
282
|
+
KEY_VCR2 = 0x17c # VCR Plus
|
283
|
+
KEY_SAT = 0x17d # Media Select Satellite
|
284
|
+
KEY_SAT2 = 0x17e
|
285
|
+
KEY_CD = 0x17f # Media Select CD
|
286
|
+
KEY_TAPE = 0x180 # Media Select Tape
|
287
|
+
KEY_RADIO = 0x181
|
288
|
+
KEY_TUNER = 0x182 # Media Select Tuner
|
289
|
+
KEY_PLAYER = 0x183
|
290
|
+
KEY_TEXT = 0x184
|
291
|
+
KEY_DVD = 0x185 # Media Select DVD
|
292
|
+
KEY_AUX = 0x186
|
293
|
+
KEY_MP3 = 0x187
|
294
|
+
KEY_AUDIO = 0x188 # AL Audio Browser
|
295
|
+
KEY_VIDEO = 0x189 # AL Movie Browser
|
296
|
+
KEY_DIRECTORY = 0x18a
|
297
|
+
KEY_LIST = 0x18b
|
298
|
+
KEY_MEMO = 0x18c # Media Select Messages
|
299
|
+
KEY_CALENDAR = 0x18d
|
300
|
+
KEY_RED = 0x18e
|
301
|
+
KEY_GREEN = 0x18f
|
302
|
+
KEY_YELLOW = 0x190
|
303
|
+
KEY_BLUE = 0x191
|
304
|
+
KEY_CHANNELUP = 0x192 # Channel Increment
|
305
|
+
KEY_CHANNELDOWN = 0x193 # Channel Decrement
|
306
|
+
KEY_FIRST = 0x194
|
307
|
+
KEY_LAST = 0x195 # Recall Last
|
308
|
+
KEY_AB = 0x196
|
309
|
+
KEY_NEXT = 0x197
|
310
|
+
KEY_RESTART = 0x198
|
311
|
+
KEY_SLOW = 0x199
|
312
|
+
KEY_SHUFFLE = 0x19a
|
313
|
+
KEY_BREAK = 0x19b
|
314
|
+
KEY_PREVIOUS = 0x19c
|
315
|
+
KEY_DIGITS = 0x19d
|
316
|
+
KEY_TEEN = 0x19e
|
317
|
+
KEY_TWEN = 0x19f
|
318
|
+
KEY_VIDEOPHONE = 0x1a0 # Media Select Video Phone
|
319
|
+
KEY_GAMES = 0x1a1 # Media Select Games
|
320
|
+
KEY_ZOOMIN = 0x1a2 # AC Zoom In
|
321
|
+
KEY_ZOOMOUT = 0x1a3 # AC Zoom Out
|
322
|
+
KEY_ZOOMRESET = 0x1a4 # AC Zoom
|
323
|
+
KEY_WORDPROCESSOR = 0x1a5 # AL Word Processor
|
324
|
+
KEY_EDITOR = 0x1a6 # AL Text Editor
|
325
|
+
KEY_SPREADSHEET = 0x1a7 # AL Spreadsheet
|
326
|
+
KEY_GRAPHICSEDITOR = 0x1a8 # AL Graphics Editor
|
327
|
+
KEY_PRESENTATION = 0x1a9 # AL Presentation App
|
328
|
+
KEY_DATABASE = 0x1aa # AL Database App
|
329
|
+
KEY_NEWS = 0x1ab # AL Newsreader
|
330
|
+
KEY_VOICEMAIL = 0x1ac # AL Voicemail
|
331
|
+
KEY_ADDRESSBOOK = 0x1ad # AL Contacts/Address Book
|
332
|
+
KEY_MESSENGER = 0x1ae # AL Instant Messaging
|
333
|
+
KEY_DISPLAYTOGGLE = 0x1af # Turn display (LCD) on and off
|
334
|
+
KEY_BRIGHTNESS_TOGGLE = KEY_DISPLAYTOGGLE
|
335
|
+
KEY_SPELLCHECK = 0x1b0 # AL Spell Check
|
336
|
+
KEY_LOGOFF = 0x1b1 # AL Logoff
|
337
|
+
KEY_DOLLAR = 0x1b2
|
338
|
+
KEY_EURO = 0x1b3
|
339
|
+
KEY_FRAMEBACK = 0x1b4 # Consumer - transport controls
|
340
|
+
KEY_FRAMEFORWARD = 0x1b5
|
341
|
+
KEY_CONTEXT_MENU = 0x1b6 # GenDesc - system context menu
|
342
|
+
KEY_MEDIA_REPEAT = 0x1b7 # Consumer - transport control
|
343
|
+
KEY_10CHANNELSUP = 0x1b8 # 10 channels up (10+)
|
344
|
+
KEY_10CHANNELSDOWN = 0x1b9 # 10 channels down (10-)
|
345
|
+
KEY_IMAGES = 0x1ba # AL Image Browser
|
346
|
+
KEY_NOTIFICATION_CENTER = 0x1bc # Show/hide the notification center
|
347
|
+
KEY_PICKUP_PHONE = 0x1bd # Answer incoming call
|
348
|
+
KEY_HANGUP_PHONE = 0x1be # Decline incoming call
|
349
|
+
KEY_DEL_EOL = 0x1c0
|
350
|
+
KEY_DEL_EOS = 0x1c1
|
351
|
+
KEY_INS_LINE = 0x1c2
|
352
|
+
KEY_DEL_LINE = 0x1c3
|
353
|
+
KEY_FN = 0x1d0
|
354
|
+
KEY_FN_ESC = 0x1d1
|
355
|
+
KEY_FN_F1 = 0x1d2
|
356
|
+
KEY_FN_F2 = 0x1d3
|
357
|
+
KEY_FN_F3 = 0x1d4
|
358
|
+
KEY_FN_F4 = 0x1d5
|
359
|
+
KEY_FN_F5 = 0x1d6
|
360
|
+
KEY_FN_F6 = 0x1d7
|
361
|
+
KEY_FN_F7 = 0x1d8
|
362
|
+
KEY_FN_F8 = 0x1d9
|
363
|
+
KEY_FN_F9 = 0x1da
|
364
|
+
KEY_FN_F10 = 0x1db
|
365
|
+
KEY_FN_F11 = 0x1dc
|
366
|
+
KEY_FN_F12 = 0x1dd
|
367
|
+
KEY_FN_1 = 0x1de
|
368
|
+
KEY_FN_2 = 0x1df
|
369
|
+
KEY_FN_D = 0x1e0
|
370
|
+
KEY_FN_E = 0x1e1
|
371
|
+
KEY_FN_F = 0x1e2
|
372
|
+
KEY_FN_S = 0x1e3
|
373
|
+
KEY_FN_B = 0x1e4
|
374
|
+
KEY_FN_RIGHT_SHIFT = 0x1e5
|
375
|
+
KEY_BRL_DOT1 = 0x1f1
|
376
|
+
KEY_BRL_DOT2 = 0x1f2
|
377
|
+
KEY_BRL_DOT3 = 0x1f3
|
378
|
+
KEY_BRL_DOT4 = 0x1f4
|
379
|
+
KEY_BRL_DOT5 = 0x1f5
|
380
|
+
KEY_BRL_DOT6 = 0x1f6
|
381
|
+
KEY_BRL_DOT7 = 0x1f7
|
382
|
+
KEY_BRL_DOT8 = 0x1f8
|
383
|
+
KEY_BRL_DOT9 = 0x1f9
|
384
|
+
KEY_BRL_DOT10 = 0x1fa
|
385
|
+
KEY_NUMERIC_0 = 0x200 # used by phones, remote controls,
|
386
|
+
KEY_NUMERIC_1 = 0x201 # and other keypads
|
387
|
+
KEY_NUMERIC_2 = 0x202
|
388
|
+
KEY_NUMERIC_3 = 0x203
|
389
|
+
KEY_NUMERIC_4 = 0x204
|
390
|
+
KEY_NUMERIC_5 = 0x205
|
391
|
+
KEY_NUMERIC_6 = 0x206
|
392
|
+
KEY_NUMERIC_7 = 0x207
|
393
|
+
KEY_NUMERIC_8 = 0x208
|
394
|
+
KEY_NUMERIC_9 = 0x209
|
395
|
+
KEY_NUMERIC_STAR = 0x20a
|
396
|
+
KEY_NUMERIC_POUND = 0x20b
|
397
|
+
KEY_NUMERIC_A = 0x20c # Phone key A - HUT Telephony 0xb9
|
398
|
+
KEY_NUMERIC_B = 0x20d
|
399
|
+
KEY_NUMERIC_C = 0x20e
|
400
|
+
KEY_NUMERIC_D = 0x20f
|
401
|
+
KEY_CAMERA_FOCUS = 0x210
|
402
|
+
KEY_WPS_BUTTON = 0x211 # WiFi Protected Setup key
|
403
|
+
KEY_TOUCHPAD_TOGGLE = 0x212 # Request switch touchpad on or off
|
404
|
+
KEY_TOUCHPAD_ON = 0x213
|
405
|
+
KEY_TOUCHPAD_OFF = 0x214
|
406
|
+
KEY_CAMERA_ZOOMIN = 0x215
|
407
|
+
KEY_CAMERA_ZOOMOUT = 0x216
|
408
|
+
KEY_CAMERA_UP = 0x217
|
409
|
+
KEY_CAMERA_DOWN = 0x218
|
410
|
+
KEY_CAMERA_LEFT = 0x219
|
411
|
+
KEY_CAMERA_RIGHT = 0x21a
|
412
|
+
KEY_ATTENDANT_ON = 0x21b
|
413
|
+
KEY_ATTENDANT_OFF = 0x21c
|
414
|
+
KEY_ATTENDANT_TOGGLE = 0x21d # Attendant call on or off
|
415
|
+
KEY_LIGHTS_TOGGLE = 0x21e # Reading light on or off
|
416
|
+
KEY_ALS_TOGGLE = 0x230 # Ambient light sensor
|
417
|
+
KEY_ROTATE_LOCK_TOGGLE = 0x231 # Display rotation lock
|
418
|
+
KEY_BUTTONCONFIG = 0x240 # AL Button Configuration
|
419
|
+
KEY_TASKMANAGER = 0x241 # AL Task/Project Manager
|
420
|
+
KEY_JOURNAL = 0x242 # AL Log/Journal/Timecard
|
421
|
+
KEY_CONTROLPANEL = 0x243 # AL Control Panel
|
422
|
+
KEY_APPSELECT = 0x244 # AL Select Task/Application
|
423
|
+
KEY_SCREENSAVER = 0x245 # AL Screen Saver
|
424
|
+
KEY_VOICECOMMAND = 0x246 # Listening Voice Command
|
425
|
+
KEY_ASSISTANT = 0x247 # AL Context-aware desktop assistant
|
426
|
+
KEY_KBD_LAYOUT_NEXT = 0x248 # AC Next Keyboard Layout Select
|
427
|
+
KEY_EMOJI_PICKER = 0x249 # Show/hide emoji picker (HUTRR101)
|
428
|
+
KEY_BRIGHTNESS_MIN = 0x250 # Set Brightness to Minimum
|
429
|
+
KEY_BRIGHTNESS_MAX = 0x251 # Set Brightness to Maximum
|
430
|
+
KEY_KBDINPUTASSIST_PREV = 0x260
|
431
|
+
KEY_KBDINPUTASSIST_NEXT = 0x261
|
432
|
+
KEY_KBDINPUTASSIST_PREVGROUP = 0x262
|
433
|
+
KEY_KBDINPUTASSIST_NEXTGROUP = 0x263
|
434
|
+
KEY_KBDINPUTASSIST_ACCEPT = 0x264
|
435
|
+
KEY_KBDINPUTASSIST_CANCEL = 0x265
|
436
|
+
KEY_RIGHT_UP = 0x266
|
437
|
+
KEY_RIGHT_DOWN = 0x267
|
438
|
+
KEY_LEFT_UP = 0x268
|
439
|
+
KEY_LEFT_DOWN = 0x269
|
440
|
+
KEY_ROOT_MENU = 0x26a # Show Device's Root Menu
|
441
|
+
KEY_MEDIA_TOP_MENU = 0x26b
|
442
|
+
KEY_NUMERIC_11 = 0x26c
|
443
|
+
KEY_NUMERIC_12 = 0x26d
|
444
|
+
KEY_AUDIO_DESC = 0x26e
|
445
|
+
KEY_3D_MODE = 0x26f
|
446
|
+
KEY_NEXT_FAVORITE = 0x270
|
447
|
+
KEY_STOP_RECORD = 0x271
|
448
|
+
KEY_PAUSE_RECORD = 0x272
|
449
|
+
KEY_VOD = 0x273 # Video on Demand
|
450
|
+
KEY_UNMUTE = 0x274
|
451
|
+
KEY_FASTREVERSE = 0x275
|
452
|
+
KEY_SLOWREVERSE = 0x276
|
453
|
+
KEY_DATA = 0x277
|
454
|
+
KEY_ONSCREEN_KEYBOARD = 0x278
|
455
|
+
KEY_PRIVACY_SCREEN_TOGGLE = 0x279
|
456
|
+
KEY_SELECTIVE_SCREENSHOT = 0x27a
|
457
|
+
KEY_MACRO1 = 0x290
|
458
|
+
KEY_MACRO2 = 0x291
|
459
|
+
KEY_MACRO3 = 0x292
|
460
|
+
KEY_MACRO4 = 0x293
|
461
|
+
KEY_MACRO5 = 0x294
|
462
|
+
KEY_MACRO6 = 0x295
|
463
|
+
KEY_MACRO7 = 0x296
|
464
|
+
KEY_MACRO8 = 0x297
|
465
|
+
KEY_MACRO9 = 0x298
|
466
|
+
KEY_MACRO10 = 0x299
|
467
|
+
KEY_MACRO11 = 0x29a
|
468
|
+
KEY_MACRO12 = 0x29b
|
469
|
+
KEY_MACRO13 = 0x29c
|
470
|
+
KEY_MACRO14 = 0x29d
|
471
|
+
KEY_MACRO15 = 0x29e
|
472
|
+
KEY_MACRO16 = 0x29f
|
473
|
+
KEY_MACRO17 = 0x2a0
|
474
|
+
KEY_MACRO18 = 0x2a1
|
475
|
+
KEY_MACRO19 = 0x2a2
|
476
|
+
KEY_MACRO20 = 0x2a3
|
477
|
+
KEY_MACRO21 = 0x2a4
|
478
|
+
KEY_MACRO22 = 0x2a5
|
479
|
+
KEY_MACRO23 = 0x2a6
|
480
|
+
KEY_MACRO24 = 0x2a7
|
481
|
+
KEY_MACRO25 = 0x2a8
|
482
|
+
KEY_MACRO26 = 0x2a9
|
483
|
+
KEY_MACRO27 = 0x2aa
|
484
|
+
KEY_MACRO28 = 0x2ab
|
485
|
+
KEY_MACRO29 = 0x2ac
|
486
|
+
KEY_MACRO30 = 0x2ad
|
487
|
+
KEY_MACRO_RECORD_START = 0x2b0
|
488
|
+
KEY_MACRO_RECORD_STOP = 0x2b1
|
489
|
+
KEY_MACRO_PRESET_CYCLE = 0x2b2
|
490
|
+
KEY_MACRO_PRESET1 = 0x2b3
|
491
|
+
KEY_MACRO_PRESET2 = 0x2b4
|
492
|
+
KEY_MACRO_PRESET3 = 0x2b5
|
493
|
+
KEY_KBD_LCD_MENU1 = 0x2b8
|
494
|
+
KEY_KBD_LCD_MENU2 = 0x2b9
|
495
|
+
KEY_KBD_LCD_MENU3 = 0x2ba
|
496
|
+
KEY_KBD_LCD_MENU4 = 0x2bb
|
497
|
+
KEY_KBD_LCD_MENU5 = 0x2bc
|
498
|
+
KEY_MIN_INTERESTING = KEY_MUTE
|
499
|
+
KEY_MAX = 0x2ff
|
500
|
+
KEY_CNT = (KEY_MAX+1)
|
501
|
+
end
|
502
|
+
|
503
|
+
CODE_KEY = {}
|
504
|
+
KeyCode.constants.each do |k|
|
505
|
+
next unless k =~ /\AKEY_/
|
506
|
+
code = KeyCode.const_get(k)
|
507
|
+
CODE_KEY[code] = k unless CODE_KEY[code]
|
508
|
+
end
|
509
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module FFI
|
4
|
+
typedef :pointer, :Display
|
5
|
+
typedef :ulong, :XID
|
6
|
+
typedef :XID, :Window
|
7
|
+
typedef :int, :Status
|
8
|
+
typedef :ulong, :Atom
|
9
|
+
end
|
10
|
+
|
11
|
+
class Rkremap
|
12
|
+
# アプリの name, class, title を取得する
|
13
|
+
class WinAttr
|
14
|
+
def initialize
|
15
|
+
@app_win = {}
|
16
|
+
@display = X11.XOpenDisplay(nil) or raise "Cannot open display: #{ENV['DISPLAY']}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def focus_win
|
20
|
+
win = FFI::MemoryPointer.new(:Window)
|
21
|
+
revert_to = FFI::MemoryPointer.new(:int)
|
22
|
+
X11.XGetInputFocus(@display, win, revert_to)
|
23
|
+
win.read(:Window)
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [Array<window, name, class>]
|
27
|
+
def app_win(window)
|
28
|
+
return @app_win[window] if @app_win[window]
|
29
|
+
class_hint = XClassHint.new
|
30
|
+
root = FFI::MemoryPointer.new(:Window)
|
31
|
+
parent = FFI::MemoryPointer.new(:Window)
|
32
|
+
children = FFI::MemoryPointer.new(:pointer)
|
33
|
+
nchildren = FFI::MemoryPointer.new(:int)
|
34
|
+
win = window
|
35
|
+
while win > 0
|
36
|
+
X11.XGetClassHint(@display, win, class_hint)
|
37
|
+
X11.XQueryTree(@display, win, root, parent, children, nchildren)
|
38
|
+
X11.XFree(children.read_pointer)
|
39
|
+
break unless class_hint[:name].null? && class_hint[:class].null?
|
40
|
+
win = parent.read(:Window)
|
41
|
+
end
|
42
|
+
unless class_hint[:name].null?
|
43
|
+
win_name = class_hint[:name].read_string
|
44
|
+
X11.XFree(class_hint[:name])
|
45
|
+
end
|
46
|
+
unless class_hint[:class].null?
|
47
|
+
win_class = class_hint[:class].read_string
|
48
|
+
X11.XFree(class_hint[:class])
|
49
|
+
end
|
50
|
+
@app_win[window] = [win, win_name, win_class]
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [String]
|
54
|
+
def app_title(window)
|
55
|
+
win = app_win(window)[0]
|
56
|
+
prop = XTextProperty.new
|
57
|
+
text_list = FFI::MemoryPointer.new(:pointer)
|
58
|
+
count = FFI::MemoryPointer.new(:int)
|
59
|
+
X11.XGetWMName(@display, win, prop)
|
60
|
+
X11.Xutf8TextPropertyToTextList(@display, prop, text_list, count)
|
61
|
+
title = text_list.read(:pointer).read(:string)&.force_encoding('utf-8')
|
62
|
+
X11.XFreeStringList(text_list.read(:pointer))
|
63
|
+
title
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class XClassHint < FFI::Struct
|
68
|
+
layout(
|
69
|
+
:name, :pointer,
|
70
|
+
:class, :pointer,
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
class XTextProperty < FFI::Struct
|
75
|
+
layout(
|
76
|
+
:value, :pointer,
|
77
|
+
:encoding, :Atom,
|
78
|
+
:format, :int,
|
79
|
+
:nitems, :ulong,
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
module X11
|
84
|
+
extend FFI::Library
|
85
|
+
ffi_lib 'X11'
|
86
|
+
attach_function :XOpenDisplay, [:string], :Display
|
87
|
+
attach_function :XGetInputFocus, [:Display, :pointer, :pointer], :int
|
88
|
+
attach_function :XGetClassHint, [:Display, :Window, XClassHint.by_ref], :int
|
89
|
+
attach_function :XQueryTree, [:Display, :Window, :pointer, :pointer, :pointer, :pointer], :Status
|
90
|
+
attach_function :XGetWMName, [:Display, :Window, XTextProperty.by_ref], :void
|
91
|
+
attach_function :Xutf8TextPropertyToTextList, [:Display, XTextProperty.by_ref, :pointer, :pointer], :int
|
92
|
+
attach_function :XFree, [:pointer], :int
|
93
|
+
attach_function :XFreeStringList, [:pointer], :void
|
94
|
+
end
|
95
|
+
end
|
data/lib/rkremap.rb
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "rkremap/version"
|
4
|
+
require_relative 'rkremap/keycode'
|
5
|
+
require_relative 'rkremap/winattr'
|
6
|
+
|
7
|
+
class Rkremap
|
8
|
+
include KeyCode
|
9
|
+
|
10
|
+
# ioctl constants
|
11
|
+
EVIOCGRAB = 1074021776
|
12
|
+
UI_SET_EVBIT = 1074025828
|
13
|
+
UI_SET_KEYBIT = 1074025829
|
14
|
+
UI_DEV_SETUP = 1079792899
|
15
|
+
UI_DEV_CREATE = 21761
|
16
|
+
EV_KEY = 1
|
17
|
+
EV_SYN = 0
|
18
|
+
SYN_REPORT = 0
|
19
|
+
|
20
|
+
EVENT_TYPE_VALUE = {
|
21
|
+
release: 0,
|
22
|
+
press: 1,
|
23
|
+
repeat: 2,
|
24
|
+
}
|
25
|
+
|
26
|
+
attr_accessor :grab
|
27
|
+
attr_accessor :modifiers
|
28
|
+
attr_accessor :x11
|
29
|
+
|
30
|
+
# @param device [String]
|
31
|
+
def initialize(device)
|
32
|
+
@input = File.open(device)
|
33
|
+
@uinput = File.open('/dev/uinput', 'w')
|
34
|
+
setup_uinput
|
35
|
+
@grab = false
|
36
|
+
@x11 = false
|
37
|
+
@modifiers = [
|
38
|
+
KEY_LEFTCTRL, KEY_RIGHTCTRL,
|
39
|
+
KEY_LEFTSHIFT, KEY_RIGHTSHIFT,
|
40
|
+
KEY_LEFTALT, KEY_RIGHTALT,
|
41
|
+
KEY_LEFTMETA, KEY_RIGHTMETA,
|
42
|
+
]
|
43
|
+
@events = []
|
44
|
+
@mutex = Mutex.new
|
45
|
+
end
|
46
|
+
|
47
|
+
# @param code [Integer]
|
48
|
+
# @param type [Symbol] :press / :release / :repeat
|
49
|
+
def match(code: nil, type: nil, &block)
|
50
|
+
@events.push [{code: code, type: type}, block]
|
51
|
+
end
|
52
|
+
|
53
|
+
def start(&block)
|
54
|
+
@mod_state = @modifiers.map{|m| [m, false]}.to_h
|
55
|
+
@winattr = WinAttr.new if @x11
|
56
|
+
@input.ioctl(EVIOCGRAB, 1) if @grab
|
57
|
+
while true
|
58
|
+
@keys = []
|
59
|
+
raw = @input.sysread(24)
|
60
|
+
sec, usec, type, code, value = raw.unpack('Q!Q!SSl')
|
61
|
+
next if type != EV_KEY
|
62
|
+
time = Time.at(sec, usec)
|
63
|
+
event = Event.new(time, code, value, @winattr)
|
64
|
+
@events.each do |cond, b|
|
65
|
+
synchronize{ b.call event } if event.match?(**cond)
|
66
|
+
break if event.skipped
|
67
|
+
end
|
68
|
+
next if event.skipped
|
69
|
+
synchronize{ proc_event(code, value, event) }
|
70
|
+
@keys.each do |c, mod, app|
|
71
|
+
synchronize{ block.call(c, mod, app) } if block
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def synchronize(&block)
|
77
|
+
@mutex.synchronize(&block)
|
78
|
+
end
|
79
|
+
|
80
|
+
# @param code [Integer]
|
81
|
+
# @param type [Symbol] :press / :release / :repeat
|
82
|
+
# @param ev [Rkmap::Event]
|
83
|
+
def event(code: nil, type: nil, event: nil)
|
84
|
+
value = EVENT_TYPE_VALUE[type] or raise "invalid type: #{type.inspect}"
|
85
|
+
proc_event(code, value, event)
|
86
|
+
end
|
87
|
+
|
88
|
+
# @param code [Integer]
|
89
|
+
# @param mod [Hash] {MOD_KEY => true, ...}
|
90
|
+
def key(code, mod={})
|
91
|
+
mod_diff(mod).each do |mcode, state|
|
92
|
+
write_event(mcode, state ? 1 : 0)
|
93
|
+
end
|
94
|
+
write_event(code, 1)
|
95
|
+
write_event(code, 0)
|
96
|
+
mod_diff(mod).each do |mcode, _|
|
97
|
+
write_event(mcode, @mod_state[mcode] ? 1 : 0)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def setup_uinput
|
104
|
+
@uinput.ioctl(UI_SET_EVBIT, EV_KEY)
|
105
|
+
KEY_CNT.times{|k| @uinput.ioctl(UI_SET_KEYBIT, k)}
|
106
|
+
bustype = 0x03 # BUS_USB
|
107
|
+
vendor = 0x1234 # てきとー
|
108
|
+
product = 0x5678 # てきとー
|
109
|
+
version = 1 # てきとー
|
110
|
+
name = 'rkremap'
|
111
|
+
ff_efects_max = 0
|
112
|
+
setup = [bustype, vendor, product, version, name, ff_efects_max].pack("SSSSZ80L") # struct uinput_setup
|
113
|
+
@uinput.ioctl(UI_DEV_SETUP, setup)
|
114
|
+
@uinput.ioctl(UI_DEV_CREATE)
|
115
|
+
end
|
116
|
+
|
117
|
+
def proc_event(code, value, event)
|
118
|
+
if @mod_state.include?(code)
|
119
|
+
@mod_state[code] = value != 0
|
120
|
+
write_event(code, value)
|
121
|
+
elsif value != 0
|
122
|
+
@keys.push [code, @mod_state.dup, App.new(event&.win, @winattr)]
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def mod_diff(mod)
|
127
|
+
mod.select{|k, v| @mod_state[k] != v}
|
128
|
+
end
|
129
|
+
|
130
|
+
# @param code [Integer]
|
131
|
+
# @param value [Integer] 0:release / 1:press / 2:repeat
|
132
|
+
def write_event(code, value)
|
133
|
+
@uinput.syswrite(['', EV_KEY, code, value].pack('a16SSl'))
|
134
|
+
@uinput.syswrite(['', EV_SYN, SYN_REPORT, 0].pack('a16SSl'))
|
135
|
+
end
|
136
|
+
|
137
|
+
class Event
|
138
|
+
attr_reader :time
|
139
|
+
attr_reader :code
|
140
|
+
attr_reader :type
|
141
|
+
attr_reader :win
|
142
|
+
attr_reader :skipped
|
143
|
+
|
144
|
+
def initialize(time, code, value, winattr)
|
145
|
+
@time = time
|
146
|
+
@code = code
|
147
|
+
@value = value
|
148
|
+
@type = value == 1 ? :press : value == 0 ? :release : :repeat
|
149
|
+
@win = winattr&.focus_win
|
150
|
+
@skipped = false
|
151
|
+
end
|
152
|
+
|
153
|
+
def match?(code: nil, type: nil)
|
154
|
+
(code.nil? || Array(code).include?(@code)) && (type.nil? || Array(type).include?(@type))
|
155
|
+
end
|
156
|
+
|
157
|
+
def skip
|
158
|
+
@skipped = true
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
class App
|
163
|
+
def initialize(win, winattr)
|
164
|
+
@win = win
|
165
|
+
@winattr = winattr
|
166
|
+
end
|
167
|
+
|
168
|
+
def class_name
|
169
|
+
@winattr.app_win(@win)[2] if @winattr && @win
|
170
|
+
end
|
171
|
+
|
172
|
+
def title
|
173
|
+
@winattr.app_title(@win) if @winattr && @win
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rkremap
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- TOMITA Masahiro
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-01-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ffi
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
description: key remapper
|
28
|
+
email:
|
29
|
+
- tommy@tmtm.org
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- README.md
|
35
|
+
- example/henkan-alt.rb
|
36
|
+
- example/keylogger.rb
|
37
|
+
- example/mac-shortcut.rb
|
38
|
+
- example/tmtms.rb
|
39
|
+
- lib/rkremap.rb
|
40
|
+
- lib/rkremap/keycode.rb
|
41
|
+
- lib/rkremap/version.rb
|
42
|
+
- lib/rkremap/winattr.rb
|
43
|
+
homepage: https://github.com/tmtm/rkremap
|
44
|
+
licenses:
|
45
|
+
- MIT
|
46
|
+
metadata:
|
47
|
+
homepage_uri: https://github.com/tmtm/rkremap
|
48
|
+
source_code_uri: https://github.com/tmtm/rkremap
|
49
|
+
documentation_uri: https://www.rubydoc.info/gems/rkremap
|
50
|
+
rubygems_mfa_required: 'true'
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 2.6.0
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
requirements: []
|
66
|
+
rubygems_version: 3.3.3
|
67
|
+
signing_key:
|
68
|
+
specification_version: 4
|
69
|
+
summary: key remapper
|
70
|
+
test_files: []
|