fusuma-plugin-remap 0.10.0 → 0.11.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13ff7a06cbeae8f56ebc57ffbc347fe6adf2d7dba7b9fab4977047be9786aebc
4
- data.tar.gz: 80a99b69509058b34c58fcea076be99b881a008193bbfb7065134c2d4f75291b
3
+ metadata.gz: c1a6f601df78486fb3bf89f9c7902fe9fd46e45c33e2807eff9f0c4b5a38ec45
4
+ data.tar.gz: 50ca1d1da716e62d9ed9cc3973b201f9b8c93b00b5e313559bc5d7d4a73bfd3d
5
5
  SHA512:
6
- metadata.gz: ed14e66220bb7a483c666f777f2a17cbdd2d0be0ca8b0659f28ca2259d310ac7601f3280f2601ffc4fb809e87d7b37875c352e8cf01d92587e23123fe79f0be6
7
- data.tar.gz: 97faa8067e4a49ba9821298a2347d2e3b6ce18a0137f2af1a718ea1a2d5e543a0bb089e081b6544d9375977f498079547d9f657c089730753cf58874a587c808
6
+ metadata.gz: 881a29098c368a60f0d4469d77b1ffc118d0c9eb2df02d2b7c492ba356f30ab0ad740a73bfa96e229a1fd16d46a7a839139c7b4077e26fb30b092d0c142ca28c
7
+ data.tar.gz: 50dd4b8c9554ee17e338a5ded7248d1b4f9215d03ca5d19d5e2c8d97731687b42b1edb2105d7ebf7539ac2718bb3d3085db4c800db26cad54426be93fe854643
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "../remap/touchpad_remapper"
4
- # require_relative "../remap/layer_manager"
5
4
 
6
5
  module Fusuma
7
6
  module Plugin
@@ -35,22 +34,7 @@ module Fusuma
35
34
 
36
35
  gesture = "touch"
37
36
  finger = data["finger"]
38
-
39
- # @touch_state ||= {}
40
- # @mt_slot ||= 0
41
- # @touch_state[@mt_slot] ||= {
42
- # MT_TRACKING_ID: nil,
43
- # X: nil,
44
- # Y: nil,
45
- # valid_touch_point: false
46
- # }
47
- # TODO: implement update touch_state
48
- status =
49
- if data["touch_state"].any? { |_, v| v["valid_touch_point"] }
50
- "begin"
51
- else
52
- "end"
53
- end
37
+ status = data["status"]
54
38
 
55
39
  Events::Records::GestureRecord.new(gesture: gesture, status: status, finger: finger, delta: nil)
56
40
  rescue EOFError => e
@@ -13,6 +13,14 @@ module Fusuma
13
13
 
14
14
  VIRTUAL_KEYBOARD_NAME = "fusuma_virtual_keyboard"
15
15
 
16
+ # Key conversion tables for better performance and readability
17
+ KEYMAP = Revdev.constants.select { |c| c.start_with?("KEY_", "BTN_") }
18
+ .map { |c| [Revdev.const_get(c), c.to_s.delete_prefix("KEY_")] }
19
+ .to_h.freeze
20
+ CODEMAP = Revdev.constants.select { |c| c.start_with?("KEY_", "BTN_") }
21
+ .map { |c| [c, Revdev.const_get(c)] }
22
+ .to_h.freeze
23
+
16
24
  # @param layer_manager [Fusuma::Plugin::Remap::LayerManager]
17
25
  # @param fusuma_writer [IO]
18
26
  # @param config [Hash]
@@ -53,7 +61,7 @@ module Fusuma
53
61
  end
54
62
 
55
63
  input_event = @source_keyboards.find { |kbd| kbd.file == io }.read_input_event
56
- input_key = find_key_from_code(input_event.code)
64
+ input_key = code_to_key(input_event.code)
57
65
 
58
66
  if input_event.type == EV_KEY
59
67
  @emergency_stop.call(old_ie, input_event)
@@ -61,7 +69,13 @@ module Fusuma
61
69
  old_ie = input_event
62
70
  if input_event.value != 2 # repeat
63
71
  data = {key: input_key, status: input_event.value, layer: layer}
64
- @fusuma_writer.write(data.to_msgpack)
72
+ begin
73
+ @fusuma_writer.write(data.to_msgpack)
74
+ rescue IOError => e
75
+ MultiLogger.error("Failed to write to fusuma_writer: #{e.message}")
76
+ @destroy&.call(1)
77
+ return
78
+ end
65
79
  end
