fusuma-plugin-sendkey 0.2.1 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 37cb58747c750acf4c991fd174a8e19182336f518a54f4b2c816e3ead7f628eb
4
- data.tar.gz: 9309dd43e32c3cd8b6791fe6c1a56f439fff6d7a05af41f9654e96360efd76bd
3
+ metadata.gz: d27660bea09b33620ab905e3b112cf0f9884b3617097daadd6d8ca03d2d5c14b
4
+ data.tar.gz: 70b1f7ddffaa8d874a44feaec361c60d0bca6744f30ec6a5c6f3c3efb1fe2a9f
5
5
  SHA512:
6
- metadata.gz: 9f93e2a400820e3b4e138da96e71f90067bf514d35751bc6f31f6d58d9d4bc72ec18e621f04ede71eaa26131bbede74b7fb8bda420e8c38e3895f78299169616
7
- data.tar.gz: 934f126d52d893d577fa9b5cec25209a88fbb3298d0004238e004676a898ced197ff481bed6aa1e3015fb55a05d33762aac9823b4a10d3bc796a940dc5e28ffc
6
+ metadata.gz: 0257fa54b43876536bb7729c74f05ff06d0a12e57885b5d544b9bdd209815780811496296339efca5353102f14fb811c1be7b82839b51542463c3cbbc90ad6b4
7
+ data.tar.gz: '049d2d9cf06c538800189db3addb7508e4c98a4390c3da8eb1a41dae2eb007fe11246fbfb86fe2ac76c131a81c7fa7255d2f7951f23d37fea92780920761617a'
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [Fusuma](https://github.com/iberianpig/fusuma) plugin that sending virtual keyboard events
4
4
 
5
- * Emulate keyboard events with evemu-event
5
+ * Send keyboard events with writing event /dev/input/eventN
6
6
  * This plugin is wayland compatible and alternative to xdotool
7
7
 
8
8
  ## Installation
@@ -12,7 +12,7 @@ Run the following code in your terminal.
12
12
  ### Install dependencies
13
13
 
14
14
  ```sh
15
- $ sudo apt-get install evemu-tools libevdev-dev ruby-ffi
15
+ $ sudo apt-get install libevdev-dev ruby-ffi
16
16
  ```
17
17
 
18
18
  ### Install fusuma-plugin-sendkey
@@ -22,7 +22,7 @@ $ sudo gem install fusuma-plugin-sendkey
22
22
  ```
23
23
 
24
24
 
25
- ## List avaiable keys
25
+ ## List available keys
26
26
 
27
27
  ```sh
28
28
  $ fusuma-sendkey -l
@@ -30,12 +30,13 @@ $ fusuma-sendkey -l
30
30
 
31
31
  ## Run fusuma-sendkey on Terminal
32
32
 
33
- * `fusuma-sendkey` can emulate keyboard inputs as a command
33
+ * `fusuma-sendkey` command is available on your terminal
34
+ * `fusuma-sendkey` can send multiple key events
34
35
  * Combine keys for pressing the same time with `+`
35
36
 
36
37
 
37
38
  ```sh
38
- $ fusuma-sendkey LEFTCTRL+T
39
+ $ fusuma-sendkey LEFTCTRL+T # press ctrl key + t key
39
40
  ```
40
41
 
41
42
 
data/bin/console CHANGED
@@ -1,14 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require "bundler/setup"
4
+ require 'fusuma/plugin/executors/executor'
4
5
  require "fusuma/plugin/sendkey"
5
6
 
6
7
  # You can add fixtures and/or initialization code here to make experimenting
7
8
  # with your gem easier. You can also use a different console, if you like.
8
9
 
9
10
  # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start(__FILE__)
11
+ require "pry"
12
+ Pry.start
data/exe/fusuma-sendkey CHANGED
@@ -20,7 +20,7 @@ end
20
20
  opt.parse!(ARGV)
21
21
 
22
22
  if option[:list]
23
- puts Fusuma::Plugin::Sendkey::Keyboard.new.available_codes
23
+ puts Fusuma::Plugin::Sendkey::Keyboard.new.search_codes
24
24
  return
25
25
  end
26
26
 
@@ -37,6 +37,5 @@ if param.nil?
37
37
  exit 1
38
38
  end
39
39
 
40
- Fusuma::Plugin::Sendkey::Keyboard.new.type_command(param: param).tap do |command|
41
- exec(command)
42
- end
40
+ keyboard = Fusuma::Plugin::Sendkey::Keyboard.new
41
+ keyboard.valid?(param: param) && keyboard.type(param: param)
@@ -24,8 +24,9 @@ Gem::Specification.new do |spec|
24
24
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
25
  spec.require_paths = ['lib']
26
26
 
27
- spec.add_dependency 'evdev'
28
- spec.add_dependency 'fusuma', '~> 1.5.0'
27
+ spec.add_dependency 'evdev', '~> 1.0'
28
+ spec.add_dependency 'fusuma', '~> 1.5'
29
+ spec.add_dependency 'linux_input', '~> 1.1'
29
30
 
30
31
  spec.add_development_dependency 'bundler'
31
32
  spec.add_development_dependency 'github_changelog_generator', '~> 1.14'
@@ -17,12 +17,10 @@ module Fusuma
17
17
  # @param event [Event]
18
18
  # @return [nil]
19
19
  def execute(event)
20
- return if search_command(event).nil?
21
-
22
20
  MultiLogger.info(sendkey: search_param(event))
23
21
  pid = fork do
24
22
  Process.daemon(true)
25
- exec(search_command(event))
23
+ keyboard.type(param: search_param(event))
26
24
  end
27
25
 
28
26
  Process.detach(pid)
@@ -34,22 +32,18 @@ module Fusuma
34
32
  def executable?(event)
35
33
  event.tag.end_with?('_detector') &&
36
34
  event.record.type == :index &&
37
- search_command(event)
35
+ keyboard.valid?(param: search_param(event))
38
36
  end
39
37
 
40
- # @param event [Event]
41
- # @return [String]
42
- # @return [NilClass]
43
- def search_command(event)
38
+ private
39
+
40
+ def keyboard
44
41
  @keyboard ||= begin
45
42
  device = Sendkey::Device.new(path: config_params(:device_path))
46
43
  Sendkey::Keyboard.new(device: device)
47
44
  end
48
- @keyboard.type_command(param: search_param(event))
49
45
  end
50
46
 
51
- private
52
-
53
47
  def search_param(event)
54
48
  index = Config::Index.new([*event.record.index.keys, :sendkey])
55
49
  Config.search(index)
@@ -7,18 +7,16 @@ module Fusuma
7
7
  module Sendkey
8
8
  # handle Evdev device
9
9
  class Device
10
- attr_reader :device_id
11
10
  def initialize(path: nil)
12
11
  return if path && (@evdev = Evdev.new(path))
13
12
 
14
13
  (0..99).lazy.find do |i|
15
- begin
16
- evdev = Evdev.new("/dev/input/event#{i}")
17
- @evdev = evdev if evdev.supports_event?(convert_keycode('LEFTALT'))
18
- rescue Errno::ENOENT # No such file or directory
19
- false
20
- # TODO: rescue Errno::EACCES
21
- end
14
+ evdev = Evdev.new("/dev/input/event#{i}")
15
+ # NOTE: find keyboard device
16
+ @evdev = evdev if evdev.supports_event?('KEY_LEFTALT')
17
+ rescue Errno::ENOENT # No such file or directory
18
+ false
19
+ # TODO: rescue Errno::EACCES
22
20
  end
23
21
  end
24
22
 
@@ -28,36 +26,11 @@ module Fusuma
28
26
  @path ||= @evdev.file.path
29
27
  end
30
28
 
31
- def support?(code)
32
- keycode = convert_keycode(code)
29
+ def support?(keycode)
33
30
  @evdev.supports_event?(keycode)
34
31
  rescue NameError
35
- candidates = search_codes(code: code)
36
-
37
- warn "Did you mean? #{candidates.join(' / ')}" unless candidates.empty?
38
-
39
32
  false
40
33
  end
41
-
42
- def search_codes(code: nil)
43
- query = code&.upcase
44
- LinuxInput.constants
45
- .select { |c| c[/KEY_.*#{query}.*/] }
46
- .select { |c| @evdev.supports_event?(c) }
47
- .map { |c| c.to_s.gsub('KEY_', '') }
48
- end
49
-
50
- def emulate(code:, press: true)
51
- keycode = convert_keycode(code)
52
- v = press ? 1 : 0
53
- "evemu-event #{path} --type EV_KEY --code #{keycode} --value #{v} --sync"
54
- end
55
-
56
- private
57
-
58
- def convert_keycode(code)
59
- "KEY_#{code.upcase}"
60
- end
61
34
  end
62
35
  end
63
36
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'linux_input'
4
+ require 'fcntl'
3
5
  require_relative './device.rb'
4
6
 
5
7
  module Fusuma
@@ -12,41 +14,100 @@ module Fusuma
12
14
  end
13
15
 
14
16
  # @param param [String]
15
- def type_command(param:)
17
+ def type(param:)
16
18
  return unless param.is_a?(String)
17
19
 
18
- codes = param.split('+')
19
- press_commands = codes.map { |code| press_command(code) }
20
- release_commands = codes.reverse.map { |code| release_command(code) }
20
+ keycodes = split_param(param)
21
21
 
22
- (press_commands | release_commands).join(' && ')
22
+ clear_modifiers
23
+ keycodes.each { |keycode| key_event(keycode: keycode, press: true) }
24
+ key_sync(press: true)
25
+ keycodes.reverse.map { |keycode| key_event(keycode: keycode, press: false) }
26
+ key_sync(press: false)
27
+ device_file.close
23
28
  end
24
29
 
25
- def press_command(code)
26
- return unless support?(code)
30
+ # @param param [String]
31
+ def valid?(param:)
32
+ return unless param.is_a?(String)
33
+
34
+ keycodes = split_param(param)
35
+ keycodes.all? { |keycode| support?(keycode) }
36
+ end
37
+
38
+ def device_file
39
+ return @device_file if @device_file && !@device_file.closed?
27
40
 
28
- @device.emulate(code: code, press: true)
41
+ @device_file = File.open(@device.path, Fcntl::O_WRONLY | Fcntl::O_NDELAY)
29
42
  end
30
43
 
31
- def release_command(code)
32
- return unless support?(code)
44
+ def key_event(keycode:, press: true)
45
+ event = LinuxInput::InputEvent.new
46
+ event[:time] = LinuxInput::Timeval.new
47
+ event[:time][:tv_sec] = Time.now.to_i
48
+ event[:type] = LinuxInput::EV_KEY
49
+ event[:code] = keycode_const(keycode)
50
+ event[:value] = press ? 1 : 0
51
+ device_file.syswrite(event.pointer.read_bytes(event.size))
52
+ end
33
53
 
34
- @device.emulate(code: code, press: false)
54
+ def key_sync(press: true)
55
+ event = LinuxInput::InputEvent.new
56
+ event[:time] = LinuxInput::Timeval.new
57
+ event[:time][:tv_sec] = Time.now.to_i
58
+ event[:type] = LinuxInput::EV_SYN
59
+ event[:code] = LinuxInput::SYN_REPORT
60
+ event[:value] = press ? 1 : 0
61
+ device_file.syswrite(event.pointer.read_bytes(event.size))
35
62
  end
36
63
 
37
- def support?(code)
64
+ def support?(keycode)
38
65
  @supported_code ||= {}
39
- @supported_code[code] ||= if @device.support?(code)
40
- true
41
- else
42
- warn "sendkey: #{code} is unsupported."
43
- warn 'Please check your config.yml.'
44
- exit 1
45
- end
66
+ @supported_code[keycode] ||= if @device.support?(keycode)
67
+ true
68
+ else
69
+ search_candidates(keycode: keycode)
70
+ exit(1)
71
+ end
72
+ end
73
+
74
+ def search_candidates(keycode:)
75
+ candidates = search_codes(keycode: keycode)
76
+
77
+ warn "Did you mean? #{candidates.join(' / ')}" unless candidates.empty?
78
+ warn "sendkey: #{remove_prefix(keycode)} is unsupported."
79
+ end
80
+
81
+ def search_codes(keycode: nil)
82
+ query = keycode&.upcase&.gsub('KEY_', '')
83
+ LinuxInput.constants
84
+ .select { |c| c[/KEY_.*#{query}.*/] }
85
+ .select { |c| @device.support?(c) }
86
+ .map { |c| c.to_s.gsub('KEY_', '') }
87
+ end
88
+
89
+ def keycode_const(keycode)
90
+ Object.const_get "LinuxInput::#{keycode}"
91
+ end
92
+
93
+ def clear_modifiers
94
+ modifiers = %w[ CAPSLOCK LEFTALT LEFTCTRL LEFTMETA
95
+ LEFTSHIFT RIGHTALT RIGHTCTRL RIGHTSHIFT ]
96
+ modifiers.each { |code| key_event(keycode: key_prefix(code), press: false) }
97
+ end
98
+
99
+ private
100
+
101
+ def split_param(param)
102
+ param.split('+').map { |code| key_prefix(code) }
103
+ end
104
+
105
+ def key_prefix(code)
106
+ "KEY_#{code.upcase}"
46
107
  end
47
108
 
48
- def available_codes
49
- @device.search_codes
109
+ def remove_prefix(keycode)
110
+ keycode.gsub('KEY_', '')
50
111
  end
51
112
  end
52
113
  end
@@ -3,7 +3,7 @@
3
3
  module Fusuma
4
4
  module Plugin
5
5
  module Sendkey
6
- VERSION = '0.2.1'
6
+ VERSION = '0.3.0'
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,43 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fusuma-plugin-sendkey
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - iberianpig
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-04 00:00:00.000000000 Z
11
+ date: 2020-03-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: evdev
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '1.0'
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: '0'
26
+ version: '1.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: fusuma
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.5.0
33
+ version: '1.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: linux_input
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.1'
34
48
  type: :runtime
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
- version: 1.5.0
54
+ version: '1.1'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -224,7 +238,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
224
238
  - !ruby/object:Gem::Version
225
239
  version: '0'
226
240
  requirements: []
227
- rubygems_version: 3.0.6
241
+ rubygems_version: 3.0.3
228
242
  signing_key:
229
243
  specification_version: 4
230
244
  summary: Fusuma plugin that sending virtual keyboard events