From bf90047e52ddd74fa5165d4cb68cc834c75a3b20 Mon Sep 17 00:00:00 2001 From: Ivan Kuchin Date: Tue, 7 Jan 2025 11:48:13 +0100 Subject: [PATCH] correctly set mouse events buttons property (#509) --- lib/ferrum/mouse.rb | 27 +++++++++++++++++++++---- spec/mouse_spec.rb | 49 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 64 insertions(+), 12 deletions(-) diff --git a/lib/ferrum/mouse.rb b/lib/ferrum/mouse.rb index 54083b11..6b1c340e 100644 --- a/lib/ferrum/mouse.rb +++ b/lib/ferrum/mouse.rb @@ -3,11 +3,19 @@ module Ferrum class Mouse CLICK_WAIT = ENV.fetch("FERRUM_CLICK_WAIT", 0.1).to_f - VALID_BUTTONS = %w[none left middle right back forward].freeze + BUTTON_MASKS = { + "none" => 0, + "left" => 1, + "right" => 2, + "middle" => 4, + "back" => 8, + "forward" => 16 + }.freeze def initialize(page) @page = page @x = @y = 0 + @buttons = 0 end # @@ -130,7 +138,8 @@ def move(x:, y:, steps: 1) slowmoable: true, type: "mouseMoved", x: new_x.to_i, - y: new_y.to_i) + y: new_y.to_i, + buttons: @buttons) end self @@ -140,16 +149,26 @@ def move(x:, y:, steps: 1) def mouse_event(type:, button: :left, count: 1, modifiers: nil, wait: 0) button = validate_button(button) - options = { x: @x, y: @y, type: type, button: button, clickCount: count } + register_event_button(type, button) + options = { x: @x, y: @y, type: type, button: button, buttons: @buttons, clickCount: count } options.merge!(modifiers: modifiers) if modifiers @page.command("Input.dispatchMouseEvent", wait: wait, slowmoable: true, **options) end def validate_button(button) button = button.to_s - raise "Invalid button: #{button}" unless VALID_BUTTONS.include?(button) + raise "Invalid button: #{button}" unless BUTTON_MASKS.key?(button) button end + + def register_event_button(type, button) + case type + when "mousePressed" + @buttons |= BUTTON_MASKS[button] + when "mouseReleased" + @buttons &= ~BUTTON_MASKS[button] + end + end end end diff --git a/spec/mouse_spec.rb b/spec/mouse_spec.rb index ee1c7fcd..73ae1a37 100644 --- a/spec/mouse_spec.rb +++ b/spec/mouse_spec.rb @@ -44,20 +44,16 @@ end describe "#move" do - let(:tracking_code) do - <<~JS + it "splits into steps" do + browser.go_to("/ferrum/simple") + browser.mouse.move(x: 100, y: 100) + browser.evaluate_async(<<~JS, browser.timeout) window.result = []; document.addEventListener("mousemove", e => { window.result.push([e.clientX, e.clientY]); }); arguments[0](); JS - end - - it "splits into steps" do - browser.go_to("/ferrum/simple") - browser.mouse.move(x: 100, y: 100) - browser.evaluate_async(tracking_code, browser.timeout) browser.mouse.move(x: 200, y: 300, steps: 5) @@ -69,6 +65,43 @@ [200, 300] ]) end + + it "sets buttons property" do + browser.go_to("/ferrum/simple") + browser.mouse.move(x: 100, y: 100) + browser.evaluate_async(<<~JS, browser.timeout) + window.result = []; + ["move", "up", "down"].forEach(type => + document.addEventListener(`mouse${type}`, e => { + window.result.push([type, e.clientX, e.clientY, e.buttons]); + }) + ); + arguments[0](); + JS + + browser.mouse + .move(x: 101, y: 102) + .down(button: :left) + .move(x: 103, y: 104) + .down(button: :right) + .move(x: 105, y: 106) + .up(button: :left) + .move(x: 107, y: 108) + .up(button: :right) + .move(x: 109, y: 110) + + expect(browser.evaluate("window.result")).to eq([ + ["move", 101, 102, 0], # none pressed + ["down", 101, 102, 1], # left down + ["move", 103, 104, 1], # left pressed + ["down", 103, 104, 3], # right down, left pressed + ["move", 105, 106, 3], # both pressed + ["up", 105, 106, 2], # left up, right pressed + ["move", 107, 108, 2], # right pressed + ["up", 107, 108, 0], # right up + ["move", 109, 110, 0] # none pressed + ]) + end end context "mouse support", skip: true do