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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6476d10293c91c5afb744c6ebe1162d26ab253ad06aade6f5f2568db05bb7631
4
- data.tar.gz: 35fd73d5a2d71ca797fd626397a789e8f22b5bd54cfa2ef0ca08f46adc6efa7f
3
+ metadata.gz: 2052faf03d55e5ca684ee7c991fe42ecb187f2294376216e333d9aced2a45188
4
+ data.tar.gz: cc901a01fec47fcafc320ea355c5ea71dd8cc8e54c05f4f7774f02beda3ab328
5
5
  SHA512:
6
- metadata.gz: bdf4f1364db8aa24dc49dab823e4f16200994058a6ff8d8e3323272d0783139af49f6fcdbb7f22b573dab92554d39d92429d24aa7b5fedf80e27139cf62bd120
7
- data.tar.gz: d868e6b7af37edfa90324014669ff7de5595f392116bedeaf011cf95cd49ce9621782f1dda6e402c4e6117509ae0a0337322447028975ab743324da318479d0b
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
  なにかキーを押されたらブロックを実行する。修飾キー単体ではブロックは実行されない。
@@ -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
- timer = Tmtms::Timer.new
13
- jobs = {
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
- rk.match(code: [KEY_HENKAN, KEY_MUHENKAN]) do |event|
24
- if event.type == :press
25
- job = timer.set(0.5) do
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: /touchpad/i)
7
+ rk = Rkremap.new(*ARGV, mouse: true, exclude: /\AELAN0676/i)
9
8
  rk.grab = true
10
9
  rk.x11 = true
11
10
 
12
- until system "xinput | grep -q rkremap"
13
- sleep 0.1
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
- timer = Tmtms::Timer.new
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.match(code: KEY_CAPSLOCK) do |event|
64
- event.code = KEY_LEFTCTRL
65
- end
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Rkremap
4
- VERSION = "0.4.1"
4
+ VERSION = "0.5.0"
5
5
  end
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.1
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-08-27 00:00:00.000000000 Z
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