fusuma-plugin-thumbsense 0.7.0 → 0.8.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: 30004fbb68724dafdc6cdafc0b8ab756ed1f3104c505327adb2a4435617c6400
4
- data.tar.gz: bbdd89545b405e673e87e61cae5c9fb3052c4b8a788c28e889664618cbd95a4b
3
+ metadata.gz: 1bdd2539bacc9ce3db7375ce445affc2a22fcadfc5a7849243737c8fe028911e
4
+ data.tar.gz: 4b4b1e40b305ef98b032ae186828dbd69b50fb8d82e978fb02d7a2540f8da517
5
5
  SHA512:
6
- metadata.gz: af54a3831c6b69e9449efde47bad16be777902eaf65492edd7cf2291cbfc30202b16cbe63e5632707f253ff5eb445ed3a54654618a409783629ae3168547bfde
7
- data.tar.gz: afdb2ed48a5f1629875a77c282606c0460a7dc6664561ffb4b12e2d947281a0988d2c2af78ad662818c85a14f12f128130bc8c853beaf68cf484f6e99bb1f1fb
6
+ metadata.gz: e69801eb4e32d544bf7ba7a322b9204683211372e94ef36375e1c2c70a730254638da594fcbf3e13b4c31a7d3a9cba64a25ef3b086696e44bf1dbccb5b145724
7
+ data.tar.gz: 16d973013a91adc273687a849f48915c6acff2d3bff72ed97aaf44e7b89328051d32c32e1e0a2fb514453cdda80b0989df12bbe039df3209bd69d3d659780e1b
data/README.md CHANGED
@@ -17,40 +17,93 @@ Implemented as [Fusuma](https://github.com/iberianpig/fusuma) Plugin.
17
17
  - fusuma-plugin-keypress is used to get keyboard input and is installed automatically.
18
18
  - [fusuma-plugin-remap](https://github.com/iberianpig/fusuma-plugin-remap)
19
19
  - You need to set up udev rules for creating a virtual input device.
20
+ - fusuma-plugin-remap is installed automatically.
20
21
  - Please refer to [fusuma-plugin-remap's README](https://github.com/iberianpig/fusuma-plugin-remap?tab=readme-ov-file#set-up-udev-rules) for details.
21
22
 
22
- ### Install fusuma-plugin-thumbsense
23
+ ### Install and set up fusuma-plugin-thumbsense
23
24
 
24
25
  Run the following code in your terminal.
25
26
 
27
+ #### Install ruby-dev and build-essential for installing native extension
28
+ ```sh
29
+ $ sudo apt install ruby-dev build-essential
30
+ ```
31
+
32
+ #### Install libevdev-dev for building fusuma-plugin-remap
33
+ ```sh
34
+ $ sudo apt install libevdev-dev
35
+ ```
36
+
37
+ #### set up udev rules for creating a virtual input device (fusuma-plugin-remap)
38
+ ```sh
39
+ $ echo 'KERNEL=="uinput", MODE="0660", GROUP="input", OPTIONS+="static_node=uinput"' | sudo tee /etc/udev/rules.d/60-udev-fusuma-remap.rules
40
+ $ sudo udevadm control --reload-rules && sudo udevadm trigger
41
+ ```
42
+
43
+
44
+ #### Install fusuma-plugin-thumbsense
26
45
  ```sh
27
46
  $ sudo gem install fusuma-plugin-thumbsense
28
47
  ```
29
48
 
30
49
  ## Properties
31
50
 
32
- ### Thumbsense
51
+ ### Thumbsense context
52
+
53
+ First, add the thumbsense `context` to `~/.config/fusuma/config.yml`.
54
+ The `context` is separated by `---` and specified by `context: thumbsense`.
55
+ Fusuma will switch to the `thumbsense` context while tapping the touchpad.
56
+
57
+ ### Remap key to mouse button
33
58
 
34
- First, add the `thumbsense` context to `~/.config/fusuma/config.yml`.
35
- The context is separated by `---` and specified by `context: thumbsense`.
59
+ You can remap keys to mouse buttons while tapping the touchpad.
60
+ The `remap` property is specified in the `thumbsense` context.
61
+
62
+ Available mouse buttons are:
63
+
64
+ - `BTN_LEFT`
65
+ - `BTN_MIDDLE`
66
+ - `BTN_RIGHT`
67
+ - `BTN_SIDE`
68
+ - `BTN_EXTRA`
69
+ - `BTN_FORWARD`
70
+ - `BTN_BACK`
71
+ - `BTN_TASK`
72
+ - `BTN_0`
73
+ - `BTN_1`
74
+ - ...
75
+ - `BTN_9`
36
76
 
37
77
  ## Example
38
78
 
39
79
  Set the following code in `~/.config/fusuma/config.yml`.
40
80
 
41
81
  ```yaml
82
+ # add thumbsense context
83
+
42
84
  ---
43
85
  context: thumbsense
44
86
 
45
87
  remap:
88
+ F: BTN_LEFT
89
+ E: BTN_MIDDLE
90
+ D: BTN_RIGHT
91
+ SPACE: BTN_LEFT
46
92
  J: BTN_LEFT
47
93
  K: BTN_RIGHT
48
94
  ```
49
95
 
50
- ### TODO
96
+ ## TODO
97
+
98
+ - thumbsense
99
+ - [x] change layer of remap while tapping
100
+ - [ ] make it possible to execute executor like `command:` `sendkey:`
51
101
 
52
- - Using the fusuma-plugin-sendkey to emulate mouse buttons
53
- - Creating a simple key remapper using evdev and uinput to prevent the pressing of J/K keys on the physical keyboard from being sent.
102
+ - remap
103
+ - [x] remap to single key like `remap: { J: BTN_LEFT }`
104
+ - [x] send BTN_LEFT/BTN_MIDDLE/BTN_RIGHT click `remap: { I: BTN_MIDDLE }`
105
+ - [ ] remap multiple keys like `remap: { H: LEFTCTRL+TAB }`
106
+ - [ ] remap POINTER_MOTION to POINTER_SCROLL_FINGER `remap: { S: POINTER_SCROLL_FINGER }`
54
107
 
55
108
  ## Contributing
56
109
 
@@ -25,8 +25,8 @@ Gem::Specification.new do |spec|
25
25
  # https://packages.ubuntu.com/search?keywords=ruby&searchon=names&exact=1&suite=all&section=main
26
26
  # support focal (20.04LTS) 2.7
27
27
  spec.add_dependency "fusuma", ">= 3.2"
28
- spec.add_dependency "fusuma-plugin-keypress", ">= 0.5"
29
- spec.add_dependency "fusuma-plugin-remap"
28
+ spec.add_dependency "fusuma-plugin-keypress", ">= 0.11"
29
+ spec.add_dependency "fusuma-plugin-remap", ">= 0.4"
30
30
  spec.metadata = {
31
31
  "rubygems_mfa_required" => "true"
32
32
  }
@@ -5,7 +5,7 @@ module Fusuma
5
5
  module Buffers
6
6
  # manage events and generate command
7
7
  class ThumbsenseBuffer < Buffer
8
- DEFAULT_SOURCE = "thumbsense_parser"
8
+ DEFAULT_SOURCE = "remap_touchpad_input"
9
9
 
10
10
  def config_param_types
11
11
  {
@@ -20,8 +20,7 @@ module Fusuma
20
20
  # skip palm/begin record
21
21
  return if !ended?(@events.last)
22
22
 
23
- released_finger = @events.last.record.finger
24
- @events.delete_if { |e| e.record.finger == released_finger }
23
+ clear
25
24
  end
26
25
 
27
26
  # @param event [Event]
@@ -0,0 +1,4 @@
1
+ plugin:
2
+ buffers:
3
+ thumbsense_buffer:
4
+ source: remap_touchpad_input
@@ -10,8 +10,8 @@ module Fusuma
10
10
  module Detectors
11
11
  # Detect Thumbsense context and change remap layer of fusuma-plugin-remap
12
12
  class ThumbsenseDetector < Detector
13
+ # keypress buffer is used to detect modifier keys
13
14
  SOURCES = %w[thumbsense keypress].freeze
14
- BUFFER_TYPE = "thumbsense"
15
15
 
16
16
  MODIFIER_KEYS = Set.new(%w[
17
17
  CAPSLOCK
@@ -28,51 +28,74 @@ module Fusuma
28
28
  LAYER_CONTEXT = {thumbsense: true}.freeze
29
29
 
30
30
  # Detect Context event and change remap layer of fusuma-plugin-remap
31
- # @param buffers [Array<Buffer>]
31
+ # @param buffers [Array<Buffer>] ThumbsenseBuffer, KeypressBuffer
32
32
  # @return [Event] if Thumbsense context is detected
33
+ # @return [Array<Event>] if Thumbsense context and Remap index when keypress is detected
33
34
  # @return [NilClass] if event is NOT detected
34
35
  def detect(buffers)
35
- thumbsense_buffer = buffers.find { |b| b.type == BUFFER_TYPE }
36
-
37
- return if thumbsense_buffer.empty?
38
-
39
- MultiLogger.debug("thumbsense_buffer: #{thumbsense_buffer.events.map(&:record).map { |r| "#{r.finger} #{r.gesture} #{r.status}" }}")
36
+ @thumbsense_buffer ||= find_buffer(buffers, "thumbsense")
37
+ @keypress_buffer ||= find_buffer(buffers, "keypress")
40
38
 
41
39
  layer_manager = Fusuma::Plugin::Remap::LayerManager.instance
42
40
 
43
- if touch_released?(thumbsense_buffer)
41
+ # layer is thumbsense => create thumbsense context and remap index
42
+ # touch is touching => create thumbsense context and remap index
43
+ # touch is released => remove thumbsense context
44
+ # keypress -> touch => remove thumbsense context
45
+ if touch_released? && !thumbsense_layer?
46
+ MultiLogger.debug("thumbsense layer removed")
44
47
  layer_manager.send_layer(layer: LAYER_CONTEXT, remove: true)
45
48
  return
46
49
  end
47
50
 
48
- keypress_buffer = buffers.find { |b| b.type == "keypress" }
51
+ # When keypress event is first:
52
+ # If current layer is thumbsense, the layer should not be changed
53
+ # If current layer is not thumbsense, it should remain a normal key
54
+ # In other words, if the key event comes first, do nothing
55
+ if keypress_first?
56
+ MultiLogger.debug("keypress event is first")
49
57
 
50
- # If only modifier keys are pressed or no key is pressed
51
- if pressed_codes(keypress_buffer).all? { |code| MODIFIER_KEYS.include?(code) }
52
-
53
- # Even if the palm is detected, keep the thumbsense layer until `:end` event
54
- if palm_detected?(thumbsense_buffer)
55
- layer_manager.send_layer(layer: LAYER_CONTEXT, remove: true)
56
- return
57
- end
58
+ return
59
+ end
58
60
 
59
- layer_manager.send_layer(layer: LAYER_CONTEXT)
61
+ MultiLogger.debug("thumbsense context created") unless thumbsense_layer?
62
+ layer_manager.send_layer(layer: LAYER_CONTEXT)
60
63
 
61
- # create thumbsense context
62
- record = Events::Records::ContextRecord.new(
64
+ # create thumbsense context
65
+ context = create_event(
66
+ record: Events::Records::ContextRecord.new(
63
67
  name: :thumbsense,
64
68
  value: true
65
69
  )
66
- return create_event(record: record)
70
+ )
71
+
72
+ # TODO: Threshold
73
+ # create remap index
74
+ index = if (keys = pressed_codes) && !keys.empty?
75
+ MultiLogger.debug("thumbsense remap index created: #{keys}")
76
+ combined_keys = keys.join("+")
77
+ create_event(
78
+ record: Events::Records::IndexRecord.new(
79
+ index: Config::Index.new([:remap, combined_keys])
80
+ )
81
+ )
67
82
  end
68
83
 
69
- nil
84
+ [context, index].compact
70
85
  end
71
86
 
72
87
  private
73
88
 
74
- def pressed_codes(keypress_buffer)
75
- records = keypress_buffer.events.map(&:record)
89
+ # @param buffers [Array<Buffer>]
90
+ # @param type [String]
91
+ # @return [Buffer]
92
+ def find_buffer(buffers, type)
93
+ buffers.find { |b| b.type == type }
94
+ end
95
+
96
+ # @return [Array<String>]
97
+ def pressed_codes
98
+ records = @keypress_buffer.events.map(&:record)
76
99
  codes = []
77
100
  records.each do |r|
78
101
  if r.status == "pressed"
@@ -84,45 +107,43 @@ module Fusuma
84
107
  codes
85
108
  end
86
109
 
87
- def touching?(thumbsense_buffer)
88
- !touch_released?(thumbsense_buffer)
110
+ # @return [TrueClass, FalseClass]
111
+ def touching?
112
+ !touch_released?(@thumbsense_buffer)
89
113
  end
90
114
 
91
115
  # @return [TrueClass, FalseClass]
92
- def touch_released?(thumbsense_buffer)
93
- thumbsense_events = thumbsense_buffer.events
94
- touch_num = thumbsense_events.count { |e| (e.record.status == "begin") }
95
- release_num = thumbsense_events.count { |e| e.record.status == "end" }
116
+ def touch_released?
117
+ return true if @thumbsense_buffer.empty?
96
118
 
97
- touch_num <= release_num
119
+ @thumbsense_buffer.events.map(&:record).last&.status == "end"
98
120
  end
99
121
 
100
- # Detect palm, except when there is another touch
101
- # @param thumbsense_buffer [Buffer]
102
122
  # @return [TrueClass, FalseClass]
103
- def palm_detected?(thumbsense_buffer)
104
- # finger is a number to distinguish different touches and palms
105
- # If the count remains, it is judged as a touch state
106
- touch_state_per_finger = {}
107
- thumbsense_buffer.events.each do |e|
108
- f = e.record.finger
109
- touch_state_per_finger[f] ||= 0
110
-
111
- case e.record.status
112
- when "begin"
113
- touch_state_per_finger[f] += 1
114
- when "palm"
115
- if touch_state_per_finger[f] < 0
116
- # NOTE: If Palm continues, it is equivalent to end
117
- touch_state_per_finger[f] = 0
118
- else
119
- touch_state_per_finger[f] -= 1
120
- end
121
- when "end"
122
- touch_state_per_finger[f] = 0
123
- end
123
+ def thumbsense_layer?
124
+ return if @keypress_buffer.empty?
125
+
126
+ last_keypress = @keypress_buffer.events.last.record
127
+ return if last_keypress.status == "released"
128
+
129
+ current_layer = last_keypress&.layer
130
+ current_layer && current_layer["thumbsense"]
131
+ end
132
+
133
+ # Check if keypress event is first, before thumbsense event
134
+ # If last keypress event is modifier key, return false
135
+ # @param keypress_buffer [Buffer]
136
+ # @param thumbsense_buffer [Buffer]
137
+ # @return [TrueClass] if keypress event is first
138
+ # @return [FalseClass] if keypress event is NOT first or buffers are empty
139
+ def keypress_first?
140
+ return false if @thumbsense_buffer.empty? || @keypress_buffer.empty?
141
+
142
+ if (keys = pressed_codes) && !keys.empty?
143
+ return false if MODIFIER_KEYS.include?(keys.first)
124
144
  end
125
- touch_state_per_finger.values.all? { |count| count <= 0 }
145
+
146
+ @keypress_buffer.events.first.time < @thumbsense_buffer.events.first.time
126
147
  end
127
148
  end
128
149
  end
@@ -3,7 +3,7 @@
3
3
  module Fusuma
4
4
  module Plugin
5
5
  module Thumbsense
6
- VERSION = "0.7.0"
6
+ VERSION = "0.8.0"
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-thumbsense
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - iberianpig
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-09-24 00:00:00.000000000 Z
11
+ date: 2024-04-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fusuma
@@ -30,28 +30,28 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0.5'
33
+ version: '0.11'
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: '0.5'
40
+ version: '0.11'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: fusuma-plugin-remap
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: '0.4'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: '0.4'
55
55
  description: fusuma-plugin-thumbsense is Fusuma plugin for thumbsense.
56
56
  email:
57
57
  - yhkyky@gmail.com
@@ -65,10 +65,8 @@ files:
65
65
  - bin/setup
66
66
  - fusuma-plugin-thumbsense.gemspec
67
67
  - lib/fusuma/plugin/buffers/thumbsense_buffer.rb
68
+ - lib/fusuma/plugin/buffers/thumbsense_buffer.yml
68
69
  - lib/fusuma/plugin/detectors/thumbsense_detector.rb
69
- - lib/fusuma/plugin/filters/thumbsense_filter.rb
70
- - lib/fusuma/plugin/filters/thumbsense_filter.yml
71
- - lib/fusuma/plugin/parsers/thumbsense_parser.rb
72
70
  - lib/fusuma/plugin/thumbsense.rb
73
71
  - lib/fusuma/plugin/thumbsense/version.rb
74
72
  homepage: https://github.com/iberianpig/fusuma-plugin-thumbsense
@@ -91,7 +89,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
91
89
  - !ruby/object:Gem::Version
92
90
  version: '0'
93
91
  requirements: []
94
- rubygems_version: 3.4.10
92
+ rubygems_version: 3.4.19
95
93
  signing_key:
96
94
  specification_version: 4
97
95
  summary: Thumbsense plugin for Fusuma
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "fusuma/device"
4
-
5
- module Fusuma
6
- module Plugin
7
- module Filters
8
- # Filter keyboard events from libinput_command_input
9
- class ThumbsenseFilter < Filter
10
- DEFAULT_SOURCE = "libinput_command_input"
11
-
12
- # @return [TrueClass] when keeping it
13
- # @return [FalseClass] when discarding it
14
- def keep?(record)
15
- case record.to_s
16
- when %r{\sevent\d+\s+-\sbutton state: touch (?<finger>[[:digit:]])}
17
- true
18
- when %r{\sevent\d+\s+-\spalm: touch (?<finger>[[:digit:]])}
19
- true
20
- else
21
- false
22
- end
23
- end
24
- end
25
- end
26
- end
27
- end
@@ -1,5 +0,0 @@
1
- plugin:
2
- inputs:
3
- libinput_command_input:
4
- verbose: true
5
- disable-dwt: true
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # require 'fusuma/plugin/parsers/parser.rb'
4
- # require 'fusuma/plugin/events/event.rb'
5
-
6
- module Fusuma
7
- module Plugin
8
- module Parsers
9
- # parse libinput and generate event
10
- class ThumbsenseParser < Parser
11
- DEFAULT_SOURCE = "libinput_command_input"
12
-
13
- # ... event7 - button state: touch 3 from BUTTON_STATE_AREA event BUTTON_EVENT_UP to BUTTON_STATE_NONE
14
- # 10766: event7 - button state: touch 1 from BUTTON_STATE_AREA event BUTTON_EVENT_UP to BUTTON_STATE_NONE
15
- # 10768: event7 - button state: touch 0 from BUTTON_STATE_AREA event BUTTON_EVENT_UP to BUTTON_STATE_NONE
16
-
17
- # @param record [String]
18
- # @return [Records::Gesture, nil]
19
- def parse_record(record)
20
- gesture = "touch"
21
-
22
- case record.to_s
23
-
24
- # touched
25
- when %r{\sevent\d+\s+-\sbutton state: touch (?<finger>[[:digit:]]) from BUTTON_STATE_NONE}
26
- status = "begin"
27
- finger = $~[:finger].to_i + 1
28
- # released
29
- when %r{\sevent\d+\s+-\sbutton state: touch (?<finger>[[:digit:]]) .* to BUTTON_STATE_NONE}
30
- status = "end"
31
- finger = $~[:finger].to_i + 1
32
-
33
- # palm
34
- when %r{\sevent\d+\s+-\spalm: touch (?<finger>[[:digit:]]) .*}
35
- status = "palm"
36
- finger = $~[:finger].to_i + 1
37
- else
38
- return
39
- end
40
-
41
- Events::Records::GestureRecord.new(status: status, gesture: gesture, finger: finger, delta: nil)
42
- end
43
-
44
- def tag
45
- "thumbsense_parser"
46
- end
47
- end
48
- end
49
- end
50
- end