rkremap 0.3.0 → 0.4.1

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.
data/lib/rkremap.rb CHANGED
@@ -1,13 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "rkremap/version"
3
+ require_relative 'rkremap/version'
4
4
  require_relative 'rkremap/keycode'
5
5
  require_relative 'rkremap/winattr'
6
+ require_relative 'rkremap/evdev_list'
6
7
  require_relative 'rkremap/evdev'
8
+ require_relative 'rkremap/event'
9
+ require_relative 'rkremap/uinput'
7
10
 
8
11
  class Rkremap
9
12
  include KeyCode
10
13
 
14
+ # /usr/include/linux/input-event-codes.h
15
+ EV_SYN = 0
16
+ EV_KEY = 1
17
+ EV_REL = 2
18
+ EV_ABS = 3
19
+ EV_MSC = 4
20
+ SYN_REPORT = 0
21
+
11
22
  EVENT_TYPE_VALUE = {
12
23
  release: 0,
13
24
  press: 1,
@@ -18,17 +29,21 @@ class Rkremap
18
29
  attr_accessor :modifiers
19
30
  attr_accessor :x11
20
31
  attr_accessor :auto_detect
32
+ attr_accessor :exclude
33
+ attr_accessor :mouse
21
34
 
22
35
  # @param devices [Array<String>, String]
23
- def initialize(devices=nil)
24
- if devices
25
- devices = Array(devices)
26
- @inputs = devices.map{|d| Evdev.new(d)}
27
- else
36
+ # @param exclude [Regexp]
37
+ # @param mouse [Boolean]
38
+ def initialize(devices=[], exclude: nil, mouse: false)
39
+ if devices.empty?
28
40
  @auto_detect = true
29
- @inputs = Evdev.detect.select(&:keyboard?)
41
+ else
42
+ devices = Array(devices)
30
43
  end
31
- raise 'Unable to detect keyboard device' if @inputs.empty?
44
+ @devices = devices
45
+ @exclude = exclude
46
+ @mouse = mouse
32
47
  @uinput = Uinput.new
33
48
  @grab = false
34
49
  @x11 = false
@@ -38,60 +53,43 @@ class Rkremap
38
53
  KEY_LEFTALT, KEY_RIGHTALT,
39
54
  KEY_LEFTMETA, KEY_RIGHTMETA,
40
55
  ]
41
- @events = []
56
+ @event_procs = []
42
57
  @mutex = Mutex.new
43
58
  end
44
59
 
60
+ # @param device [Symbol, Regexp]
45
61
  # @param code [Integer]
46
62
  # @param type [Symbol] :press / :release / :repeat
47
- def match(code: nil, type: nil, &block)
48
- @events.push [{code: code, type: type}, block]
63
+ # @param app [Regexp, String]
64
+ def match(device: nil, code: nil, type: nil, app: nil, &block)
65
+ @event_procs.push [{device: device, code: code, type: type, app: app}, block]
49
66
  end
50
67
 
51
68
  def start(&block)
52
- detect_device_loop if @auto_detect
69
+ @evdev_list = EvdevList.new(@devices, auto_detect: @auto_detect, exclude: @exclude, detect_mouse: @mouse)
70
+ @evdev_list.grab = @grab
71
+ @evdev_list.detect_loop
53
72
  @mod_state = @modifiers.map.to_h{|m| [m, false]}
54
- @winattr = WinAttr.new if @x11
55
- @inputs.each(&:grab) if @grab
73
+ winattr = WinAttr.new if @x11
56
74
  while true
57
75
  @keys = []
58
- time, type, code, value = read_event
59
- next if type != EV_KEY
60
- event = Event.new(time, code, value, @winattr)
61
- @events.each do |cond, b|
62
- synchronize{ b.call event } if event.match?(**cond)
63
- break if event.skipped
64
- end
65
- next if event.skipped
66
- synchronize{ proc_event(code, value, event) }
67
- @keys.each do |c, mod, app|
68
- synchronize{ block.call(c, mod, app) } if block
69
- end
70
- end
71
- end
72
-
73
- def detect_device_loop
74
- Thread.new do
75
- while true
76
- sleep 3
77
- new_devs = Evdev.detect.select(&:keyboard?)
78
- unless new_devs.empty?
79
- new_devs.each(&:grab) if @grab
80
- @inputs += new_devs
76
+ event = @evdev_list.read_event
77
+ if event.ev_type != EV_KEY
78
+ if event.device.grab?
79
+ @uinput.write_event(event.ev_type, event.code, event.value)
81
80
  end
