diff --git a/bounce_c/.gitignore b/bounce_c/.gitignore deleted file mode 100644 index 60e5a2c..0000000 --- a/bounce_c/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.exe -*.pdb \ No newline at end of file diff --git a/bounce_v1.py.old b/bounce_v1.py.old deleted file mode 100644 index f32d295..0000000 --- a/bounce_v1.py.old +++ /dev/null @@ -1,72 +0,0 @@ -from ctypes import POINTER, WINFUNCTYPE, byref, windll -from ctypes.wintypes import BOOL, HWND, INT, LPARAM, LPPOINT, POINT -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) - -def get_mouse() -> tuple[int, int]: - point = POINT() - user32.GetCursorPos(byref(point)) - x, y = point.x, point.y - return x, y - -def get_resolution() -> tuple[int, int]: - SM_CXSCREEN = 0 - SM_CYSCREEN = 1 - - return ( - user32.GetSystemMetrics(SM_CXSCREEN), - user32.GetSystemMetrics(SM_CYSCREEN) - ) - -def set_mouse(x: int, y: int): - user32.SetCursorPos(x, y) - - -class MouseBody(object): - def __init__(self): - self._last_mouse = None - self.velocity = 0.0 - - def update(self): - mouse_x, mouse_y = get_mouse() - if self._last_mouse: - last_x, last_y = self._last_mouse - dx = mouse_x - last_x - dy = mouse_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 / 64, 1.0) - - _, res_y = get_resolution() - self.velocity += 1 - - new_y = int(mouse_y + self.velocity) - - if new_y > res_y: - # simulate an inelastic collision - self.velocity = -self.velocity * 0.75 - new_y = int(new_y + self.velocity) - - set_mouse(mouse_x, new_y) - self._last_mouse = (mouse_x, new_y) - -def main(): - body = MouseBody() - while True: - time.sleep(1/120.0) - body.update() - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/bounce_c/bounce.c b/c/bounce.c similarity index 59% rename from bounce_c/bounce.c rename to c/bounce.c index a4ff37b..8df84ae 100644 --- a/bounce_c/bounce.c +++ b/c/bounce.c @@ -2,48 +2,36 @@ #include #include #include -#include #define MAX_WINDOWS 1024 -// resolution +// == globals == uint32_t res_y; -void globals_init() { +void globals_update() { res_y = GetSystemMetrics(SM_CYSCREEN); } -// bodies +// == bodies == typedef struct body_t { - int32_t last_x; - int32_t last_y; - float offset_x; float offset_y; float velocity; } body_t; void body_init(body_t* body) { - body->last_x = -1; - body->last_y = -1; - body->offset_x = 0.5; body->offset_y = 0.5; body->velocity = 0.0; } -void body_update(body_t* body, int32_t x, int32_t y, int32_t* x_new, int32_t* y_new) { - if (body->last_x != -1 && body->last_y != -1) { - int32_t dx = x - body->last_x; - int32_t dy = y - body->last_y; - double dist = sqrt((double) dx * dx + dy * dy); - body->velocity *= 1.0 - min(dist / 128, 1.0); - } +void body_update(body_t* body, int32_t *y_ptr) { + int32_t y = *y_ptr; - float float_x = x + body->offset_x; - float float_y = y + body->offset_y; - for (uint8_t step = 0; step < 100; step += 1) { + float y_float = y + body->offset_y; + + for (size_t step = 0; step < 100; step++) { body->velocity += 0.0002; + y_float += body->velocity; - float_y += body->velocity; - if (float_y > res_y && body->velocity > 0) { + if (y_float > res_y && body->velocity > 0) { body->velocity = -body->velocity * 0.75; if (-body->velocity < 0.05) { body->velocity = 0; @@ -51,12 +39,9 @@ void body_update(body_t* body, int32_t x, int32_t y, int32_t* x_new, int32_t* y_ } } - *x_new = (int) float_x; - *y_new = (int) float_y; - body->last_x = *x_new; - body->last_y = *y_new; - body->offset_x = float_x - *x_new; - body->offset_y = float_y - *y_new; + *y_ptr = min((int) y_float, res_y); + + body->offset_y = y_float - *y_ptr; } // == mouse == @@ -73,9 +58,9 @@ void mouse_init() { void mouse_update() { POINT xy; GetCursorPos(&xy); - int32_t new_x, new_y; - body_update(&mouse_body.body, xy.x, xy.y, &new_x, &new_y); - SetCursorPos(new_x, new_y); + int32_t x = xy.x, y = xy.y; + body_update(&mouse_body.body, &y); + SetCursorPos(x, y); } // == window == @@ -97,12 +82,9 @@ void window_init() { } BOOL CALLBACK window_handle_enum(HWND window, LPARAM _) { - if (_n_new_windows >= MAX_WINDOWS) { - return 0; - } - if (!IsWindowVisible(window)) { - return 1; - } + if (_n_new_windows >= MAX_WINDOWS) { return 0; } + if (!IsWindowVisible(window)) { return 1; } + window_body_t new; new.window = window; body_init(&new.body); @@ -119,7 +101,6 @@ BOOL CALLBACK window_handle_enum(HWND window, LPARAM _) { void window_enumerate() { EnumWindows(window_handle_enum, 0); - // do the swap window_body_t* tmp_windows = windows; n_windows = _n_new_windows; @@ -138,22 +119,28 @@ void window_update() { int32_t x = rect.left; int32_t y = rect.bottom; - body_update(&windows[i].body, x, y, &x, &y); + body_update(&windows[i].body, &y); int32_t height = rect.bottom - rect.top; - uint32_t flags = SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER | SWP_ASYNCWINDOWPOS; - SetWindowPos(windows[i].window, 0, x, y - height, -1, -1, flags); + SetWindowPos( + windows[i].window, 0, + x, y - height, + -1, -1, + SWP_NOACTIVATE | SWP_NOSIZE | + SWP_NOZORDER | SWP_ASYNCWINDOWPOS + ); } } +// == main == int main() { - globals_init(); - mouse_init(); window_init(); while (1) { - // mouse_update(); + globals_update(); + + mouse_update(); window_update(); Sleep(1000/120); diff --git a/c/bounce.exe b/c/bounce.exe new file mode 100644 index 0000000..5889eca Binary files /dev/null and b/c/bounce.exe differ diff --git a/c/bounce.pdb b/c/bounce.pdb new file mode 100644 index 0000000..0203f0c Binary files /dev/null and b/c/bounce.pdb differ diff --git a/bounce_c/run.bat b/c/run.bat similarity index 100% rename from bounce_c/run.bat rename to c/run.bat diff --git a/main.py.old b/main.py.old deleted file mode 100644 index 515ec15..0000000 --- a/main.py.old +++ /dev/null @@ -1,88 +0,0 @@ -from ctypes import POINTER, WINFUNCTYPE, WinError, create_unicode_buffer, get_last_error, windll -from ctypes.wintypes import BOOL, DWORD, HBRUSH, HDC, HINSTANCE, HMENU, HWND, LPARAM, LPCWSTR, LPVOID, LPWSTR, INT, RECT -import time - -user32 = windll.user32 -gdi32 = windll.gdi32 - -CB_ENUM_WINDOWS = WINFUNCTYPE(BOOL, HWND, LPARAM) - -# thanks: https://stackoverflow.com/questions/37501191/how-to-get-windows-window-names-with-ctypes-in-python -def check_zero(result, func, args): - if not result: - err = get_last_error() - if err: - raise WinError(err) - return args - -user32.CreateWindowExW.argtypes = [ - DWORD, LPCWSTR, LPCWSTR, DWORD, - INT, INT, INT, INT, - HWND, HMENU, HINSTANCE, LPVOID -] -user32.CreateWindowExW.errcheck = check_zero - -user32.FillRect.argtypes = [HDC, POINTER(RECT), HBRUSH] - -user32.GetWindowDC.argtypes = [HWND] -user32.GetWindowDC.errcheck = check_zero - -user32.GetWindowTextLengthW.argtypes = [HWND] -user32.GetWindowTextLengthW.errcheck = check_zero - -user32.GetWindowTextW.argtypes = [HWND, LPWSTR, INT] -user32.GetWindowTextW.errcheck = check_zero - -def find_all_windows(): - windows = [] - - @CB_ENUM_WINDOWS - def _handle_window(hwnd, lparam): - # +1: make room for the null - length = user32.GetWindowTextLengthW(hwnd) + 1 - buffer = create_unicode_buffer(length) - user32.GetWindowTextW(hwnd, buffer, length) - windows.append((hwnd, buffer.value)) - return True - - user32.EnumWindows(_handle_window, 0) - return windows - -def fix_window(window): - """ - hdc = user32.GetWindowDC(window) - rect = RECT(0, 0, 10000, 10000) - brush = gdi32.CreateSolidBrush(0x00FF0000) - user32.FillRect(hdc, rect, brush) - gdi32.DeleteObject(brush) - print(window) - """ - classname = create_unicode_buffer("overlapper\x00") - windowname = create_unicode_buffer("overlapper\x00") - window = user32.CreateWindowExW( - 0x08000000 | # WS_EX_NOACTIVATE - 0x8 | # WS_EX_TOPMOST - 0x0, # 0x20, # WS_EX_TRANSPARENT - classname, - windowname, - 0x10000000, # WS_VISIBLE - 0, 0, 128, 128, # x y w h - None, None, - None, None - ) - user32.ShowWindow(window, 5) # SW_SHOW - -def fix_step(): - windows = find_all_windows() - for window_id, window_name in windows: - if window_name.endswith("Visual Studio Code"): - fix_window(window_id) - -def main(): - fix_step() - - while True: - time.sleep(1) - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/main.py b/python/main.py similarity index 71% rename from main.py rename to python/main.py index f4cbada..09e854d 100644 --- a/main.py +++ b/python/main.py @@ -2,16 +2,14 @@ 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] +user32.GetSystemMetrics.argtypes = [INT] + CB_ENUM_WINDOWS = WINFUNCTYPE(BOOL, HWND, LPARAM) user32.EnumWindows.argtypes = [CB_ENUM_WINDOWS, LPARAM] @@ -20,13 +18,18 @@ user32.GetWindowRect.argtypes = [HWND, LPRECT] user32.SetWindowPos.argtypes = [HWND, INT, INT, INT, INT, INT, INT] user32.IsWindowVisible.argtypes = [HWND] +def get_resolution_y() -> int: + SM_CYSCREEN = 1 + return user32.GetSystemMetrics(SM_CYSCREEN) + + class BouncyObject(ABC): @abstractmethod def get_position(self) -> tuple[int, int]: raise NotImplementedError @abstractmethod - def set_position(self, xy: tuple[int, int]): + def set_position(self, xy: tuple[int, int]) -> None: raise NotImplementedError @@ -34,7 +37,7 @@ class Mouse(BouncyObject): def get_position(self) -> tuple[int, int]: point = POINT() user32.GetCursorPos(byref(point)) - return point.x, point.y + return point.x, point.y def set_position(self, xy: tuple[int, int]): x, y = xy @@ -44,95 +47,78 @@ class Mouse(BouncyObject): 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]): + + def set_position(self, xy: tuple[int, int]) -> None: 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, + self._handle, 0, x, y - height, -1, -1, 0x0010 | # SWP_NOACTIVATE 0x0001 | # SWP_NOSIZE 0x0004 | # SWP_NOZORDER - 0x4000 # SWP_ASYNCWINDOWPOS + 0x4000 # SWP_ASYNCWINDOWPOS ) +class Body(object): + def __init__(self, controlled_object: BouncyObject): + self._last_offset: tuple[float, float] = (0.5, 0.5) + self._velocity = 0.0 + self._controlled_object = controlled_object + + def update(self, res_y: int) -> None: + x, y = self._controlled_object.get_position() + ox, oy = self._last_offset + x += ox + y += oy + + 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 + + x_int, y_int = int(x), min(int(y), res_y) + self._controlled_object.set_position((x_int, y_int)) + self._last_offset = x - x_int, y - y_int + + def enumerate_windows() -> list[int]: windows: list[int] = [] @CB_ENUM_WINDOWS - def _handle_window(hwnd, lparam): + def _handle_window(hwnd: int, _lparam: int): 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 = {} + + def enumerate(self): + windows_2 = {} for i in enumerate_windows(): if existing := self._windows.get(i): - windows2[i] = existing + windows_2[i] = existing else: - windows2[i] = Body(Window(i)) - self._windows = windows2 + windows_2[i] = Body(Window(i)) + self._windows = windows_2 def get(self) -> list[Body]: return [self._mouse, *self._windows.values()] @@ -143,11 +129,13 @@ def main(): while True: res_y = get_resolution_y() - bodies.update_list() - print(len(bodies.get())); + bodies.enumerate() + for b in bodies.get(): b.update(res_y) - time.sleep(1/120.0) + + time.sleep(1.0/120.0) + if __name__ == "__main__": main() \ No newline at end of file