fusuma-plugin-remap 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fb42159c757f56d2da9af424bfc088719bc22c965ad72bed52bc9bd81ad86e9f
4
- data.tar.gz: cdddfbf418ecb85c1ad0cd3991d04ca5f022833ce4b344b1e9e37594c6c82ae9
3
+ metadata.gz: bec502b65cb84aeaf03d897edfcbab0374570ccbd442b7707b6c9ace75b9fd9b
4
+ data.tar.gz: 72ba8b3567fd3cd6ced5557bbb2e61a71f688485283561dd8a080a493eeb5e53
5
5
  SHA512:
6
- metadata.gz: d8255feb9082b3f8e18962b8edfe73ba44ebb61d53f159ebeeadf6fda53ca796cbce18f100d4efdb8dcf3c8290920458c30ccffb924973b8a6a9eb0c855db555
7
- data.tar.gz: c24ca94224d7aadb892af07c62fe689ff74e07b38ff09cc0a15b6755d1aa3092a2255c553aff93f6c6c4401220456ec665776fd9eb5b57da3e102816929f9182
6
+ metadata.gz: '0787b15d69a53a2e1404ce927e630d900d34be8f33f94b18f85ad3198a437229cd06ac33c43d1826f1cc2a1c5a2c1b516c511a93c7356cbb40a8e78bb3b13357'
7
+ data.tar.gz: 7c8e9cf9b42d93b265f54e49fe66021b19ba80a1e944ec6d35d586704c6f6d88b894d6d473149d7d036af1f3affbf06cd7f4dcb2ea2f42bdb7f397792c042972
data/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # Fusuma::Plugin::Remap [![Gem Version](https://badge.fury.io/rb/fusuma-plugin-remap.svg)](https://badge.fury.io/rb/fusuma-plugin-remap) [![Build Status](https://github.com/iberianpig/fusuma-plugin-remap/actions/workflows/main.yml/badge.svg)](https://github.com/iberianpig/fusuma-plugin-remap/actions/workflows/main.yml)
2
2
 
3
- ## Installation
3
+ A Fusuma plugin for remapping keyboard events into virtual input devices. Compatible with other Fusuma plugins.
4
4
 
5
5
  **THIS PLUGIN IS EXPERIMENTAL.**
6
6
 
7
- A Fusuma plugin for remapping keyboard events into virtual input devices. Compatible with other Fusuma plugins.
8
-
9
7
  This plugin empowers users to manipulate keyboard events and convert them into virtual input devices. It is designed to integrate seamlessly with other Fusuma plugins, thus enabling users to construct sophisticated input configurations and achieve distinctive functionalities. A key feature is the dynamic alteration of remapping layers within the Fusuma process, thereby enabling users to adapt their keyboard inputs to suit specific tasks or applications.
10
8
 
