22
33## Project Overview
44
5- GhostDraw is a Windows desktop application that allows users to draw directly on the screen using a keyboard hotkey (Ctrl+Alt+D) and mouse input. The application uses:
5+ GhostDraw is a Windows desktop application that allows users to draw directly on the screen using a keyboard hotkey to activate and mouse input. The application uses:
66
7- - ** WPF** for UI and overlay rendering
8- - ** Global Windows Hooks** for keyboard/mouse capture
9- - ** Dependency Injection** with Microsoft.Extensions.DependencyInjection
10- - ** Structured Logging** with Serilog + Microsoft.Extensions.Logging
11- - ** .NET 8** target framework
12-
13- ### Directory Structure
14- From repo root (` C:\code\github\ghost-draw\ ` ):
15- - ` src/ ` - Main application code. .sln and project files here. ** This is the project root / workspace directory.**
16- - ` .github/copilot-instructions.md ` - This file.
17- - ` docs/ ` - Additional documentation, design notes, etc. When adding docs here, update the solution file docs folder to show them in IDEs.
18- - ` tests/ ` - Unit and integration tests.
19- - ` README.md ` - Project overview and setup instructions.
20-
21- ** Important** : When creating or editing files:
22- - ** Repo root** = ` C:\code\github\ghost-draw\ ` (where README.md, .github/, docs/, tests/ live)
23- - ** Project root / Workspace** = ` C:\code\github\ghost-draw\src\ ` (where .csproj and source code live)
24- - Documentation files (` .md ` ) should go in the ** repo root** or ` docs/ ` directory, NOT in ` src/ `
25- - Source code files (` .cs ` , ` .xaml ` , etc.) should go in the ** project root** (` src/ ` ) or subdirectories within it
7+ - ** WPF** for UI and overlay rendering
8+ - ** Global Windows Hooks** for keyboard/mouse capture
9+ - ** Dependency Injection** with Microsoft.Extensions.DependencyInjection
10+ - ** Structured Logging** with Serilog + Microsoft.Extensions.Logging
11+ - ** .NET 8** target framework
2612
2713## Critical Safety Requirements
2814
29- ### ?? PRIORITY #1 : User Safety & System Stability
15+ ### PRIORITY #1 : User Safety & System Stability
3016
3117This application intercepts global keyboard and mouse input and displays a fullscreen transparent overlay. ** If the application crashes or hangs, the user could be locked out of their system.** All code must prioritize robustness and graceful failure.
3218
33- ### ?? PRIORITY #2 : Ensure all new code is tested via unit tests or integration tests where applicable.
34- Ensure The GhostDraw.Tests project has adequate coverage for any new features or changes and that all tests pass.
19+ ### PRIORITY #2 : Ensure all new code is tested via unit tests or integration tests where applicable.
3520
21+ Ensure The GhostDraw.Tests project has adequate coverage for any new features or changes and that all tests pass.
3622
3723#### Mandatory Safety Practices
3824
39251 . ** Always Use Try-Catch in Critical Paths**
40- ``` csharp
41- // ? GOOD - Protected hook callback
42- private IntPtr HookCallback (int nCode , IntPtr wParam , IntPtr lParam )
43- {
44- try
45- {
46- // Hook logic here
47- }
48- catch (Exception ex )
49- {
50- _logger .LogError (ex , " Hook callback failed" );
51- // MUST allow hook chain to continue
52- }
53- return CallNextHookEx (_hookID , nCode , wParam , lParam );
54- }
55- ```
56-
57262 . ** Hook Callbacks MUST Always Call CallNextHookEx**
58- - Never block the hook chain
59- - Always return from hook callbacks quickly (< 5ms)
60- - Never throw unhandled exceptions from hooks
61-
27+ - Never block the hook chain
28+ - Always return from hook callbacks quickly (< 5ms)
29+ - Never throw unhandled exceptions from hooks
62303 . ** Overlay Window Safety**
63- - Overlay must NEVER prevent access to underlying windows when hidden
64- - Always hide overlay on unhandled exceptions
65- - Provide emergency escape mechanisms (ESC key should always hide overlay)
66- - Window must properly release input focus when hidden
67-
31+ - Overlay must NEVER prevent access to underlying windows when hidden
32+ - Always hide overlay on unhandled exceptions
33+ - Provide emergency escape mechanisms (ESC key should always hide overlay)
34+ - Window must properly release input focus when hidden
68354 . ** Cleanup on Exit**
69- ``` csharp
70- // Always unhook on dispose/exit
71- protected override void OnExit (ExitEventArgs e )
72- {
73- try
74- {
75- _keyboardHook ? .Dispose (); // Removes hooks
76- _notifyIcon ? .Dispose ();
77- ServiceConfiguration .Shutdown ();
78- }
79- catch (Exception ex )
80- {
81- _logger ? .LogCritical (ex , " Failed during cleanup" );
82- }
83- base .OnExit (e );
84- }
85- ```
86-
87365 . ** Emergency Bailout**
88- - Consider adding ESC key as emergency override to hide overlay
89- - Add Ctrl+Alt+Shift+X as emergency kill switch
90- - Log all critical errors before application termination
91-
92- ### Hook-Related Guidelines
93-
94- - ** Never** perform blocking operations in hook callbacks
95- - ** Never** call MessageBox or show dialogs from hook callbacks
96- - ** Never** do heavy processing in hook callbacks (delegate to background tasks)
97- - ** Always** log hook installation success/failure
98- - ** Always** verify hook is properly uninstalled on exit
99-
100- ### Overlay Window Guidelines
101-
102- - ** Always** set ` Topmost = true ` but ensure it doesn't block system dialogs
103- - ** Never** set ` ShowInTaskbar = true ` (prevents Alt+Tab interference)
104- - ** Always** ensure overlay is truly transparent when not drawing
105- - ** Always** hide overlay on application deactivation/suspend
106- - ** Always** test that mouse/keyboard input passes through when inactive
107-
108- ## Architecture Guidelines
109-
110- ### Dependency Injection
111-
112- All components should use constructor injection:
113-
114- ``` csharp
115- public class MyComponent
116- {
117- private readonly ILogger <MyComponent > _logger ;
118- private readonly SomeDependency _dependency ;
119-
120- public MyComponent (ILogger <MyComponent > logger , SomeDependency dependency )
121- {
122- _logger = logger ;
123- _dependency = dependency ;
124- }
125- }
126- ```
127-
128- Register new services in ` ServiceConfiguration.ConfigureServices() ` :
129-
130- ``` csharp
131- services .AddSingleton <MyComponent >();
132- ```
37+ - Log all critical errors before application termination
13338
13439### Logging Standards
13540
@@ -154,50 +59,6 @@ _logger.LogCritical(ex, "Keyboard hook installation failed");
15459
15560** Never log on every mouse move** - use ` LogTrace ` and ensure it's filtered by default.
15661
157- ### Event Handling Pattern
158-
159- ``` csharp
160- // ? GOOD - Safe event invocation
161- try
162- {
163- HotkeyPressed ? .Invoke (this , EventArgs .Empty );
164- }
165- catch (Exception ex )
166- {
167- _logger .LogError (ex , " Event handler failed" );
168- // Continue execution
169- }
170-
171- // ? BAD - Unprotected event invocation
172- HotkeyPressed ? .Invoke (this , EventArgs .Empty ); // Could crash app
173- ```
174-
175- ## Code Style Guidelines
176-
177- ### Naming Conventions
178-
179- - Private fields: ` _camelCase `
180- - Constants: ` UPPER_SNAKE_CASE ` or ` PascalCase `
181- - Public/Internal: ` PascalCase `
182- - Interfaces: ` IPascalCase `
183-
184- ### Error Messages
185-
186- Include context in error messages:
187-
188- ``` csharp
189- _logger .LogError (ex , " Failed to install keyboard hook. HookID={HookId}" , _hookID );
190- ```
191-
192- ### Null Safety
193-
194- Leverage C# 8+ nullable reference types:
195-
196- ``` csharp
197- private ILogger < MyClass > ? _logger ; // Nullable
198- private readonly Config _config = null ! ; // Non-null assertion (set in constructor)
199- ```
200-
20162## Testing Considerations
20263
20364When adding new features:
@@ -209,44 +70,6 @@ When adding new features:
209705 . ** Test rapid hotkey toggles** - No race conditions
210716 . ** Test high DPI scaling** - Drawing should work on all DPI settings
21172
212- ## Common Pitfalls to Avoid
213-
214- ? ** Don't** : Use ` Application.Current.Dispatcher.Invoke ` in hook callbacks
215- ? ** Do** : Queue work to background thread if needed
216-
217- ? ** Don't** : Store large objects in hook callback scope
218- ? ** Do** : Keep hook callbacks lean and fast
219-
220- ? ** Don't** : Assume hook callbacks run on UI thread
221- ? ** Do** : Marshal to UI thread only when needed
222-
223- ? ** Don't** : Show error messages directly to user from background code
224- ? ** Do** : Log errors and handle them gracefully
225-
226- ? ** Don't** : Use ` Thread.Sleep ` or blocking waits in hook callbacks
227- ? ** Do** : Use async/await patterns when possible (not in hooks though!)
228-
229- ## Windows API (P/Invoke) Guidelines
230-
231- Always check return values from Windows APIs:
232-
233- ``` csharp
234- _hookID = SetWindowsHookEx (WH_KEYBOARD_LL , _proc , hMod , 0 );
235- if (_hookID == IntPtr .Zero )
236- {
237- int error = Marshal .GetLastWin32Error ();
238- _logger .LogError (" SetWindowsHookEx failed with error code: {ErrorCode}" , error );
239- throw new Win32Exception (error );
240- }
241- ```
242-
243- ## Performance Guidelines
244-
245- - Hook callbacks should complete in < 5ms
246- - Don't allocate large objects in hot paths
247- - Consider object pooling for frequently created objects
248- - Profile with multiple monitors (more pixels = more work)
249-
25073## Feature Development Workflow
25174
25275When adding new features:
@@ -258,41 +81,13 @@ When adding new features:
258815 . ** Update settings UI** - Add configuration options when appropriate
259826 . ** Document in code** - Add XML comments for public APIs
26083
261- ## Future Considerations
262-
263- When suggesting new features, consider:
264-
265- - ** Brush customization** (color, thickness, opacity)
266- - ** Stroke persistence** (save/load drawings)
267- - ** Undo/redo functionality**
268- - ** Screenshot integration**
269- - ** Multi-user scenarios** (Terminal Server, Fast User Switching)
270- - ** Accessibility** (screen readers, high contrast mode)
271- - ** Localization** (internationalization support)
272-
273- ## Settings Architecture
274-
275- ** IMPORTANT** : Before modifying any settings-related code, read the comprehensive settings architecture documentation:
276-
277- 📄 ** [ Settings Architecture Guide] ( ../docs/settings-architecture.md ) **
278-
279- This document covers:
280- - Settings data flow and persistence
281- - The critical ** nesting level pattern** (prevents recursion bugs)
282- - Event handling best practices
283- - Common pitfalls and solutions
284- - How to add new settings correctly
285- - Testing considerations
286-
287- ** Key Rule** : When updating UI from events or calling settings service methods, ALWAYS use the nesting level pattern to prevent infinite recursion.
288-
28984## Resources
29085
291- - [ Low-Level Keyboard Hook Documentation] ( https://learn.microsoft.com/en-us/windows/win32/winmsg/lowlevelkeyboardproc )
292- - [ WPF Transparent Windows Best Practices] ( https://learn.microsoft.com/en-us/dotnet/desktop/wpf/windows/ )
293- - [ Serilog Best Practices] ( https://github.com/serilog/serilog/wiki/Writing-Log-Events )
294- - [ Microsoft.Extensions.Logging Documentation] ( https://learn.microsoft.com/en-us/dotnet/core/extensions/logging )
295- - [ Settings Architecture Guide] ( ../docs/settings-architecture.md ) - Internal architecture documentation
86+ - [ Low-Level Keyboard Hook Documentation] ( https://learn.microsoft.com/en-us/windows/win32/winmsg/lowlevelkeyboardproc )
87+ - [ WPF Transparent Windows Best Practices] ( https://learn.microsoft.com/en-us/dotnet/desktop/wpf/windows/ )
88+ - [ Serilog Best Practices] ( https://github.com/serilog/serilog/wiki/Writing-Log-Events )
89+ - [ Microsoft.Extensions.Logging Documentation] ( https://learn.microsoft.com/en-us/dotnet/core/extensions/logging )
90+ - [ Settings Architecture Guide] ( ../docs/settings-architecture.md ) - Internal architecture documentation
29691
29792---
29893
@@ -306,4 +101,4 @@ This document covers:
3061016 . ** Test Edge Cases** - Crashes, multi-monitor, high DPI, rapid input
3071027 . ** Document Risks** - Comment any potentially dangerous code paths
308103
309- Remember: This application has elevated privileges and intercepts user input. With great power comes great responsibility! ???
104+ Remember: This application has elevated privileges and intercepts user input. With great power comes great responsibility!
0 commit comments