from abc import ABC, abstractmethod from ctypes import WINFUNCTYPE, byref, windll from ctypes.wintypes import BOOL, HWND, INT, LPARAM, LPPOINT, LPRECT, POINT, RECT import time import math user32 = windll.user32 gdi32 = windll.gdi32 user32.GetSystemMetrics.argtypes = [INT] user32.GetCursorPos.argtypes = [LPPOINT] user32.SetCursorPos.argtypes = [INT, INT] CB_ENUM_WINDOWS = WINFUNCTYPE(BOOL, HWND, LPARAM) user32.EnumWindows.argtypes = [CB_ENUM_WINDOWS, LPARAM] user32.GetWindowRect.argtypes = [HWND, LPRECT] user32.SetWindowPos.argtypes = [HWND, INT, INT, INT, INT, INT, INT] user32.IsWindowVisible.argtypes = [HWND] class BouncyObject(ABC): @abstractmethod def get_position(self) -> tuple[int, int]: raise NotImplementedError @abstractmethod def set_position(self, xy: tuple[int, int]): raise NotImplementedError class Mouse(BouncyObject): def get_position(self) -> tuple[int, int]: point = POINT() user32.GetCursorPos(byref(point)) return point.x, point.y def set_position(self, xy: tuple[int, int]): x, y = xy user32.SetCursorPos(x, y) class Window(BouncyObject): def __init__(self, handle: int): self._handle = handle def get_position(self) -> tuple[int, int]: rect = RECT() user32.GetWindowRect(self._handle, byref(rect)) return (rect.left, rect.bottom) def set_position(self, xy: tuple[int, int]): rect = RECT() user32.GetWindowRect(self._handle, byref(rect)) width = rect.right - rect.left height = rect.bottom - rect.top x, y = xy user32.SetWindowPos( self._handle, 0, x, y - height, -1, -1, 0x0010 | # SWP_NOACTIVATE 0x0001 | # SWP_NOSIZE 0x0004 | # SWP_NOZORDER 0x4000 # SWP_ASYNCWINDOWPOS ) def enumerate_windows() -> list[int]: windows: list[int] = [] @CB_ENUM_WINDOWS def _handle_window(hwnd, lparam): if user32.IsWindowVisible(hwnd): windows.append(hwnd) return True user32.EnumWindows(_handle_window, 0) return windows def get_resolution_y() -> int: SM_CYSCREEN = 1 return user32.GetSystemMetrics(SM_CYSCREEN) class Body(object): def __init__(self, controlled_object: BouncyObject): self._last_xy: tuple[int, int] | None =None self._last_offset: tuple[float, float] = (0.5, 0.5) self._velocity = 0.0 self._controlled_object = controlled_object def update(self, res_y): x, y = self._controlled_object.get_position() ox, oy = self._last_offset x += ox y += oy if self._last_xy: last_x, last_y = self._last_xy dx = x - last_x dy = y - last_y dist = math.sqrt(dx * dx + dy * dy) # if they move the mouse they can fight it # (but they have to move it a lot) self._velocity *= 1.0 - min(dist / 128, 1.0) for _ in range(100): self._velocity += 0.0002 y += self._velocity if y > res_y and self._velocity > 0: self._velocity = -self._velocity * 0.75 if abs(self._velocity) < 0.05: self._velocity = 0 self._controlled_object.set_position((int(x), int(y))) self._last_xy = (int(x), int(y)) self._last_offset = (x % 1, y % 1) class Bodies(object): def __init__(self): self._mouse = Body(Mouse()) self._windows = {} def update_list(self): windows2 = {} for i in enumerate_windows(): if existing := self._windows.get(i): windows2[i] = existing else: windows2[i] = Body(Window(i)) self._windows = windows2 def get(self) -> list[Body]: return [self._mouse, *self._windows.values()] def main(): bodies = Bodies() while True: res_y = get_resolution_y() bodies.update_list() print(len(bodies.get())); for b in bodies.get(): b.update(res_y) time.sleep(1/120.0) if __name__ == "__main__": main()