lib/fusuma/plugin/sendkey/keyboard.rb in fusuma-plugin-sendkey-0.6.4 vs lib/fusuma/plugin/sendkey/keyboard.rb in fusuma-plugin-sendkey-0.7.1

- old
+ new

@@ -1,11 +1,11 @@ # frozen_string_literal: true -require 'revdev' -require 'fusuma/device' +require "revdev" +require "fusuma/device" -require_relative './device' +require_relative "./device" module Fusuma module Plugin module Sendkey # Emulate Keyboard @@ -27,118 +27,124 @@ def self.find_device(name_pattern:) Fusuma::Device.all.find { |d| d.name.match(/#{name_pattern}/) } end def initialize(name_pattern: nil) - name_pattern ||= 'keyboard|Keyboard|KEYBOARD' + name_pattern ||= "keyboard|Keyboard|KEYBOARD" device = Keyboard.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_reader :device - # @param param [String] # @param keep [String] - def type(param:) + def type(param:, keep: "") return unless param.is_a?(String) - keycodes = split_param(param) - clear_modifiers(MODIFIER_KEY_CODES - keycodes) - keycodes.each { |keycode| key_event(keycode: keycode, press: true) && wait } - key_sync(press: true) - keycodes.reverse.each { |keycode| key_event(keycode: keycode, press: false) && wait } - key_sync(press: false) + param_keycodes = param_to_keycodes(param) + keep_keycodes = param_to_keycodes(keep) + + type_keycodes = param_keycodes - keep_keycodes + # release other modifier keys before sending key + clear_modifiers(MODIFIER_KEY_CODES - param_keycodes) + type_keycodes.each { |keycode| keydown(keycode) && key_sync } + type_keycodes.reverse_each { |keycode| keyup(keycode) && key_sync } end + def keydown(keycode) + send_event(code: keycode, press: true) + end + + def keyup(keycode) + send_event(code: keycode, press: false) + end + # @param param [String] def valid?(param:) return unless param.is_a?(String) - keycodes = split_param(param) + keycodes = param_to_keycodes(param) keycodes.all? { |keycode| support?(keycode) } end - def key_event(keycode:, press: true) + def send_event(code:, press: true) event = Revdev::InputEvent.new( nil, Revdev.const_get(:EV_KEY), - Revdev.const_get(keycode), + Revdev.const_get(code), press ? 1 : 0 ) @device.write_event(event) end - def key_sync(press: true) + def key_sync event = Revdev::InputEvent.new( nil, Revdev.const_get(:EV_SYN), Revdev.const_get(:SYN_REPORT), - press ? 1 : 0 + 0 ) @device.write_event(event) + sleep(INTERVAL) end def support?(keycode) @supported_code ||= {} - @supported_code[keycode] ||= if find_code(keycode: keycode) - true - else - search_candidates(keycode: keycode) - end + @supported_code[keycode] ||= find_code(keycode: keycode) end - def search_candidates(keycode:) - query = keycode&.upcase&.gsub('KEY_', '') + def warn_undefined_codes(keycode:) + query = keycode&.upcase&.gsub("KEY_", "") candidates = search_codes(query: query) - warn "Did you mean? #{candidates.join(' / ')}" unless candidates.empty? + warn "Did you mean? #{candidates.join(" / ")}" unless candidates.empty? warn "sendkey: #{remove_prefix(keycode)} is unsupported." end def search_codes(query: nil) Revdev.constants - .select { |c| c[/KEY_.*#{query}.*/] } - .map { |c| c.to_s.gsub('KEY_', '') } + .select { |c| c[/KEY_.*#{query}.*/] } + .map { |c| c.to_s.gsub("KEY_", "") } end def find_code(keycode: nil) - query = keycode&.upcase&.gsub('KEY_', '') + query = keycode&.upcase&.gsub("KEY_", "") - Revdev.constants.find { |c| c == "KEY_#{query}".to_sym } + result = Revdev.constants.find { |c| c == "KEY_#{query}".to_sym } + + warn_undefined_codes(keycode: keycode) unless result + result end def keycode_const(keycode) Object.const_get "LinuxInput::#{keycode}" end # @param [Array<String>] keycodes to be released def clear_modifiers(keycodes) - keycodes.each { |code| key_event(keycode: code, press: false) } + keycodes.each { |code| send_event(code: code, press: false) } end - private - - def split_param(param) - param.split('+').map { |code| key_prefix(code) } + # @param [String] + # @return [Array<String>] + def param_to_keycodes(param) + param.split("+").map { |keyname| add_key_prefix(keyname) } end - def key_prefix(code) + private + + def add_key_prefix(code) "KEY_#{code.upcase}" end def remove_prefix(keycode) - keycode.gsub('KEY_', '') - end - - def wait - sleep(INTERVAL) + keycode.gsub("KEY_", "") end end end end end