rkremap 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +38 -0
- data/example/henkan-super.rb +7 -34
- data/example/tmtms.rb +16 -57
- data/lib/rkremap/remap.rb +105 -0
- data/lib/rkremap/version.rb +1 -1
- data/lib/rkremap.rb +12 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2052faf03d55e5ca684ee7c991fe42ecb187f2294376216e333d9aced2a45188
|
4
|
+
data.tar.gz: cc901a01fec47fcafc320ea355c5ea71dd8cc8e54c05f4f7774f02beda3ab328
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dad24b3679af4213746a787811812afe8791d4964eba2ea018debffb94f7558dec29915a9be18e3aa1952a6817ea6ec823045c0ab8ae45afc9d22649f8c90374
|
7
|
+
data.tar.gz: 6dbef790e758293b32891d2aabd4cc939b3259b55b5c6d5ed297d2a96ffe9feaeb657675c98b16cd3c73480f3d6f0b35e98f12fadd0d0f41a3020cca894cf069
|
data/README.md
CHANGED
@@ -79,6 +79,44 @@ rkremap.exclude = /touchpad/i
|
|
79
79
|
`true` の場合はキーボードデバイスの接続を自動検知する。
|
80
80
|
`new` 時にデバイスファイルが指定されない場合は `true` になる。
|
81
81
|
|
82
|
+
### Rkremap#remap
|
83
|
+
|
84
|
+
引数の Hash で変換するキーを指定する:
|
85
|
+
```ruby
|
86
|
+
rk.remap(KEY_CAPSLOCK => KEY_LEFTCTRL)
|
87
|
+
```
|
88
|
+
|
89
|
+
変換元を配列で修飾キーを書くとその修飾キーとの組み合わせで変換する:
|
90
|
+
```ruby
|
91
|
+
rk.remap([KEY_LEFTCTRL, KEY_A] => KEY_HOME)
|
92
|
+
```
|
93
|
+
|
94
|
+
hold を指定すると指定秒数長押ししたときだけ変換する:
|
95
|
+
```ruby
|
96
|
+
rk.remap(hold: 0.5, map: {
|
97
|
+
KEY_MUHENKAN => KEY_RIGHTMETA,
|
98
|
+
KEY_HENKAN => KEY_RIGHTMETA,
|
99
|
+
})
|
100
|
+
```
|
101
|
+
|
102
|
+
次のように書くと、A も B も C もすべて A になってしまう:
|
103
|
+
```ruby
|
104
|
+
rk.remap(KEY_A => KEY_B)
|
105
|
+
rk.remap(KEY_B => KEY_C)
|
106
|
+
rk.remap(KEY_C => KEY_A)
|
107
|
+
```
|
108
|
+
|
109
|
+
A を B, B を C, C を A と変換したい場合は次のように書く:
|
110
|
+
```ruby
|
111
|
+
rk.remap(
|
112
|
+
KEY_A => KEY_B,
|
113
|
+
KEY_B => KEY_C,
|
114
|
+
KEY_C => KEY_A
|
115
|
+
)
|
116
|
+
```
|
117
|
+
|
118
|
+
`#remap` で実現できないような複雑な処理は、後述の `#match` や `#start` で書くことができるかもしれない。
|
119
|
+
|
82
120
|
### Rkremap#start
|
83
121
|
|
84
122
|
なにかキーを押されたらブロックを実行する。修飾キー単体ではブロックは実行されない。
|
data/example/henkan-super.rb
CHANGED
@@ -2,51 +2,24 @@
|
|
2
2
|
# 0.5秒以内でも変換/無変換キーを押しながら他のキーを押すとSUPERキーとして扱う。
|
3
3
|
|
4
4
|
require 'rkremap'
|
5
|
-
require 'tmtms_timer'
|
6
5
|
|
7
6
|
include Rkremap::KeyCode
|
8
7
|
|
9
|
-
rk = Rkremap.new
|
8
|
+
rk = Rkremap.new(*ARGV, mouse: true)
|
10
9
|
rk.grab = true
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
KEY_HENKAN => nil,
|
15
|
-
KEY_MUHENKAN => nil,
|
16
|
-
}
|
17
|
-
|
18
|
-
henkan_map = {
|
11
|
+
# HENKAN, MUHENKAN を 0.5秒以上押したら SUPER とする
|
12
|
+
rk.remap(hold: 0.5, map: {
|
19
13
|
KEY_HENKAN => KEY_RIGHTMETA,
|
20
14
|
KEY_MUHENKAN => KEY_RIGHTMETA, # LEFTMETA だとデスクトップ環境のメニューが開いたりするため
|
21
|
-
}
|
15
|
+
})
|
22
16
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
rk.synchronize do
|
27
|
-
rk.event(code: henkan_map[event.code], type: :press)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
jobs[event.code] = job
|
31
|
-
elsif event.type == :release
|
32
|
-
if jobs[event.code]&.cancel # 0.5秒以内に離された
|
33
|
-
rk.key(event.code)
|
34
|
-
else
|
35
|
-
rk.event(code: henkan_map[event.code], type: :release)
|
36
|
-
end
|
37
|
-
end
|
17
|
+
# マウスボタンイベントはそのまま
|
18
|
+
rk.match(device: :mouse) do |event|
|
19
|
+
rk.event(code: event.code, type: event.type)
|
38
20
|
event.skip
|
39
21
|
end
|
40
22
|
|
41
|
-
# 何かキーが押されたときに HENKAN, MUHENKAN が押されてれば SUPER が押されてることにする
|
42
|
-
rk.match(type: :press) do
|
43
|
-
[KEY_HENKAN, KEY_MUHENKAN].each do |code|
|
44
|
-
if jobs[code]&.cancel # 0.5秒以内
|
45
|
-
rk.event(code: henkan_map[code], type: :press)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
23
|
rk.start do |code, mod|
|
51
24
|
rk.key(code, mod)
|
52
25
|
end
|
data/example/tmtms.rb
CHANGED
@@ -1,57 +1,22 @@
|
|
1
1
|
# tmtms 用
|
2
2
|
|
3
3
|
require 'rkremap'
|
4
|
-
require 'tmtms_timer'
|
5
4
|
|
6
5
|
include Rkremap::KeyCode
|
7
6
|
|
8
|
-
rk = Rkremap.new(*ARGV, mouse: true, exclude: /
|
7
|
+
rk = Rkremap.new(*ARGV, mouse: true, exclude: /\AELAN0676/i)
|
9
8
|
rk.grab = true
|
10
9
|
rk.x11 = true
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
end
|
11
|
+
# rkremap がシステムに認識されたら中ボタンスクロールを有効にする
|
12
|
+
sleep 0.1 until system "xinput | grep -q rkremap"
|
15
13
|
system "xinput set-prop pointer:rkremap 'libinput Scroll Method Enabled' 0 0 1"
|
16
14
|
|
17
15
|
# HENKAN, MUHENKAN を 0.5秒以上押したら SUPER とする
|
18
|
-
|
19
|
-
jobs = {
|
20
|
-
KEY_HENKAN => nil,
|
21
|
-
KEY_MUHENKAN => nil,
|
22
|
-
}
|
23
|
-
|
24
|
-
henkan_map = {
|
16
|
+
rk.remap(hold: 0.5, map: {
|
25
17
|
KEY_HENKAN => KEY_RIGHTMETA,
|
26
18
|
KEY_MUHENKAN => KEY_RIGHTMETA, # LEFTMETA だとデスクトップ環境のメニューが開いたりするため
|
27
|
-
}
|
28
|
-
|
29
|
-
rk.match(code: [KEY_HENKAN, KEY_MUHENKAN]) do |event|
|
30
|
-
if event.type == :press
|
31
|
-
job = timer.set(0.5) do
|
32
|
-
rk.synchronize do
|
33
|
-
rk.event(code: henkan_map[event.code], type: :press)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
jobs[event.code] = job
|
37
|
-
elsif event.type == :release
|
38
|
-
if jobs[event.code]&.cancel # 0.5秒以内に離された
|
39
|
-
rk.key(event.code)
|
40
|
-
else
|
41
|
-
rk.event(code: henkan_map[event.code], type: :release)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
event.skip
|
45
|
-
end
|
46
|
-
|
47
|
-
# 何かキーが押されたときに HENKAN, MUHENKAN が押されてれば SUPER が押されてることにする
|
48
|
-
rk.match(type: :press) do
|
49
|
-
[KEY_HENKAN, KEY_MUHENKAN].each do |code|
|
50
|
-
if jobs[code]&.cancel # 0.5秒以内
|
51
|
-
rk.event(code: henkan_map[code], type: :press)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
19
|
+
})
|
55
20
|
|
56
21
|
# マウスボタンイベントはそのまま
|
57
22
|
rk.match(device: :mouse) do |event|
|
@@ -60,9 +25,17 @@ rk.match(device: :mouse) do |event|
|
|
60
25
|
end
|
61
26
|
|
62
27
|
# CAPSLOCK は CTRL に変換
|
63
|
-
rk.
|
64
|
-
|
65
|
-
|
28
|
+
rk.remap(KEY_CAPSLOCK => KEY_LEFTCTRL)
|
29
|
+
|
30
|
+
# JISキーボードを英語配列にしたときに一部キーを変える
|
31
|
+
rk.remap(
|
32
|
+
KEY_YEN => KEY_BACKSLASH,
|
33
|
+
KEY_BACKSLASH => KEY_GRAVE,
|
34
|
+
KEY_GRAVE => KEY_ESC,
|
35
|
+
[KEY_LEFTSHIFT, KEY_RO] => [KEY_LEFTSHIFT, KEY_MINUS],
|
36
|
+
[KEY_RIGHTSHIFT, KEY_RO] => [KEY_LEFTSHIFT, KEY_MINUS],
|
37
|
+
KEY_RO => KEY_BACKSLASH,
|
38
|
+
)
|
66
39
|
|
67
40
|
mod_disable_ctrl = {
|
68
41
|
KEY_LEFTCTRL => false,
|
@@ -82,20 +55,6 @@ mod_disable_meta = {
|
|
82
55
|
}
|
83
56
|
mod_disable_all = {}.merge(mod_disable_ctrl, mod_disable_shift, mod_disable_alt, mod_disable_meta)
|
84
57
|
|
85
|
-
# JISキーボードを英語配列にしたときに一部キーを変える
|
86
|
-
key_map = {
|
87
|
-
KEY_YEN => KEY_BACKSLASH,
|
88
|
-
KEY_BACKSLASH => KEY_GRAVE,
|
89
|
-
KEY_GRAVE => KEY_ESC,
|
90
|
-
}
|
91
|
-
rk.match do |event, mod|
|
92
|
-
event.code = key_map[event.code] || event.code
|
93
|
-
# RO キーは「\」(SHIFTキーを押してる場合は「_」)
|
94
|
-
if event.code == KEY_RO
|
95
|
-
event.code = (mod[KEY_LEFTSHIFT] || mod[KEY_RIGHTSHIFT]) ? KEY_MINUS : KEY_BACKSLASH
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
58
|
# Emacs や VirtualBox ではそのまま
|
100
59
|
rk.match(app: /Emacs|VirtualBox Machine/) do |event|
|
101
60
|
rk.event(code: event.code, type: event.type)
|
@@ -0,0 +1,105 @@
|
|
1
|
+
class Rkremap
|
2
|
+
class Remap
|
3
|
+
# @param map [Hash] from => to
|
4
|
+
# @param hold [Numeric] seconds
|
5
|
+
def initialize(rk, map:, hold:)
|
6
|
+
@rk = rk
|
7
|
+
@pressed = {}
|
8
|
+
|
9
|
+
if hold
|
10
|
+
setup_holding_event(map, hold)
|
11
|
+
else
|
12
|
+
setup_event(map)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param map [Hash] {form => to}
|
17
|
+
def setup_event(map)
|
18
|
+
keycodes = map.keys.flatten
|
19
|
+
|
20
|
+
@rk.match(code: keycodes, type: :press) do |event, current_mod|
|
21
|
+
map.each do |from, to|
|
22
|
+
if event_match?(from, event, current_mod)
|
23
|
+
make_press_event(to, event)
|
24
|
+
break
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
@rk.match(code: keycodes, type: :release) do |event|
|
30
|
+
if @pressed[event.code]
|
31
|
+
@rk.event(code: @pressed[event.code], type: :release)
|
32
|
+
@pressed[event.code] = nil
|
33
|
+
event.skip
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# @param map [Hash] {form => to}
|
39
|
+
# @param hold [Numeric] seconds
|
40
|
+
def setup_holding_event(map, hold)
|
41
|
+
keycodes = map.keys.flatten
|
42
|
+
timer = Tmtms::Timer.new
|
43
|
+
jobs = map.transform_values{nil}
|
44
|
+
|
45
|
+
@rk.match(code: keycodes, type: :press) do |event|
|
46
|
+
map.each do |from, to|
|
47
|
+
if from == event.code
|
48
|
+
jobs[event.code] = timer.set(hold) do
|
49
|
+
@rk.synchronize{ make_press_event(to) }
|
50
|
+
end
|
51
|
+
event.skip
|
52
|
+
break
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
@rk.match(code: keycodes, type: :repeat) do |event|
|
58
|
+
event.skip
|
59
|
+
end
|
60
|
+
|
61
|
+
@rk.match(code: keycodes, type: :release) do |event|
|
62
|
+
if jobs[event.code]&.cancel
|
63
|
+
@rk.key(event.code)
|
64
|
+
elsif map[event.code]
|
65
|
+
@rk.event(code: map[event.code], type: :release)
|
66
|
+
end
|
67
|
+
event.skip
|
68
|
+
end
|
69
|
+
|
70
|
+
@rk.match(type: :press) do
|
71
|
+
jobs.each do |code, job|
|
72
|
+
make_press_event(map[code]) if job&.cancel
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# @param keys [Integer, Array<Integer>] KEY_A, [KEY_LEFTCTRL, KEY_A], [:SHIFT, KEY_A], ...
|
78
|
+
# @param event [Rkremap::Event]
|
79
|
+
# @param mod [Hash] current modifiers status
|
80
|
+
def event_match?(keys, event, mod)
|
81
|
+
if keys == event.code
|
82
|
+
return true
|
83
|
+
end
|
84
|
+
keys = Array(keys)
|
85
|
+
return false unless keys.include? event.code
|
86
|
+
(keys - [event.code]).all?{mod[_1]}
|
87
|
+
end
|
88
|
+
|
89
|
+
# @param to [Integer, Array<Integer>]
|
90
|
+
# @param event [Rkremap::Event, nil]
|
91
|
+
def make_press_event(to, event=nil)
|
92
|
+
Array(to).each do |key|
|
93
|
+
@pressed[event.code] = key if event
|
94
|
+
if @rk.modifiers.include? key
|
95
|
+
@rk.event(code: key, type: :press)
|
96
|
+
event&.skip
|
97
|
+
elsif event
|
98
|
+
event.code = key
|
99
|
+
else
|
100
|
+
@rk.key(code: key, type: :press)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/lib/rkremap/version.rb
CHANGED
data/lib/rkremap.rb
CHANGED
@@ -7,6 +7,7 @@ require_relative 'rkremap/evdev_list'
|
|
7
7
|
require_relative 'rkremap/evdev'
|
8
8
|
require_relative 'rkremap/event'
|
9
9
|
require_relative 'rkremap/uinput'
|
10
|
+
require_relative 'rkremap/remap'
|
10
11
|
|
11
12
|
class Rkremap
|
12
13
|
include KeyCode
|
@@ -57,6 +58,17 @@ class Rkremap
|
|
57
58
|
@mutex = Mutex.new
|
58
59
|
end
|
59
60
|
|
61
|
+
# @overload remap(map)
|
62
|
+
# @param map [Hash] from => to
|
63
|
+
# @overload remap(map:, hold: nil)
|
64
|
+
# @param map [Hash] from => to
|
65
|
+
# @param hold [Numeric] seconds
|
66
|
+
def remap(**opts)
|
67
|
+
map, hold = opts[:map], opts[:hold]
|
68
|
+
map ||= opts
|
69
|
+
Remap.new(self, map: map, hold: hold)
|
70
|
+
end
|
71
|
+
|
60
72
|
# @param device [Symbol, Regexp]
|
61
73
|
# @param code [Integer]
|
62
74
|
# @param type [Symbol] :press / :release / :repeat
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rkremap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- TOMITA Masahiro
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tmtms_timer
|
@@ -41,6 +41,7 @@ files:
|
|
41
41
|
- lib/rkremap/evdev_list.rb
|
42
42
|
- lib/rkremap/event.rb
|
43
43
|
- lib/rkremap/keycode.rb
|
44
|
+
- lib/rkremap/remap.rb
|
44
45
|
- lib/rkremap/uinput.rb
|
45
46
|
- lib/rkremap/version.rb
|
46
47
|
- lib/rkremap/winattr.rb
|