@@ -20,6 +20,7 @@ public class GlobalKeyboardHook : IDisposable
2020 private const int VK_C = 0x43 ; // 67 - 'C' key for circle tool
2121 private const int VK_F1 = 0x70 ; // 112 - 'F1' key for help
2222 private const int VK_S = 0x53 ; // 83 - 'S' key for screenshot (Ctrl+S only)
23+ private const int VK_Z = 0x5A ; // 90 - 'Z' key for undo (Ctrl+Z only)
2324 private const int VK_LCONTROL = 0xA2 ; // 162 - Left Control key
2425 private const int VK_RCONTROL = 0xA3 ; // 163 - Right Control key
2526
@@ -41,6 +42,7 @@ public class GlobalKeyboardHook : IDisposable
4142 public event EventHandler ? CircleToolPressed ;
4243 public event EventHandler ? HelpPressed ;
4344 public event EventHandler ? ScreenshotFullPressed ;
45+ public event EventHandler ? UndoPressed ;
4446
4547 // NEW: Raw key events for recorder
4648 public event EventHandler < KeyEventArgs > ? KeyPressed ;
@@ -51,7 +53,7 @@ public class GlobalKeyboardHook : IDisposable
5153 private Dictionary < int , bool > _keyStates = new ( ) ;
5254 private bool _wasHotkeyActive = false ;
5355 private volatile bool _isControlPressed = false ;
54-
56+
5557 // Drawing mode state - used to determine if we should suppress keys
5658 private volatile bool _isDrawingModeActive = false ;
5759
@@ -65,7 +67,7 @@ public GlobalKeyboardHook(ILogger<GlobalKeyboardHook> logger)
6567 foreach ( var vk in _hotkeyVKs )
6668 _keyStates [ vk ] = false ;
6769 }
68-
70+
6971 /// <summary>
7072 /// Configures the hotkey combination
7173 /// </summary>
@@ -184,7 +186,7 @@ private nint SetHook(LowLevelKeyboardProc proc)
184186 private nint HookCallback ( int nCode , nint wParam , nint lParam )
185187 {
186188 bool shouldSuppressKey = false ;
187-
189+
188190 try
189191 {
190192 if ( nCode >= 0 )
@@ -202,8 +204,8 @@ private nint HookCallback(int nCode, nint wParam, nint lParam)
202204 if ( vkCode == VK_LCONTROL || vkCode == VK_RCONTROL )
203205 {
204206 _isControlPressed = isKeyDown ;
205- _logger . LogDebug ( "Control key ({Type}) {State}" ,
206- vkCode == VK_LCONTROL ? "Left" : "Right" ,
207+ _logger . LogDebug ( "Control key ({Type}) {State}" ,
208+ vkCode == VK_LCONTROL ? "Left" : "Right" ,
207209 isKeyDown ? "PRESSED" : "RELEASED" ) ;
208210 }
209211
@@ -269,12 +271,12 @@ private nint HookCallback(int nCode, nint wParam, nint lParam)
269271 _logger . LogInformation ( "====== CTRL+S DETECTED ======" ) ;
270272 _logger . LogInformation ( "Control key state: {IsControlPressed}" , _isControlPressed ) ;
271273 _logger . LogInformation ( "Drawing mode active: {IsDrawingModeActive}" , _isDrawingModeActive ) ;
272-
274+
273275 _logger . LogInformation ( "Ctrl+S pressed - firing ScreenshotFullPressed event" ) ;
274276 ScreenshotFullPressed ? . Invoke ( this , EventArgs . Empty ) ;
275- _logger . LogInformation ( "ScreenshotFullPressed event fired, subscribers: {Count}" ,
277+ _logger . LogInformation ( "ScreenshotFullPressed event fired, subscribers: {Count}" ,
276278 ScreenshotFullPressed ? . GetInvocationList ( ) . Length ?? 0 ) ;
277-
279+
278280 // Suppress Ctrl+S when drawing mode is active to prevent Windows Snipping Tool
279281 if ( _isDrawingModeActive )
280282 {
@@ -285,10 +287,21 @@ private nint HookCallback(int nCode, nint wParam, nint lParam)
285287 {
286288 _logger . LogInformation ( "KEY WILL NOT BE SUPPRESSED - Drawing mode is inactive" ) ;
287289 }
288-
290+
289291 _logger . LogInformation ( "====== END CTRL+S HANDLING ======" ) ;
290292 }
291293
294+ // Check for Ctrl+Z key press (undo - only when drawing mode is active)
295+ if ( vkCode == VK_Z && isKeyDown && _isControlPressed && _isDrawingModeActive )
296+ {
297+ _logger . LogInformation ( "Ctrl+Z pressed - firing UndoPressed event" ) ;
298+ UndoPressed ? . Invoke ( this , EventArgs . Empty ) ;
299+
300+ // Suppress Ctrl+Z when drawing mode is active to prevent underlying apps from receiving it
301+ shouldSuppressKey = true ;
302+ _logger . LogDebug ( "Ctrl+Z suppressed - drawing mode is active" ) ;
303+ }
304+
292305 // Track hotkey state
293306 if ( _hotkeyVKs . Contains ( vkCode ) )
294307 {
@@ -328,7 +341,7 @@ private nint HookCallback(int nCode, nint wParam, nint lParam)
328341 _logger . LogTrace ( "Key suppressed - not calling CallNextHookEx" ) ;
329342 return ( nint ) 1 ;
330343 }
331-
344+
332345 // MUST call CallNextHookEx for non-suppressed keys to allow other applications to process them
333346 return CallNextHookEx ( _hookID , nCode , wParam , lParam ) ;
334347 }
@@ -359,7 +372,7 @@ public void SetDrawingModeActive(bool isActive)
359372 {
360373 var previousState = _isDrawingModeActive ;
361374 _isDrawingModeActive = isActive ;
362-
375+
363376 if ( previousState != isActive )
364377 {
365378 _logger . LogInformation ( "====== DRAWING MODE STATE CHANGED ======" ) ;
0 commit comments