Commit 51f68a9
Claude/fix active target mode 011 c uy l7 ny9 pfo gabvg1q lj w (#12)
* adding active target mode
* Fix active target mode and add click test window
Changes:
- Added ClickTestWindow.swift with visual click targets for testing
- Integrated test window into Advanced tab Developer Tools section
- Fixed mouse monitoring lifecycle to prevent conflicts during automation
- Disable mouse monitor when automation starts in active target mode
- Re-enable mouse monitor when automation stops or on emergency stop
- Added cursor cleanup to app termination handler
- Improved active target mode stability and user experience
The test window provides 5 colored targets with click counters,
making it easy to validate auto-clicker functionality in both
regular and active target modes.
* Fix click test window layout and increase size
Changes:
- Fixed click registration issue by replacing absolute positioning with VStack/HStack layout
- All targets now properly register clicks (not just bottom-right)
- Increased window size to 1000x800 (ideal 1200x900) for better visibility
- Increased target size from 120px to 150px
- Enhanced font sizes and visual styling
- Removed unused calculatePosition method
The layout now uses proper SwiftUI stack-based layout instead of
absolute positioning, preventing targets from overlapping in the
z-order and ensuring all tap gestures work correctly.
* Fix window overflow and add always-visible close button
Critical fixes:
- Fixed window size to 900x750 (fits on all screens)
- Removed NavigationView/toolbar approach that caused overflow
- Added custom header with always-visible Close and Reset buttons
- Added Escape key shortcut to close window (Cmd+.)
- Made content scrollable to prevent overflow issues
- Adjusted target sizes (130px) and spacing to fit properly
This fixes the issue where users couldn't close the window and
had to force quit the application.
* Make click test window separate and movable
Changed the click test window from a modal sheet to an independent WindowGroup
that can be moved around the screen independently from the main ClickIt window.
Changes:
- Added new WindowGroup with id "click-test-window" in ClickItApp.swift
- Updated AdvancedTab to use openWindow environment action instead of sheet
- Modified DeveloperTools component to open separate window
- Updated button description to clarify it opens in a separate window
This allows users to position the click test window anywhere on screen to
properly test the auto-clicker functionality without being constrained to
the main application window.
* Fix active target mode to enable continuous clicking
Fixed an issue where active target mode would only perform a single click
after being enabled. The automation configuration was hardcoded to use
fixed position clicking (useDynamicMouseTracking: false) instead of
respecting the active target mode setting.
Changes:
- Updated createAutomationConfiguration() to set useDynamicMouseTracking
based on clickSettings.isActiveTargetMode
- When active target mode is enabled, automation now follows cursor position
- When active target mode is disabled, automation uses fixed position
This fixes the reported issue where autoclicking would only do 1 click
after enabling active target mode and making the first click.
Fixes: ClickItViewModel.swift:234
* Fix active target mode: disable stopOnError to allow continuous clicking
Root cause analysis revealed that automation was stopping after a single
click due to strict timing constraints combined with stopOnError=true:
1. Click timing constraints are very strict (15ms total: 10ms delay + 5ms deviation)
2. First clicks often exceed this on busy systems
3. stopOnError defaulted to true, stopping automation on first timing failure
4. Visual feedback showed regardless, masking the actual failure
Solution:
- Disable stopOnError specifically for active target mode
- Active target mode is designed for continuous clicking
- Users can manually stop by clicking again
- Occasional timing failures shouldn't halt the entire automation
- Normal automation modes still respect the stopOnError setting
This complements the previous fix (a821c39) which enabled dynamic mouse
tracking. Both changes are needed for active target mode to work correctly:
- a821c39: Made clicks follow cursor position (useDynamicMouseTracking)
- This commit: Prevents stopping on timing errors (stopOnError)
Fixes: ClickItViewModel.swift:231
* Fix coordinate system conversion for active target mode
Fixed an issue where clicks in active target mode would alternate between
two different screen positions due to coordinate system mismatch.
Problem:
- NSEvent.mouseLocation returns AppKit coordinates (origin bottom-left, Y↑)
- ClickEngine expects CoreGraphics coordinates (origin top-left, Y↓)
- Mouse position was being used directly without conversion
- This caused clicks to alternate between intended position and mirrored position
Solution:
- Convert AppKit coordinates to CoreGraphics before clicking
- Track separate coordinates for clicking vs visual feedback
- clickLocation: CoreGraphics coordinates for ClickEngine
- visualFeedbackLocation: AppKit coordinates for overlay
- Use existing convertAppKitToCoreGraphicsMultiMonitor() method
Changes:
- Line 368-373: Convert mouse position from AppKit to CoreGraphics
- Line 375-377: Also convert fixed positions for visual feedback
- Line 390-392: Use AppKit coordinates for visual feedback overlay
This ensures clicks happen exactly where the cursor is positioned,
not at a vertically mirrored location.
Fixes: ClickCoordinator.swift:368
* Implement hybrid start/stop controls for active target mode
Added intuitive mouse-based controls for active target mode with
redundant stop options for maximum flexibility and ease of use.
Controls:
- LEFT-CLICK: Start autoclicking at cursor position
- RIGHT-CLICK: Stop autoclicking immediately
- ESC KEY: Stop autoclicking (emergency stop - already existed)
Changes in HotkeyManager.swift:
- Added onRightMouseClick callback for stop action
- Updated registerMouseMonitor to monitor both .leftMouseDown and .rightMouseDown
- Enhanced handleMouseClick to differentiate between left/right clicks
- Updated logging to show LEFT=START, RIGHT=STOP
Changes in ClickItViewModel.swift:
- Split handleActiveTargetClick into:
- handleActiveTargetLeftClick: Only starts automation
- handleActiveTargetRightClick: Only stops automation
- Updated setupMouseClickHandler to register both left and right handlers
- Updated removeMouseClickHandler to clean up both handlers
- Improved logging to clearly indicate which action is being performed
Benefits:
- No more confusing toggle behavior
- Clear separation: left=start, right=stop
- Two ways to stop (right-click or ESC) for maximum flexibility
- Mouse-only users can use right-click
- Keyboard users can use ESC
- More intuitive and less prone to accidental toggles
This complements previous fixes:
- a821c39: Dynamic mouse tracking
- c548735: Disabled stopOnError
- 9ce9775: Coordinate system conversion
* Simplify to right-click toggle with emergency key stops
Changed active target mode controls to use a simpler, more intuitive scheme:
- Right-click to toggle (start/stop) automation
- All emergency keys (ESC, DELETE, F1, etc.) still work to stop
This simplifies the control scheme from the previous hybrid approach and
eliminates confusion between left and right mouse buttons.
Controls:
- RIGHT-CLICK: Toggle automation on/off at cursor position
- ESC/DELETE/F1/etc: Stop automation (emergency stops)
Changes in HotkeyManager.swift:
- Removed onLeftMouseClick callback (no longer needed)
- Changed onRightMouseClick to handle toggle behavior
- Updated registerMouseMonitor to only monitor .rightMouseDown
- Simplified handleMouseClick to only process right-clicks
- Updated logging to reflect toggle behavior
Changes in ClickItViewModel.swift:
- Removed handleActiveTargetLeftClick (no longer needed)
- Updated handleActiveTargetRightClick to toggle (start/stop)
- Simplified setupMouseClickHandler to only register right-click
- Simplified removeMouseClickHandler to only remove right-click
- Updated logging to reflect toggle behavior
Benefits:
- Single mouse button for all mouse control (right-click)
- Clear toggle behavior: click once to start, click again to stop
- Emergency keys still available for instant stop
- Simpler mental model: one button, one action (toggle)
- Fewer lines of code, easier to maintain
Supersedes: fe68ce8 (hybrid left/right approach)
* Fix active target mode: correct UI text and remove double validation
Fixed two critical issues preventing active target mode from working:
Issue 1: Incorrect UI Instruction
- QuickStartTab.swift line 311 said "Left-click" but implementation uses "Right-click"
- Users were clicking the wrong button!
- Fixed: Changed text to "Right-click to start/stop clicking at cursor position"
Issue 2: Double Validation Barrier
- handleActiveTargetRightClick() allowed active target mode through first check
- But startAutomation() had second guard that didn't account for active target mode
- This blocked automation from starting even with valid right-click
- Fixed: Added active target mode bypass in startAutomation()
Changes:
QuickStartTab.swift:
- Line 311: Changed "Left-click" → "Right-click" in help text
ClickItViewModel.swift:
- Lines 164-173: Updated startAutomation() guard logic
- In active target mode: only requires targetPoint + interval + !isRunning
- In normal mode: uses full canStartAutomation validation
- Added detailed debug logging to help troubleshoot prerequisites
User Workflow Now:
1. Enable "Active Target Mode" toggle (cursor becomes crosshair)
2. Right-click anywhere to start (no need for "Start Automation" button!)
3. Automation clicks continuously at cursor position with configured interval
4. Right-click again to stop, OR use ESC/DELETE/F1 emergency keys
Prerequisites for Active Target Mode:
- Interval must be > 0 (✅ default is 10 seconds)
- Automation must not already be running
- That's it! No need to pre-set target or validate other settings
Fixes: QuickStartTab.swift:311, ClickItViewModel.swift:164
* Fix active target mode: re-enable mouse monitoring after external stops
Fixed critical bug where right-click would not restart automation after
stopping via ESC key or natural completion (maxClicks/maxDuration reached).
Root Cause:
When automation stops externally (not via ViewModel.stopAutomation()), the
$isActive observer (line 486) updates UI state but forgets to re-register
mouse monitoring. This left right-click detection disabled after the first
stop, making restart impossible.
The Bug Flow:
1. Right-click to start → executeAutomation() unregisters mouse monitoring
2. Press ESC key → ClickCoordinator.emergencyStopAutomation() called
3. isActive becomes false → observer triggers
4. Observer updates isRunning/isPaused/appStatus ✅
5. Observer calls cancelTimer() ✅
6. Observer FORGETS to re-register mouse monitoring ❌
7. Next right-click does nothing (no monitors listening!)
Comparison:
- stopAutomation() (line 294): ✅ Re-registers monitoring
- emergencyStopAutomation() (line 604): ✅ Re-registers monitoring
- $isActive observer (line 490): ❌ Forgot to re-register (NOW FIXED)
The Fix:
Added mouse monitoring re-registration to the $isActive observer at lines
498-502, matching the logic in stopAutomation() and emergencyStopAutomation().
Now works for ALL stop scenarios:
✅ Manual right-click stop → re-registers monitoring
✅ ESC/DELETE/F1 emergency stop → re-registers monitoring
✅ Natural completion (maxClicks) → re-registers monitoring
✅ Timer expiration → re-registers monitoring
User can now:
1. Enable active target mode
2. Right-click to start
3. Stop via ANY method (ESC, right-click, completion)
4. Right-click again to restart ← NOW WORKS!
Fixes: ClickItViewModel.swift:498-502
---------
Co-authored-by: Claude <[email protected]>1 parent d4521aa commit 51f68a9
File tree
10 files changed
+814
-37
lines changed- ClickIt
- Sources/ClickIt
- Core
- Click
- Hotkeys
- Models
- Services
- UI
- ViewModels
- Views
10 files changed
+814
-37
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
22 | | - | |
| 22 | + | |
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
47 | 55 | | |
48 | 56 | | |
49 | 57 | | |
| |||
76 | 84 | | |
77 | 85 | | |
78 | 86 | | |
| 87 | + | |
| 88 | + | |
79 | 89 | | |
80 | 90 | | |
81 | 91 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
360 | 360 | | |
361 | 361 | | |
362 | 362 | | |
363 | | - | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
364 | 380 | | |
365 | 381 | | |
366 | 382 | | |
367 | 383 | | |
368 | | - | |
| 384 | + | |
369 | 385 | | |
370 | 386 | | |
371 | 387 | | |
372 | | - | |
373 | | - | |
| 388 | + | |
| 389 | + | |
374 | 390 | | |
375 | | - | |
| 391 | + | |
376 | 392 | | |
377 | | - | |
| 393 | + | |
378 | 394 | | |
379 | 395 | | |
380 | 396 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | | - | |
| 20 | + | |
21 | 21 | | |
22 | 22 | | |
| 23 | + | |
| 24 | + | |
23 | 25 | | |
24 | 26 | | |
25 | 27 | | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
26 | 36 | | |
27 | 37 | | |
28 | 38 | | |
| |||
36 | 46 | | |
37 | 47 | | |
38 | 48 | | |
| 49 | + | |
39 | 50 | | |
40 | 51 | | |
41 | 52 | | |
| |||
70 | 81 | | |
71 | 82 | | |
72 | 83 | | |
73 | | - | |
| 84 | + | |
74 | 85 | | |
75 | 86 | | |
76 | 87 | | |
77 | 88 | | |
78 | | - | |
| 89 | + | |
79 | 90 | | |
80 | 91 | | |
81 | 92 | | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
82 | 127 | | |
83 | 128 | | |
84 | 129 | | |
| |||
91 | 136 | | |
92 | 137 | | |
93 | 138 | | |
94 | | - | |
| 139 | + | |
95 | 140 | | |
96 | 141 | | |
97 | 142 | | |
98 | 143 | | |
99 | | - | |
| 144 | + | |
100 | 145 | | |
101 | 146 | | |
102 | 147 | | |
103 | 148 | | |
104 | 149 | | |
105 | 150 | | |
106 | 151 | | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
107 | 171 | | |
108 | 172 | | |
109 | 173 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
105 | 105 | | |
106 | 106 | | |
107 | 107 | | |
108 | | - | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
109 | 116 | | |
110 | 117 | | |
111 | 118 | | |
| |||
231 | 238 | | |
232 | 239 | | |
233 | 240 | | |
| 241 | + | |
234 | 242 | | |
235 | 243 | | |
236 | 244 | | |
| |||
268 | 276 | | |
269 | 277 | | |
270 | 278 | | |
| 279 | + | |
271 | 280 | | |
272 | 281 | | |
273 | 282 | | |
| |||
293 | 302 | | |
294 | 303 | | |
295 | 304 | | |
| 305 | + | |
296 | 306 | | |
297 | 307 | | |
298 | 308 | | |
| |||
318 | 328 | | |
319 | 329 | | |
320 | 330 | | |
321 | | - | |
322 | | - | |
| 331 | + | |
| 332 | + | |
323 | 333 | | |
324 | 334 | | |
325 | 335 | | |
| |||
331 | 341 | | |
332 | 342 | | |
333 | 343 | | |
| 344 | + | |
| 345 | + | |
334 | 346 | | |
335 | 347 | | |
336 | 348 | | |
| |||
353 | 365 | | |
354 | 366 | | |
355 | 367 | | |
| 368 | + | |
356 | 369 | | |
357 | 370 | | |
358 | 371 | | |
359 | 372 | | |
360 | 373 | | |
361 | 374 | | |
362 | | - | |
| 375 | + | |
363 | 376 | | |
364 | 377 | | |
365 | 378 | | |
| |||
403 | 416 | | |
404 | 417 | | |
405 | 418 | | |
| 419 | + | |
406 | 420 | | |
407 | 421 | | |
408 | 422 | | |
| |||
527 | 541 | | |
528 | 542 | | |
529 | 543 | | |
| 544 | + | |
530 | 545 | | |
531 | 546 | | |
532 | 547 | | |
| |||
550 | 565 | | |
551 | 566 | | |
552 | 567 | | |
| 568 | + | |
553 | 569 | | |
554 | 570 | | |
555 | 571 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
0 commit comments