diff --git a/src/glide/browser/base/content/browser.mts b/src/glide/browser/base/content/browser.mts index 5ceadfb2..09c78973 100644 --- a/src/glide/browser/base/content/browser.mts +++ b/src/glide/browser/base/content/browser.mts @@ -100,6 +100,8 @@ class GlideBrowserClass { document!.addEventListener("keydown", this.#on_keydown.bind(this), true); document!.addEventListener("keypress", this.#on_keypress.bind(this), true); document!.addEventListener("keyup", this.#on_keyup.bind(this), true); + document!.addEventListener("mousedown", this.#on_mousedown.bind(this), true); + document!.addEventListener("wheel", this.#on_wheel.bind(this), true); window.addEventListener("MozDOMFullscreen:Entered", this.#on_fullscreen_enter.bind(this), true); window.addEventListener("MozDOMFullscreen:Exited", this.#on_fullscreen_exit.bind(this), true); @@ -1790,6 +1792,41 @@ class GlideBrowserClass { } } + async #on_mousedown(event: MouseEvent) { + if ((event.target as any).$glide_hack_click_from_hint) { + return; + } + const has_partial = this.key_manager.has_partial_mapping; + if (!has_partial) { + return; + } + const mode = this.state.mode; + this._log.debug("mousedown event", "resetting key sequence"); + this.key_manager.reset_sequence(); + this.#display_keyseq([]); + this.#invoke_keystatechanged_autocmd({ + mode, + sequence: [], + partial: false, + }); + } + + async #on_wheel(_event: WheelEvent) { + const has_partial = this.key_manager.has_partial_mapping; + if (!has_partial) { + return; + } + const mode = this.state.mode; + this._log.debug("scroll event", "resetting key sequence"); + this.key_manager.reset_sequence(); + this.#display_keyseq([]); + this.#invoke_keystatechanged_autocmd({ + mode, + sequence: [], + partial: false, + }); + } + /** * Returns the Glide JSActor for the currently focused frame. * diff --git a/src/glide/browser/base/content/test/mode/browser_keyseq_display.ts b/src/glide/browser/base/content/test/mode/browser_keyseq_display.ts index 46a1912a..17d8b612 100644 --- a/src/glide/browser/base/content/test/mode/browser_keyseq_display.ts +++ b/src/glide/browser/base/content/test/mode/browser_keyseq_display.ts @@ -120,3 +120,40 @@ add_task(async function test_keyseq_display_without_toolbar_button() { // Restore the button for other tests document!.body!.appendChild(original_button!); }); + +add_task(async function test_click_resets_partial_leader_sequence() { + await reload_config(function _() {}); + await keys(""); + await keys(""); + await sleep_frames(2); + is(GlideBrowser.key_manager.has_partial_mapping, true, "Leader key should start partial sequence"); + is(GlideBrowser.key_manager.current_sequence.join(""), "", "Sequence should contain space"); + + const body = document!.querySelector("body")!; + EventUtils.synthesizeMouse(body, 100, 100, {}, window); + await sleep_frames(2); + is(GlideBrowser.key_manager.has_partial_mapping, false, "Click should reset partial sequence"); + is(GlideBrowser.key_manager.current_sequence.length, 0, "Sequence should be empty after click"); +}); + +add_task(async function test_wheel_resets_partial_leader_sequence() { + await reload_config(function _() {}); + await BrowserTestUtils.withNewTab( + "http://mochi.test:8888/browser/glide/browser/base/content/test/mode/key_test.html", + async () => { + await keys(""); + GlideBrowser.key_manager.reset_sequence(); + await keys(""); + await sleep_frames(2); + + is(GlideBrowser.key_manager.has_partial_mapping, true, "Leader key should start partial sequence"); + EventUtils.synthesizeWheel(document!.querySelector("body")!, 100, 100, { + deltaY: 100, + }, window); + await sleep_frames(2); + + is(GlideBrowser.key_manager.has_partial_mapping, false, "Wheel should reset partial sequence"); + is(GlideBrowser.key_manager.current_sequence.length, 0, "Sequence should be empty after wheel"); + }, + ); +});