Skip to content

Commit

Permalink
Merge pull request #34 from iberianpig/feature/type-multiple-keys
Browse files Browse the repository at this point in the history
Send multiple keys
  • Loading branch information
iberianpig committed Aug 30, 2024
2 parents 4b034d8 + f08bd6d commit 40a5b3a
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 23 deletions.
20 changes: 16 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,23 @@ NEXTSONG
PREVIOUSSONG
```

## Run fusuma-sendkey on Terminal
## Running fusuma-sendkey on Terminal

* `fusuma-sendkey` command is available on your terminal
* `fusuma-sendkey` command is available on your terminal for testing.
* `fusuma-sendkey` supports modifier keys and multiple key presses.
Combine keys for pressing the same time with `+`
- Combine keys for pressing the same time with `+`
- Separate keys for pressing sequentially with `,`

### Example (Sendkey with Modifier Keys)

```sh
$ fusuma-sendkey LEFTCTRL+T # press ctrl key + t key
$ fusuma-sendkey LEFTCTRL+T # Open a new tab
```

### Example (Sendkey with Multiple Key Presses)

```sh
$ fusuma-sendkey ["LEFTSHIFT+F10", "T", "ENTER", "ESC"] # Google Translate
```

Some of the keys found with `fusuma-sendkey -l` may actually be invalid keys.
Expand All @@ -83,6 +91,10 @@ swipe:
sendkey: "LEFTCTRL+T" # open new tab
down:
sendkey: "LEFTCTRL+W" # close tab

hold:
3:
sendkey: ["LEFTSHIFT+F10", "T", "ENTER", "ESC"] # Translate in Google Chrome
```
### clearmodifiers
Expand Down
18 changes: 15 additions & 3 deletions exe/fusuma-sendkey
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,25 @@ if option[:version]
return
end

param = ARGV.first
args = ARGV.first

if param.nil?
if args.nil?
warn 'fusuma-sendkey require 1 arugument'
warn 'e.g. fusuma-sendkey LEFTALT+LEFT'
warn 'e.g. fusuma-sendkey [A, B, C]'
exit 1
end


# remove [ and ] from args
params = args.delete('[]').split(',').map(&:strip)
require 'debug'; debugger

keyboard = Fusuma::Plugin::Sendkey::Keyboard.new(name_pattern: device_name)
keyboard.valid?(param: param) && keyboard.type(param: param)
return unless keyboard.valid?(params)

if params.size == 1
keyboard.type(param: params.first)
else
keyboard.types(params)
end
23 changes: 16 additions & 7 deletions lib/fusuma/plugin/executors/sendkey_executor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,21 @@ def config_param_types
# @param event [Event]
# @return [nil]
def execute(event)
MultiLogger.info(sendkey: search_param(event))
keyboard.type(
param: search_param(event),
keep: search_keypress(event),
clear: clearmodifiers(event)
)
params = search_param(event)
MultiLogger.info(sendkey: params)
case params
when Array
keyboard.types(params)
when String
keyboard.type(
param: params,
keep: search_keypress(event),
clear: clearmodifiers(event)
)
else
MultiLogger.error("sendkey: Invalid config: #{params}")
nil
end
end

# check executable
Expand All @@ -40,7 +49,7 @@ def execute(event)
def executable?(event)
event.tag.end_with?("_detector") &&
event.record.type == :index &&
keyboard.valid?(param: search_param(event))
keyboard.valid?(search_param(event))
end

private
Expand Down
31 changes: 26 additions & 5 deletions lib/fusuma/plugin/sendkey/keyboard.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,20 @@ def initialize(name_pattern: nil)
@device = Device.new(path: "/dev/input/#{device.id}")
end

# @param params [Array]
def types(args)
return unless args.is_a?(Array)

args.each do |arg|
case arg
when String
type(param: arg)
when Hash
type(**arg)
end
end
end

# @param param [String] key names separated by '+' to type
# @param keep [String] key names separated by '+' to keep
# @param clear [String, Symbol, TrueClass] key names separated by '+' to clear or :all to release all modifiers
Expand Down Expand Up @@ -80,11 +94,18 @@ def keyup(keycode)
end