81
+ next
82
82
  end
83
- end
84
- end
85
-
86
- def read_event
87
- while true
88
- begin
89
- input = Evdev.select(@inputs, 3)
90
- next unless input
91
- return input.read_event
92
- rescue Errno::ENODEV
93
- input.close rescue nil
94
- @inputs.delete input
83
+ app = App.new(winattr) if winattr
84
+ event.app = app
85
+ @event_procs.each do |cond, b|
86
+ synchronize{ b.call(event, @mod_state.dup, app) } if event.match?(**cond)
87
+ break if event.skipped?
88
+ end
89
+ next if event.skipped?
90
+ synchronize{ proc_event(event, app) }
91
+ @keys.each do |c, mod, app_|
92
+ synchronize{ block.call(c, mod, app_) } if block
95
93
  end
96
94
  end
97
95
  end
@@ -102,20 +100,27 @@ class Rkremap
102
100
 
103
101
  # @param code [Integer]
104
102
  # @param type [Symbol] :press / :release / :repeat
105
- # @param ev [Rkmap::Event]
106
- def event(code: nil, type: nil, event: nil)
103
+ def event(code: nil, type: nil)
107
104
  value = EVENT_TYPE_VALUE[type] or raise "invalid type: #{type.inspect}"
108
- proc_event(code, value, event)
105
+ update_modifiers(code, value)
106
+ write_event(code, value)
109
107
  end
110
108
 
111
109
  # @param code [Integer]
112
110
  # @param mod [Hash] {MOD_KEY => true, ...}
113
111
  def key(code, mod={})
112
+ with_modifier(mod) do
113
+ write_event(code, 1)
114
+ write_event(code, 0)
115
+ end
116
+ end
117
+
118
+ # @param mod [Hash] {MOD_KEY => true, ...}
119
+ def with_modifier(mod, &block)
114
120
  mod_diff(mod).each do |mcode, state|
115
121
  write_event(mcode, state ? 1 : 0)
116
122
  end
117
- write_event(code, 1)
118
- write_event(code, 0)
123
+ block.call
119
124
  mod_diff(mod).each do |mcode, _|
120
125
  write_event(mcode, @mod_state[mcode] ? 1 : 0)
121
126
  end
@@ -123,12 +128,23 @@ class Rkremap
123
128
 
124
129
  private
125
130
 
126
- def proc_event(code, value, event)
131
+ def update_modifiers(code, value)
127
132
  if @mod_state.include?(code)
128
133
  @mod_state[code] = value != 0
134
+ end
135
+ end
136
+
137
+ # @param event [Rkremap::Event]
138
+ # @param app [Rkremap::App]
139
+ def proc_event(event, app)
140
+ code, value = event.code, event.value
141
+ if @mod_state.include?(code)
142
+ write_event(code, value)
143
+ update_modifiers(code, value)
144
+ elsif value == 0
129
145
  write_event(code, value)
130
- elsif value != 0
131
- @keys.push [code, @mod_state.dup, App.new(event&.win, @winattr)]
146
+ else
147
+ @keys.push [code, @mod_state.dup, app]
132
148
  end
133
149
  end
134
150
 
@@ -140,46 +156,46 @@ class Rkremap
140
156
  # @param value [Integer] 0:release / 1:press / 2:repeat
141
157
  def write_event(code, value)
142
158
  @uinput.write_event(EV_KEY, code, value)