9
+ ## Installation
10
+
11
11
  This plugin requires [fusuma](https://github.com/iberianpig/fusuma#update) 2.0
12
12
 
13
13
  ### Install dependencies
@@ -65,6 +65,13 @@ remap:
65
65
  SPACE: BTN_LEFT
66
66
  ```
67
67
 
68
+ ## Emergency stop keybind for virtual keyboard
69
+
70
+ This is a special keybind for emergency stop.
71
+ If you press following keybind, physical keyboard will be ungrabbed and Fusuma process will be terminated.
72
+
73
+ <kbd>RIGHTCTRL</kbd> → <kbd>LEFTCTRL</kbd>
74
+
68
75
  ## Contributing
69
76
 
70
77
  Bug reports and pull requests are welcome on GitHub at https://github.com/iberianpig/fusuma-plugin-remap. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
data/exe/fusuma-remap CHANGED
@@ -1,44 +1,93 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "fusuma/plugin/inputs/input"
5
+ require_relative "../lib/fusuma/plugin/inputs/remap_keyboard_input"
4
6
  require_relative "../lib/fusuma/plugin/remap/version"
5
- require_relative "../lib/fusuma/plugin/remap/remapper"
7
+ require_relative "../lib/fusuma/plugin/remap/keyboard_remapper"
6
8
  require_relative "../lib/fusuma/plugin/remap/layer_manager"
7
9
  require "fusuma/config"
8
- require "revdev"
10
+ require "fusuma/multi_logger"
9
11
  require "msgpack"
12
+ require "irb"
10
13
 
11
- include Revdev
14
+ Fusuma::MultiLogger.instance.debug_mode = true
15
+ Fusuma::Config.instance.custom_path = "~/.config/fusuma/config.yml"
12
16
 
13
- if ARGV.length > 1
14
- source_keyboards = [Revdev::EventDevice.new(ARGV.shift)]
15
- internal_touchpad = Revdev::EventDevice.new(ARGV.shift)
16
- else
17
- warn "Usage: #{$PROGRAM_NAME} /dev/input/KEYBOARD /dev/input/TOUCHPAD"
18
- exit false
17
+ # FIXME: use OptionParser and implement help
18
+ if ARGV.length < 1
19
+ puts "you can specify keyboard name pattern and touchpad name pattern"
20
+ puts "$ #{$PROGRAM_NAME} 'AT Translated Set 2 keyboard' 'SynPS/2 Synaptics TouchPad'"
19
21
  end
20
22
 
21
- Fusuma::Config.instance.custom_path = "~/.config/fusuma/config.yml"
23
+ keyboard_name_pattern ||= ARGV.shift || ["keyboard", "Keyboard", "KEYBOARD"]
24
+ touchpad_name_pattern ||= ARGV.shift || ["touchpad", "Touchpad", "TOUCHPAD"]
25
+
26
+ source_keyboards = Fusuma::Plugin::Inputs::RemapKeyboardInput::KeyboardSelector.new(keyboard_name_pattern).select
27
+ internal_touchpad = Fusuma::Plugin::Inputs::RemapKeyboardInput::TouchpadSelector.new(touchpad_name_pattern).select.first
28
+
29
+ if source_keyboards.empty?
30
+ warn "no keyboard found"
31
+ exit 1
32
+ end
33
+
34
+ if internal_touchpad.nil?
35
+ warn "no touchpad found"
36
+ exit 1
37
+ end
38
+
39
+ @layer_manager = Fusuma::Plugin::Remap::LayerManager.instance
22
40
 
23
- layer_manager = Fusuma::Plugin::Remap::LayerManager.instance
41
+ keyboard_reader, fusuma_writer = IO.pipe
24
42
 
25
- _keyboard_reader, keyboard_writer = IO.pipe
43
+ layers = Fusuma::Config.instance.keymap.select { |m| m[:context] && m[:remap] }.map { |m| m[:context] }.uniq
26
44
  Thread.new do
27
- layer_manager.send_layer(layer: {foo: "bar"})
28
- sleep 3
29
- layer_manager.send_layer(layer: {thumbsense: true})
30
- sleep 3
31
- layer_manager.send_layer(layer: {thumbsense: true}, remove: true)
32
-
33
- # u = MessagePack::Unpacker.new(keyboard_reader)
34
- # loop do
35
- # puts "unpack: #{u.unpack}"
36
- # end
45
+ layers.each do |layer|
46
+ @layer_manager.send_layer(layer: layer)
47
+ @layer_manager.send_layer(layer: layer, remove: true)
48
+ sleep 1
49
+ end
50
+
51
+ puts "=================================================="
52
+ puts "press key UP or DOWN to change layer"
53
+ puts "=================================================="
54
+
55
+ layer_selector = Fiber.new do
56
+ layers = ([{}] | layers)
57
+ @reverse = false
58
+ pos = 0
59
+ loop do
60
+ pos = if @reverse
61
+ (pos - 1) % layers.size
62
+ else
63
+ (pos + 1) % layers.size
64
+ end
65
+ @layer_manager.send_layer(layer: @layer_manager.current_layer, remove: true)
66
+ @layer_manager.send_layer(layer: layers[pos])
67
+ Fiber.yield
68
+ end
69
+ end
70
+
71
+ unpacker = MessagePack::Unpacker.new(keyboard_reader)
72
+ loop do
73
+ data = unpacker.unpack
74
+ next unless data.is_a? Hash
75
+ next unless data["status"] == 1
76
+
77
+ case data["key"]
78
+ when "UP"
79
+ @reverse = false
80
+ layer_selector.resume
81
+ when "DOWN"
82
+ @reverse = true
83
+ layer_selector.resume
84
+ end
85
+ end
37
86
  end
38
87
 
39
- Fusuma::Plugin::Remap::Remapper.new(
40
- layer_manager: layer_manager,
41
- keyboard_writer: keyboard_writer,
88
+ Fusuma::Plugin::Remap::KeyboardRemapper.new(
89
+ layer_manager: @layer_manager,
90
+ fusuma_writer: fusuma_writer,
42
91
  source_keyboards: source_keyboards,
43
92
  internal_touchpad: internal_touchpad
44
93
  ).run
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "fusuma/plugin/inputs/input"
5
+ require_relative "../lib/fusuma/plugin/inputs/remap_touchpad_input"
6
+ require_relative "../lib/fusuma/plugin/remap/version"
7
+ require_relative "../lib/fusuma/plugin/remap/touchpad_remapper"
8
+ require_relative "../lib/fusuma/plugin/remap/layer_manager"
9
+ require "fusuma/config"
10
+ require "fusuma/multi_logger"
11
+ require "revdev"
12
+ require "msgpack"
13
+ require "irb"
14
+
15
+ Fusuma::MultiLogger.instance.debug_mode = true
16
+ Fusuma::Config.instance.custom_path = "~/.config/fusuma/config.yml"
17
+
18
+ touchpad_name_pattern = ["touchpad", "Touchpad", "TOUCHPAD"]
19
+
20
+ # $DEBUG=true # puts events
21
+
22
+ internal_touchpad = Fusuma::Plugin::Inputs::RemapKeyboardInput::TouchpadSelector.new(touchpad_name_pattern).select.first
23
+
24
+ if internal_touchpad.nil?
25
+ warn "no touchpad found"
26
+ exit 1
27
+ end
28
+
29
+ touchpad_reader, touchpad_writer = IO.pipe
30
+
31
+ Thread.new do
32
+ unpacker = MessagePack::Unpacker.new(touchpad_reader)
33
+ loop do
34
+ data = unpacker.unpack
35
+ puts data
36
+ end
37
+ end
38
+
39
+ Fusuma::Plugin::Remap::TouchpadRemapper.new(
40
+ touchpad_writer: touchpad_writer,
41
+ source_touchpad: internal_touchpad
42
+ ).run
@@ -24,8 +24,8 @@ Gem::Specification.new do |spec|
24
24
  # https://packages.ubuntu.com/search?keywords=ruby&searchon=names&exact=1&suite=all&section=main
25
25
  # support focal (20.04LTS) 2.7
26
26
 
27
- spec.add_dependency "fusuma", ">= 3.1"
28
- spec.add_dependency "fusuma-plugin-keypress", "~> 0.5"
27
+ spec.add_dependency "fusuma", ">= 3.4"
28
+ spec.add_dependency "fusuma-plugin-keypress", ">= 0.11.0"
29
29
  spec.add_dependency "msgpack"
30
30
  spec.add_dependency "revdev"
31
31
  spec.add_dependency "ruinput"
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "fusuma/device"
4
- require "fusuma/plugin/remap/remapper"
5
- require "fusuma/plugin/remap/layer_manager"
4
+ require_relative "../remap/keyboard_remapper"
5
+ require_relative "../remap/layer_manager"
6
6
 
7
7
  module Fusuma
8
8
  module Plugin
@@ -26,84 +26,46 @@ module Fusuma
26
26
  end
27
27
 
28
28
  def io
29
- @keyboard_reader
29
+ @fusuma_reader
30
30
  end
31
31
 
32
- # @param record [String]
33
- # @return [Event]
34
- def create_event(record:)
35
- data = MessagePack.unpack(record) # => {"key"=>"J", "status"=>1}
32
+ # override Input#read_from_io
33
+ # @return [Record]
34
+ def read_from_io
35
+ @unpacker ||= MessagePack::Unpacker.new(io)
36
+ data = @unpacker.unpack
36
37
 
37
- unless data.is_a? Hash
38
- MultiLogger.error("Invalid record: #{record}", data: data)
39
- return
40
- end
38
+ raise "data is not Hash : #{data}" unless data.is_a? Hash
41
39
 
42
- code = data["key"]
43
40
  status = (data["status"] == 1) ? "pressed" : "released"
44
- record = Events::Records::KeypressRecord.new(status: status, code: code)
45
-
46
- e = Events::Event.new(tag: tag, record: record)
47
- MultiLogger.debug(input_event: e)
48
- e
41
+ Events::Records::KeypressRecord.new(status: status, code: data["key"], layer: data["layer"])
49
42
  end
50
43
 
51
44
  private
52
45
 
53
46
  def setup_remapper
54
- source_keyboards = KeyboardSelector.new(config_params(:keyboard_name_patterns)).select
55
- internal_touchpad = TouchpadSelector.new(config_params(:touchpad_name_patterns)).select.first
56
- MultiLogger.info(source_keyboards: source_keyboards.map(&:device_name), internal_touchpad: internal_touchpad.device_name)
47
+ config = {
48
+ keyboard_name_patterns: config_params(:keyboard_name_patterns),
49
+ touchpad_name_patterns: config_params(:touchpad_name_patterns)
50
+ }
57
51
 
58
52
  layer_manager = Remap::LayerManager.instance
59
53
 
60
54
  # physical keyboard input event
61
- @keyboard_reader, keyboard_writer = IO.pipe
55
+ @fusuma_reader, fusuma_writer = IO.pipe
62
56
 
63
57
  @pid = fork do
64
58
  layer_manager.writer.close
65
- @keyboard_reader.close
66
- remapper = Remap::Remapper.new(
59
+ @fusuma_reader.close
60
+ remapper = Remap::KeyboardRemapper.new(
67
61
  layer_manager: layer_manager,
68
- source_keyboards: source_keyboards,
69
- keyboard_writer: keyboard_writer,
70
- internal_touchpad: internal_touchpad
62
+ fusuma_writer: fusuma_writer,
63
+ config: config
71
64
  )
72
65
  remapper.run
73
66
  end
74
67
  layer_manager.reader.close
75
- keyboard_writer.close
76
- end
77
-
78
- # Devices to detect key presses and releases
79
- class KeyboardSelector
80
- def initialize(names = ["keyboard", "Keyboard", "KEYBOARD"])
81
- @names = names
82
- end
83
-
84
- # @return [Array<Revdev::EventDevice>]
85
- def select
86
- devices = Fusuma::Device.all.select { |d| Array(@names).any? { |name| d.name =~ /#{name}/ } }
87
- devices.map { |d| Revdev::EventDevice.new("/dev/input/#{d.id}") }
88
- end
89
- end
90
-
91
- class TouchpadSelector
92
- def initialize(names)
93
- @names = names
94
- end
95
-
96
- # @return [Array<Revdev::EventDevice>]
97
- def select
98
- devices = if @names
99
- Fusuma::Device.all.select { |d| Array(@names).any? { |name| d.name =~ /#{name}/ } }
100
- else
101
- # available returns only touchpad devices
102
- Fusuma::Device.available
103
- end
104
-
105
- devices.map { |d| Revdev::EventDevice.new("/dev/input/#{d.id}") }
106
- end
68
+ fusuma_writer.close
107
69
  end
108
70
  end
109
71
  end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fusuma/device"
4
+ require_relative "../remap/touchpad_remapper"
5
+ # require_relative "../remap/layer_manager"
6
+
7
+ module Fusuma
8
+ module Plugin
9
+ module Inputs
10
+ # Get touchpad events from remapper
11
+ class RemapTouchpadInput < Input
12
+ include CustomProcess
13
+
14
+ def config_param_types
15
+ {
16
+ touchpad_name_patterns: [Array, String]
17
+ }
18
+ end
19
+
20
+ attr_reader :pid
21
+
22
+ def initialize
23
+ super
24
+ setup_remapper
25
+ end
26
+
27
+ def io
28
+ @fusuma_reader
29
+ end
30
+
31
+ # override Input#read_from_io
32
+ # @return [Record]
33
+ def read_from_io
34
+ @unpacker ||= MessagePack::Unpacker.new(io)
35
+ data = @unpacker.unpack
36
+
37
+ raise "data is not Hash : #{data}" unless data.is_a? Hash
38
+
39
+ gesture = "touch"
40
+ finger = data["finger"]
41
+
42
+ # @touch_state ||= {}
43
+ # @mt_slot ||= 0
44
+ # @touch_state[@mt_slot] ||= {
45
+ # MT_TRACKING_ID: nil,
46
+ # X: nil,
47
+ # Y: nil,
48
+ # valid_touch_point: false
49
+ # }
50
+ # TODO: implement update touch_state
51
+ status =
52
+ if data["touch_state"].any? { |_, v| v["valid_touch_point"] }
53
+ "begin"
54
+ else
55
+ "end"
56
+ end
57
+
58
+ Events::Records::GestureRecord.new(gesture: gesture, status: status, finger: finger, delta: nil)
59
+ end
60
+
61
+ private
62
+
63
+ def setup_remapper
64
+ internal_touchpad = TouchpadSelector.new(config_params(:touchpad_name_patterns)).select.first
65
+ if internal_touchpad.nil?
66
+ MultiLogger.error("No touchpad found: #{config_params(:touchpad_name_patterns)}")
67
+ exit
68
+ end
69
+
70
+ MultiLogger.info("set up remapper")
71
+ MultiLogger.info("internal_touchpad: #{internal_touchpad.device_name}")
72
+
73
+ # layer_manager = Remap::LayerManager.instance
74
+
75
+ # physical touchpad input event
76
+ @fusuma_reader, fusuma_writer = IO.pipe
77
+
78
+ @pid = fork do
79
+ # layer_manager.writer.close
80
+ @fusuma_reader.close
81
+ remapper = Remap::TouchpadRemapper.new(
82
+ # layer_manager: layer_manager,
83
+ fusuma_writer: fusuma_writer,
84
+ source_touchpad: internal_touchpad
85
+ )
86
+ remapper.run
87
+ end
88
+ # layer_manager.reader.close
89
+ fusuma_writer.close
90
+ end
91
+
92
+ class TouchpadSelector
93
+ def initialize(names = nil)
94
+ @names = names
95
+ end
96
+
97
+ # @return [Array<Revdev::EventDevice>]
98
+ def select
99
+ devices = if @names
100
+ Fusuma::Device.all.select { |d| Array(@names).any? { |name| d.name =~ /#{name}/ } }
101
+ else
102
+ # available returns only touchpad devices
103
+ Fusuma::Device.available
104
+ end
105
+
106
+ devices.map { |d| Revdev::EventDevice.new("/dev/input/#{d.id}") }
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,4 @@
1
+ plugin:
2
+ inputs:
3
+ remap_touchpad_input:
4
+ touchpad_name_patterns: ["touchpad", "Touchpad", "TOUCHPAD"]