dotfiles/talon/community/community-cursorless-0.4.0/code/mouse.py
2024-11-16 20:27:38 -07:00

373 lines
11 KiB
Python

import os
import pathlib
import subprocess
from talon import (
Context,
Module,
actions,
app,
cron,
ctrl,
clip,
imgui,
noise,
settings,
ui,
)
from talon_plugins import eye_mouse, eye_zoom_mouse, speech
from talon_plugins.eye_mouse import config, toggle_camera_overlay, toggle_control
key = actions.key
self = actions.self
scroll_amount = 0
click_job = None
scroll_job = None
gaze_job = None
cancel_scroll_on_pop = True
default_cursor = {
"AppStarting": r"%SystemRoot%\Cursors\aero_working.ani",
"Arrow": r"%SystemRoot%\Cursors\aero_arrow.cur",
"Hand": r"%SystemRoot%\Cursors\aero_link.cur",
"Help": r"%SystemRoot%\Cursors\aero_helpsel.cur",
"No": r"%SystemRoot%\Cursors\aero_unavail.cur",
"NWPen": r"%SystemRoot%\Cursors\aero_pen.cur",
"Person": r"%SystemRoot%\Cursors\aero_person.cur",
"Pin": r"%SystemRoot%\Cursors\aero_pin.cur",
"SizeAll": r"%SystemRoot%\Cursors\aero_move.cur",
"SizeNESW": r"%SystemRoot%\Cursors\aero_nesw.cur",
"SizeNS": r"%SystemRoot%\Cursors\aero_ns.cur",
"SizeNWSE": r"%SystemRoot%\Cursors\aero_nwse.cur",
"SizeWE": r"%SystemRoot%\Cursors\aero_ew.cur",
"UpArrow": r"%SystemRoot%\Cursors\aero_up.cur",
"Wait": r"%SystemRoot%\Cursors\aero_busy.ani",
"Crosshair": "",
"IBeam": "",
}
# todo figure out why notepad++ still shows the cursor sometimes.
hidden_cursor = os.path.join(
os.path.dirname(os.path.realpath(__file__)), r"Resources\HiddenCursor.cur"
)
mod = Module()
mod.list(
"mouse_button", desc="List of mouse button words to mouse_click index parameter"
)
setting_mouse_enable_pop_click = mod.setting(
"mouse_enable_pop_click",
type=int,
default=0,
desc="Enable pop to click when control mouse is enabled.",
)
setting_mouse_enable_pop_stops_scroll = mod.setting(
"mouse_enable_pop_stops_scroll",
type=int,
default=0,
desc="When enabled, pop stops continuous scroll modes (wheel upper/downer/gaze)",
)
setting_mouse_wake_hides_cursor = mod.setting(
"mouse_wake_hides_cursor",
type=int,
default=0,
desc="When enabled, mouse wake will hide the cursor. mouse_wake enables zoom mouse.",
)
setting_mouse_hide_mouse_gui = mod.setting(
"mouse_hide_mouse_gui",
type=int,
default=0,
desc="When enabled, the 'Scroll Mouse' GUI will not be shown.",
)
setting_mouse_continuous_scroll_amount = mod.setting(
"mouse_continuous_scroll_amount",
type=int,
default=80,
desc="The default amount used when scrolling continuously",
)
setting_mouse_wheel_down_amount = 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)",
)
continuous_scoll_mode = ""
@imgui.open(x=700, y=0)
def gui_wheel(gui: imgui.GUI):
gui.text("Scroll mode: {}".format(continuous_scoll_mode))
gui.line()
if gui.button("Wheel Stop [stop scrolling]"):
actions.user.mouse_scroll_stop()
@mod.action_class
class Actions:
def mouse_show_cursor():
"""Shows the cursor"""
show_cursor_helper(True)
def mouse_hide_cursor():
"""Hides the cursor"""
show_cursor_helper(False)
def mouse_wake():
"""Enable control mouse, zoom mouse, and disables cursor"""
eye_zoom_mouse.toggle_zoom_mouse(True)
# eye_mouse.control_mouse.enable()
if setting_mouse_wake_hides_cursor.get() >= 1:
show_cursor_helper(False)
def mouse_calibrate():
"""Start calibration"""
eye_mouse.calib_start()
def mouse_toggle_control_mouse():
"""Toggles control mouse"""
toggle_control(not config.control_mouse)
def mouse_toggle_camera_overlay():
"""Toggles camera overlay"""
toggle_camera_overlay(not config.show_camera)
def mouse_toggle_zoom_mouse():
"""Toggles zoom mouse"""
eye_zoom_mouse.toggle_zoom_mouse(not eye_zoom_mouse.zoom_mouse.enabled)
def mouse_cancel_zoom_mouse():
"""Cancel zoom mouse if pending"""
if (
eye_zoom_mouse.zoom_mouse.enabled
and eye_zoom_mouse.zoom_mouse.state != eye_zoom_mouse.STATE_IDLE
):
eye_zoom_mouse.zoom_mouse.cancel()
def mouse_trigger_zoom_mouse():
"""Trigger zoom mouse if enabled"""
if eye_zoom_mouse.zoom_mouse.enabled:
eye_zoom_mouse.zoom_mouse.on_pop(eye_zoom_mouse.zoom_mouse.state)
def mouse_drag():
"""(TEMPORARY) Press and hold/release button 0 depending on state for dragging"""
# todo: fixme temporary fix for drag command
button_down = len(list(ctrl.mouse_buttons_down())) > 0
print(str(ctrl.mouse_buttons_down()))
if not button_down:
# print("start drag...")
ctrl.mouse_click(button=0, down=True)
# app.notify("drag started")
else:
# print("end drag...")
ctrl.mouse_click(button=0, up=True)
# app.notify("drag stopped")
def mouse_sleep():
"""Disables control mouse, zoom mouse, and re-enables cursor"""
eye_zoom_mouse.toggle_zoom_mouse(False)
toggle_control(False)
show_cursor_helper(True)
stop_scroll()
# todo: fixme temporary fix for drag command
button_down = len(list(ctrl.mouse_buttons_down())) > 0
if button_down:
ctrl.mouse_click(button=0, up=True)
def mouse_scroll_down():
"""Scrolls down"""
mouse_scroll(setting_mouse_wheel_down_amount.get())()
def mouse_scroll_down_continuous():
"""Scrolls down continuously"""
global continuous_scoll_mode
continuous_scoll_mode = "scroll down continuous"
mouse_scroll(setting_mouse_continuous_scroll_amount.get())()
if scroll_job is None:
start_scroll()
if setting_mouse_hide_mouse_gui.get() == 0:
gui_wheel.show()
def mouse_scroll_up():
"""Scrolls up"""
mouse_scroll(-setting_mouse_wheel_down_amount.get())()
def mouse_scroll_up_continuous():
"""Scrolls up continuously"""
global continuous_scoll_mode
continuous_scoll_mode = "scroll up continuous"
mouse_scroll(-setting_mouse_continuous_scroll_amount.get())()
if scroll_job is None:
start_scroll()
if setting_mouse_hide_mouse_gui.get() == 0:
gui_wheel.show()
def mouse_scroll_stop():
"""Stops scrolling"""
stop_scroll()
def mouse_gaze_scroll():
"""Starts gaze scroll"""
global continuous_scoll_mode
continuous_scoll_mode = "gaze scroll"
start_cursor_scrolling()
if setting_mouse_hide_mouse_gui.get() == 0:
gui_wheel.show()
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 show_cursor_helper(show):
"""Show/hide the cursor"""
if app.platform == "windows":
import ctypes
import winreg
import win32con
try:
Registrykey = winreg.OpenKey(
winreg.HKEY_CURRENT_USER, r"Control Panel\Cursors", 0, winreg.KEY_WRITE
)
for value_name, value in default_cursor.items():
if show:
winreg.SetValueEx(
Registrykey, value_name, 0, winreg.REG_EXPAND_SZ, value
)
else:
winreg.SetValueEx(
Registrykey, value_name, 0, winreg.REG_EXPAND_SZ, hidden_cursor
)
winreg.CloseKey(Registrykey)
ctypes.windll.user32.SystemParametersInfoA(
win32con.SPI_SETCURSORS, 0, None, 0
)
except WindowsError:
print("Unable to show_cursor({})".format(str(show)))
else:
ctrl.cursor_visible(show)
def on_pop(active):
pass
# actions.core.repeat_command()
noise.register("pop", on_pop)
def mouse_scroll(amount):
def scroll():
global scroll_amount
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
): # or eye_zoom_mouse.zoom_mouse.state == eye_zoom_mouse.STATE_SLEEP):
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)
# if eye_zoom_mouse.zoom_mouse.enabled and eye_mouse.mouse.attached_tracker is not None:
# eye_zoom_mouse.zoom_mouse.sleep(True)
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
scroll_amount = 0
if scroll_job:
cron.cancel(scroll_job)
if gaze_job:
cron.cancel(gaze_job)
scroll_job = None
gaze_job = None
gui_wheel.hide()
# if eye_zoom_mouse.zoom_mouse.enabled and eye_mouse.mouse.attached_tracker is not None:
# eye_zoom_mouse.zoom_mouse.sleep(False)
def start_cursor_scrolling():
global scroll_job, gaze_job
stop_scroll()
gaze_job = cron.interval("60ms", gaze_scroll)
# if eye_zoom_mouse.zoom_mouse.enabled and eye_mouse.mouse.attached_tracker is not None:
# eye_zoom_mouse.zoom_mouse.sleep(True)
if app.platform == "mac":
from talon import tap
def on_move(e):
if not config.control_mouse:
buttons = ctrl.mouse_buttons_down()
# print(str(ctrl.mouse_buttons_down()))
if not e.flags & tap.DRAG and buttons:
e.flags |= tap.DRAG
# buttons is a set now
e.button = list(buttons)[0]
e.modify()
tap.register(tap.MMOVE | tap.HOOK, on_move)