143
- @uinput.write_event(EV_SYN, SYN_REPORT, 0)
144
- end
145
-
146
- class Event
147
- attr_reader :time
148
- attr_reader :code
149
- attr_reader :type
150
- attr_reader :win
151
- attr_reader :skipped
152
-
153
- def initialize(time, code, value, winattr)
154
- @time = time
155
- @code = code
156
- @value = value
157
- @type = value == 1 ? :press : value == 0 ? :release : :repeat
158
- @win = winattr&.focus_win
159
- @skipped = false
160
- end
161
-
162
- def match?(code: nil, type: nil)
163
- (code.nil? || Array(code).include?(@code)) && (type.nil? || Array(type).include?(@type))
164
- end
165
-
166
- def skip
167
- @skipped = true
168
- end
169
159
  end
170
160
 
171
161
  class App
172
- def initialize(win, winattr)
173
- @win = win
162
+ # @param winattr [Rkremap::WinAttr]
163
+ def initialize(winattr)
174
164
  @winattr = winattr
165
+ @win = winattr.focus_win
175
166
  end
176
167
 
168
+ # @return [String, nil]
177
169
  def class_name
178
170
  @winattr.app_win(@win)[2] if @winattr && @win
179
171
  end
180
172
 
173
+ # @return [String, nil]
181
174
  def title
182
175
  @winattr.app_title(@win) if @winattr && @win
183
176
  end
177
+
178
+ # @param app [Array, Hash, String, Regexp]
179
+ # @return [Boolean]
180
+ def match?(app)
181
+ Array(app).each do |a|
182
+ a = {class_name: a, title: a} unless a.is_a? Hash
183
+ return true if match_sub(a[:class_name], class_name) || match_sub(a[:title], title)
184
+ end
185
+ false
186
+ end
187
+
188
+ # @param a [String, Regexp]
189
+ # @param b [String]
190
+ def match_sub(a, b)
191
+ case a
192
+ when String
193
+ a == b
194
+ when Regexp
195
+ a =~ b
196
+ else
197
+ false
198
+ end
199
+ end
184
200
  end
185
201
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rkremap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.1
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-03-05 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2022-08-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: tmtms_timer
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.3'
13
27
  description: key remapper
14
28
  email:
15
29
  - tommy@tmtm.org
@@ -18,21 +32,24 @@ extensions: []
18
32
  extra_rdoc_files: []
19
33
  files:
20
34
  - README.md
21
- - example/henkan-alt.rb
35
+ - example/henkan-super.rb
22
36
  - example/keylogger.rb
23
37
  - example/mac-shortcut.rb
24
38
  - example/tmtms.rb
25
39
  - lib/rkremap.rb
26
40
  - lib/rkremap/evdev.rb
41
+ - lib/rkremap/evdev_list.rb
42
+ - lib/rkremap/event.rb
27
43
  - lib/rkremap/keycode.rb
44
+ - lib/rkremap/uinput.rb
28
45
  - lib/rkremap/version.rb
29
46
  - lib/rkremap/winattr.rb
30
- homepage: https://github.com/tmtm/rkremap
47
+ homepage: https://gitlab.com/tmtms/rkremap
31
48
  licenses:
32
49
  - MIT
33
50
  metadata:
34
- homepage_uri: https://github.com/tmtm/rkremap
35
- source_code_uri: https://github.com/tmtm/rkremap
51
+ homepage_uri: https://gitlab.com/tmtms/rkremap
52
+ source_code_uri: https://gitlab.com/tmtms/rkremap
36
53
  documentation_uri: https://www.rubydoc.info/gems/rkremap
37
54
  rubygems_mfa_required: 'true'
38
55
  post_install_message:
@@ -50,7 +67,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
50
67
  - !ruby/object:Gem::Version
51
68
  version: '0'
52
69
  requirements: []
53
- rubygems_version: 3.3.3
70
+ rubygems_version: 3.3.7
54
71
  signing_key:
55
72
  specification_version: 4
56
73
  summary: key remapper
@@ -1,93 +0,0 @@
1
- # 変換/無変換キーを0.5秒以上押してるとALTキーとして扱う。
2
- # 0.5秒以内でも変換/無変換キーを押しながら他のキーを押すとALTキーとして扱う。
3
-
4
- require 'rkremap'
5
- include Rkremap::KeyCode
6
-
7
- rk = Rkremap.new
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