66
80
  end
67
81
 
@@ -71,7 +85,14 @@ module Fusuma
71
85
  next
72
86
  end
73
87
 
74
- remapped_event = InputEvent.new(nil, input_event.type, find_code_from_key(remapped), input_event.value)
88
+ remapped_code = key_to_code(remapped)
89
+ if remapped_code.nil?
90
+ MultiLogger.warn("Invalid remapped key: #{remapped}, skipping...")
91
+ uinput_keyboard.write_input_event(input_event)
92
+ next
93
+ end
94
+
95
+ remapped_event = InputEvent.new(nil, input_event.type, remapped_code, input_event.value)
75
96
 
76
97
  # Workaround to solve the problem that the remapped key remains pressed
77
98
  # when the key pressed before remapping is released after remapping
@@ -203,28 +224,30 @@ module Fusuma
203
224
  Signal.trap(:TERM) { @destroy.call(1) }
204
225
  end
205
226
 
227
+ DEFAULT_EMERGENCY_KEYBIND = "RIGHTCTRL+LEFTCTRL".freeze
228
+
206
229
  # Emergency stop keybind for virtual keyboard
207
230
  def set_emergency_ungrab_keys(keybind_string)
208
231
  keybinds = keybind_string&.split("+")
209
232
  # TODO: Extract to a configuration file or make it optional
210
233
  # it should stop other remappers
211
234
  if keybinds&.size != 2
212
- MultiLogger.error "Invalid emergency ungrab keybinds: #{keybinds}"
213
- MultiLogger.error "Please set two keys separated by '+'"
214
- MultiLogger.error <<~YAML
235
+ MultiLogger.warn "Invalid emergency ungrab keybinds: #{keybinds}, fallback to #{DEFAULT_EMERGENCY_KEYBIND}"
236
+ MultiLogger.warn "Please set two keys separated by '+'"
237
+ MultiLogger.warn <<~YAML
215
238
  plugin:
216
239
  inputs:
217
240
  remap_keyboard_input:
218
241
  emergency_ungrab_keys: RIGHTCTRL+LEFTCTRL
219
242
  YAML
220
243
 
221
- exit 1
244
+ keybinds = DEFAULT_EMERGENCY_KEYBIND.split("+")
222
245
  end
223
246
 
224
247
  MultiLogger.info "Emergency ungrab keybind: #{keybinds[0]}+#{keybinds[1]}"
225
248
 
226
- first_keycode = find_code_from_key(keybinds[0])
227
- second_keycode = find_code_from_key(keybinds[1])
249
+ first_keycode = key_to_code(keybinds[0])
250
+ second_keycode = key_to_code(keybinds[1])
228
251
 
229
252
  @emergency_stop = lambda do |prev, current|
230
253
  if (prev&.code == first_keycode && prev.value != 0) && (current.code == second_keycode && current.value != 0)
@@ -246,48 +269,45 @@ module Fusuma
246
269
  # @param [Integer] code
247
270
  # @return [Integer, nil]
248
271
  def find_remapped_code(mapping, code)
249
- key = find_key_from_code(code) # key = "A"
272
+ key = code_to_key(code) # key = "A"
250
273
  remapped_key = mapping.fetch(key.to_sym, nil) # remapped_key = "b"
251
274
  return code unless remapped_key # return original code if key is not found
252
275
 
253
- find_code_from_key(remapped_key) # remapped_code = 48
276
+ key_to_code(remapped_key) # remapped_code = 48
254
277
  end
255
278
 
256
279
  # Find key name from key code
257
280
  # @example
258
- # find_key_from_code(30) # => "A"
259
- # find_key_from_code(48) # => "B"
281
+ # code_to_key(30) # => "A"
282
+ # code_to_key(48) # => "B"
283
+ # code_to_key(272) # => "BTN_LEFT"
260
284
  # @param [Integer] code
261
285
  # @return [String]
262
- def find_key_from_code(code)
263
- # { 30 => :A, 48 => :B, ... }
264
- @keys_per_code ||= Revdev.constants.select { |c| c.start_with? "KEY_" }.map { |c| [Revdev.const_get(c), c.to_s.delete_prefix("KEY_")] }.to_h
265
- @keys_per_code[code]
286
+ # @return [nil] when key is not found
287
+ def code_to_key(code)
288
+ KEYMAP[code]
266
289
  end
