fusuma 0.9.2 → 0.10.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
- data/.reek.yml +48 -0
- data/README.md +10 -2
- data/fusuma.gemspec +1 -1
- data/lib/fusuma.rb +11 -9
- data/lib/fusuma/command_executor.rb +34 -0
- data/lib/fusuma/config.rb +34 -26
- data/lib/fusuma/event_stack.rb +87 -0
- data/lib/fusuma/{gesture_action.rb → gesture_event.rb} +14 -14
- data/lib/fusuma/libinput_commands.rb +1 -0
- data/lib/fusuma/pinch.rb +14 -11
- data/lib/fusuma/swipe.rb +17 -13
- data/lib/fusuma/version.rb +1 -1
- metadata +8 -6
- data/ISSUE_TEMPLATE.md +0 -37
- data/lib/fusuma/action_stack.rb +0 -97
- data/lib/fusuma/event_trigger.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 22f6d4a9eb59ada95b2021e8b76b589ec6897cad
|
4
|
+
data.tar.gz: 7a2bb9add47630c73242f701f0cf80c19315b9bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cff32b3422a740ce8c68cc87db2ac73698cabc01218cfb137d694db5a96cd0bae1b59cf0e362c149e0afa5048b10497dae9c9fae1ab7df5003d2f673e1f6fdd4
|
7
|
+
data.tar.gz: b8f42fdb9cb09d972914f43c0eb0dfaaa64f0516591303c3b6ea62c096783e98606888a22e57dbf113b9ab074161e7c5d5b8385473b9fd074624b4989d74e74b
|
@@ -0,0 +1,32 @@
|
|
1
|
+
---
|
2
|
+
name: Bug report
|
3
|
+
about: Create a report to help us improve
|
4
|
+
|
5
|
+
---
|
6
|
+
|
7
|
+
<!--
|
8
|
+
Before create a report, please check below,
|
9
|
+
* Read Documents. https://github.com/iberianpig/fusuma#installation
|
10
|
+
* Checked that `libinput-debug-events` or `libinput debug-events` worked correctly.
|
11
|
+
* Reproduced the problem in latest version. Update fusuma with `gem update fusuma`
|
12
|
+
* Checked that your issue isn't already filed: https://github.com/iberianpig/fusuma/issues
|
13
|
+
-->
|
14
|
+
|
15
|
+
**Describe the bug**
|
16
|
+
A clear and concise description of what the bug is.
|
17
|
+
|
18
|
+
**To Reproduce**
|
19
|
+
Steps to reproduce the behavior:
|
20
|
+
1. [First Step]
|
21
|
+
2. [Second Step]
|
22
|
+
3. [and so on...]
|
23
|
+
|
24
|
+
**Expected behavior**
|
25
|
+
A clear and concise description of what you expected to happen.
|
26
|
+
|
27
|
+
**Versions**
|
28
|
+
You can get this information from copy and paste the output of `fusuma --version` from the command line. Also, please include the OS and what version of the OS you're running.
|
29
|
+
|
30
|
+
|
31
|
+
**Additional context**
|
32
|
+
Any additional context, your `~/.config/fusuma/config.yml` or data that might be necessary to reproduce the issue.
|
@@ -0,0 +1,17 @@
|
|
1
|
+
---
|
2
|
+
name: Feature request
|
3
|
+
about: Suggest an idea for this project
|
4
|
+
|
5
|
+
---
|
6
|
+
|
7
|
+
**Is your feature request related to a problem? Please describe.**
|
8
|
+
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
9
|
+
|
10
|
+
**Describe the solution you'd like**
|
11
|
+
A clear and concise description of what you want to happen.
|
12
|
+
|
13
|
+
**Describe alternatives you've considered**
|
14
|
+
A clear and concise description of any alternative solutions or features you've considered.
|
15
|
+
|
16
|
+
**Additional context**
|
17
|
+
Add any other context about the feature request here.
|
data/.reek.yml
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
---
|
2
|
+
|
3
|
+
### Generic smell configuration
|
4
|
+
|
5
|
+
detectors:
|
6
|
+
# # You can disable smells completely
|
7
|
+
# IrresponsibleModule:
|
8
|
+
# enabled: false
|
9
|
+
UncommunicativeVariableName:
|
10
|
+
enabled: false
|
11
|
+
|
12
|
+
#
|
13
|
+
# # You can use filters to silence Reek warnings.
|
14
|
+
# # Either because you simply disagree with Reek (we are not the police) or
|
15
|
+
# # because you want to fix this at a later point in time.
|
16
|
+
# NestedIterators:
|
17
|
+
# exclude:
|
18
|
+
# - "MyWorker#self.class_method" # should be refactored
|
19
|
+
# - "AnotherWorker#instance_method" # should be refactored as well
|
20
|
+
#
|
21
|
+
# # A lot of smells allow fine tuning their configuration. You can look up all available options
|
22
|
+
# # in the corresponding smell documentation in /docs. In most cases you probably can just go
|
23
|
+
# # with the defaults as documented in defaults.reek.yml.
|
24
|
+
# DataClump:
|
25
|
+
# max_copies: 3
|
26
|
+
# min_clump_size: 3
|
27
|
+
|
28
|
+
|
29
|
+
# ### Directory specific configuration
|
30
|
+
#
|
31
|
+
# # You can configure smells on a per-directory base.
|
32
|
+
# # E.g. the classic Rails case: controllers smell of NestedIterators (see /docs/Nested-Iterators.md) and
|
33
|
+
# # helpers smell of UtilityFunction (see docs/Utility-Function.md)
|
34
|
+
# # Note that we only allow configuration on a directory level, not a file level, so all paths have to point to directories.
|
35
|
+
# directories:
|
36
|
+
# "web_app/app/controllers":
|
37
|
+
# NestedIterators:
|
38
|
+
# enabled: false
|
39
|
+
# "web_app/app/helpers":
|
40
|
+
# UtilityFunction:
|
41
|
+
# enabled: false
|
42
|
+
|
43
|
+
# ### Excluding directories
|
44
|
+
#
|
45
|
+
# # Directories below will not be scanned at all
|
46
|
+
# exclude_paths:
|
47
|
+
# - lib/legacy
|
48
|
+
# - lib/rake/legacy_tasks
|
data/README.md
CHANGED
@@ -69,7 +69,7 @@ $ mkdir -p ~/.config/fusuma # create config directory
|
|
69
69
|
$ nano ~/.config/fusuma/config.yml # edit config file.
|
70
70
|
```
|
71
71
|
|
72
|
-
### Example (Gesture Mapping for
|
72
|
+
### Example (Gesture Mapping for elementary OS)
|
73
73
|
|
74
74
|
```yaml
|
75
75
|
swipe:
|
@@ -80,8 +80,10 @@ swipe:
|
|
80
80
|
command: 'xdotool key alt+Right'
|
81
81
|
up:
|
82
82
|
command: 'xdotool key ctrl+t'
|
83
|
+
threshold: 1.5
|
83
84
|
down:
|
84
85
|
command: 'xdotool key ctrl+w'
|
86
|
+
threshold: 1.5
|
85
87
|
4:
|
86
88
|
left:
|
87
89
|
command: 'xdotool key super+Left'
|
@@ -94,8 +96,10 @@ swipe:
|
|
94
96
|
pinch:
|
95
97
|
in:
|
96
98
|
command: 'xdotool key ctrl+plus'
|
99
|
+
threshold: 0.1
|
97
100
|
out:
|
98
101
|
command: 'xdotool key ctrl+minus'
|
102
|
+
threshold: 0.1
|
99
103
|
|
100
104
|
threshold:
|
101
105
|
swipe: 1
|
@@ -106,7 +110,7 @@ interval:
|
|
106
110
|
pinch: 1
|
107
111
|
```
|
108
112
|
|
109
|
-
if `command: ` properties are blank, the swipe/pinch doesn't
|
113
|
+
if `command: ` properties are blank, the swipe/pinch doesn't execute command.
|
110
114
|
|
111
115
|
`threshold:` is sensitivity to swipe/pinch. Default value is 1.
|
112
116
|
If the swipe's threshold is `0.5`, shorten swipe-length by half.
|
@@ -147,6 +151,10 @@ swipe:
|
|
147
151
|
2. Open `$ gnome-session-properties`
|
148
152
|
3. Add Fusuma and input location where you checked above's path
|
149
153
|
|
154
|
+
## Support
|
155
|
+
|
156
|
+
[![Patreon](https://c5.patreon.com/external/logo/become_a_patron_button.png)](https://www.patreon.com/iberianpig)
|
157
|
+
|
150
158
|
## Contributing
|
151
159
|
|
152
160
|
Bug reports and pull requests are welcome on GitHub at https://github.com/iberianpig/fusuma. 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/fusuma.gemspec
CHANGED
data/lib/fusuma.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require_relative 'fusuma/version'
|
2
|
-
require_relative 'fusuma/
|
3
|
-
require_relative 'fusuma/
|
4
|
-
require_relative 'fusuma/
|
2
|
+
require_relative 'fusuma/event_stack'
|
3
|
+
require_relative 'fusuma/gesture_event'
|
4
|
+
require_relative 'fusuma/command_executor'
|
5
5
|
require_relative 'fusuma/swipe.rb'
|
6
6
|
require_relative 'fusuma/pinch.rb'
|
7
7
|
require_relative 'fusuma/multi_logger'
|
@@ -68,14 +68,16 @@ module Fusuma
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
+
def initialize
|
72
|
+
@event_stack = EventStack.new
|
73
|
+
end
|
74
|
+
|
71
75
|
def run
|
72
76
|
LibinputCommands.new.debug_events do |line|
|
73
|
-
|
74
|
-
next
|
75
|
-
@
|
76
|
-
@
|
77
|
-
event_trigger = @action_stack.generate_event_trigger
|
78
|
-
event_trigger.exec_command unless event_trigger.nil?
|
77
|
+
gesture_event = GestureEvent.initialize_by(line, Device.ids)
|
78
|
+
next unless gesture_event
|
79
|
+
@event_stack << gesture_event
|
80
|
+
@event_stack.generate_command_executor.tap { |c| c.execute if c }
|
79
81
|
end
|
80
82
|
end
|
81
83
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Fusuma
|
2
|
+
# Execute Command
|
3
|
+
class CommandExecutor
|
4
|
+
def initialize(finger, vector)
|
5
|
+
@finger = finger.to_i
|
6
|
+
@direction = vector.direction
|
7
|
+
@event_type = vector.class::TYPE
|
8
|
+
end
|
9
|
+
attr_reader :finger, :direction, :event_type
|
10
|
+
|
11
|
+
def execute
|
12
|
+
`#{command_or_shortcut}`
|
13
|
+
MultiLogger.info("Execute: #{command_or_shortcut}")
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def command_or_shortcut
|
19
|
+
@command_or_shortcut ||= command || shortcut || no_command
|
20
|
+
end
|
21
|
+
|
22
|
+
def command
|
23
|
+
Config.command(self)
|
24
|
+
end
|
25
|
+
|
26
|
+
def shortcut
|
27
|
+
Config.shortcut(self).tap { |s| return "xdotool key #{s}" if s }
|
28
|
+
end
|
29
|
+
|
30
|
+
def no_command
|
31
|
+
'echo "Command is not assigned"'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/fusuma/config.rb
CHANGED
@@ -6,20 +6,20 @@ module Fusuma
|
|
6
6
|
include Singleton
|
7
7
|
|
8
8
|
class << self
|
9
|
-
def command(
|
10
|
-
instance.command(
|
9
|
+
def command(command_executor)
|
10
|
+
instance.command(command_executor)
|
11
11
|
end
|
12
12
|
|
13
|
-
def shortcut(
|
14
|
-
instance.shortcut(
|
13
|
+
def shortcut(command_executor)
|
14
|
+
instance.shortcut(command_executor)
|
15
15
|
end
|
16
16
|
|
17
|
-
def threshold(
|
18
|
-
instance.threshold(
|
17
|
+
def threshold(command_executor)
|
18
|
+
instance.threshold(command_executor)
|
19
19
|
end
|
20
20
|
|
21
|
-
def interval(
|
22
|
-
instance.interval(
|
21
|
+
def interval(command_executor)
|
22
|
+
instance.interval(command_executor)
|
23
23
|
end
|
24
24
|
|
25
25
|
def reload
|
@@ -31,7 +31,7 @@ module Fusuma
|
|
31
31
|
attr_accessor :custom_path
|
32
32
|
|
33
33
|
def initialize
|
34
|
-
|
34
|
+
self.custom_path = nil
|
35
35
|
reload
|
36
36
|
end
|
37
37
|
|
@@ -41,28 +41,36 @@ module Fusuma
|
|
41
41
|
self
|
42
42
|
end
|
43
43
|
|
44
|
-
def command(
|
45
|
-
seek_index = [*
|
46
|
-
|
44
|
+
def command(command_executor)
|
45
|
+
seek_index = [*event_index(command_executor), 'command']
|
46
|
+
search_config_cached(seek_index)
|
47
47
|
end
|
48
48
|
|
49
|
-
def shortcut(
|
50
|
-
seek_index = [*
|
51
|
-
|
49
|
+
def shortcut(command_executor)
|
50
|
+
seek_index = [*event_index(command_executor), 'shortcut']
|
51
|
+
search_config_cached(seek_index)
|
52
52
|
end
|
53
53
|
|
54
|
-
def threshold(
|
55
|
-
|
56
|
-
|
54
|
+
def threshold(command_executor)
|
55
|
+
seek_index_specific = [*event_index(command_executor), 'threshold']
|
56
|
+
seek_index_global = ['threshold', command_executor.event_type]
|
57
|
+
search_config_cached(seek_index_specific) ||
|
58
|
+
search_config_cached(seek_index_global) || 1
|
57
59
|
end
|
58
60
|
|
59
|
-
def interval(
|
60
|
-
|
61
|
-
|
61
|
+
def interval(command_executor)
|
62
|
+
seek_index_specific = [*event_index(command_executor), 'interval']
|
63
|
+
seek_index_global = ['interval', command_executor.event_type]
|
64
|
+
search_config_cached(seek_index_specific) ||
|
65
|
+
search_config_cached(seek_index_global) || 1
|
62
66
|
end
|
63
67
|
|
64
68
|
private
|
65
69
|
|
70
|
+
def search_config_cached(seek_index)
|
71
|
+
cache(seek_index) { search_config(keymap, seek_index) }
|
72
|
+
end
|
73
|
+
|
66
74
|
def search_config(keymap_node, seek_index)
|
67
75
|
if seek_index == []
|
68
76
|
return nil if keymap_node.is_a? Hash
|
@@ -98,11 +106,11 @@ module Fusuma
|
|
98
106
|
File.expand_path "../../#{filename}", __FILE__
|
99
107
|
end
|
100
108
|
|
101
|
-
def
|
102
|
-
|
103
|
-
finger =
|
104
|
-
direction =
|
105
|
-
[
|
109
|
+
def event_index(command_executor)
|
110
|
+
event_type = command_executor.event_type
|
111
|
+
finger = command_executor.finger
|
112
|
+
direction = command_executor.direction
|
113
|
+
[event_type, finger, direction]
|
106
114
|
end
|
107
115
|
|
108
116
|
def cache(key)
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Fusuma
|
2
|
+
# manage events and generate command
|
3
|
+
class EventStack < Array
|
4
|
+
ELAPSED_TIME = 0.01
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
super(*args)
|
8
|
+
end
|
9
|
+
|
10
|
+
# @return [CommandExecutor, nil]
|
11
|
+
def generate_command_executor
|
12
|
+
return unless enough_events?
|
13
|
+
vector = generate_vector(detect_event_type)
|
14
|
+
trigger = CommandExecutor.new(finger, vector)
|
15
|
+
return unless vector.enough?(trigger)
|
16
|
+
clear
|
17
|
+
trigger
|
18
|
+
end
|
19
|
+
|
20
|
+
# @params [GestureEvent]
|
21
|
+
def push(gesture_event)
|
22
|
+
super(gesture_event)
|
23
|
+
clear if event_end?
|
24
|
+
end
|
25
|
+
alias << push
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def generate_vector(event_type)
|
30
|
+
case event_type
|
31
|
+
when 'swipe'
|
32
|
+
avg_swipe
|
33
|
+
when 'pinch'
|
34
|
+
avg_pinch
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def finger
|
39
|
+
last.finger
|
40
|
+
end
|
41
|
+
|
42
|
+
def avg_swipe
|
43
|
+
move_x = avg_attrs(:move_x)
|
44
|
+
move_y = avg_attrs(:move_y)
|
45
|
+
Swipe.new(move_x, move_y)
|
46
|
+
end
|
47
|
+
|
48
|
+
def avg_pinch
|
49
|
+
diameter = avg_attrs(:zoom)
|
50
|
+
delta_diameter = diameter - first.zoom
|
51
|
+
Pinch.new(delta_diameter)
|
52
|
+
end
|
53
|
+
|
54
|
+
def sum_attrs(attr)
|
55
|
+
send('map') do |gesture_event|
|
56
|
+
gesture_event.send(attr.to_sym.to_s)
|
57
|
+
end.compact.inject(:+)
|
58
|
+
end
|
59
|
+
|
60
|
+
def avg_attrs(attr)
|
61
|
+
sum_attrs(attr) / length
|
62
|
+
end
|
63
|
+
|
64
|
+
def event_end?
|
65
|
+
last_event_name =~ /_END$/
|
66
|
+
end
|
67
|
+
|
68
|
+
def last_event_name
|
69
|
+
return false if last.class != GestureEvent
|
70
|
+
last.event
|
71
|
+
end
|
72
|
+
|
73
|
+
def enough_events?
|
74
|
+
length > 2
|
75
|
+
end
|
76
|
+
|
77
|
+
def enough_elapsed_time?
|
78
|
+
return false if length.zero?
|
79
|
+
(last.time - first.time) > ELAPSED_TIME
|
80
|
+
end
|
81
|
+
|
82
|
+
def detect_event_type
|
83
|
+
first.event =~ /GESTURE_(.*?)_/
|
84
|
+
Regexp.last_match(1).downcase
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
module Fusuma
|
2
|
-
# pinch or swipe
|
3
|
-
class
|
4
|
-
def initialize(time,
|
5
|
-
@time
|
6
|
-
@
|
2
|
+
# pinch or swipe or rotate event
|
3
|
+
class GestureEvent
|
4
|
+
def initialize(time, event, finger, directions)
|
5
|
+
@time = time.to_f
|
6
|
+
@event = event
|
7
7
|
@finger = finger
|
8
8
|
@move_x = directions[:move][:x].to_f
|
9
9
|
@move_y = directions[:move][:y].to_f
|
10
10
|
@zoom = directions[:zoom].to_f
|
11
11
|
end
|
12
|
-
attr_reader :time, :
|
12
|
+
attr_reader :time, :event, :finger,
|
13
13
|
:move_x, :move_y, :zoom
|
14
14
|
|
15
15
|
class << self
|
@@ -19,25 +19,25 @@ module Fusuma
|
|
19
19
|
end
|
20
20
|
return if line.to_s =~ /_BEGIN/
|
21
21
|
return unless line.to_s =~ /GESTURE_SWIPE|GESTURE_PINCH/
|
22
|
-
time,
|
23
|
-
MultiLogger.debug(time: time,
|
22
|
+
time, event, finger, directions = gesture_event_arguments(line)
|
23
|
+
MultiLogger.debug(time: time, event: event,
|
24
24
|
finger: finger, directions: directions)
|
25
|
-
|
25
|
+
GestureEvent.new(time, event, finger, directions)
|
26
26
|
end
|
27
27
|
|
28
28
|
private
|
29
29
|
|
30
|
-
def
|
31
|
-
|
30
|
+
def gesture_event_arguments(libinput_line)
|
31
|
+
event, time, finger, other = parse_libinput(libinput_line)
|
32
32
|
move_x, move_y, zoom = parse_finger_directions(other)
|
33
33
|
directions = { move: { x: move_x, y: move_y }, zoom: zoom }
|
34
|
-
[time,
|
34
|
+
[time, event, finger, directions]
|
35
35
|
end
|
36
36
|
|
37
37
|
def parse_libinput(line)
|
38
|
-
_device,
|
38
|
+
_device, event, time, other = line.strip.split(nil, 4)
|
39
39
|
finger, other = other.split(nil, 2)
|
40
|
-
[
|
40
|
+
[event, time, finger, other]
|
41
41
|
end
|
42
42
|
|
43
43
|
def parse_finger_directions(line)
|
data/lib/fusuma/pinch.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module Fusuma
|
2
2
|
# vector data
|
3
3
|
class Pinch
|
4
|
+
TYPE = 'pinch'.freeze
|
5
|
+
|
4
6
|
BASE_THERESHOLD = 0.3
|
5
7
|
BASE_INTERVAL = 0.05
|
6
8
|
|
@@ -15,33 +17,34 @@ module Fusuma
|
|
15
17
|
'out'
|
16
18
|
end
|
17
19
|
|
18
|
-
def enough?
|
20
|
+
def enough?(trigger)
|
19
21
|
MultiLogger.debug(diameter: diameter)
|
20
|
-
enough_diameter? && enough_interval? &&
|
22
|
+
enough_diameter?(trigger) && enough_interval?(trigger) &&
|
23
|
+
self.class.touch_last_time
|
21
24
|
end
|
22
25
|
|
23
26
|
private
|
24
27
|
|
25
|
-
def enough_diameter?
|
26
|
-
diameter.abs > threshold
|
28
|
+
def enough_diameter?(trigger)
|
29
|
+
diameter.abs > threshold(trigger)
|
27
30
|
end
|
28
31
|
|
29
|
-
def enough_interval?
|
32
|
+
def enough_interval?(trigger)
|
30
33
|
return true if first_time?
|
31
|
-
return true if (Time.now - self.class.last_time) > interval_time
|
34
|
+
return true if (Time.now - self.class.last_time) > interval_time(trigger)
|
32
35
|
false
|
33
36
|
end
|
34
37
|
|
35
38
|
def first_time?
|
36
|
-
self.class.last_time
|
39
|
+
!self.class.last_time
|
37
40
|
end
|
38
41
|
|
39
|
-
def threshold
|
40
|
-
@threshold ||= BASE_THERESHOLD * Config.threshold(
|
42
|
+
def threshold(trigger)
|
43
|
+
@threshold ||= BASE_THERESHOLD * Config.threshold(trigger)
|
41
44
|
end
|
42
45
|
|
43
|
-
def interval_time
|
44
|
-
@interval_time ||= BASE_INTERVAL * Config.interval(
|
46
|
+
def interval_time(trigger)
|
47
|
+
@interval_time ||= BASE_INTERVAL * Config.interval(trigger)
|
45
48
|
end
|
46
49
|
|
47
50
|
class << self
|
data/lib/fusuma/swipe.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
module Fusuma
|
2
2
|
# vector data
|
3
3
|
class Swipe
|
4
|
+
TYPE = 'swipe'.freeze
|
5
|
+
|
4
6
|
BASE_THERESHOLD = 20
|
5
7
|
BASE_INTERVAL = 0.5
|
6
8
|
|
7
|
-
def initialize(
|
8
|
-
@x =
|
9
|
-
@y =
|
9
|
+
def initialize(move_x, move_y)
|
10
|
+
@x = move_x
|
11
|
+
@y = move_y
|
10
12
|
end
|
11
13
|
attr_reader :x, :y
|
12
14
|
|
@@ -15,33 +17,35 @@ module Fusuma
|
|
15
17
|
y > 0 ? 'down' : 'up'
|
16
18
|
end
|
17
19
|
|
18
|
-
def enough?
|
20
|
+
def enough?(trigger)
|
19
21
|
MultiLogger.debug(x: x, y: y)
|
20
|
-
enough_distance? && enough_interval? &&
|
22
|
+
enough_distance?(trigger) && enough_interval?(trigger) &&
|
23
|
+
self.class.touch_last_time
|
21
24
|
end
|
22
25
|
|
23
26
|
private
|
24
27
|
|
25
|
-
def enough_distance?
|
28
|
+
def enough_distance?(trigger)
|
29
|
+
threshold = threshold(trigger)
|
26
30
|
(x.abs > threshold) || (y.abs > threshold)
|
27
31
|
end
|
28
32
|
|
29
|
-
def enough_interval?
|
33
|
+
def enough_interval?(trigger)
|
30
34
|
return true if first_time?
|
31
|
-
return true if (Time.now - self.class.last_time) > interval_time
|
35
|
+
return true if (Time.now - self.class.last_time) > interval_time(trigger)
|
32
36
|
false
|
33
37
|
end
|
34
38
|
|
35
39
|
def first_time?
|
36
|
-
self.class.last_time
|
40
|
+
!self.class.last_time
|
37
41
|
end
|
38
42
|
|
39
|
-
def threshold
|
40
|
-
@threshold ||= BASE_THERESHOLD * Config.threshold(
|
43
|
+
def threshold(trigger)
|
44
|
+
@threshold ||= BASE_THERESHOLD * Config.threshold(trigger)
|
41
45
|
end
|
42
46
|
|
43
|
-
def interval_time
|
44
|
-
@interval_time ||= BASE_INTERVAL * Config.interval(
|
47
|
+
def interval_time(trigger)
|
48
|
+
@interval_time ||= BASE_INTERVAL * Config.interval(trigger)
|
45
49
|
end
|
46
50
|
|
47
51
|
class << self
|
data/lib/fusuma/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fusuma
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- iberianpig
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-08-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -118,14 +118,16 @@ executables:
|
|
118
118
|
extensions: []
|
119
119
|
extra_rdoc_files: []
|
120
120
|
files:
|
121
|
+
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
122
|
+
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
121
123
|
- ".github/stale.yml"
|
122
124
|
- ".gitignore"
|
125
|
+
- ".reek.yml"
|
123
126
|
- ".rspec"
|
124
127
|
- ".rubocop.yml"
|
125
128
|
- ".travis.yml"
|
126
129
|
- CODE_OF_CONDUCT.md
|
127
130
|
- Gemfile
|
128
|
-
- ISSUE_TEMPLATE.md
|
129
131
|
- LICENSE
|
130
132
|
- README.md
|
131
133
|
- Rakefile
|
@@ -134,12 +136,12 @@ files:
|
|
134
136
|
- exe/fusuma
|
135
137
|
- fusuma.gemspec
|
136
138
|
- lib/fusuma.rb
|
137
|
-
- lib/fusuma/
|
139
|
+
- lib/fusuma/command_executor.rb
|
138
140
|
- lib/fusuma/config.rb
|
139
141
|
- lib/fusuma/config.yml
|
140
142
|
- lib/fusuma/device.rb
|
141
|
-
- lib/fusuma/
|
142
|
-
- lib/fusuma/
|
143
|
+
- lib/fusuma/event_stack.rb
|
144
|
+
- lib/fusuma/gesture_event.rb
|
143
145
|
- lib/fusuma/libinput_commands.rb
|
144
146
|
- lib/fusuma/multi_logger.rb
|
145
147
|
- lib/fusuma/pinch.rb
|
data/ISSUE_TEMPLATE.md
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
<!--
|
2
|
-
|
3
|
-
Have you read Fusuma's CODE_OF_CONDUCT.md? By filing an Issue, you are expected to comply with it, including treating everyone with respect: https://github.com/iberianpig/fusuma/blob/master/CODE_OF_CONDUCT.md
|
4
|
-
|
5
|
-
-->
|
6
|
-
|
7
|
-
### Prerequisites
|
8
|
-
|
9
|
-
* [ ] Put an X between the brackets on this line if you have done all of the following:
|
10
|
-
* Read Documents. https://github.com/iberianpig/fusuma#installation
|
11
|
-
* Checked that `libinput-debug-events` worked correctly.
|
12
|
-
* Reproduced the problem in latest version. Update fusuma with `gem update fusuma`
|
13
|
-
* Checked that your issue isn't already filed: https://github.com/iberianpig/fusuma/issues
|
14
|
-
|
15
|
-
### Description
|
16
|
-
|
17
|
-
[Description of the issue]
|
18
|
-
|
19
|
-
### Steps to Reproduce
|
20
|
-
|
21
|
-
1. [First Step]
|
22
|
-
2. [Second Step]
|
23
|
-
3. [and so on...]
|
24
|
-
|
25
|
-
**Expected behavior:** [What you expect to happen]
|
26
|
-
|
27
|
-
**Actual behavior:** [What actually happens]
|
28
|
-
|
29
|
-
**Reproduces how often:** [What percentage of the time does it reproduce?]
|
30
|
-
|
31
|
-
### Versions
|
32
|
-
|
33
|
-
You can get this information from copy and pasting the output of `fusuma --version` from the command line. Also, please include the OS and what version of the OS you're running.
|
34
|
-
|
35
|
-
### Additional Information
|
36
|
-
|
37
|
-
Any additional information, your `~/.config/fusuma/config.yml` or data that might be necessary to reproduce the issue.
|
data/lib/fusuma/action_stack.rb
DELETED
@@ -1,97 +0,0 @@
|
|
1
|
-
module Fusuma
|
2
|
-
# manage actions
|
3
|
-
class ActionStack < Array
|
4
|
-
ELAPSED_TIME = 0.01
|
5
|
-
|
6
|
-
def initialize(*args)
|
7
|
-
super(*args)
|
8
|
-
end
|
9
|
-
|
10
|
-
def generate_event_trigger
|
11
|
-
return unless enough_actions?
|
12
|
-
action_type = detect_action_type
|
13
|
-
direction = detect_direction(action_type)
|
14
|
-
return if direction.nil?
|
15
|
-
@last_triggered_time = last.time
|
16
|
-
finger = detect_finger
|
17
|
-
clear
|
18
|
-
EventTrigger.new(finger, direction, action_type)
|
19
|
-
end
|
20
|
-
|
21
|
-
def push(gesture_action)
|
22
|
-
super(gesture_action)
|
23
|
-
clear if action_end?
|
24
|
-
end
|
25
|
-
alias << push
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def detect_direction(action_type)
|
30
|
-
vector = generate_vector(action_type)
|
31
|
-
return if vector && !vector.enough?
|
32
|
-
vector.direction
|
33
|
-
end
|
34
|
-
|
35
|
-
def generate_vector(action_type)
|
36
|
-
case action_type
|
37
|
-
when 'swipe'
|
38
|
-
avg_swipe
|
39
|
-
when 'pinch'
|
40
|
-
avg_pinch
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def detect_finger
|
45
|
-
last.finger
|
46
|
-
end
|
47
|
-
|
48
|
-
def avg_swipe
|
49
|
-
move_x = avg_attrs(:move_x)
|
50
|
-
move_y = avg_attrs(:move_y)
|
51
|
-
Swipe.new(move_x, move_y)
|
52
|
-
end
|
53
|
-
|
54
|
-
def avg_pinch
|
55
|
-
diameter = avg_attrs(:zoom)
|
56
|
-
delta_diameter = diameter - first.zoom
|
57
|
-
Pinch.new(delta_diameter)
|
58
|
-
end
|
59
|
-
|
60
|
-
def sum_attrs(attr)
|
61
|
-
send('map') do |gesture_action|
|
62
|
-
gesture_action.send(attr.to_sym.to_s)
|
63
|
-
end.compact.inject(:+)
|
64
|
-
end
|
65
|
-
|
66
|
-
def avg_attrs(attr)
|
67
|
-
sum_attrs(attr) / length
|
68
|
-
end
|
69
|
-
|
70
|
-
def action_end?
|
71
|
-
last_action_name =~ /_END$/
|
72
|
-
end
|
73
|
-
|
74
|
-
def last_action_name
|
75
|
-
return false if last.class != GestureAction
|
76
|
-
last.action
|
77
|
-
end
|
78
|
-
|
79
|
-
def enough_actions?
|
80
|
-
length > 2
|
81
|
-
end
|
82
|
-
|
83
|
-
def enough_elapsed_time?
|
84
|
-
return false if length.zero?
|
85
|
-
(last.time - first.time) > ELAPSED_TIME
|
86
|
-
end
|
87
|
-
|
88
|
-
def last_triggered_time
|
89
|
-
@last_triggered_time ||= 0
|
90
|
-
end
|
91
|
-
|
92
|
-
def detect_action_type
|
93
|
-
first.action =~ /GESTURE_(.*?)_/
|
94
|
-
Regexp.last_match(1).downcase
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
data/lib/fusuma/event_trigger.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
module Fusuma
|
2
|
-
# manage actions
|
3
|
-
class EventTrigger
|
4
|
-
def initialize(finger, direction, action_type)
|
5
|
-
@finger = finger.to_i
|
6
|
-
@direction = direction
|
7
|
-
@action_type = action_type
|
8
|
-
end
|
9
|
-
attr_reader :finger, :direction, :action_type
|
10
|
-
|
11
|
-
def exec_command
|
12
|
-
return if command.nil?
|
13
|
-
`#{command}`
|
14
|
-
MultiLogger.info("trigger event: #{command}")
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def command
|
20
|
-
Config.command(self).tap { |c| return c if c }
|
21
|
-
Config.shortcut(self).tap { |s| return "xdotool key #{s}" if s }
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|