# mousehook.py import ctypes from ctypes import wintypes, c_void_p, sizeof import win32gui import threading user32 = ctypes.windll.user32 kernel32 = ctypes.windll.kernel32 WM_LBUTTONDBLCLK = 0x0203 WH_MOUSE_LL = 14 # Fix for ULONG_PTR if sizeof(c_void_p) == 8: ULONG_PTR = ctypes.c_uint64 else: ULONG_PTR = ctypes.c_uint32 class MSLLHOOKSTRUCT(ctypes.Structure): _fields_ = [("pt", wintypes.POINT), ("mouseData", wintypes.DWORD), ("flags", wintypes.DWORD), ("time", wintypes.DWORD), ("dwExtraInfo", ULONG_PTR)] class MouseHook: def __init__(self, target_hwnd, callback): self.target_hwnd = target_hwnd self.callback = callback self.hooked = None self.running = False def _low_level_mouse_proc(self, nCode, wParam, lParam): if nCode == 0: mouse_struct = ctypes.cast(lParam, ctypes.POINTER(MSLLHOOKSTRUCT)).contents hwnd_under_cursor = win32gui.WindowFromPoint((mouse_struct.pt.x, mouse_struct.pt.y)) if hwnd_under_cursor == self.target_hwnd and wParam == WM_LBUTTONDBLCLK: print("✅ Double-click blocked from VLC — calling toggle_fullscreen()") self.callback() return 1 # block event return user32.CallNextHookEx(self.hooked, nCode, wParam, lParam) def start(self): self.running = True CMPFUNC = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_void_p) self.pointer = CMPFUNC(self._low_level_mouse_proc) h_module = kernel32.GetModuleHandleW(None) self.hooked = user32.SetWindowsHookExW(WH_MOUSE_LL, self.pointer, h_module, 0) msg = wintypes.MSG() while user32.GetMessageW(ctypes.byref(msg), 0, 0, 0) != 0: user32.TranslateMessage(ctypes.byref(msg)) user32.DispatchMessageW(ctypes.byref(msg)) def stop(self): self.running = False if self.hooked: user32.UnhookWindowsHookEx(self.hooked) self.hooked = None