lib/fusuma/plugin/sendkey/keyboard.rb in fusuma-plugin-sendkey-0.3.0 vs lib/fusuma/plugin/sendkey/keyboard.rb in fusuma-plugin-sendkey-0.4.0
- old
+ new
@@ -1,20 +1,31 @@
# frozen_string_literal: true
-require 'linux_input'
-require 'fcntl'
+require 'revdev'
+require 'fusuma/device'
+
require_relative './device.rb'
module Fusuma
module Plugin
module Sendkey
# Emulate Keyboard
class Keyboard
- def initialize(device: nil)
- @device = device || Device.new
+ def initialize(name_pattern: nil)
+ name_pattern ||= 'keyboard'
+ device = find_device(name_pattern: name_pattern)
+
+ if device.nil?
+ warn "sendkey: Keyboard /#{name_pattern}/ is not found"
+ exit(1)
+ end
+
+ @device = Device.new(path: "/dev/input/#{device.id}")
end
+ attr_writer :device
+
# @param param [String]
def type(param:)
return unless param.is_a?(String)
keycodes = split_param(param)
@@ -22,70 +33,68 @@
clear_modifiers
keycodes.each { |keycode| key_event(keycode: keycode, press: true) }
key_sync(press: true)
keycodes.reverse.map { |keycode| key_event(keycode: keycode, press: false) }
key_sync(press: false)
- device_file.close
end
# @param param [String]
def valid?(param:)
return unless param.is_a?(String)
keycodes = split_param(param)
keycodes.all? { |keycode| support?(keycode) }
end
- def device_file
- return @device_file if @device_file && !@device_file.closed?
-
- @device_file = File.open(@device.path, Fcntl::O_WRONLY | Fcntl::O_NDELAY)
- end
-
def key_event(keycode:, press: true)
- event = LinuxInput::InputEvent.new
- event[:time] = LinuxInput::Timeval.new
- event[:time][:tv_sec] = Time.now.to_i
- event[:type] = LinuxInput::EV_KEY
- event[:code] = keycode_const(keycode)
- event[:value] = press ? 1 : 0
- device_file.syswrite(event.pointer.read_bytes(event.size))
+ event = Revdev::InputEvent.new(
+ nil,
+ Revdev.const_get(:EV_KEY),
+ Revdev.const_get(keycode),
+ press ? 1 : 0
+ )
+ @device.write_event(event)
end
def key_sync(press: true)
- event = LinuxInput::InputEvent.new
- event[:time] = LinuxInput::Timeval.new
- event[:time][:tv_sec] = Time.now.to_i
- event[:type] = LinuxInput::EV_SYN
- event[:code] = LinuxInput::SYN_REPORT
- event[:value] = press ? 1 : 0
- device_file.syswrite(event.pointer.read_bytes(event.size))
+ event = Revdev::InputEvent.new(
+ nil,
+ Revdev.const_get(:EV_SYN),
+ Revdev.const_get(:SYN_REPORT),
+ press ? 1 : 0
+ )
+ @device.write_event(event)
end
def support?(keycode)
@supported_code ||= {}
- @supported_code[keycode] ||= if @device.support?(keycode)
+ @supported_code[keycode] ||= if find_code(keycode: keycode)
true
else
search_candidates(keycode: keycode)
- exit(1)
end
end
def search_candidates(keycode:)
- candidates = search_codes(keycode: keycode)
+ query = keycode&.upcase&.gsub('KEY_', '')
+ candidates = search_codes(query: query)
+
warn "Did you mean? #{candidates.join(' / ')}" unless candidates.empty?
warn "sendkey: #{remove_prefix(keycode)} is unsupported."
end
- def search_codes(keycode: nil)
+ def search_codes(query: nil)
+ Revdev.constants
+ .select { |c| c[/KEY_.*#{query}.*/] }
+ .map { |c| c.to_s.gsub('KEY_', '') }
+ end
+
+ def find_code(keycode: nil)
query = keycode&.upcase&.gsub('KEY_', '')
- LinuxInput.constants
- .select { |c| c[/KEY_.*#{query}.*/] }
- .select { |c| @device.support?(c) }
- .map { |c| c.to_s.gsub('KEY_', '') }
+
+ Revdev.constants.find { |c| c == "KEY_#{query}".to_sym }
end
def keycode_const(keycode)
Object.const_get "LinuxInput::#{keycode}"
end
@@ -95,9 +104,13 @@
LEFTSHIFT RIGHTALT RIGHTCTRL RIGHTSHIFT ]
modifiers.each { |code| key_event(keycode: key_prefix(code), press: false) }
end
private
+
+ def find_device(name_pattern:)
+ Fusuma::Device.all.find { |d| d.name.match(/#{name_pattern}/) }
+ end
def split_param(param)
param.split('+').map { |code| key_prefix(code) }
end