Gleb Khmyznikov 725535b760
Some checks failed
Spell checking / Check Spelling (push) Has been cancelled
Spell checking / Report (Push) (push) Has been cancelled
Spell checking / Report (PR) (push) Has been cancelled
Spell checking / Update PR (push) Has been cancelled
[DevDocs] More content and restructure (#40165)
## Summary of the Pull Request
Accumulated information from internal transition about the modules
development, and reworked it to be added in dev docs. Also the dev docs
intself was restructured to be more organized. New pages was
verified by transition team.

## PR Checklist
- [x] **Dev docs:** Added/updated

---------

Co-authored-by: Zhaopeng Wang (from Dev Box) <zhaopengwang@microsoft.com>
Co-authored-by: Hao Liu <liuhao3418@gmail.com>
Co-authored-by: Peiyao Zhao <105847726+zhaopy536@users.noreply.github.com>
Co-authored-by: Mengyuan <162882040+chenmy77@users.noreply.github.com>
Co-authored-by: zhaopeng wang <33367956+wang563681252@users.noreply.github.com>
Co-authored-by: Jaylyn Barbee <51131738+Jaylyn-Barbee@users.noreply.github.com>
2025-07-01 14:27:34 +02:00

3.9 KiB

Mouse Pointer Crosshairs

Mouse Pointer Crosshairs is a utility that displays horizontal and vertical lines that intersect at the mouse cursor position, making it easier to track the cursor location on screen.

Implementation

Mouse Pointer Crosshairs runs within the PowerToys Runner process and draws crosshair lines that follow the cursor in real-time.

Key Files

  • src/modules/MouseUtils/MousePointerCrosshairs/InclusiveCrosshairs.cpp - Contains the main implementation
  • Key function: WndProc - Handles window messages and mouse events

Enabling Process

When the utility is enabled:

  1. A background thread is created to run the crosshairs logic asynchronously:

    std::thread([=]() { InclusiveCrosshairsMain(hInstance, settings); }).detach();
    
  2. The InclusiveCrosshairs instance is initialized and configured with user settings:

    InclusiveCrosshairs crosshairs;
    InclusiveCrosshairs::instance = &crosshairs;
    crosshairs.ApplySettings(settings, false);
    crosshairs.MyRegisterClass(hInstance);
    
  3. The utility:

    • Creates the crosshairs visuals using Windows Composition API inside CreateInclusiveCrosshairs()
    • Handles the WM_CREATE message to initialize the Windows Composition API (Compositor, visuals, and target)
    • Creates a transparent, layered window for drawing the crosshairs with specific extended window styles (e.g., WS_EX_LAYERED, WS_EX_TRANSPARENT)

Activation Process

The activation process works as follows:

  1. Shortcut Detection

    • When the activation shortcut is pressed, the window procedure (WndProc) receives a custom message WM_SWITCH_ACTIVATION_MODE
  2. Toggle Drawing State

    case WM_SWITCH_ACTIVATION_MODE:
        if (instance->m_drawing)
        {
            instance->StopDrawing();
        }
        else
        {
            instance->StartDrawing();
        }
        break;
    
  3. Start Drawing Function

    • The StartDrawing() function is called to:
      • Log the start of drawing
      • Update the crosshairs position
      • Check if the cursor should be auto-hidden, and set a timer for auto-hide if enabled
      • Show the crosshairs window if the cursor is visible
      • Set a low-level mouse hook to track mouse movements asynchronously
    void InclusiveCrosshairs::StartDrawing()
    {
        Logger::info("Start drawing crosshairs.");
        UpdateCrosshairsPosition();
    
        m_hiddenCursor = false;
        if (m_crosshairs_auto_hide)
        {
            CURSORINFO cursorInfo{};
            cursorInfo.cbSize = sizeof(cursorInfo);
            if (GetCursorInfo(&cursorInfo))
            {
                m_hiddenCursor = !(cursorInfo.flags & CURSOR_SHOWING);
            }
    
            SetAutoHideTimer();
        }
    
        if (!m_hiddenCursor)
        {
            ShowWindow(m_hwnd, SW_SHOWNOACTIVATE);
        }
    
        m_drawing = true;
        m_mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, m_hinstance, 0);
    }
    
  4. Stop Drawing Function

    • The StopDrawing() function is called to:
      • Remove the mouse hook
      • Kill the auto-hide timer
      • Hide the crosshairs window
      • Log the stop of drawing

Cursor Tracking

While active, the utility:

  1. Uses a low-level mouse hook (WH_MOUSE_LL) to track cursor movement
  2. Updates crosshair positions in real-time as the mouse moves
  3. Supports auto-hiding functionality when the cursor is inactive for a specified period

Debugging

To debug Mouse Pointer Crosshairs:

  • Attach to the PowerToys Runner process directly
  • Set breakpoints in the InclusiveCrosshairs.cpp file
  • Be aware that during debugging, moving the mouse may cause unexpected or "strange" visual behavior because:
    • The mouse hook (MouseHookProc) updates the crosshairs position on every WM_MOUSEMOVE event
    • This frequent update combined with the debugger's overhead or breakpoints can cause visual glitches or stutters