From 96de2b03a2c647a795d7a54c298ef0b1377470a8 Mon Sep 17 00:00:00 2001 From: Ralph Date: Sat, 16 May 2026 23:23:02 -0400 Subject: [PATCH 1/2] Crash fixes --- CHANGELOG.md | 10 ++++------ pyproject.toml | 2 +- src/powermouse/adapters/devices.py | 3 +-- src/powermouse/domain/usecases/track_face.py | 12 ++++++++---- src/powermouse/main.py | 19 ++++++++++--------- 5 files changed, 24 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 074c023..716e607 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,7 @@ # Changelog -## v0.0.6 +## v0.0.7 -- Added `CONTRIBUTING.md`to project. -- Updated license document with full text. -- Fixed crash on Onboarding cancel. - - +- Fixed crash from probing for available cameras. +- Added background tracking loop to keep the application responsive. +- Mouse events no longer block the application via resource exhaustion due to spawning excessive threads. diff --git a/pyproject.toml b/pyproject.toml index f4a4869..e378b0c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "PowerMouse" -version = "0.0.6" +version = "0.0.7" description = "Hands-free mouse control using face tracking" authors = [ { name = "Ralph Dugue", email = "ralph@phito.dev" } diff --git a/src/powermouse/adapters/devices.py b/src/powermouse/adapters/devices.py index 215aed9..c78a302 100644 --- a/src/powermouse/adapters/devices.py +++ b/src/powermouse/adapters/devices.py @@ -1,5 +1,3 @@ -import glob -import os import platform import cv2 @@ -25,6 +23,7 @@ def get_devices(self) -> list[Camera]: fps = cap.get(cv2.CAP_PROP_FPS) height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) + cap.release() frame = _EMPTY_FRAME cameras.append( Camera( diff --git a/src/powermouse/domain/usecases/track_face.py b/src/powermouse/domain/usecases/track_face.py index e1d73f4..359b874 100644 --- a/src/powermouse/domain/usecases/track_face.py +++ b/src/powermouse/domain/usecases/track_face.py @@ -1,13 +1,12 @@ -import threading import time from powermouse.domain.controllers import camera, inference, mouse, profile -from powermouse.domain.usecases.gesture_mapping import GestureToMouseTranslator from powermouse.domain.models.mouse import MouseButton, MouseEvent, MouseEventType +from powermouse.domain.usecases.gesture_mapping import GestureToMouseTranslator def _dispatch(mouse_controller: mouse.MouseController, event: MouseEvent) -> None: - threading.Thread(target=mouse_controller.handle_event, args=(event,)).start() + mouse_controller.handle_event(event) def tracking_step( @@ -26,7 +25,12 @@ def tracking_step( cursor = inference_controller.get_cursor_position() _dispatch( mouse_controller, - MouseEvent(button=MouseButton.LEFT, x=cursor[0], y=cursor[1], event_type=MouseEventType.MOVE), + MouseEvent( + button=MouseButton.LEFT, + x=cursor[0], + y=cursor[1], + event_type=MouseEventType.MOVE, + ), ) # Drain any queued gestures and dispatch their mouse events. diff --git a/src/powermouse/main.py b/src/powermouse/main.py index bb5ff0f..d7826b2 100644 --- a/src/powermouse/main.py +++ b/src/powermouse/main.py @@ -110,15 +110,16 @@ def main() -> None: # Create a background thread for tracking def background_tracking_loop(): - tracking_step( - frame_processor=camera_widget.update_frame, - mouse_controller=mouse_controller, - inference_controller=inference_controller, - camera_controller=camera_controller, - gesture_translator=gesture_translator, - ) - - time.sleep(0.005) + while dpg.is_dearpygui_running(): + tracking_step( + frame_processor=camera_widget.update_frame, + mouse_controller=mouse_controller, + inference_controller=inference_controller, + camera_controller=camera_controller, + gesture_translator=gesture_translator, + ) + + time.sleep(0.005) tracking_thread = threading.Thread(target=background_tracking_loop, daemon=True) tracking_thread.start() From a4cbbf995c4e8481fe717d3db785f31aa63ce14e Mon Sep 17 00:00:00 2001 From: Ralph Date: Sat, 16 May 2026 23:26:01 -0400 Subject: [PATCH 2/2] Update devices.py --- src/powermouse/adapters/devices.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/powermouse/adapters/devices.py b/src/powermouse/adapters/devices.py index c78a302..f055a09 100644 --- a/src/powermouse/adapters/devices.py +++ b/src/powermouse/adapters/devices.py @@ -20,6 +20,9 @@ def get_devices(self) -> list[Camera]: for i, name in devices.items(): cap = cv2.VideoCapture(i) + if not cap.isOpened(): + continue + fps = cap.get(cv2.CAP_PROP_FPS) height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)