# @param param [String]
def valid?(param:)
return unless param.is_a?(String)

keycodes = param_to_keycodes(param)
keycodes.all? { |keycode| support?(keycode) }
def valid?(params)
case params
when Array
params.all? { |param| valid?(param) }
when String
param = params
keycodes = param_to_keycodes(param)
keycodes.all? { |keycode| support?(keycode) }
else
MultiLogger.error "sendkey: Invalid config: #{params}"
nil
end
end

def send_event(code:, press: true)
Expand Down
21 changes: 18 additions & 3 deletions spec/fusuma/plugin/executors/sendkey_executor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ module Executors
sendkey: KEY_CODE_WITH_KEYPRESS_WITH_CLEAR
clearmodifiers: true
direction2: { sendkey: ["LEFTSHIFT+F10", "T", "ENTER", "ESC"] }
plugin:
executors:
sendkey_executor:
Expand Down Expand Up @@ -78,15 +80,28 @@ module Executors
end
end
end

context "with multiple keys from sendkey array" do
before do
index_with_array = Config::Index.new([:dummy, 1, :direction2])
record = Events::Records::IndexRecord.new(index: index_with_array)
@event = Events::Event.new(tag: "dummy_detector", record: record)
end

it "sends each key from the sendkey array to keyboard" do
expect(@keyboard).to receive(:types).with(["LEFTSHIFT+F10", "T", "ENTER", "ESC"])
subject
end
end
end

describe "#executable?" do
before do
allow(@keyboard).to receive(:valid?).with(param: "MODIFIER_CODE+KEY_CODE")
allow(@keyboard).to receive(:valid?).with("MODIFIER_CODE+KEY_CODE")
.and_return true
allow(@keyboard).to receive(:valid?).with(param: "KEY_CODE")
allow(@keyboard).to receive(:valid?).with("KEY_CODE")
.and_return true
allow(@keyboard).to receive(:valid?).with(param: "INVALID_CODE")
allow(@keyboard).to receive(:valid?).with("INVALID_CODE")
.and_return false
end

Expand Down
34 changes: 33 additions & 1 deletion spec/fusuma/plugin/sendkey/keyboard_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ module Sendkey

@device = instance_double(Sendkey::Device)
allow(@device).to receive(:write_event).with(anything)
# allow(@device).to receive(:valid?).with(param: 'KEY_A')

allow(Sendkey::Device).to receive(:new).and_return(@device)

Expand Down Expand Up @@ -284,6 +283,39 @@ module Sendkey
end
end
end

describe "#types" do
subject { @keyboard.types(@args) }
context "with multiple keys(Array)" do
before do
allow(Keyboard)
.to receive(:find_device)
.and_return(Fusuma::Device.new(name: "dummy keyboard"))

@device = instance_double(Sendkey::Device)
allow(@device).to receive(:write_event).with(anything)

allow(Sendkey::Device).to receive(:new).and_return(@device)

@keyboard = Keyboard.new
@args = ["LEFTSHIFT+F10", "T", "ENTER", "ESC"]
end

it "types LEFTSHIFT+F10, T, ENTER, ESC" do
expect(@keyboard).to receive(:send_event).with(code: "KEY_LEFTSHIFT", press: true).ordered
expect(@keyboard).to receive(:send_event).with(code: "KEY_F10", press: true).ordered
expect(@keyboard).to receive(:send_event).with(code: "KEY_F10", press: false).ordered
expect(@keyboard).to receive(:send_event).with(code: "KEY_LEFTSHIFT", press: false).ordered
expect(@keyboard).to receive(:send_event).with(code: "KEY_T", press: true).ordered
expect(@keyboard).to receive(:send_event).with(code: "KEY_T", press: false).ordered
expect(@keyboard).to receive(:send_event).with(code: "KEY_ENTER", press: true).ordered
expect(@keyboard).to receive(:send_event).with(code: "KEY_ENTER", press: false).ordered
expect(@keyboard).to receive(:send_event).with(code: "KEY_ESC", press: true).ordered
expect(@keyboard).to receive(:send_event).with(code: "KEY_ESC", press: false).ordered
subject
end
end
end
end
end
end
Expand Down

0 comments on commit 40a5b3a

Please sign in to comment.