Bouncy mouse, bouncy windows, initial code

This commit is contained in:
Pyrex 2025-04-17 21:51:04 -07:00
commit 16b3b6fa1e
6 changed files with 479 additions and 0 deletions

2
bounce_c/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.exe
*.pdb

161
bounce_c/bounce.c Normal file
View File

@ -0,0 +1,161 @@
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <windows.h>
#include <time.h>
#define MAX_WINDOWS 1024
// resolution
uint32_t res_y;
void globals_init() {
res_y = GetSystemMetrics(SM_CYSCREEN);
}
// 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);
}
float float_x = x + body->offset_x;
float float_y = y + body->offset_y;
for (uint8_t step = 0; step < 100; step += 1) {
body->velocity += 0.0002;
float_y += body->velocity;
if (float_y > res_y && body->velocity > 0) {
body->velocity = -body->velocity * 0.75;
if (-body->velocity < 0.05) {
body->velocity = 0;
}
}
}
*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;
}
// == mouse ==
typedef struct mouse_body_t {
body_t body;
} mouse_body_t;
mouse_body_t mouse_body;
void mouse_init() {
body_init(&mouse_body.body);
}
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);
}
// == window ==
typedef struct window_body_t {
HWND window;
body_t body;
} window_body_t;
size_t n_windows;
window_body_t* windows;
size_t _n_new_windows;
window_body_t* _new_windows;
void window_init() {
n_windows = 0;
windows = calloc(sizeof(window_body_t), MAX_WINDOWS);
_n_new_windows = 0;
_new_windows = calloc(sizeof(window_body_t), MAX_WINDOWS);
}
BOOL CALLBACK window_handle_enum(HWND window, LPARAM _) {
if (_n_new_windows >= MAX_WINDOWS) {
return 0;
}
if (!IsWindowVisible(window)) {
return 1;
}
window_body_t new;
new.window = window;
body_init(&new.body);
for (size_t i = 0; i < n_windows; i++) {
if (windows[i].window == new.window) {
new.body = windows[i].body;
break;
}
}
_new_windows[_n_new_windows++] = new;
return 1;
}
void window_enumerate() {
EnumWindows(window_handle_enum, 0);
// do the swap
window_body_t* tmp_windows = windows;
n_windows = _n_new_windows;
windows = _new_windows;
_n_new_windows = 0;
_new_windows = tmp_windows;
}
void window_update() {
window_enumerate();
for (size_t i = 0; i < n_windows; i++) {
RECT rect;
GetWindowRect(windows[i].window, &rect);
int32_t x = rect.left;
int32_t y = rect.bottom;
body_update(&windows[i].body, x, y, &x, &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);
}
}
int main() {
globals_init();
mouse_init();
window_init();
while (1) {
// mouse_update();
window_update();
Sleep(1000/120);
}
}

3
bounce_c/run.bat Normal file
View File

@ -0,0 +1,3 @@
del bounce.exe
zig cc bounce.c -o bounce.exe -Wall -Ofast
bounce.exe

72
bounce_v1.py.old Normal file
View File

@ -0,0 +1,72 @@
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()

153
main.py Normal file
View File

@ -0,0 +1,153 @@
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()

88
main.py.old Normal file
View File

@ -0,0 +1,88 @@
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()