267
290
 
268
291
  # Find key code from key name (e.g. "A", "B", "BTN_LEFT")
269
292
  # If key name is not found, return nil
270
293
  # @example
271
- # find_code_from_key("A") # => 30
272
- # find_code_from_key("B") # => 48
273
- # find_code_from_key("BTN_LEFT") # => 272
274
- # find_code_from_key("NOT_FOUND") # => nil
294
+ # key_to_code("A") # => 30
295
+ # key_to_code("B") # => 48
296
+ # key_to_code("BTN_LEFT") # => 272
297
+ # key_to_code("NOT_FOUND") # => nil
275
298
  # @param [String] key
276
299
  # @return [Integer] when key is available
277
300
  # @return [nil] when key is not available
278
- def find_code_from_key(key)
279
- # { KEY_A => 30, KEY_B => 48, ... }
280
- @codes_per_key ||= Revdev.constants.select { |c| c.start_with?("KEY_", "BTN_") }.map { |c| [c, Revdev.const_get(c)] }.to_h
281
-
301
+ def key_to_code(key)
282
302
  case key
283
303
  when String
284
304
  if key.start_with?("BTN_")
285
- @codes_per_key[key.upcase.to_sym]
305
+ CODEMAP[key.upcase.to_sym]
286
306
  else
287
- @codes_per_key["KEY_#{key}".upcase.to_sym]
307
+ CODEMAP["KEY_#{key}".upcase.to_sym]
288
308
  end
289
309
  when Integer
290
- @codes_per_key["KEY_#{key}".upcase.to_sym]
310
+ CODEMAP["KEY_#{key}".upcase.to_sym]
291
311
  end
292
312
  end
293
313
 
@@ -303,7 +323,12 @@ module Fusuma
303
323
  break true
304
324
  else
305
325
  # wait until all keys are released
306
- device.read_input_event
326
+ begin
327
+ device.read_input_event
328
+ rescue Errno::ENODEV => e
329
+ MultiLogger.warn("Device removed while waiting to release keys: #{e.message}")
330
+ return false
331
+ end
307
332
  end
308
333
  end
309
334
  end
@@ -18,7 +18,6 @@ module Fusuma
18
18
  @source_touchpads = source_touchpads # original touchpad
19
19
  @fusuma_writer = fusuma_writer # write event to fusuma_input
20
20
 
21
- # FIXME: PalmDetection should be initialized with each touchpad
22
21
  @palm_detectors = @source_touchpads.each_with_object({}) do |source_touchpad, palm_detectors|
23
22
  palm_detectors[source_touchpad] = PalmDetection.new(source_touchpad)
24
23
  end
@@ -34,6 +33,9 @@ module Fusuma
34
33
  touch_state = {}
35
34
  mt_slot = 0
36
35
  finger_state = nil
36
+
37
+ prev_valid_touch = false
38
+ prev_status = nil
37
39
  loop do
38
40
  ios = IO.select(@source_touchpads.map(&:file)) # , @layer_manager.reader])
39
41
  io = ios&.first&.first
@@ -131,10 +133,29 @@ module Fusuma
131
133
  end
132
134
 
133
135
  if syn_report
136
+ # Whether any slot is valid (touching)
137
+ valid_touch = touch_state.any? { |_, st| st[:valid_touch_point] }
138
+
139
+ status =
140
+ if valid_touch
141
+ prev_valid_touch ? "update" : "begin"
142
+ else
143
+ prev_valid_touch ? "end" : "cancelled"
144
+ end
145
+
146
+ if status == prev_status
147
+ next
148
+ end
149
+
134
150
  # TODO: define format as fusuma_input
135
151
  # TODO: Add data to identify multiple touchpads
136
- data = {finger: finger_state, touch_state: touch_state}
152
+ data = {
153
+ finger: finger_state,
154
+ status: status
155
+ }
137
156
  @fusuma_writer.write(data.to_msgpack)
157
+ prev_status = status
158
+ prev_valid_touch = valid_touch
138
159
  end
139
160
  end
140
161
  rescue => e
@@ -3,7 +3,7 @@
3
3
  module Fusuma
4
4
  module Plugin
5
5
  module Remap
6
- VERSION = "0.10.0"
6
+ VERSION = "0.11.1"
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fusuma-plugin-remap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - iberianpig
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-05-11 00:00:00.000000000 Z
11
+ date: 2025-09-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fusuma