Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor mouse scrolling code #1594

Merged
merged 7 commits into from
Nov 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
292 changes: 39 additions & 253 deletions plugin/mouse/mouse.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
from talon import Context, Module, actions, app, clip, cron, ctrl, imgui, settings, ui
from talon import Context, Module, actions, clip, ctrl, settings, ui
from talon_plugins import eye_zoom_mouse

key = actions.key
self = actions.self
scroll_amount = 0
click_job = None
scroll_job = None
gaze_job = None
cancel_scroll_on_pop = True
control_mouse_forced = False
hiss_scroll_up = False

mod = Module()
ctx = Context()

Expand All @@ -36,52 +26,12 @@
default=False,
desc="When enabled, pop stops mouse drag",
)
mod.setting(
"mouse_enable_hiss_scroll",
type=bool,
default=False,
desc="Hiss noise scrolls down when enabled",
)
mod.setting(
"mouse_wake_hides_cursor",
type=bool,
default=False,
desc="When enabled, mouse wake will hide the cursor. mouse_wake enables zoom mouse.",
)
mod.setting(
"mouse_hide_mouse_gui",
type=bool,
default=False,
desc="When enabled, the 'Scroll Mouse' GUI will not be shown.",
)
mod.setting(
"mouse_continuous_scroll_amount",
type=int,
default=80,
desc="The default amount used when scrolling continuously",
)
mod.setting(
"mouse_wheel_down_amount",
type=int,
default=120,
desc="The amount to scroll up/down (equivalent to mouse wheel on Windows by default)",
)
mod.setting(
"mouse_wheel_horizontal_amount",
type=int,
default=40,
desc="The amount to scroll left/right",
)

continuous_scroll_mode = ""


@imgui.open(x=700, y=0)
def gui_wheel(gui: imgui.GUI):
gui.text(f"Scroll mode: {continuous_scroll_mode}")
gui.line()
if gui.button("Wheel Stop [stop scrolling]"):
actions.user.mouse_scroll_stop()


@mod.action_class
Expand All @@ -104,19 +54,23 @@ def mouse_drag(button: int):
actions.user.mouse_drag_end()

# Start drag
ctrl.mouse_click(button=button, down=True)
actions.mouse_drag(button)

def mouse_drag_end():
def mouse_drag_end() -> bool:
"""Releases any held mouse buttons"""
for button in ctrl.mouse_buttons_down():
ctrl.mouse_click(button=button, up=True)
buttons = ctrl.mouse_buttons_down()
if buttons:
for button in buttons:
actions.mouse_release(button)
return True
return False

def mouse_drag_toggle(button: int):
"""If the button is held down, release the button, else start dragging"""
if button in list(ctrl.mouse_buttons_down()):
ctrl.mouse_click(button=button, up=True)
if button in ctrl.mouse_buttons_down():
actions.mouse_release(button)
else:
actions.user.mouse_drag(button=button)
actions.mouse_drag(button)

def mouse_sleep():
"""Disables control mouse, zoom mouse, and re-enables cursor"""
Expand All @@ -125,80 +79,9 @@ def mouse_sleep():
actions.tracking.control1_toggle(False)

actions.user.mouse_cursor_show()
stop_scroll()
actions.user.mouse_scroll_stop()
actions.user.mouse_drag_end()

def mouse_scroll_down(amount: float = 1):
"""Scrolls down"""
mouse_scroll(amount * settings.get("user.mouse_wheel_down_amount"))()

def mouse_scroll_down_continuous():
"""Scrolls down continuously"""
global continuous_scroll_mode
continuous_scroll_mode = "scroll down continuous"
mouse_scroll(settings.get("user.mouse_continuous_scroll_amount"))()

if scroll_job is None:
start_scroll()

if not settings.get("user.mouse_hide_mouse_gui"):
gui_wheel.show()

def mouse_scroll_up(amount: float = 1):
"""Scrolls up"""
mouse_scroll(-amount * settings.get("user.mouse_wheel_down_amount"))()

def mouse_scroll_up_continuous():
"""Scrolls up continuously"""
global continuous_scroll_mode
continuous_scroll_mode = "scroll up continuous"
mouse_scroll(-settings.get("user.mouse_continuous_scroll_amount"))()

if scroll_job is None:
start_scroll()
if not settings.get("user.mouse_hide_mouse_gui"):
gui_wheel.show()

def mouse_scroll_left(amount: float = 1):
"""Scrolls left"""
actions.mouse_scroll(
0, -amount * settings.get("user.mouse_wheel_horizontal_amount")
)

def mouse_scroll_right(amount: float = 1):
"""Scrolls right"""
actions.mouse_scroll(
0, amount * settings.get("user.mouse_wheel_horizontal_amount")
)

def mouse_scroll_stop():
"""Stops scrolling"""
stop_scroll()

def mouse_gaze_scroll():
"""Starts gaze scroll"""
global continuous_scroll_mode
# this calls stop_scroll, which resets continuous_scroll_mode
start_cursor_scrolling()

continuous_scroll_mode = "gaze scroll"

if not settings.get("user.mouse_hide_mouse_gui"):
gui_wheel.show()

# enable 'control mouse' if eye tracker is present and not enabled already
global control_mouse_forced
if not actions.tracking.control_enabled():
actions.tracking.control_toggle(True)
control_mouse_forced = True

