dotfiles/talon/user/community/plugin/mouse/mouse.py

346 lines
10 KiB
Python

from talon import Context, Module, actions, app, clip, cron, ctrl, imgui, 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()
mod.list(
"mouse_button",
desc="List of mouse button words to mouse_click index parameter",
)
mod.setting(
"mouse_enable_pop_click",
type=int,
default=0,
desc="Pop noise clicks left mouse button. 0 = off, 1 = on with eyetracker but not with zoom mouse mode, 2 = on but not with zoom mouse mode",
)
mod.setting(
"mouse_enable_pop_stops_scroll",
type=bool,
default=False,
desc="When enabled, pop stops continuous scroll modes (wheel upper/downer/gaze)",
)
mod.setting(
"mouse_enable_pop_stops_drag",
type=bool,
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
class Actions:
def zoom_close():
"""Closes an in-progress zoom. Talon will move the cursor position but not click."""
if eye_zoom_mouse.zoom_mouse.state == eye_zoom_mouse.STATE_OVERLAY:
actions.tracking.zoom_cancel()
def mouse_wake():
"""Enable control mouse, zoom mouse, and disables cursor"""
actions.tracking.control_zoom_toggle(True)
if settings.get("user.mouse_wake_hides_cursor"):
actions.user.mouse_cursor_hide()
def mouse_drag(button: int):
"""Press and hold/release a specific mouse button for dragging"""
# Clear any existing drags
actions.user.mouse_drag_end()
# Start drag
ctrl.mouse_click(button=button, down=True)
def mouse_drag_end():
"""Releases any held mouse buttons"""
for button in ctrl.mouse_buttons_down():
ctrl.mouse_click(button=button, up=True)
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)
else:
actions.user.mouse_drag(button=button)
def mouse_sleep():
"""Disables control mouse, zoom mouse, and re-enables cursor"""
actions.tracking.control_zoom_toggle(False)
actions.tracking.control_toggle(False)
actions.tracking.control1_toggle(False)
actions.user.mouse_cursor_show()
stop_scroll()
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()
clip.set_text(repr(position))
def mouse_move_center_active_window():
"""move the mouse cursor to the center of the currently 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
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))
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!")
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}")
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 = ""
def start_cursor_scrolling():
global scroll_job, gaze_job
stop_scroll()
gaze_job = cron.interval("60ms", gaze_scroll)