mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 17:56:44 +02:00
Mouse Utils - Mouse Pointer Crosshair (#15633)
* Apply PowerToys template * Add CppWinRt package * Add Settings reference * Use proper output dir * Proper WindowsTargetPlatformVersion * Add filters to vcxproj * Proper resource file generation * Remove boilerplate code * Initial implementation of the mouse crosshair * Add enable module to settings page * Change hotkey in settings * Add color, opacity, thickness settings * Add telemetry * Add Oobe entry * Add installer instructions * Add dll to pipelines * Add crosshair borders * Fix settings case * Tweak defaults to make it look like the specs * fix spellchecker * Fix resources and binary info * Correct composition tree comment typo * Reduce argument copy * Start disabled by default * Add maximum to crosshair thickness and border size * Set minimum border size of 0 * Fix comment * Add maximum to radius * Add comment for non-localizable strings * Rename "Inclusive Mouse"-"Mouse Pointer Crosshair"
This commit is contained in:
@@ -0,0 +1,452 @@
|
||||
// InclusiveCrosshair.cpp : Defines the entry point for the application.
|
||||
//
|
||||
|
||||
#include "pch.h"
|
||||
#include "InclusiveCrosshair.h"
|
||||
#include "trace.h"
|
||||
|
||||
#ifdef COMPOSITION
|
||||
namespace winrt
|
||||
{
|
||||
using namespace winrt::Windows::System;
|
||||
using namespace winrt::Windows::UI::Composition;
|
||||
}
|
||||
|
||||
namespace ABI
|
||||
{
|
||||
using namespace ABI::Windows::System;
|
||||
using namespace ABI::Windows::UI::Composition::Desktop;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct InclusiveCrosshair
|
||||
{
|
||||
bool MyRegisterClass(HINSTANCE hInstance);
|
||||
static InclusiveCrosshair* instance;
|
||||
void Terminate();
|
||||
void SwitchActivationMode();
|
||||
void ApplySettings(InclusiveCrosshairSettings& settings, bool applyToRuntimeObjects);
|
||||
|
||||
private:
|
||||
enum class MouseButton
|
||||
{
|
||||
Left,
|
||||
Right
|
||||
};
|
||||
|
||||
void DestroyInclusiveCrosshair();
|
||||
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) noexcept;
|
||||
void StartDrawing();
|
||||
void StopDrawing();
|
||||
bool CreateInclusiveCrosshair();
|
||||
void UpdateCrosshairPosition();
|
||||
HHOOK m_mouseHook = NULL;
|
||||
static LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) noexcept;
|
||||
|
||||
static constexpr auto m_className = L"MousePointerCrosshair";
|
||||
static constexpr auto m_windowTitle = L"PowerToys Mouse Pointer Crosshair";
|
||||
HWND m_hwndOwner = NULL;
|
||||
HWND m_hwnd = NULL;
|
||||
HINSTANCE m_hinstance = NULL;
|
||||
static constexpr DWORD WM_SWITCH_ACTIVATION_MODE = WM_APP;
|
||||
|
||||
winrt::DispatcherQueueController m_dispatcherQueueController{ nullptr };
|
||||
winrt::Compositor m_compositor{ nullptr };
|
||||
winrt::Desktop::DesktopWindowTarget m_target{ nullptr };
|
||||
winrt::ContainerVisual m_root{ nullptr };
|
||||
winrt::LayerVisual m_crosshair_border_layer{ nullptr };
|
||||
winrt::LayerVisual m_crosshair_layer{ nullptr };
|
||||
winrt::SpriteVisual m_left_crosshair_border{ nullptr };
|
||||
winrt::SpriteVisual m_left_crosshair{ nullptr };
|
||||
winrt::SpriteVisual m_right_crosshair_border{ nullptr };
|
||||
winrt::SpriteVisual m_right_crosshair{ nullptr };
|
||||
winrt::SpriteVisual m_top_crosshair_border{ nullptr };
|
||||
winrt::SpriteVisual m_top_crosshair{ nullptr };
|
||||
winrt::SpriteVisual m_bottom_crosshair_border{ nullptr };
|
||||
winrt::SpriteVisual m_bottom_crosshair{ nullptr };
|
||||
|
||||
bool m_visible = false;
|
||||
bool m_destroyed = false;
|
||||
|
||||
// Configurable Settings
|
||||
winrt::Windows::UI::Color m_crosshair_border_color = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIR_BORDER_COLOR;
|
||||
winrt::Windows::UI::Color m_crosshair_color = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIR_COLOR;
|
||||
float m_crosshair_radius = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIR_RADIUS;
|
||||
float m_crosshair_thickness = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIR_THICKNESS;
|
||||
float m_crosshair_border_size = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIR_BORDER_SIZE;
|
||||
float m_crosshair_opacity = max(0.f, min(1.f, (float)INCLUSIVE_MOUSE_DEFAULT_CROSSHAIR_OPACITY / 100.0f));
|
||||
};
|
||||
|
||||
InclusiveCrosshair* InclusiveCrosshair::instance = nullptr;
|
||||
|
||||
bool InclusiveCrosshair::CreateInclusiveCrosshair()
|
||||
{
|
||||
try
|
||||
{
|
||||
// We need a dispatcher queue.
|
||||
DispatcherQueueOptions options = {
|
||||
sizeof(options),
|
||||
DQTYPE_THREAD_CURRENT,
|
||||
DQTAT_COM_ASTA,
|
||||
};
|
||||
ABI::IDispatcherQueueController* controller;
|
||||
winrt::check_hresult(CreateDispatcherQueueController(options, &controller));
|
||||
*winrt::put_abi(m_dispatcherQueueController) = controller;
|
||||
|
||||
// Create the compositor for our window.
|
||||
m_compositor = winrt::Compositor();
|
||||
ABI::IDesktopWindowTarget* target;
|
||||
winrt::check_hresult(m_compositor.as<ABI::ICompositorDesktopInterop>()->CreateDesktopWindowTarget(m_hwnd, false, &target));
|
||||
*winrt::put_abi(m_target) = target;
|
||||
|
||||
// Our composition tree:
|
||||
//
|
||||
// [root] ContainerVisual
|
||||
// \ [crosshair border layer] LayerVisual
|
||||
// \ [crosshair border sprites]
|
||||
// [crosshair layer] LayerVisual
|
||||
// \ [crosshair sprites]
|
||||
|
||||
m_root = m_compositor.CreateContainerVisual();
|
||||
m_root.RelativeSizeAdjustment({ 1.0f, 1.0f });
|
||||
m_target.Root(m_root);
|
||||
|
||||
m_root.Opacity(m_crosshair_opacity);
|
||||
|
||||
m_crosshair_border_layer = m_compositor.CreateLayerVisual();
|
||||
m_crosshair_border_layer.RelativeSizeAdjustment({ 1.0f, 1.0f });
|
||||
m_root.Children().InsertAtTop(m_crosshair_border_layer);
|
||||
m_crosshair_border_layer.Opacity(1.0f);
|
||||
|
||||
m_crosshair_layer = m_compositor.CreateLayerVisual();
|
||||
m_crosshair_layer.RelativeSizeAdjustment({ 1.0f, 1.0f });
|
||||
|
||||
// Create the crosshair sprites.
|
||||
m_left_crosshair_border = m_compositor.CreateSpriteVisual();
|
||||
m_left_crosshair_border.AnchorPoint({ 1.0f, 0.5f });
|
||||
m_left_crosshair_border.Brush(m_compositor.CreateColorBrush(m_crosshair_border_color));
|
||||
m_crosshair_border_layer.Children().InsertAtTop(m_left_crosshair_border);
|
||||
m_left_crosshair = m_compositor.CreateSpriteVisual();
|
||||
m_left_crosshair.AnchorPoint({ 1.0f, 0.5f });
|
||||
m_left_crosshair.Brush(m_compositor.CreateColorBrush(m_crosshair_color));
|
||||
m_crosshair_layer.Children().InsertAtTop(m_left_crosshair);
|
||||
|
||||
m_right_crosshair_border = m_compositor.CreateSpriteVisual();
|
||||
m_right_crosshair_border.AnchorPoint({ 0.0f, 0.5f });
|
||||
m_right_crosshair_border.Brush(m_compositor.CreateColorBrush(m_crosshair_border_color));
|
||||
m_crosshair_border_layer.Children().InsertAtTop(m_right_crosshair_border);
|
||||
m_right_crosshair = m_compositor.CreateSpriteVisual();
|
||||
m_right_crosshair.AnchorPoint({ 0.0f, 0.5f });
|
||||
m_right_crosshair.Brush(m_compositor.CreateColorBrush(m_crosshair_color));
|
||||
m_crosshair_layer.Children().InsertAtTop(m_right_crosshair);
|
||||
|
||||
m_top_crosshair_border = m_compositor.CreateSpriteVisual();
|
||||
m_top_crosshair_border.AnchorPoint({ 0.5f, 1.0f });
|
||||
m_top_crosshair_border.Brush(m_compositor.CreateColorBrush(m_crosshair_border_color));
|
||||
m_crosshair_border_layer.Children().InsertAtTop(m_top_crosshair_border);
|
||||
m_top_crosshair = m_compositor.CreateSpriteVisual();
|
||||
m_top_crosshair.AnchorPoint({ 0.5f, 1.0f });
|
||||
m_top_crosshair.Brush(m_compositor.CreateColorBrush(m_crosshair_color));
|
||||
m_crosshair_layer.Children().InsertAtTop(m_top_crosshair);
|
||||
|
||||
m_bottom_crosshair_border = m_compositor.CreateSpriteVisual();
|
||||
m_bottom_crosshair_border.AnchorPoint({ 0.5f, 0.0f });
|
||||
m_bottom_crosshair_border.Brush(m_compositor.CreateColorBrush(m_crosshair_border_color));
|
||||
m_crosshair_border_layer.Children().InsertAtTop(m_bottom_crosshair_border);
|
||||
m_bottom_crosshair = m_compositor.CreateSpriteVisual();
|
||||
m_bottom_crosshair.AnchorPoint({ 0.5f, 0.0f });
|
||||
m_bottom_crosshair.Brush(m_compositor.CreateColorBrush(m_crosshair_color));
|
||||
m_crosshair_layer.Children().InsertAtTop(m_bottom_crosshair);
|
||||
|
||||
m_crosshair_border_layer.Children().InsertAtTop(m_crosshair_layer);
|
||||
m_crosshair_layer.Opacity(1.0f);
|
||||
|
||||
UpdateCrosshairPosition();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void InclusiveCrosshair::UpdateCrosshairPosition()
|
||||
{
|
||||
POINT ptCursor;
|
||||
|
||||
GetCursorPos(&ptCursor);
|
||||
|
||||
HMONITOR cursorMonitor = MonitorFromPoint(ptCursor, MONITOR_DEFAULTTONEAREST);
|
||||
|
||||
if (cursorMonitor == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MONITORINFO monitorInfo;
|
||||
monitorInfo.cbSize = sizeof(monitorInfo);
|
||||
|
||||
if (!GetMonitorInfo(cursorMonitor, &monitorInfo))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
POINT ptMonitorUpperLeft;
|
||||
ptMonitorUpperLeft.x = monitorInfo.rcMonitor.left;
|
||||
ptMonitorUpperLeft.y = monitorInfo.rcMonitor.top;
|
||||
|
||||
POINT ptMonitorBottomRight;
|
||||
ptMonitorBottomRight.x = monitorInfo.rcMonitor.right;
|
||||
ptMonitorBottomRight.y = monitorInfo.rcMonitor.bottom;
|
||||
|
||||
// Convert everything to client coordinates.
|
||||
ScreenToClient(m_hwnd, &ptCursor);
|
||||
ScreenToClient(m_hwnd, &ptMonitorUpperLeft);
|
||||
ScreenToClient(m_hwnd, &ptMonitorBottomRight);
|
||||
|
||||
// Position crosshair components around the mouse pointer.
|
||||
m_left_crosshair_border.Offset({ (float)ptCursor.x - m_crosshair_radius + m_crosshair_border_size, (float)ptCursor.y, .0f });
|
||||
m_left_crosshair_border.Size({ (float)ptCursor.x - (float)ptMonitorUpperLeft.x - m_crosshair_radius + m_crosshair_border_size, m_crosshair_thickness + m_crosshair_border_size * 2 });
|
||||
m_left_crosshair.Offset({ (float)ptCursor.x - m_crosshair_radius, (float)ptCursor.y, .0f });
|
||||
m_left_crosshair.Size({ (float)ptCursor.x - (float)ptMonitorUpperLeft.x - m_crosshair_radius, m_crosshair_thickness });
|
||||
|
||||
m_right_crosshair_border.Offset({ (float)ptCursor.x + m_crosshair_radius - m_crosshair_border_size, (float)ptCursor.y, .0f });
|
||||
m_right_crosshair_border.Size({ (float)ptMonitorBottomRight.x - (float)ptCursor.x - m_crosshair_radius + m_crosshair_border_size, m_crosshair_thickness + m_crosshair_border_size * 2 });
|
||||
m_right_crosshair.Offset({ (float)ptCursor.x + m_crosshair_radius, (float)ptCursor.y, .0f });
|
||||
m_right_crosshair.Size({ (float)ptMonitorBottomRight.x - (float)ptCursor.x - m_crosshair_radius, m_crosshair_thickness });
|
||||
|
||||
m_top_crosshair_border.Offset({ (float)ptCursor.x, (float)ptCursor.y - m_crosshair_radius + m_crosshair_border_size, .0f });
|
||||
m_top_crosshair_border.Size({ m_crosshair_thickness + m_crosshair_border_size * 2, (float)ptCursor.y - (float)ptMonitorUpperLeft.y - m_crosshair_radius + m_crosshair_border_size });
|
||||
m_top_crosshair.Offset({ (float)ptCursor.x, (float)ptCursor.y - m_crosshair_radius, .0f });
|
||||
m_top_crosshair.Size({ m_crosshair_thickness, (float)ptCursor.y - (float)ptMonitorUpperLeft.y - m_crosshair_radius });
|
||||
|
||||
m_bottom_crosshair_border.Offset({ (float)ptCursor.x, (float)ptCursor.y + m_crosshair_radius - m_crosshair_border_size, .0f });
|
||||
m_bottom_crosshair_border.Size({ m_crosshair_thickness + m_crosshair_border_size * 2, (float)ptMonitorBottomRight.y - (float)ptCursor.y - m_crosshair_radius + m_crosshair_border_size });
|
||||
m_bottom_crosshair.Offset({ (float)ptCursor.x, (float)ptCursor.y + m_crosshair_radius, .0f });
|
||||
m_bottom_crosshair.Size({ m_crosshair_thickness, (float)ptMonitorBottomRight.y - (float)ptCursor.y - m_crosshair_radius });
|
||||
|
||||
}
|
||||
|
||||
LRESULT CALLBACK InclusiveCrosshair::MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
if (nCode >= 0)
|
||||
{
|
||||
MSLLHOOKSTRUCT* hookData = (MSLLHOOKSTRUCT*)lParam;
|
||||
if (wParam == WM_MOUSEMOVE) {
|
||||
instance->UpdateCrosshairPosition();
|
||||
}
|
||||
}
|
||||
return CallNextHookEx(0, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
void InclusiveCrosshair::StartDrawing()
|
||||
{
|
||||
Logger::info("Start drawing crosshairs.");
|
||||
Trace::StartDrawingCrosshair();
|
||||
m_visible = true;
|
||||
SetWindowPos(m_hwnd, HWND_TOPMOST, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN), GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN), 0);
|
||||
ShowWindow(m_hwnd, SW_SHOWNOACTIVATE);
|
||||
m_mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, m_hinstance, 0);
|
||||
UpdateCrosshairPosition();
|
||||
}
|
||||
|
||||
void InclusiveCrosshair::StopDrawing()
|
||||
{
|
||||
Logger::info("Stop drawing crosshairs.");
|
||||
m_visible = false;
|
||||
ShowWindow(m_hwnd, SW_HIDE);
|
||||
UnhookWindowsHookEx(m_mouseHook);
|
||||
m_mouseHook = NULL;
|
||||
}
|
||||
|
||||
void InclusiveCrosshair::SwitchActivationMode()
|
||||
{
|
||||
PostMessage(m_hwnd, WM_SWITCH_ACTIVATION_MODE, 0, 0);
|
||||
}
|
||||
|
||||
void InclusiveCrosshair::ApplySettings(InclusiveCrosshairSettings& settings, bool applyToRunTimeObjects)
|
||||
{
|
||||
m_crosshair_radius = (float)settings.crosshairRadius;
|
||||
m_crosshair_thickness = (float)settings.crosshairThickness;
|
||||
m_crosshair_color = settings.crosshairColor;
|
||||
m_crosshair_opacity = max(0.f, min(1.f, (float)settings.crosshairOpacity / 100.0f));
|
||||
m_crosshair_border_color = settings.crosshairBorderColor;
|
||||
m_crosshair_border_size = (float)settings.crosshairBorderSize;
|
||||
|
||||
if (applyToRunTimeObjects)
|
||||
{
|
||||
// Runtime objects already created. Should update in the owner thread.
|
||||
auto dispatcherQueue = m_dispatcherQueueController.DispatcherQueue();
|
||||
InclusiveCrosshairSettings localSettings = settings;
|
||||
bool enqueueSucceeded = dispatcherQueue.TryEnqueue([=]() {
|
||||
if (!m_destroyed)
|
||||
{
|
||||
// Apply new settings to runtime composition objects.
|
||||
m_left_crosshair.Brush().as<winrt::CompositionColorBrush>().Color(m_crosshair_color);
|
||||
m_right_crosshair.Brush().as<winrt::CompositionColorBrush>().Color(m_crosshair_color);
|
||||
m_top_crosshair.Brush().as<winrt::CompositionColorBrush>().Color(m_crosshair_color);
|
||||
m_bottom_crosshair.Brush().as<winrt::CompositionColorBrush>().Color(m_crosshair_color);
|
||||
m_left_crosshair_border.Brush().as<winrt::CompositionColorBrush>().Color(m_crosshair_border_color);
|
||||
m_right_crosshair_border.Brush().as<winrt::CompositionColorBrush>().Color(m_crosshair_border_color);
|
||||
m_top_crosshair_border.Brush().as<winrt::CompositionColorBrush>().Color(m_crosshair_border_color);
|
||||
m_bottom_crosshair_border.Brush().as<winrt::CompositionColorBrush>().Color(m_crosshair_border_color);
|
||||
m_root.Opacity(m_crosshair_opacity);
|
||||
UpdateCrosshairPosition();
|
||||
}
|
||||
});
|
||||
if (!enqueueSucceeded)
|
||||
{
|
||||
Logger::error("Couldn't enqueue message to update the crosshair settings.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InclusiveCrosshair::DestroyInclusiveCrosshair()
|
||||
{
|
||||
StopDrawing();
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK InclusiveCrosshair::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_NCCREATE:
|
||||
instance->m_hwnd = hWnd;
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
case WM_CREATE:
|
||||
return instance->CreateInclusiveCrosshair() ? 0 : -1;
|
||||
case WM_NCHITTEST:
|
||||
return HTTRANSPARENT;
|
||||
case WM_SWITCH_ACTIVATION_MODE:
|
||||
if (instance->m_visible)
|
||||
{
|
||||
instance->StopDrawing();
|
||||
}
|
||||
else
|
||||
{
|
||||
instance->StartDrawing();
|
||||
}
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
instance->DestroyInclusiveCrosshair();
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool InclusiveCrosshair::MyRegisterClass(HINSTANCE hInstance)
|
||||
{
|
||||
WNDCLASS wc{};
|
||||
|
||||
m_hinstance = hInstance;
|
||||
|
||||
SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
if (!GetClassInfoW(hInstance, m_className, &wc))
|
||||
{
|
||||
wc.lpfnWndProc = WndProc;
|
||||
wc.hInstance = hInstance;
|
||||
wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
|
||||
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
|
||||
wc.lpszClassName = m_className;
|
||||
|
||||
if (!RegisterClassW(&wc))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_hwndOwner = CreateWindow(L"static", nullptr, WS_POPUP, 0, 0, 0, 0, nullptr, nullptr, hInstance, nullptr);
|
||||
|
||||
DWORD exStyle = WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_NOREDIRECTIONBITMAP | WS_EX_TOOLWINDOW;
|
||||
return CreateWindowExW(exStyle, m_className, m_windowTitle, WS_POPUP, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, m_hwndOwner, nullptr, hInstance, nullptr) != nullptr;
|
||||
}
|
||||
|
||||
void InclusiveCrosshair::Terminate()
|
||||
{
|
||||
auto dispatcherQueue = m_dispatcherQueueController.DispatcherQueue();
|
||||
bool enqueueSucceeded = dispatcherQueue.TryEnqueue([=]() {
|
||||
m_destroyed = true;
|
||||
DestroyWindow(m_hwndOwner);
|
||||
});
|
||||
if (!enqueueSucceeded)
|
||||
{
|
||||
Logger::error("Couldn't enqueue message to destroy the window.");
|
||||
}
|
||||
}
|
||||
|
||||
#pragma region InclusiveCrosshair_API
|
||||
|
||||
void InclusiveCrosshairApplySettings(InclusiveCrosshairSettings& settings)
|
||||
{
|
||||
if (InclusiveCrosshair::instance != nullptr)
|
||||
{
|
||||
Logger::info("Applying settings.");
|
||||
InclusiveCrosshair::instance->ApplySettings(settings, true);
|
||||
}
|
||||
}
|
||||
|
||||
void InclusiveCrosshairSwitch()
|
||||
{
|
||||
if (InclusiveCrosshair::instance != nullptr)
|
||||
{
|
||||
Logger::info("Switching activation mode.");
|
||||
InclusiveCrosshair::instance->SwitchActivationMode();
|
||||
}
|
||||
}
|
||||
|
||||
void InclusiveCrosshairDisable()
|
||||
{
|
||||
if (InclusiveCrosshair::instance != nullptr)
|
||||
{
|
||||
Logger::info("Terminating the crosshair instance.");
|
||||
InclusiveCrosshair::instance->Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
bool InclusiveCrosshairIsEnabled()
|
||||
{
|
||||
return (InclusiveCrosshair::instance != nullptr);
|
||||
}
|
||||
|
||||
int InclusiveCrosshairMain(HINSTANCE hInstance, InclusiveCrosshairSettings& settings)
|
||||
{
|
||||
Logger::info("Starting a crosshair instance.");
|
||||
if (InclusiveCrosshair::instance != nullptr)
|
||||
{
|
||||
Logger::error("A crosshair instance was still working when trying to start a new one.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Perform application initialization:
|
||||
InclusiveCrosshair crosshair;
|
||||
InclusiveCrosshair::instance = &crosshair;
|
||||
crosshair.ApplySettings(settings, false);
|
||||
if (!crosshair.MyRegisterClass(hInstance))
|
||||
{
|
||||
Logger::error("Couldn't initialize a crosshair instance.");
|
||||
InclusiveCrosshair::instance = nullptr;
|
||||
return FALSE;
|
||||
}
|
||||
Logger::info("Initialized the crosshair instance.");
|
||||
|
||||
MSG msg;
|
||||
|
||||
// Main message loop:
|
||||
while (GetMessage(&msg, nullptr, 0, 0))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
Logger::info("Crosshair message loop ended.");
|
||||
InclusiveCrosshair::instance = nullptr;
|
||||
|
||||
return (int)msg.wParam;
|
||||
}
|
||||
|
||||
#pragma endregion InclusiveCrosshair_API
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
|
||||
constexpr int INCLUSIVE_MOUSE_DEFAULT_CROSSHAIR_OPACITY = 75;
|
||||
const winrt::Windows::UI::Color INCLUSIVE_MOUSE_DEFAULT_CROSSHAIR_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(255, 255, 0, 0);
|
||||
const winrt::Windows::UI::Color INCLUSIVE_MOUSE_DEFAULT_CROSSHAIR_BORDER_COLOR = winrt::Windows::UI::ColorHelper::FromArgb(255, 255, 255, 255);
|
||||
constexpr int INCLUSIVE_MOUSE_DEFAULT_CROSSHAIR_RADIUS = 20;
|
||||
constexpr int INCLUSIVE_MOUSE_DEFAULT_CROSSHAIR_THICKNESS = 5;
|
||||
constexpr int INCLUSIVE_MOUSE_DEFAULT_CROSSHAIR_BORDER_SIZE = 1;
|
||||
|
||||
struct InclusiveCrosshairSettings
|
||||
{
|
||||
winrt::Windows::UI::Color crosshairColor = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIR_COLOR;
|
||||
winrt::Windows::UI::Color crosshairBorderColor = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIR_BORDER_COLOR;
|
||||
int crosshairRadius = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIR_RADIUS;
|
||||
int crosshairThickness = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIR_THICKNESS;
|
||||
int crosshairOpacity = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIR_OPACITY;
|
||||
int crosshairBorderSize = INCLUSIVE_MOUSE_DEFAULT_CROSSHAIR_BORDER_SIZE;
|
||||
};
|
||||
|
||||
int InclusiveCrosshairMain(HINSTANCE hinst, InclusiveCrosshairSettings& settings);
|
||||
void InclusiveCrosshairDisable();
|
||||
bool InclusiveCrosshairIsEnabled();
|
||||
void InclusiveCrosshairSwitch();
|
||||
void InclusiveCrosshairApplySettings(InclusiveCrosshairSettings& settings);
|
||||
@@ -0,0 +1,40 @@
|
||||
#include <windows.h>
|
||||
#include "resource.h"
|
||||
#include "../../../common/version/version.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
#include "winres.h"
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION FILE_VERSION
|
||||
PRODUCTVERSION PRODUCT_VERSION
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
|
||||
BEGIN
|
||||
VALUE "CompanyName", COMPANY_NAME
|
||||
VALUE "FileDescription", FILE_DESCRIPTION
|
||||
VALUE "FileVersion", FILE_VERSION_STRING
|
||||
VALUE "InternalName", INTERNAL_NAME
|
||||
VALUE "LegalCopyright", COPYRIGHT_NOTE
|
||||
VALUE "OriginalFilename", ORIGINAL_FILENAME
|
||||
VALUE "ProductName", PRODUCT_NAME
|
||||
VALUE "ProductVersion", PRODUCT_VERSION_STRING
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
|
||||
END
|
||||
END
|
||||
@@ -0,0 +1,145 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{eae14c0e-7a6b-45da-9080-a7d8c077ba6e}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>MousePointerCrosshair</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>MousePointerCrosshair</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\MouseUtils\</OutDir>
|
||||
<TargetName>PowerToys.MousePointerCrosshair</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\MouseUtils\</OutDir>
|
||||
<TargetName>PowerToys.MousePointerCrosshair</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)src\;$(SolutionDir)src\modules;$(SolutionDir)src\common\Telemetry;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(CIBuild)'!='true'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="InclusiveCrosshair.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="InclusiveCrosshair.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="MousePointerCrosshair.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SetttingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="InclusiveCrosshair.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="InclusiveCrosshair.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Generated Files">
|
||||
<UniqueIdentifier>{890924c4-f592-4e84-b140-4b07a607a224}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{a9a2fd9b-de66-43dc-99b2-56f0d1ddecda}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{b5d0d62e-0275-439b-a910-e7c5befad045}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{5e350f4d-b07a-4bb2-8e63-b2c527358234}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="MousePointerCrosshair.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
312
src/modules/MouseUtils/MousePointerCrosshair/dllmain.cpp
Normal file
312
src/modules/MouseUtils/MousePointerCrosshair/dllmain.cpp
Normal file
@@ -0,0 +1,312 @@
|
||||
#include "pch.h"
|
||||
#include <interface/powertoy_module_interface.h>
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include "trace.h"
|
||||
#include "InclusiveCrosshair.h"
|
||||
#include "common/utils/color.h"
|
||||
|
||||
// Non-Localizable strings
|
||||
namespace
|
||||
{
|
||||
const wchar_t JSON_KEY_PROPERTIES[] = L"properties";
|
||||
const wchar_t JSON_KEY_VALUE[] = L"value";
|
||||
const wchar_t JSON_KEY_ACTIVATION_SHORTCUT[] = L"activation_shortcut";
|
||||
const wchar_t JSON_KEY_CROSSHAIR_COLOR[] = L"crosshair_color";
|
||||
const wchar_t JSON_KEY_CROSSHAIR_OPACITY[] = L"crosshair_opacity";
|
||||
const wchar_t JSON_KEY_CROSSHAIR_RADIUS[] = L"crosshair_radius";
|
||||
const wchar_t JSON_KEY_CROSSHAIR_THICKNESS[] = L"crosshair_thickness";
|
||||
const wchar_t JSON_KEY_CROSSHAIR_BORDER_COLOR[] = L"crosshair_border_color";
|
||||
const wchar_t JSON_KEY_CROSSHAIR_BORDER_SIZE[] = L"crosshair_border_size";
|
||||
}
|
||||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
HMODULE m_hModule;
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
m_hModule = hModule;
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
Trace::RegisterProvider();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
Trace::UnregisterProvider();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// The PowerToy name that will be shown in the settings.
|
||||
const static wchar_t* MODULE_NAME = L"MousePointerCrosshair";
|
||||
// Add a description that will we shown in the module settings page.
|
||||
const static wchar_t* MODULE_DESC = L"<no description>";
|
||||
|
||||
// Implement the PowerToy Module Interface and all the required methods.
|
||||
class MousePointerCrosshair : public PowertoyModuleIface
|
||||
{
|
||||
private:
|
||||
// The PowerToy state.
|
||||
bool m_enabled = false;
|
||||
|
||||
// Hotkey to invoke the module
|
||||
HotkeyEx m_hotkey;
|
||||
|
||||
// Mouse Pointer Crosshair specific settings
|
||||
InclusiveCrosshairSettings m_inclusiveCrosshairSettings;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
MousePointerCrosshair()
|
||||
{
|
||||
LoggerHelpers::init_logger(MODULE_NAME, L"ModuleInterface", LogSettings::mousePointerCrosshairLoggerName);
|
||||
init_settings();
|
||||
};
|
||||
|
||||
// Destroy the powertoy and free memory
|
||||
virtual void destroy() override
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
// Return the localized display name of the powertoy
|
||||
virtual const wchar_t* get_name() override
|
||||
{
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
// Return the non localized key of the powertoy, this will be cached by the runner
|
||||
virtual const wchar_t* get_key() override
|
||||
{
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
// Return JSON with the configuration options.
|
||||
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
|
||||
{
|
||||
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
||||
|
||||
PowerToysSettings::Settings settings(hinstance, get_name());
|
||||
|
||||
return settings.serialize_to_buffer(buffer, buffer_size);
|
||||
}
|
||||
|
||||
// Signal from the Settings editor to call a custom action.
|
||||
// This can be used to spawn more complex editors.
|
||||
virtual void call_custom_action(const wchar_t* action) override
|
||||
{
|
||||
}
|
||||
|
||||
// Called by the runner to pass the updated settings values as a serialized JSON.
|
||||
virtual void set_config(const wchar_t* config) override
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse the input JSON string.
|
||||
PowerToysSettings::PowerToyValues values =
|
||||
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
||||
|
||||
parse_settings(values);
|
||||
|
||||
InclusiveCrosshairApplySettings(m_inclusiveCrosshairSettings);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
Logger::error("Invalid json when trying to parse Mouse Pointer Crosshair settings json.");
|
||||
}
|
||||
}
|
||||
|
||||
// Enable the powertoy
|
||||
virtual void enable()
|
||||
{
|
||||
m_enabled = true;
|
||||
Trace::EnableMousePointerCrosshair(true);
|
||||
std::thread([=]() { InclusiveCrosshairMain(m_hModule, m_inclusiveCrosshairSettings); }).detach();
|
||||
}
|
||||
|
||||
// Disable the powertoy
|
||||
virtual void disable()
|
||||
{
|
||||
m_enabled = false;
|
||||
Trace::EnableMousePointerCrosshair(false);
|
||||
InclusiveCrosshairDisable();
|
||||
}
|
||||
|
||||
// Returns if the powertoys is enabled
|
||||
virtual bool is_enabled() override
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
// Returns whether the PowerToys should be enabled by default
|
||||
virtual bool is_enabled_by_default() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual std::optional<HotkeyEx> GetHotkeyEx() override
|
||||
{
|
||||
return m_hotkey;
|
||||
}
|
||||
|
||||
virtual void OnHotkeyEx() override
|
||||
{
|
||||
InclusiveCrosshairSwitch();
|
||||
}
|
||||
// Load the settings file.
|
||||
void init_settings()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Load and parse the settings file for this PowerToy.
|
||||
PowerToysSettings::PowerToyValues settings =
|
||||
PowerToysSettings::PowerToyValues::load_from_settings_file(MousePointerCrosshair::get_key());
|
||||
parse_settings(settings);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
Logger::error("Invalid json when trying to load the Mouse Pointer Crosshair settings json from file.");
|
||||
}
|
||||
}
|
||||
|
||||
void parse_settings(PowerToysSettings::PowerToyValues& settings)
|
||||
{
|
||||
// TODO: refactor to use common/utils/json.h instead
|
||||
auto settingsObject = settings.get_raw_json();
|
||||
InclusiveCrosshairSettings inclusiveCrosshairSettings;
|
||||
if (settingsObject.GetView().Size())
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse HotKey
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_ACTIVATION_SHORTCUT);
|
||||
auto hotkey = PowerToysSettings::HotkeyObject::from_json(jsonPropertiesObject);
|
||||
m_hotkey = HotkeyEx();
|
||||
if (hotkey.win_pressed())
|
||||
{
|
||||
m_hotkey.modifiersMask |= MOD_WIN;
|
||||
}
|
||||
|
||||
if (hotkey.ctrl_pressed())
|
||||
{
|
||||
m_hotkey.modifiersMask |= MOD_CONTROL;
|
||||
}
|
||||
|
||||
if (hotkey.shift_pressed())
|
||||
{
|
||||
m_hotkey.modifiersMask |= MOD_SHIFT;
|
||||
}
|
||||
|
||||
if (hotkey.alt_pressed())
|
||||
{
|
||||
m_hotkey.modifiersMask |= MOD_ALT;
|
||||
}
|
||||
|
||||
m_hotkey.vkCode = hotkey.get_code();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Mouse Pointer Crosshair activation shortcut");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Opacity
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIR_OPACITY);
|
||||
inclusiveCrosshairSettings.crosshairOpacity = (uint8_t)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Opacity from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse crosshair color
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIR_COLOR);
|
||||
auto crosshairColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE);
|
||||
uint8_t r, g, b;
|
||||
if (!checkValidRGB(crosshairColor, &r, &g, &b))
|
||||
{
|
||||
Logger::error("Crosshair color RGB value is invalid. Will use default value");
|
||||
}
|
||||
else
|
||||
{
|
||||
inclusiveCrosshairSettings.crosshairColor = winrt::Windows::UI::ColorHelper::FromArgb(255, r, g, b);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize crosshair color from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Radius
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIR_RADIUS);
|
||||
inclusiveCrosshairSettings.crosshairRadius = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Radius from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse Thickness
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIR_THICKNESS);
|
||||
inclusiveCrosshairSettings.crosshairThickness = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize Thickness from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse crosshair border color
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIR_BORDER_COLOR);
|
||||
auto crosshairBorderColor = (std::wstring)jsonPropertiesObject.GetNamedString(JSON_KEY_VALUE);
|
||||
uint8_t r, g, b;
|
||||
if (!checkValidRGB(crosshairBorderColor, &r, &g, &b))
|
||||
{
|
||||
Logger::error("Crosshair border color RGB value is invalid. Will use default value");
|
||||
}
|
||||
else
|
||||
{
|
||||
inclusiveCrosshairSettings.crosshairBorderColor = winrt::Windows::UI::ColorHelper::FromArgb(255, r, g, b);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize crosshair border color from settings. Will use default value");
|
||||
}
|
||||
try
|
||||
{
|
||||
// Parse border size
|
||||
auto jsonPropertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_CROSSHAIR_BORDER_SIZE);
|
||||
inclusiveCrosshairSettings.crosshairBorderSize = (UINT)jsonPropertiesObject.GetNamedNumber(JSON_KEY_VALUE);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::warn("Failed to initialize border color from settings. Will use default value");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::info("Mouse Pointer Crosshair settings are empty");
|
||||
}
|
||||
if (!m_hotkey.modifiersMask)
|
||||
{
|
||||
Logger::info("Mouse Pointer Crosshair is going to use default shortcut");
|
||||
m_hotkey.modifiersMask = MOD_CONTROL | MOD_ALT;
|
||||
m_hotkey.vkCode = 0x50; // P key
|
||||
}
|
||||
m_inclusiveCrosshairSettings = inclusiveCrosshairSettings;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||
{
|
||||
return new MousePointerCrosshair();
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" />
|
||||
</packages>
|
||||
1
src/modules/MouseUtils/MousePointerCrosshair/pch.cpp
Normal file
1
src/modules/MouseUtils/MousePointerCrosshair/pch.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include "pch.h"
|
||||
16
src/modules/MouseUtils/MousePointerCrosshair/pch.h
Normal file
16
src/modules/MouseUtils/MousePointerCrosshair/pch.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#define COMPOSITION
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <windows.ui.composition.interop.h>
|
||||
#include <DispatcherQueue.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/Windows.System.h>
|
||||
#include <winrt/Windows.UI.Composition.Desktop.h>
|
||||
#include <ProjectTelemetry.h>
|
||||
#include <thread>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/utils/logger_helper.h>
|
||||
13
src/modules/MouseUtils/MousePointerCrosshair/resource.h
Normal file
13
src/modules/MouseUtils/MousePointerCrosshair/resource.h
Normal file
@@ -0,0 +1,13 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by MousePointerCrosshair.rc
|
||||
|
||||
//////////////////////////////
|
||||
// Non-localizable
|
||||
|
||||
#define FILE_DESCRIPTION "PowerToys MousePointerCrosshair"
|
||||
#define INTERNAL_NAME "MousePointerCrosshair"
|
||||
#define ORIGINAL_FILENAME "PowerToys.MousePointerCrosshair.dll"
|
||||
|
||||
// Non-localizable
|
||||
//////////////////////////////
|
||||
40
src/modules/MouseUtils/MousePointerCrosshair/trace.cpp
Normal file
40
src/modules/MouseUtils/MousePointerCrosshair/trace.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "pch.h"
|
||||
#include "trace.h"
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
g_hProvider,
|
||||
"Microsoft.PowerToys",
|
||||
// {38e8889b-9731-53f5-e901-e8a7c1753074}
|
||||
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
|
||||
TraceLoggingOptionProjectTelemetry());
|
||||
|
||||
void Trace::RegisterProvider() noexcept
|
||||
{
|
||||
TraceLoggingRegister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::UnregisterProvider() noexcept
|
||||
{
|
||||
TraceLoggingUnregister(g_hProvider);
|
||||
}
|
||||
|
||||
// Log if the user has MousePointerCrosshair enabled or disabled
|
||||
void Trace::EnableMousePointerCrosshair(const bool enabled) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"MousePointerCrosshair_EnableMousePointerCrosshair",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingBoolean(enabled, "Enabled"));
|
||||
}
|
||||
|
||||
// Log that the user activated the module by having the crosshair be drawn
|
||||
void Trace::StartDrawingCrosshair() noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"MousePointerCrosshair_StartDrawingCrosshair",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
||||
14
src/modules/MouseUtils/MousePointerCrosshair/trace.h
Normal file
14
src/modules/MouseUtils/MousePointerCrosshair/trace.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
class Trace
|
||||
{
|
||||
public:
|
||||
static void RegisterProvider() noexcept;
|
||||
static void UnregisterProvider() noexcept;
|
||||
|
||||
// Log if the user has MousePointerCrosshair enabled or disabled
|
||||
static void EnableMousePointerCrosshair(const bool enabled) noexcept;
|
||||
|
||||
// Log that the user activated the module by having the crosshair be drawn
|
||||
static void StartDrawingCrosshair() noexcept;
|
||||
};
|
||||
Reference in New Issue
Block a user