def mouse_gaze_scroll_toggle():
"""If not scrolling, start gaze scroll, else stop scrolling."""
if continuous_scroll_mode == "":
actions.user.mouse_gaze_scroll()
else:
actions.user.mouse_scroll_stop()

def copy_mouse_position():
"""Copy the current mouse position coordinates"""
position = ctrl.mouse_pos()
Expand All @@ -209,138 +92,41 @@ def mouse_move_center_active_window():
rect = ui.active_window().rect
ctrl.mouse_move(rect.left + (rect.width / 2), rect.top + (rect.height / 2))

def hiss_scroll_up():
"""Change mouse hiss scroll direction to up"""
global hiss_scroll_up
hiss_scroll_up = True

def hiss_scroll_down():
"""Change mouse hiss scroll direction to down"""
global hiss_scroll_up
hiss_scroll_up = False


@ctx.action_class("user")
class UserActions:
def noise_trigger_pop():
if (
settings.get("user.mouse_enable_pop_stops_drag")
and ctrl.mouse_buttons_down()
):
actions.user.mouse_drag_end()
elif settings.get("user.mouse_enable_pop_stops_scroll") and (
gaze_job or scroll_job
):
# Allow pop to stop scroll
stop_scroll()
else:
# Otherwise respect the mouse_enable_pop_click setting
setting_val = settings.get("user.mouse_enable_pop_click")

is_using_eye_tracker = (
actions.tracking.control_zoom_enabled()
or actions.tracking.control_enabled()
or actions.tracking.control1_enabled()
)
should_click = (
setting_val == 2 and not actions.tracking.control_zoom_enabled()
) or (
setting_val == 1
and is_using_eye_tracker
and not actions.tracking.control_zoom_enabled()
)
if should_click:
ctrl.mouse_click(button=0, hold=16000)

def noise_trigger_hiss(active: bool):
if settings.get("user.mouse_enable_hiss_scroll"):
if active:
if hiss_scroll_up:
actions.user.mouse_scroll_up_continuous()
else:
actions.user.mouse_scroll_down_continuous()
else:
actions.user.mouse_scroll_stop()


def mouse_scroll(amount):
def scroll():
global scroll_amount
if continuous_scroll_mode:
if (scroll_amount >= 0) == (amount >= 0):
scroll_amount += amount
else:
scroll_amount = amount
actions.mouse_scroll(y=int(amount))

return scroll
dont_click = False

# Allow pop to stop drag
if settings.get("user.mouse_enable_pop_stops_drag"):
if actions.user.mouse_drag_end():
dont_click = True

def scroll_continuous_helper():
global scroll_amount
# print("scroll_continuous_helper")
if scroll_amount and (eye_zoom_mouse.zoom_mouse.state == eye_zoom_mouse.STATE_IDLE):
actions.mouse_scroll(by_lines=False, y=int(scroll_amount / 10))
# Allow pop to stop scroll
if settings.get("user.mouse_enable_pop_stops_scroll"):
if actions.user.mouse_scroll_stop():
dont_click = True


def start_scroll():
global scroll_job
scroll_job = cron.interval("60ms", scroll_continuous_helper)


def gaze_scroll():
# print("gaze_scroll")
if (
eye_zoom_mouse.zoom_mouse.state == eye_zoom_mouse.STATE_IDLE
): # or eye_zoom_mouse.zoom_mouse.state == eye_zoom_mouse.STATE_SLEEP:
x, y = ctrl.mouse_pos()

# the rect for the window containing the mouse
rect = None

# on windows, check the active_window first since ui.windows() is not z-ordered
if app.platform == "windows" and ui.active_window().rect.contains(x, y):
rect = ui.active_window().rect
else:
windows = ui.windows()
for w in windows:
if w.rect.contains(x, y):
rect = w.rect
break

if rect is None:
# print("no window found!")
if dont_click:
return

midpoint = rect.y + rect.height / 2
amount = int(((y - midpoint) / (rect.height / 10)) ** 3)
actions.mouse_scroll(by_lines=False, y=amount)

# print(f"gaze_scroll: {midpoint} {rect.height} {amount}")
# Otherwise respect the mouse_enable_pop_click setting
setting_val = settings.get("user.mouse_enable_pop_click")

is_using_eye_tracker = (
actions.tracking.control_zoom_enabled()
or actions.tracking.control_enabled()
or actions.tracking.control1_enabled()
)

def stop_scroll():
global scroll_amount, scroll_job, gaze_job, continuous_scroll_mode
scroll_amount = 0
if scroll_job:
cron.cancel(scroll_job)

if gaze_job:
cron.cancel(gaze_job)

global control_mouse_forced
if control_mouse_forced:
actions.tracking.control_toggle(False)
control_mouse_forced = False

scroll_job = None
gaze_job = None
gui_wheel.hide()

continuous_scroll_mode = ""

should_click = (
setting_val == 2 and not actions.tracking.control_zoom_enabled()
) or (
setting_val == 1
and is_using_eye_tracker
and not actions.tracking.control_zoom_enabled()
)

def start_cursor_scrolling():
global scroll_job, gaze_job
stop_scroll()
gaze_job = cron.interval("60ms", gaze_scroll)
if should_click:
ctrl.mouse_click(button=0, hold=16000)
Loading