fusuma-plugin-remap 0.3.0 → 0.4.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 +10 -3
- data/exe/fusuma-remap +74 -25
- data/exe/fusuma-touchpad-remap +42 -0
- data/fusuma-plugin-remap.gemspec +2 -2
- data/lib/fusuma/plugin/inputs/remap_keyboard_input.rb +21 -63
- data/lib/fusuma/plugin/inputs/remap_touchpad_input.rb +112 -0
- data/lib/fusuma/plugin/inputs/remap_touchpad_input.yml +4 -0
- data/lib/fusuma/plugin/remap/keyboard_remapper.rb +343 -0
- data/lib/fusuma/plugin/remap/layer_manager.rb +18 -13
- data/lib/fusuma/plugin/remap/touchpad_remapper.rb +168 -0
- data/lib/fusuma/plugin/remap/uinput_keyboard.rb +95 -0
- data/lib/fusuma/plugin/remap/uinput_touchpad.rb +172 -0
- data/lib/fusuma/plugin/remap/version.rb +1 -1
- metadata +17 -11
- data/lib/fusuma/plugin/remap/remapper.rb +0 -233
- data/lib/fusuma/plugin/remap/ruinput_device_patched.rb +0 -49
@@ -0,0 +1,172 @@
|
|
1
|
+
require "ruinput"
|
2
|
+
|
3
|
+
class UinputTouchpad < Ruinput::UinputDevice
|
4
|
+
include Ruinput
|
5
|
+
|
6
|
+
# create from original event device
|
7
|
+
# copy absinfo using eviocgabs
|
8
|
+
def create_from_device(name:, device:)
|
9
|
+
id = Revdev::InputId.new(
|
10
|
+
{
|
11
|
+
bustype: Revdev::BUS_I8042,
|
12
|
+
vendor: device.device_id.vendor,
|
13
|
+
product: device.device_id.product,
|
14
|
+
version: device.device_id.version
|
15
|
+
}
|
16
|
+
)
|
17
|
+
|
18
|
+
absinfo = {
|
19
|
+
Revdev::ABS_X => device.absinfo_for_axis(Revdev::ABS_X),
|
20
|
+
Revdev::ABS_Y => device.absinfo_for_axis(Revdev::ABS_Y),
|
21
|
+
Revdev::ABS_MT_POSITION_X => device.absinfo_for_axis(Revdev::ABS_MT_POSITION_X),
|
22
|
+
Revdev::ABS_MT_POSITION_Y => device.absinfo_for_axis(Revdev::ABS_MT_POSITION_Y),
|
23
|
+
Revdev::ABS_MT_SLOT => device.absinfo_for_axis(Revdev::ABS_MT_SLOT),
|
24
|
+
Revdev::ABS_MT_TOOL_TYPE => device.absinfo_for_axis(Revdev::ABS_MT_TOOL_TYPE),
|
25
|
+
Revdev::ABS_MT_TRACKING_ID => device.absinfo_for_axis(Revdev::ABS_MT_TRACKING_ID)
|
26
|
+
}
|
27
|
+
|
28
|
+
uud = Ruinput::UinputUserDev.new({
|
29
|
+
name: name,
|
30
|
+
id: id,
|
31
|
+
ff_effects_max: 0,
|
32
|
+
absmax: Array.new(Revdev::ABS_CNT, 0).tap { |a| absinfo.each { |k, v| a[k] = v[:absmax] } },
|
33
|
+
absmin: Array.new(Revdev::ABS_CNT, 0).tap { |a| absinfo.each { |k, v| a[k] = v[:absmin] } },
|
34
|
+
absfuzz: Array.new(Revdev::ABS_CNT, 0).tap { |a| absinfo.each { |k, v| a[k] = v[:absfuzz] } },
|
35
|
+
absflat: Array.new(Revdev::ABS_CNT, 0).tap { |a| absinfo.each { |k, v| a[k] = v[:absflat] } },
|
36
|
+
resolution: Array.new(Revdev::ABS_CNT, 0).tap { |a| absinfo.each { |k, v| a[k] = v[:resolution] } }
|
37
|
+
})
|
38
|
+
|
39
|
+
@file.syswrite uud.to_byte_string
|
40
|
+
|
41
|
+
set_all_events
|
42
|
+
|
43
|
+
@file.ioctl UI_DEV_CREATE, nil
|
44
|
+
@is_created = true
|
45
|
+
end
|
46
|
+
|
47
|
+
def set_all_events
|
48
|
+
raise "invalid method call: this uinput is already created" if @is_created
|
49
|
+
|
50
|
+
mouse_btns = [
|
51
|
+
Revdev::BTN_0,
|
52
|
+
Revdev::BTN_MISC,
|
53
|
+
Revdev::BTN_1,
|
54
|
+
Revdev::BTN_2,
|
55
|
+
Revdev::BTN_3,
|
56
|
+
Revdev::BTN_4,
|
57
|
+
Revdev::BTN_5,
|
58
|
+
Revdev::BTN_6,
|
59
|
+
Revdev::BTN_7,
|
60
|
+
Revdev::BTN_8,
|
61
|
+
Revdev::BTN_9,
|
62
|
+
Revdev::BTN_LEFT,
|
63
|
+
Revdev::BTN_MOUSE,
|
64
|
+
Revdev::BTN_MIDDLE,
|
65
|
+
Revdev::BTN_RIGHT,
|
66
|
+
Revdev::BTN_SIDE,
|
67
|
+
Revdev::BTN_EXTRA,
|
68
|
+
Revdev::BTN_FORWARD,
|
69
|
+
Revdev::BTN_BACK,
|
70
|
+
Revdev::BTN_TASK
|
71
|
+
# Revdev::BTN_TRIGGER, # disable because libinput recognize this device as a joystick
|
72
|
+
].freeze
|
73
|
+
|
74
|
+
touchpad_btns = [
|
75
|
+
Revdev::BTN_TOUCH,
|
76
|
+
Revdev::BTN_TOOL_FINGER,
|
77
|
+
Revdev::BTN_TOOL_DOUBLETAP,
|
78
|
+
Revdev::BTN_TOOL_TRIPLETAP,
|
79
|
+
Revdev::BTN_TOOL_QUADTAP,
|
80
|
+
0x148 # define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */
|
81
|
+
].freeze
|
82
|
+
|
83
|
+
@file.ioctl UI_SET_EVBIT, Revdev::EV_KEY
|
84
|
+
@counter = 0
|
85
|
+
Revdev::KEY_CNT.times do |i|
|
86
|
+
# https://github.com/mooz/xkeysnail/pull/101/files
|
87
|
+
if mouse_btns.include?(i) || touchpad_btns.include?(i)
|
88
|
+
# puts "setting #{i} (#{Revdev::REVERSE_MAPS[:KEY][i]})"
|
89
|
+
@file.ioctl UI_SET_KEYBIT, i
|
90
|
+
else
|
91
|
+
# puts "skipping #{i} (#{Revdev::REVERSE_MAPS[:KEY][i]})"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
touchpad_abs = [
|
96
|
+
Revdev::ABS_X,
|
97
|
+
Revdev::ABS_Y,
|
98
|
+
# Revdev::ABS_PRESSURE,
|
99
|
+
Revdev::ABS_MT_SLOT,
|
100
|
+
# Revdev::ABS_MT_TOUCH_MAJOR,
|
101
|
+
# Revdev::ABS_MT_TOUCH_MINOR,
|
102
|
+
Revdev::ABS_MT_POSITION_X,
|
103
|
+
Revdev::ABS_MT_POSITION_Y,
|
104
|
+
Revdev::ABS_MT_TRACKING_ID,
|
105
|
+
Revdev::ABS_MT_TOOL_TYPE
|
106
|
+
].freeze
|
107
|
+
|
108
|
+
# kernel bug: device has min == max on ABS_Y
|
109
|
+
@file.ioctl UI_SET_EVBIT, Revdev::EV_ABS
|
110
|
+
Revdev::ABS_CNT.times do |i|
|
111
|
+
if touchpad_abs.include?(i)
|
112
|
+
puts "setting #{i} (#{Revdev::REVERSE_MAPS[:ABS][i]})"
|
113
|
+
@file.ioctl UI_SET_ABSBIT, i
|
114
|
+
else
|
115
|
+
puts "skipping #{i} (#{Revdev::REVERSE_MAPS[:ABS][i]})"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
touchpad_rels = [
|
120
|
+
Revdev::REL_X,
|
121
|
+
Revdev::REL_Y,
|
122
|
+
Revdev::REL_WHEEL,
|
123
|
+
Revdev::REL_HWHEEL
|
124
|
+
].freeze
|
125
|
+
|
126
|
+
@file.ioctl UI_SET_EVBIT, Revdev::EV_REL
|
127
|
+
Revdev::REL_CNT.times do |i|
|
128
|
+
if touchpad_rels.include?(i)
|
129
|
+
puts "setting #{i} (#{Revdev::REVERSE_MAPS[:REL][i]})"
|
130
|
+
@file.ioctl UI_SET_RELBIT, i
|
131
|
+
else
|
132
|
+
puts "skipping #{i} (#{Revdev::REVERSE_MAPS[:REL][i]})"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
@file.ioctl UI_SET_EVBIT, Revdev::EV_REP
|
137
|
+
|
138
|
+
touchpad_mscs = [
|
139
|
+
0x05 # define MSC_TIMESTAMP 0x05
|
140
|
+
]
|
141
|
+
@file.ioctl UI_SET_EVBIT, Revdev::EV_MSC
|
142
|
+
Revdev::MSC_CNT.times do |i|
|
143
|
+
if touchpad_mscs.include?(i)
|
144
|
+
# puts "setting #{i} (#{Revdev::REVERSE_MAPS[:MSC][i]})"
|
145
|
+
@file.ioctl UI_SET_MSCBIT, i
|
146
|
+
else
|
147
|
+
# puts "skipping #{i} (#{Revdev::REVERSE_MAPS[:MSC][i]})"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
class Revdev::EventDevice
|
154
|
+
def absinfo_for_axis(abs)
|
155
|
+
data = read_ioctl_with(eviocgabs(abs))
|
156
|
+
|
157
|
+
{
|
158
|
+
value: data[0, 4].unpack1("l<"),
|
159
|
+
absmin: data[4, 4].unpack1("l<"),
|
160
|
+
absmax: data[8, 4].unpack1("l<"),
|
161
|
+
absfuzz: data[12, 4].unpack1("l<"),
|
162
|
+
absflat: data[16, 4].unpack1("l<"),
|
163
|
+
resolution: data[20, 4].unpack1("l<")
|
164
|
+
}
|
165
|
+
end
|
166
|
+
|
167
|
+
# FIXME: undefined constants in revdev
|
168
|
+
def eviocgabs(abs)
|
169
|
+
# #define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo)
|
170
|
+
0x80404540 + abs # EVIOCGABS(abs)
|
171
|
+
end
|
172
|
+
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.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- iberianpig
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-04-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fusuma
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '3.
|
19
|
+
version: '3.4'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '3.
|
26
|
+
version: '3.4'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: fusuma-plugin-keypress
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 0.11.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 0.11.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: msgpack
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -90,6 +90,7 @@ email:
|
|
90
90
|
- yhkyky@gmail.com
|
91
91
|
executables:
|
92
92
|
- fusuma-remap
|
93
|
+
- fusuma-touchpad-remap
|
93
94
|
extensions: []
|
94
95
|
extra_rdoc_files: []
|
95
96
|
files:
|
@@ -98,13 +99,18 @@ files:
|
|
98
99
|
- bin/console
|
99
100
|
- bin/setup
|
100
101
|
- exe/fusuma-remap
|
102
|
+
- exe/fusuma-touchpad-remap
|
101
103
|
- fusuma-plugin-remap.gemspec
|
102
104
|
- lib/fusuma/plugin/inputs/remap_keyboard_input.rb
|
103
105
|
- lib/fusuma/plugin/inputs/remap_keyboard_input.yml
|
106
|
+
- lib/fusuma/plugin/inputs/remap_touchpad_input.rb
|
107
|
+
- lib/fusuma/plugin/inputs/remap_touchpad_input.yml
|
104
108
|
- lib/fusuma/plugin/remap.rb
|
109
|
+
- lib/fusuma/plugin/remap/keyboard_remapper.rb
|
105
110
|
- lib/fusuma/plugin/remap/layer_manager.rb
|
106
|
-
- lib/fusuma/plugin/remap/
|
107
|
-
- lib/fusuma/plugin/remap/
|
111
|
+
- lib/fusuma/plugin/remap/touchpad_remapper.rb
|
112
|
+
- lib/fusuma/plugin/remap/uinput_keyboard.rb
|
113
|
+
- lib/fusuma/plugin/remap/uinput_touchpad.rb
|
108
114
|
- lib/fusuma/plugin/remap/version.rb
|
109
115
|
homepage: https://github.com/iberianpig/fusuma-plugin-remap
|
110
116
|
licenses:
|
@@ -126,7 +132,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
126
132
|
- !ruby/object:Gem::Version
|
127
133
|
version: '0'
|
128
134
|
requirements: []
|
129
|
-
rubygems_version: 3.4.
|
135
|
+
rubygems_version: 3.4.19
|
130
136
|
signing_key:
|
131
137
|
specification_version: 4
|
132
138
|
summary: A Fusuma plugin for remapping keyboard events into virtual input devices.
|
@@ -1,233 +0,0 @@
|
|
1
|
-
require "revdev"
|
2
|
-
require "msgpack"
|
3
|
-
require "set"
|
4
|
-
require_relative "./layer_manager"
|
5
|
-
|
6
|
-
require_relative "./ruinput_device_patched"
|
7
|
-
|
8
|
-
module Fusuma
|
9
|
-
module Plugin
|
10
|
-
module Remap
|
11
|
-
class Remapper
|
12
|
-
include Revdev
|
13
|
-
# @param layer_manager [Fusuma::Plugin::Remap::LayerManager]
|
14
|
-
# @param keyboard_writer [IO]
|
15
|
-
# @param source_keyboards [Array<Revdev::Device>]
|
16
|
-
# @param internal_touchpad [Revdev::Device]
|
17
|
-
def initialize(layer_manager:, keyboard_writer:, source_keyboards:, internal_touchpad:)
|
18
|
-
@layer_manager = layer_manager # request to change layer
|
19
|
-
@keyboard_writer = keyboard_writer # write event to original keyboard
|
20
|
-
@source_keyboards = source_keyboards # original keyboard
|
21
|
-
@internal_touchpad = internal_touchpad # internal touchpad
|
22
|
-
@uinput = RuinputDevicePatched.new "/dev/uinput"
|
23
|
-
@pressed_virtual_keys = Set.new
|
24
|
-
end
|
25
|
-
|
26
|
-
def run
|
27
|
-
create_virtual_keyboard
|
28
|
-
set_trap
|
29
|
-
grab_keyboards
|
30
|
-
|
31
|
-
old_ie = nil
|
32
|
-
next_mapping = nil
|
33
|
-
current_mapping = {}
|
34
|
-
|
35
|
-
loop do
|
36
|
-
ios = IO.select([*@source_keyboards.map(&:file), @layer_manager.reader])
|
37
|
-
io = ios.first.first
|
38
|
-
|
39
|
-
if io == @layer_manager.reader
|
40
|
-
begin
|
41
|
-
@layer_manager.receive_layer
|
42
|
-
rescue EOFError
|
43
|
-
@destroy.call
|
44
|
-
end
|
45
|
-
|
46
|
-
MultiLogger.debug "Remapper#run: layer changed to #{@layer_manager.current_layer}"
|
47
|
-
next_mapping = @layer_manager.find_mapping
|
48
|
-
next
|
49
|
-
end
|
50
|
-
|
51
|
-
if next_mapping && virtual_keyboard_all_key_released?
|
52
|
-
if current_mapping != next_mapping
|
53
|
-
current_mapping = next_mapping
|
54
|
-
end
|
55
|
-
next_mapping = nil
|
56
|
-
end
|
57
|
-
|
58
|
-
input_event = @source_keyboards.find { |kbd| kbd.file == io }.read_input_event
|
59
|
-
input_key = find_key_from_code(input_event.code)
|
60
|
-
|
61
|
-
if input_event.type == EV_KEY
|
62
|
-
# FIXME: exit when RIGHTCTRL-LEFTCTRL is pressed
|
63
|
-
if (old_ie&.code == KEY_RIGHTCTRL && old_ie.value != 0) && (input_event.code == KEY_LEFTCTRL && input_event.value != 0)
|
64
|
-
@destroy.call
|
65
|
-
end
|
66
|
-
|
67
|
-
old_ie = input_event
|
68
|
-
if input_event.value != 2 # repeat
|
69
|
-
packed = {key: input_key, status: input_event.value}.to_msgpack
|
70
|
-
@keyboard_writer.puts(packed)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
remapped = current_mapping.fetch(input_key.to_sym, nil)
|
75
|
-
if remapped.nil?
|
76
|
-
@uinput.write_input_event(input_event)
|
77
|
-
next
|
78
|
-
end
|
79
|
-
|
80
|
-
remapped_event = InputEvent.new(nil, input_event.type, find_code_from_key(remapped), input_event.value)
|
81
|
-
|
82
|
-
# When Set.delete? fails, it means that the key was pressed before remapping started and was released.
|
83
|
-
unless record_virtual_keyboard_event?(remapped, remapped_event.value)
|
84
|
-
# set original key before remapping
|
85
|
-
remapped_event.code = input_event.code
|
86
|
-
end
|
87
|
-
|
88
|
-
# remap to command will be nil
|
89
|
-
# e.g) remap: { X: { command: echo 'foo' } }
|
90
|
-
# this is because the command will be executed by fusuma process
|
91
|
-
next if remapped_event.code.nil?
|
92
|
-
|
93
|
-
@uinput.write_input_event(remapped_event)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
# @param [Revdev::InputEvent] event
|
98
|
-
# @return [void]
|
99
|
-
def record_virtual_keyboard_event?(remapped_value, event_value)
|
100
|
-
case event_value
|
101
|
-
when 0
|
102
|
-
@pressed_virtual_keys.delete?(remapped_value)
|
103
|
-
when 1
|
104
|
-
@pressed_virtual_keys.add?(remapped_value)
|
105
|
-
else
|
106
|
-
# 2 is repeat
|
107
|
-
true
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
def virtual_keyboard_all_key_released?
|
112
|
-
@pressed_virtual_keys.empty?
|
113
|
-
end
|
114
|
-
|
115
|
-
def create_virtual_keyboard
|
116
|
-
@uinput.create "fusuma_virtual_keyboard",
|
117
|
-
Revdev::InputId.new(
|
118
|
-
# recognized as an internal keyboard on libinput,
|
119
|
-
# touchpad is disabled when typing
|
120
|
-
# see: (https://wayland.freedesktop.org/libinput/doc/latest/palm-detection.html#disable-while-typing)
|
121
|
-
{
|
122
|
-
bustype: Revdev::BUS_I8042,
|
123
|
-
vendor: @internal_touchpad.device_id.vendor,
|
124
|
-
product: @internal_touchpad.device_id.product,
|
125
|
-
version: @internal_touchpad.device_id.version
|
126
|
-
}
|
127
|
-
)
|
128
|
-
end
|
129
|
-
|
130
|
-
def grab_keyboards
|
131
|
-
@source_keyboards.each do |keyboard|
|
132
|
-
wait_release_all_keys(keyboard) && keyboard.grab
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
def set_trap
|
137
|
-
@destroy = lambda do
|
138
|
-
@source_keyboards.each do |kbd|
|
139
|
-
kbd.ungrab
|
140
|
-
rescue Errno::EINVAL
|
141
|
-
# already ungrabbed
|
142
|
-
end
|
143
|
-
|
144
|
-
begin
|
145
|
-
@uinput.destroy
|
146
|
-
rescue IOError
|
147
|
-
# already destroyed
|
148
|
-
end
|
149
|
-
|
150
|
-
exit 0
|
151
|
-
end
|
152
|
-
|
153
|
-
Signal.trap(:INT) { @destroy.call }
|
154
|
-
Signal.trap(:TERM) { @destroy.call }
|
155
|
-
end
|
156
|
-
|
157
|
-
# Find remappable key from mapping and return remapped key code
|
158
|
-
# If not found, return original key code
|
159
|
-
# If the key is found but its value is not valid, return nil
|
160
|
-
# @example
|
161
|
-
# find_remapped_code({ "A" => "b" }, 30) # => 48
|
162
|
-
# find_remapped_code({ "A" => "b" }, 100) # => 100
|
163
|
-
# find_remapped_code({ "A" => {command: 'echo foobar'} }, 30) # => nil
|
164
|
-
#
|
165
|
-
# @param [Hash] mapping
|
166
|
-
# @param [Integer] code
|
167
|
-
# @return [Integer, nil]
|
168
|
-
def find_remapped_code(mapping, code)
|
169
|
-
key = find_key_from_code(code) # key = "A"
|
170
|
-
remapped_key = mapping.fetch(key.to_sym, nil) # remapped_key = "b"
|
171
|
-
return code unless remapped_key # return original code if key is not found
|
172
|
-
|
173
|
-
find_code_from_key(remapped_key) # remapped_code = 48
|
174
|
-
end
|
175
|
-
|
176
|
-
# Find key name from key code
|
177
|
-
# @example
|
178
|
-
# find_key_from_code(30) # => "A"
|
179
|
-
# find_key_from_code(48) # => "B"
|
180
|
-
# @param [Integer] code
|
181
|
-
# @return [String]
|
182
|
-
def find_key_from_code(code)
|
183
|
-
# { 30 => :A, 48 => :B, ... }
|
184
|
-
@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
|
185
|
-
@keys_per_code[code]
|
186
|
-
end
|
187
|
-
|
188
|
-
# Find key code from key name (e.g. "A", "B", "BTN_LEFT")
|
189
|
-
# If key name is not found, return nil
|
190
|
-
# @example
|
191
|
-
# find_code_from_key("A") # => 30
|
192
|
-
# find_code_from_key("B") # => 48
|
193
|
-
# find_code_from_key("BTN_LEFT") # => 272
|
194
|
-
# find_code_from_key("NOT_FOUND") # => nil
|
195
|
-
# @param [String] key
|
196
|
-
# @return [Integer] when key is available
|
197
|
-
# @return [nil] when key is not available
|
198
|
-
def find_code_from_key(key)
|
199
|
-
# { KEY_A => 30, KEY_B => 48, ... }
|
200
|
-
@codes_per_key ||= Revdev.constants.select { |c| c.start_with?("KEY_", "BTN_") }.map { |c| [c, Revdev.const_get(c)] }.to_h
|
201
|
-
|
202
|
-
case key
|
203
|
-
when String
|
204
|
-
if key.start_with?("BTN_")
|
205
|
-
@codes_per_key[key.upcase.to_sym]
|
206
|
-
else
|
207
|
-
@codes_per_key["KEY_#{key}".upcase.to_sym]
|
208
|
-
end
|
209
|
-
when Integer
|
210
|
-
@codes_per_key["KEY_#{key}".upcase.to_sym]
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
def released_all_keys?(device)
|
215
|
-
# key status if all bytes are 0, the key is not pressed
|
216
|
-
bytes = device.read_ioctl_with(Revdev::EVIOCGKEY)
|
217
|
-
bytes.unpack("C*").all? { |byte| byte == 0 }
|
218
|
-
end
|
219
|
-
|
220
|
-
def wait_release_all_keys(device, &block)
|
221
|
-
loop do
|
222
|
-
if released_all_keys?(device)
|
223
|
-
break true
|
224
|
-
else
|
225
|
-
# wait until all keys are released
|
226
|
-
device.read_input_event
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
230
|
-
end
|
231
|
-
end
|
232
|
-
end
|
233
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
require "ruinput"
|
2
|
-
|
3
|
-
class RuinputDevicePatched < Ruinput::UinputDevice
|
4
|
-
include Ruinput
|
5
|
-
def set_all_events
|
6
|
-
raise "invalid method call: this uinput is already created" if @is_created
|
7
|
-
|
8
|
-
mouse_btns = [
|
9
|
-
Revdev::BTN_0,
|
10
|
-
Revdev::BTN_MISC,
|
11
|
-
Revdev::BTN_1,
|
12
|
-
Revdev::BTN_2,
|
13
|
-
Revdev::BTN_3,
|
14
|
-
Revdev::BTN_4,
|
15
|
-
Revdev::BTN_5,
|
16
|
-
Revdev::BTN_6,
|
17
|
-
Revdev::BTN_7,
|
18
|
-
Revdev::BTN_8,
|
19
|
-
Revdev::BTN_9,
|
20
|
-
Revdev::BTN_LEFT,
|
21
|
-
Revdev::BTN_MOUSE,
|
22
|
-
Revdev::BTN_MIDDLE,
|
23
|
-
Revdev::BTN_RIGHT
|
24
|
-
].freeze
|
25
|
-
|
26
|
-
keyboard_keys = Revdev.constants.select { |c| c.start_with? "KEY_" }.map { |c| Revdev.const_get(c) }.freeze
|
27
|
-
|
28
|
-
@file.ioctl UI_SET_EVBIT, Revdev::EV_KEY
|
29
|
-
(Revdev::KEY_RESERVED...Revdev::KEY_CNT).each do |n|
|
30
|
-
# https://github.com/mooz/xkeysnail/pull/101/files
|
31
|
-
next unless keyboard_keys.include?(n) || mouse_btns.include?(n)
|
32
|
-
|
33
|
-
@file.ioctl UI_SET_KEYBIT, n
|
34
|
-
end
|
35
|
-
|
36
|
-
# @file.ioctl UI_SET_EVBIT, Revdev::EV_MSC
|
37
|
-
# Revdev::MSC_CNT.times do |i|
|
38
|
-
# @file.ioctl UI_SET_MSCBIT, i
|
39
|
-
# end
|
40
|
-
|
41
|
-
# kernel bug: device has min == max on ABS_Y
|
42
|
-
# @file.ioctl UI_SET_EVBIT, Revdev::EV_ABS
|
43
|
-
# Revdev::ABS_CNT.times do |i|
|
44
|
-
# @file.ioctl UI_SET_ABSBIT, i
|
45
|
-
# end
|
46
|
-
|
47
|
-
@file.ioctl UI_SET_EVBIT, Revdev::EV_REP
|
48
|
-
end
|
49
|
-
end
|