Compare commits

..

2 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
b38c8584ac Fix color picker float format precision from 2 to 4 decimal places
Increase float color format precision to 4 decimal places so all
256 byte values (0-255) can be uniquely represented in the 0-1 float
range. With only 2 decimal places, only 101 unique values existed,
causing round-trip errors (e.g., byte 57 → 0.22 → 56.1 ≠ 57).

Changes:
- ColorFormatHelper.cs: Update 'f' format to "0.####" and 'F' to ".####"
- ColorRepresentationHelper.cs: Update ColorToFloat precision to 4
- Add test for non-trivial color that verifies precision fix

Agent-Logs-Url: https://github.com/microsoft/PowerToys/sessions/586aab56-475b-476e-b46a-7b18bea5a988

Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
2026-04-11 23:51:45 +00:00
copilot-swe-agent[bot]
f8bab81abf Initial plan 2026-04-11 23:47:13 +00:00
167 changed files with 804 additions and 3850 deletions

View File

@@ -107,7 +107,7 @@
^src/common/sysinternals/Eula/
^src/modules/cmdpal/Tests/Microsoft\.CommandPalette\.Extensions\.Toolkit\.UnitTests/FuzzyMatcherComparisonTests.cs$
^src/modules/cmdpal/Tests/Microsoft\.CommandPalette\.Extensions\.Toolkit\.UnitTests/FuzzyMatcherDiacriticsTests.cs$
^doc/devdocs/modules/cmdpal/initial-sdk-spec/list-elements-mock-002\.pdn$
^src/modules/cmdpal/doc/initial-sdk-spec/list-elements-mock-002\.pdn$
^src/modules/cmdpal/ext/SamplePagesExtension/Pages/SampleMarkdownImagesPage\.cs$
^src/modules/cmdpal/Microsoft\.CmdPal\.UI/Settings/InternalPage\.SampleData\.cs$
^src/modules/cmdpal/Tests/Microsoft\.CmdPal\.Common\.UnitTests/.*\.TestData\.cs$

View File

@@ -1641,7 +1641,6 @@ tracelogging
tracerpt
trackbar
trafficmanager
traies
transicc
TRAYMOUSEMESSAGE
triaging
@@ -1662,7 +1661,6 @@ UBR
UCallback
ucrt
ucrtd
udit
uefi
uesc
UFlags
@@ -2343,9 +2341,3 @@ YTimer
zamora
zonability
Zorder
LLMHF
RIGHTBUTTON
SIZEALL
grabandmove
GRABANDMOVEMODULEINTERFACE
INITCOMMONCONTROLSEX

View File

@@ -1,232 +0,0 @@
name: Scheduled Issue Product Labeling
on:
schedule:
- cron: "20 */6 * * *" # Every 6 hours at :20
workflow_dispatch: # Allow manual trigger
permissions:
models: read
issues: write
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: true
jobs:
label-issues:
runs-on: ubuntu-latest
steps:
- name: Label issues missing Product labels
uses: actions/github-script@v7
with:
script: |
// ── Product label mapping ──────────────────────────────────
// Canonical list of Product-* labels used in this repo,
// derived from .github/skills/release-note-generation/references/step2-labeling.md
const PRODUCT_LABELS = [
"Product-Advanced Paste",
"Product-Always on Top",
"Product-Awake",
"Product-ColorPicker",
"Product-Command not found",
"Product-Command Palette",
"Product-CropAndLock",
"Product-Cursor Wrap",
"Product-Environment Variables",
"Product-FancyZones",
"Product-File Explorer",
"Product-File Locksmith",
"Product-Find My Mouse",
"Product-Hosts",
"Product-Image Resizer",
"Product-Keyboard Manager",
"Product-LightSwitch",
"Product-Mouse Highlighter",
"Product-Mouse Jump",
"Product-Mouse Pointer Crosshairs",
"Product-Mouse Without Borders",
"Product-New+",
"Product-Peek",
"Product-PowerRename",
"Product-PowerToys Run",
"Product-Quick Accent",
"Product-Registry Preview",
"Product-Screen Ruler",
"Product-Settings",
"Product-Shortcut Guide",
"Product-Text Extractor",
"Product-Workspaces",
"Product-ZoomIt",
];
// Map from bug-report "Area(s) with issue?" dropdown values
// to Product-* labels (used as strong hints when the issue body
// contains the area dropdown answer).
const AREA_TO_LABEL = {
"Advanced Paste": "Product-Advanced Paste",
"Always on Top": "Product-Always on Top",
"Awake": "Product-Awake",
"ColorPicker": "Product-ColorPicker",
"Command not found": "Product-Command not found",
"Command Palette": "Product-Command Palette",
"Crop and Lock": "Product-CropAndLock",
"Environment Variables": "Product-Environment Variables",
"FancyZones": "Product-FancyZones",
"FancyZones Editor": "Product-FancyZones",
"File Locksmith": "Product-File Locksmith",
"File Explorer: Preview Pane": "Product-File Explorer",
"File Explorer: Thumbnail preview": "Product-File Explorer",
"Hosts File Editor": "Product-Hosts",
"Image Resizer": "Product-Image Resizer",
"Keyboard Manager": "Product-Keyboard Manager",
"Light Switch": "Product-LightSwitch",
"Mouse Utilities": "Product-Find My Mouse",
"Mouse Without Borders": "Product-Mouse Without Borders",
"New+": "Product-New+",
"Peek": "Product-Peek",
"PowerRename": "Product-PowerRename",
"PowerToys Run": "Product-PowerToys Run",
"Quick Accent": "Product-Quick Accent",
"Registry Preview": "Product-Registry Preview",
"Screen ruler": "Product-Screen Ruler",
"Shortcut Guide": "Product-Shortcut Guide",
"TextExtractor": "Product-Text Extractor",
"Workspaces": "Product-Workspaces",
"ZoomIt": "Product-ZoomIt",
};
// ── Helpers ────────────────────────────────────────────────
function hasProductLabel(labels) {
return labels.some((l) => l.name.startsWith("Product-"));
}
// Try to extract the area from the structured bug-report body
// (the "Area(s) with issue?" dropdown).
function extractAreaFromBody(body) {
if (!body) return null;
// The rendered issue body contains a heading followed by the selected values
const areaMatch = body.match(
/### Area\(s\) with issue\?\s*\n+(.+?)(?:\n###|\n\n|$)/s
);
if (!areaMatch) return null;
const areaText = areaMatch[1].trim();
if (areaText === "_No response_" || areaText === "General") return null;
// Could be comma-separated; take the first specific one
const areas = areaText.split(",").map((a) => a.trim());
for (const area of areas) {
if (AREA_TO_LABEL[area]) return AREA_TO_LABEL[area];
}
return null;
}
// Use GitHub Models to classify an issue when the dropdown area
// is not available or is "General".
const MAX_BODY_LENGTH = 3000; // Truncate body to stay within model token limits while keeping enough context
const MAX_COMPLETION_TOKENS = 60; // Enough for a Product-* label name with some margin
async function classifyWithAI(title, body) {
const truncatedBody = (body || "").slice(0, MAX_BODY_LENGTH);
const labelList = PRODUCT_LABELS.join("\n- ");
const prompt = `You are a GitHub issue triager for the microsoft/PowerToys repository.
Given the issue title and body below, determine which ONE Product label best fits.
Reply with ONLY the label name (e.g. "Product-FancyZones") or "UNKNOWN" if you cannot determine it.
Available labels:
- ${labelList}
Issue title: ${title}
Issue body:
${truncatedBody}`;
try {
const response = await fetch(
"https://models.github.ai/inference/chat/completions",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "openai/gpt-4o",
messages: [{ role: "user", content: prompt }],
max_tokens: MAX_COMPLETION_TOKENS,
temperature: 0,
}),
}
);
if (!response.ok) {
core.warning(`AI classification failed: ${response.status} ${response.statusText}`);
return null;
}
const data = await response.json();
const answer = data.choices?.[0]?.message?.content?.trim();
if (!answer || answer === "UNKNOWN") return null;
// Validate the answer is a known label
if (PRODUCT_LABELS.includes(answer)) return answer;
// Try fuzzy match (the model may include extra text)
const found = PRODUCT_LABELS.find((l) => answer.includes(l));
return found || null;
} catch (err) {
core.warning(`AI classification error: ${err.message}`);
return null;
}
}
// ── Main ───────────────────────────────────────────────────
const MAX_ISSUES = 50; // Process up to 50 issues per run
let labeled = 0;
let skipped = 0;
core.info("Searching for open issues with Needs-Triage but no Product-* label...");
// Paginate through open issues labeled Needs-Triage
for await (const response of github.paginate.iterator(
github.rest.issues.listForRepo,
{
owner: context.repo.owner,
repo: context.repo.repo,
state: "open",
labels: "Needs-Triage",
sort: "created",
direction: "desc",
per_page: 100,
}
)) {
for (const issue of response.data) {
if (labeled + skipped >= MAX_ISSUES) break;
// Skip pull requests (the API returns them too)
if (issue.pull_request) continue;
if (hasProductLabel(issue.labels)) continue;
core.info(`Processing #${issue.number}: ${issue.title}`);
// 1) Try structured area dropdown first (fast, no AI needed)
let label = extractAreaFromBody(issue.body);
// 2) Fall back to AI classification
if (!label) {
label = await classifyWithAI(issue.title, issue.body);
}
if (label) {
core.info(` → Applying "${label}" to #${issue.number}`);
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: [label],
});
labeled++;
} else {
core.info(` → Could not determine product label for #${issue.number}, skipping.`);
skipped++;
}
}
if (labeled + skipped >= MAX_ISSUES) break;
}
core.info(`Done. Labeled: ${labeled}, Skipped: ${skipped}`);

View File

@@ -250,9 +250,6 @@
"PowerToys.ZoomItModuleInterface.dll",
"PowerToys.ZoomItSettingsInterop.dll",
"PowerToys.GrabAndMove.exe",
"PowerToys.GrabAndMoveModuleInterface.dll",
"WinUI3Apps\\PowerToys.Settings.dll",
"WinUI3Apps\\PowerToys.Settings.exe",

View File

@@ -108,7 +108,6 @@ Thank you for using PowerToys!
| Microsoft.PowerToys.AwakeIndefinitelyKeepAwakeEvent | Triggered when the system is set to stay awake indefinitely. |
| Microsoft.PowerToys.AwakeNoKeepAwakeEvent | Occurs when Awake is turned off, allowing the computer to enter sleep mode. |
| Microsoft.PowerToys.AwakeTimedKeepAwakeEvent | Triggered when the system is kept awake for a specified time duration. |
| Microsoft.PowerToys.Awake_CLICommand | Triggered when an Awake CLI command is executed, logging the command name and success status. |
### Color Picker
@@ -205,7 +204,6 @@ Thank you for using PowerToys!
| Microsoft.PowerToys.FileLocksmith_Invoked | Occurs when File Locksmith is invoked. |
| Microsoft.PowerToys.FileLocksmith_InvokedRet | Triggered when File Locksmith invocation returns a result. |
| Microsoft.PowerToys.FileLocksmith_QueryContextMenuError | Occurs when there is an error querying the context menu for File Locksmith. |
| Microsoft.PowerToys.FileLocksmith_CLICommand | Triggered when a File Locksmith CLI command is executed, logging the operation mode (query, kill, query-wait, query-json, or help) and success status. |
### FileExplorerAddOns
@@ -260,7 +258,6 @@ Thank you for using PowerToys!
| Microsoft.PowerToys.ImageResizer_Invoked | Occurs when Image Resizer is invoked by the user. |
| Microsoft.PowerToys.ImageResizer_InvokedRet | Fires when the Image Resizer operation is completed and returns a result. |
| Microsoft.PowerToys.ImageResizer_QueryContextMenuError | Triggered when there is an error querying the context menu for Image Resizer. |
| Microsoft.PowerToys.ImageResizer_CLICommand | Triggered when an Image Resizer CLI command is executed, logging the command name and success status. |
### Keyboard Manager

View File

@@ -1036,10 +1036,6 @@
<Project Path="src/modules/ZoomIt/ZoomItModuleInterface/ZoomItModuleInterface.vcxproj" Id="e4585179-2ac1-4d5f-a3ff-cfc5392f694c" />
<Project Path="src/modules/ZoomIt/ZoomItSettingsInterop/ZoomItSettingsInterop.vcxproj" Id="ca7d8106-30b9-4aec-9d05-b69b31b8c461" />
</Folder>
<Folder Name="/modules/GrabAndMove/">
<Project Path="src/modules/GrabAndMove/GrabAndMove/GrabAndMove.vcxproj" Id="568c4c30-2e3c-4c2c-a691-007362073765" />
<Project Path="src/modules/GrabAndMove/GrabAndMoveModuleInterface/GrabAndMoveModuleInterface.vcxproj" Id="2c3f7770-4e57-46b7-8dc1-7428a383d0db" />
</Folder>
<Folder Name="/settings-ui/">
<Project Path="src/settings-ui/QuickAccess.UI/PowerToys.QuickAccess.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
@@ -1104,8 +1100,6 @@
<BuildDependency Project="src/modules/launcher/Microsoft.Launcher/Microsoft.Launcher.vcxproj" />
<BuildDependency Project="src/modules/LightSwitch/LightSwitchModuleInterface/LightSwitchModuleInterface.vcxproj" />
<BuildDependency Project="src/modules/LightSwitch/LightSwitchService/LightSwitchService.vcxproj" />
<BuildDependency Project="src/modules/GrabAndMove/GrabAndMoveModuleInterface/GrabAndMoveModuleInterface.vcxproj" />
<BuildDependency Project="src/modules/GrabAndMove/GrabAndMove/GrabAndMove.vcxproj" />
<BuildDependency Project="src/modules/powerrename/dll/PowerRenameExt.vcxproj" />
<BuildDependency Project="src/modules/powerrename/lib/PowerRenameLib.vcxproj" />
<BuildDependency Project="src/modules/previewpane/Common/PreviewHandlerCommon.csproj" />

View File

@@ -28,7 +28,6 @@ namespace ExprtkCalculator::internal
std::wstring ToWStringFullPrecision(double value)
{
std::wostringstream oss;
oss.imbue(std::locale::classic());
oss << std::fixed << std::setprecision(15) << value;
return oss.str();
}

View File

@@ -36,10 +36,6 @@ namespace winrt::PowerToys::GPOWrapper::implementation
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredPowerDisplayEnabledValue());
}
GpoRuleConfigured GPOWrapper::GetConfiguredGrabAndMoveEnabledValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredGrabAndMoveEnabledValue());
}
GpoRuleConfigured GPOWrapper::GetConfiguredFancyZonesEnabledValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredFancyZonesEnabledValue());

View File

@@ -15,7 +15,6 @@ namespace winrt::PowerToys::GPOWrapper::implementation
static GpoRuleConfigured GetConfiguredCropAndLockEnabledValue();
static GpoRuleConfigured GetConfiguredLightSwitchEnabledValue();
static GpoRuleConfigured GetConfiguredPowerDisplayEnabledValue();
static GpoRuleConfigured GetConfiguredGrabAndMoveEnabledValue();
static GpoRuleConfigured GetConfiguredFancyZonesEnabledValue();
static GpoRuleConfigured GetConfiguredFileLocksmithEnabledValue();
static GpoRuleConfigured GetConfiguredSvgPreviewEnabledValue();

View File

@@ -19,7 +19,6 @@ namespace PowerToys
static GpoRuleConfigured GetConfiguredCropAndLockEnabledValue();
static GpoRuleConfigured GetConfiguredLightSwitchEnabledValue();
static GpoRuleConfigured GetConfiguredPowerDisplayEnabledValue();
static GpoRuleConfigured GetConfiguredGrabAndMoveEnabledValue();
static GpoRuleConfigured GetConfiguredFancyZonesEnabledValue();
static GpoRuleConfigured GetConfiguredFileLocksmithEnabledValue();
static GpoRuleConfigured GetConfiguredSvgPreviewEnabledValue();

View File

@@ -71,10 +71,5 @@ namespace PowerToys.GPOWrapperProjection
{
return (GpoRuleConfigured)PowerToys.GPOWrapper.GPOWrapper.GetConfiguredLightSwitchEnabledValue();
}
public static GpoRuleConfigured GetConfiguredGrabAndMoveEnabledValue()
{
return (GpoRuleConfigured)PowerToys.GPOWrapper.GPOWrapper.GetConfiguredGrabAndMoveEnabledValue();
}
}
}

View File

@@ -394,8 +394,8 @@ namespace ManagedCommon
{ 'H', "X1" }, // hex uppercase one digit
{ 'x', "x2" }, // hex lowercase two digits
{ 'X', "X2" }, // hex uppercase two digits
{ 'f', "0.##" }, // float with leading zero, 2 digits
{ 'F', ".##" }, // float without leading zero, 2 digits
{ 'f', "0.####" }, // float with leading zero, 4 digits
{ 'F', ".####" }, // float without leading zero, 4 digits
{ 'p', "%" }, // percent value
{ 'i', "i" }, // int value
{ 's', "s" }, // string value

View File

@@ -36,7 +36,6 @@ namespace ManagedCommon
ShortcutGuide,
PowerOCR,
Workspaces,
GrabAndMove,
ZoomIt,
GeneralSettings,
}

View File

@@ -145,10 +145,6 @@ namespace CommonSharedConstants
// Path to the events used by ZoomIt
const wchar_t ZOOMIT_REFRESH_SETTINGS_EVENT[] = L"Local\\PowerToysZoomIt-RefreshSettingsEvent-f053a563-d519-4b0d-8152-a54489c13324";
// Path to the events used by GrabAndMove
const wchar_t GRABANDMOVE_REFRESH_SETTINGS_EVENT[] = L"Local\\PowerToysGrabAndMove-RefreshSettingsEvent-a7b3c1d2-4e5f-6a7b-8c9d-0e1f2a3b4c5d";
const wchar_t GRABANDMOVE_EXIT_EVENT[] = L"Local\\PowerToysGrabAndMove-ExitEvent-b8c4d2e3-5f6a-7b8c-9d0e-1f2a3b4c5d6e";
const wchar_t ZOOMIT_EXIT_EVENT[] = L"Local\\PowerToysZoomIt-ExitEvent-36641ce6-df02-4eac-abea-a3fbf9138220";
const wchar_t ZOOMIT_ZOOM_EVENT[] = L"Local\\PowerToysZoomIt-ZoomEvent-1e4190d7-94bc-4ad5-adc0-9a8fd07cb393";
const wchar_t ZOOMIT_DRAW_EVENT[] = L"Local\\PowerToysZoomIt-DrawEvent-56338997-404d-4549-bd9a-d132b6766975";

View File

@@ -84,7 +84,6 @@ struct LogSettings
inline const static std::string zoomItLoggerName = "zoom-it";
inline const static std::string lightSwitchLoggerName = "light-switch";
inline const static std::string powerDisplayLoggerName = "powerdisplay";
inline const static std::string grabAndMoveLoggerName = "grabandmove";
inline const static int retention = 30;
std::wstring logLevel;
LogSettings();

View File

@@ -33,7 +33,6 @@ namespace powertoys_gpo
const std::wstring POLICY_CONFIGURE_ENABLED_CROP_AND_LOCK = L"ConfigureEnabledUtilityCropAndLock";
const std::wstring POLICY_CONFIGURE_ENABLED_LIGHT_SWITCH = L"ConfigureEnabledUtilityLightSwitch";
const std::wstring POLICY_CONFIGURE_ENABLED_POWER_DISPLAY = L"ConfigureEnabledUtilityPowerDisplay";
const std::wstring POLICY_CONFIGURE_ENABLED_GRAB_AND_MOVE = L"ConfigureEnabledUtilityGrabAndMove";
const std::wstring POLICY_CONFIGURE_ENABLED_FANCYZONES = L"ConfigureEnabledUtilityFancyZones";
const std::wstring POLICY_CONFIGURE_ENABLED_FILE_LOCKSMITH = L"ConfigureEnabledUtilityFileLocksmith";
const std::wstring POLICY_CONFIGURE_ENABLED_SVG_PREVIEW = L"ConfigureEnabledUtilityFileExplorerSVGPreview";
@@ -318,11 +317,6 @@ namespace powertoys_gpo
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_POWER_DISPLAY);
}
inline gpo_rule_configured_t getConfiguredGrabAndMoveEnabledValue()
{
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_GRAB_AND_MOVE);
}
inline gpo_rule_configured_t getConfiguredFancyZonesEnabledValue()
{
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_FANCYZONES);

View File

@@ -29,7 +29,6 @@
<definition name="SUPPORTED_POWERTOYS_0_96_0" displayName="$(string.SUPPORTED_POWERTOYS_0_96_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_97_0" displayName="$(string.SUPPORTED_POWERTOYS_0_97_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_98_0" displayName="$(string.SUPPORTED_POWERTOYS_0_98_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_99_0" displayName="$(string.SUPPORTED_POWERTOYS_0_99_0)"/>
<definition name="SUPPORTED_POWERTOYS_0_64_0_TO_0_87_1" displayName="$(string.SUPPORTED_POWERTOYS_0_64_0_TO_0_87_1)"/>
</definitions>
</supportedOn>
@@ -153,7 +152,7 @@
</policy>
<policy name="ConfigureEnabledUtilityPowerDisplay" class="Both" displayName="$(string.ConfigureEnabledUtilityPowerDisplay)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityPowerDisplay">
<parentCategory ref="PowerToys" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_99_0" />
<supportedOn ref="SUPPORTED_POWERTOYS_0_95_0" />
<enabledValue>
<decimal value="1" />
</enabledValue>

View File

@@ -36,7 +36,6 @@
<string id="SUPPORTED_POWERTOYS_0_96_0">PowerToys version 0.96.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_97_0">PowerToys version 0.97.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_98_0">PowerToys version 0.98.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_99_0">PowerToys version 0.99.0 or later</string>
<string id="SUPPORTED_POWERTOYS_0_64_0_TO_0_87_1">From PowerToys version 0.64.0 until PowerToys version 0.87.1</string>
<string id="ConfigureAllUtilityGlobalEnabledStateDescription">This policy configures the enabled state for all PowerToys utilities.

View File

@@ -496,119 +496,23 @@ private:
if (!GetGUIThreadInfo(0, &gui_info))
{
Logger::warn(L"Auto-copy: GetGUIThreadInfo failed (error={})", GetLastError());
return false;
}
HWND target = gui_info.hwndFocus ? gui_info.hwndFocus : gui_info.hwndActive;
if (!target)
{
Logger::warn(L"Auto-copy: no focused or active window found");
return false;
}
DWORD_PTR result = 0;
auto sendResult = SendMessageTimeout(target, WM_COPY, 0, 0, SMTO_ABORTIFHUNG | SMTO_BLOCK, 50, &result);
return sendResult != 0;
}
// Helper: poll clipboard sequence number for a change from initial_sequence.
// Returns true if the sequence number changed within the given number of polls.
bool poll_clipboard_sequence(DWORD initial_sequence, int poll_attempts, std::chrono::milliseconds poll_delay)
{
for (int poll = 0; poll < poll_attempts; ++poll)
{
if (GetClipboardSequenceNumber() != initial_sequence)
{
return true;
}
std::this_thread::sleep_for(poll_delay);
}
return false;
}
// Helper: send Ctrl+C via SendInput, releasing any held modifier keys first
// (the hotkey combination may still have modifiers physically pressed).
bool send_ctrl_c_input()
{
std::vector<INPUT> inputs;
// Release all modifier keys that are currently held down from the hotkey.
// Without this, the target app sees e.g. Win+Shift+Ctrl+C instead of just Ctrl+C.
try_inject_modifier_key_up(inputs, VK_LCONTROL);
try_inject_modifier_key_up(inputs, VK_RCONTROL);
try_inject_modifier_key_up(inputs, VK_LWIN);
try_inject_modifier_key_up(inputs, VK_RWIN);
try_inject_modifier_key_up(inputs, VK_LSHIFT);
try_inject_modifier_key_up(inputs, VK_RSHIFT);
try_inject_modifier_key_up(inputs, VK_LMENU);
try_inject_modifier_key_up(inputs, VK_RMENU);
// Ctrl down
{
INPUT input_event = {};
input_event.type = INPUT_KEYBOARD;
input_event.ki.wVk = VK_CONTROL;
input_event.ki.dwExtraInfo = CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG;
inputs.push_back(input_event);
}
// C down
{
INPUT input_event = {};
input_event.type = INPUT_KEYBOARD;
input_event.ki.wVk = 0x43; // C
input_event.ki.dwExtraInfo = CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG;
inputs.push_back(input_event);
}
// C up
{
INPUT input_event = {};
input_event.type = INPUT_KEYBOARD;
input_event.ki.wVk = 0x43; // C
input_event.ki.dwFlags = KEYEVENTF_KEYUP;
input_event.ki.dwExtraInfo = CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG;
inputs.push_back(input_event);
}
// Ctrl up
{
INPUT input_event = {};
input_event.type = INPUT_KEYBOARD;
input_event.ki.wVk = VK_CONTROL;
input_event.ki.dwFlags = KEYEVENTF_KEYUP;
input_event.ki.dwExtraInfo = CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG;
inputs.push_back(input_event);
}
// Restore modifiers that were held down
try_inject_modifier_key_restore(inputs, VK_LCONTROL);
try_inject_modifier_key_restore(inputs, VK_RCONTROL);
try_inject_modifier_key_restore(inputs, VK_LWIN);
try_inject_modifier_key_restore(inputs, VK_RWIN);
try_inject_modifier_key_restore(inputs, VK_LSHIFT);
try_inject_modifier_key_restore(inputs, VK_RSHIFT);
try_inject_modifier_key_restore(inputs, VK_LMENU);
try_inject_modifier_key_restore(inputs, VK_RMENU);
// Prevent Start Menu from activating after Win key release/restore
INPUT dummyEvent = {};
dummyEvent.type = INPUT_KEYBOARD;
dummyEvent.ki.wVk = 0xFF;
dummyEvent.ki.dwFlags = KEYEVENTF_KEYUP;
inputs.push_back(dummyEvent);
auto uSent = SendInput(static_cast<UINT>(inputs.size()), inputs.data(), sizeof(INPUT));
if (uSent != inputs.size())
{
DWORD errorCode = GetLastError();
auto errorMessage = get_last_error_message(errorCode);
Logger::error(L"SendInput failed for Ctrl+C. Expected to send {} inputs and sent only {}. {}", inputs.size(), uSent, errorMessage.has_value() ? errorMessage.value() : L"");
Trace::AdvancedPaste_Error(errorCode, errorMessage.has_value() ? errorMessage.value() : L"", L"input.SendInput");
return false;
}
return true;
return SendMessageTimeout(target,
WM_COPY,
0,
0,
SMTO_ABORTIFHUNG | SMTO_BLOCK,
50,
&result) != 0;
}
bool send_copy_selection()
@@ -622,30 +526,78 @@ private:
for (int attempt = 0; attempt < copy_attempts; ++attempt)
{
const auto initial_sequence = GetClipboardSequenceNumber();
copy_succeeded = try_send_copy_message();
// Strategy 1: Try WM_COPY message (works for standard Win32 controls)
bool wm_copy_sent = try_send_copy_message();
if (wm_copy_sent)
if (!copy_succeeded)
{
if (poll_clipboard_sequence(initial_sequence, clipboard_poll_attempts, clipboard_poll_delay))
std::vector<INPUT> inputs;
// send Ctrl+C (key downs and key ups)
{
INPUT input_event = {};
input_event.type = INPUT_KEYBOARD;
input_event.ki.wVk = VK_CONTROL;
input_event.ki.dwExtraInfo = CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG;
inputs.push_back(input_event);
}
{
INPUT input_event = {};
input_event.type = INPUT_KEYBOARD;
input_event.ki.wVk = 0x43; // C
// Avoid triggering detection by the centralized keyboard hook.
input_event.ki.dwExtraInfo = CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG;
inputs.push_back(input_event);
}
{
INPUT input_event = {};
input_event.type = INPUT_KEYBOARD;
input_event.ki.wVk = 0x43; // C
input_event.ki.dwFlags = KEYEVENTF_KEYUP;
// Avoid triggering detection by the centralized keyboard hook.
input_event.ki.dwExtraInfo = CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG;
inputs.push_back(input_event);
}
{
INPUT input_event = {};
input_event.type = INPUT_KEYBOARD;
input_event.ki.wVk = VK_CONTROL;
input_event.ki.dwFlags = KEYEVENTF_KEYUP;
input_event.ki.dwExtraInfo = CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG;
inputs.push_back(input_event);
}
auto uSent = SendInput(static_cast<UINT>(inputs.size()), inputs.data(), sizeof(INPUT));
if (uSent != inputs.size())
{
DWORD errorCode = GetLastError();
auto errorMessage = get_last_error_message(errorCode);
Logger::error(L"SendInput failed for Ctrl+C. Expected to send {} inputs and sent only {}. {}", inputs.size(), uSent, errorMessage.has_value() ? errorMessage.value() : L"");
Trace::AdvancedPaste_Error(errorCode, errorMessage.has_value() ? errorMessage.value() : L"", L"input.SendInput");
}
else
{
copy_succeeded = true;
}
}
// Strategy 2: If WM_COPY didn't work, try SendInput Ctrl+C (works for Electron, browsers, etc.)
if (!copy_succeeded)
if (copy_succeeded)
{
const auto sequence_before_ctrl_c = GetClipboardSequenceNumber();
if (send_ctrl_c_input())
bool sequence_changed = false;
for (int poll_attempt = 0; poll_attempt < clipboard_poll_attempts; ++poll_attempt)
{
if (poll_clipboard_sequence(sequence_before_ctrl_c, clipboard_poll_attempts, clipboard_poll_delay))
if (GetClipboardSequenceNumber() != initial_sequence)
{
copy_succeeded = true;
sequence_changed = true;
break;
}
std::this_thread::sleep_for(clipboard_poll_delay);
}
copy_succeeded = sequence_changed;
}
if (copy_succeeded)
@@ -659,11 +611,6 @@ private:
}
}
if (!copy_succeeded)
{
Logger::warn(L"Auto-copy: all {} copy attempts failed — the target application did not update the clipboard after WM_COPY and Ctrl+C", copy_attempts);
}
return copy_succeeded;
}
@@ -1030,7 +977,6 @@ public:
{
if (!send_copy_selection())
{
Logger::warn(L"Auto-copy: failed to copy selection for custom action index {} — aborting action", custom_action_index);
return false;
}
}

View File

@@ -121,7 +121,7 @@ CommandResult run_command(int argc, wchar_t* argv[], IProcessFinder& finder, IPr
if (argc < 2)
{
Logger::warn("No arguments provided");
return { 1, get_usage(strings), L"help" };
return { 1, get_usage(strings) };
}
bool json_output = false;
@@ -156,18 +156,18 @@ CommandResult run_command(int argc, wchar_t* argv[], IProcessFinder& finder, IPr
catch (...)
{
Logger::error("Invalid timeout value");
return { 1, strings.GetString(IDS_ERROR_INVALID_TIMEOUT), L"query-wait" };
return { 1, strings.GetString(IDS_ERROR_INVALID_TIMEOUT) };
}
}
else
{
Logger::error("Timeout argument missing");
return { 1, strings.GetString(IDS_ERROR_TIMEOUT_ARG), L"query-wait" };
return { 1, strings.GetString(IDS_ERROR_TIMEOUT_ARG) };
}
}
else if (arg == L"--help")
{
return { 0, get_usage(strings), L"help" };
return { 0, get_usage(strings) };
}
else
{
@@ -178,7 +178,7 @@ CommandResult run_command(int argc, wchar_t* argv[], IProcessFinder& finder, IPr
if (paths.empty())
{
Logger::error("No paths specified");
return { 1, strings.GetString(IDS_ERROR_NO_PATHS), L"query" };
return { 1, strings.GetString(IDS_ERROR_NO_PATHS) };
}
Logger::info("Processing {} paths", paths.size());
@@ -213,13 +213,13 @@ CommandResult run_command(int argc, wchar_t* argv[], IProcessFinder& finder, IPr
{
Logger::warn("Timeout waiting for files to be unlocked");
ss << strings.GetString(IDS_TIMEOUT);
return { 1, ss.str(), L"query-wait" };
return { 1, ss.str() };
}
}
Sleep(200);
}
return { 0, ss.str(), L"query-wait" };
return { 0, ss.str() };
}
auto results = finder.find(paths);
@@ -244,6 +244,5 @@ CommandResult run_command(int argc, wchar_t* argv[], IProcessFinder& finder, IPr
output_ss << get_text(results, strings);
}
std::wstring cmd_name = kill ? L"kill" : (json_output ? L"query-json" : L"query");
return { 0, output_ss.str(), cmd_name };
return { 0, output_ss.str() };
}

View File

@@ -8,7 +8,6 @@ struct CommandResult
{
int exit_code;
std::wstring output;
std::wstring command_name;
};
struct IProcessFinder

View File

@@ -1,7 +1,6 @@
#include "pch.h"
#include "CLILogic.h"
#include "FileLocksmithLib/FileLocksmith.h"
#include "FileLocksmithLib/Trace.h"
#include <iostream>
#include "resource.h"
#include <common/logger/logger.h>
@@ -48,7 +47,6 @@ struct RealStringProvider : IStringProvider
int wmain(int argc, wchar_t* argv[])
{
winrt::init_apartment();
Trace::RegisterProvider();
LoggerHelpers::init_logger(L"FileLocksmithCLI", L"", LogSettings::fileLocksmithLoggerName);
Logger::info("FileLocksmithCLI started");
@@ -67,10 +65,7 @@ int wmain(int argc, wchar_t* argv[])
Logger::info("Command succeeded");
}
Trace::CLICommand(result.command_name.c_str(), result.exit_code == 0);
std::wcout << result.output;
Trace::UnregisterProvider();
return result.exit_code;
}
#endif

View File

@@ -52,7 +52,6 @@ namespace FileLocksmithCLIUnitTests
auto result = run_command(1, argv, finder, terminator, strings);
Assert::AreEqual(1, result.exit_code);
Assert::AreEqual(std::wstring(L"help"), result.command_name);
}
TEST_METHOD(TestHelp)
@@ -65,7 +64,6 @@ namespace FileLocksmithCLIUnitTests
auto result = run_command(2, argv, finder, terminator, strings);
Assert::AreEqual(0, result.exit_code);
Assert::AreEqual(std::wstring(L"help"), result.command_name);
}
TEST_METHOD(TestFindProcesses)
@@ -79,7 +77,6 @@ namespace FileLocksmithCLIUnitTests
auto result = run_command(2, argv, finder, terminator, strings);
Assert::AreEqual(0, result.exit_code);
Assert::AreEqual(std::wstring(L"query"), result.command_name);
Assert::IsTrue(result.output.find(L"123") != std::wstring::npos);
Assert::IsTrue(result.output.find(L"process") != std::wstring::npos);
}
@@ -97,7 +94,6 @@ namespace FileLocksmithCLIUnitTests
Microsoft::VisualStudio::CppUnitTestFramework::Logger::WriteMessage(result.output.c_str());
Assert::AreEqual(0, result.exit_code);
Assert::AreEqual(std::wstring(L"query-json"), result.command_name);
Assert::IsTrue(result.output.find(L"\"pid\"") != std::wstring::npos);
Assert::IsTrue(result.output.find(L"123") != std::wstring::npos);
}
@@ -113,7 +109,6 @@ namespace FileLocksmithCLIUnitTests
auto result = run_command(3, argv, finder, terminator, strings);
Assert::AreEqual(0, result.exit_code);
Assert::AreEqual(std::wstring(L"kill"), result.command_name);
Assert::AreEqual((size_t)1, terminator.terminatedPids.size());
Assert::AreEqual((DWORD)123, terminator.terminatedPids[0]);
}
@@ -130,7 +125,6 @@ namespace FileLocksmithCLIUnitTests
auto result = run_command(5, argv, finder, terminator, strings);
Assert::AreEqual(1, result.exit_code);
Assert::AreEqual(std::wstring(L"query-wait"), result.command_name);
}
};
}

View File

@@ -49,14 +49,3 @@ void Trace::QueryContextMenuError(_In_ HRESULT hr) noexcept
TraceLoggingHResult(hr),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
}
void Trace::CLICommand(_In_ PCWSTR commandName, _In_ bool successful) noexcept
{
TraceLoggingWriteWrapper(
g_hProvider,
"FileLocksmith_CLICommand",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
TraceLoggingWideString(commandName, "CommandName"),
TraceLoggingBoolean(successful, "Successful"));
}

View File

@@ -11,5 +11,4 @@ public:
static void Invoked() noexcept;
static void InvokedRet(_In_ HRESULT hr) noexcept;
static void QueryContextMenuError(_In_ HRESULT hr) noexcept;
static void CLICommand(_In_ PCWSTR commandName, _In_ bool successful) noexcept;
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 766 B

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"
xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:application>
<asmv3:windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2,PerMonitor</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>

View File

@@ -1,102 +0,0 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#include "../../../common/version/version.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_APP_ICON ICON "GrabAndMove.ico"
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
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_APP
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
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -1,197 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.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>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{568c4c30-2e3c-4c2c-a691-007362073765}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>GrabAndMove</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>GrabAndMove</ProjectName>
<TargetName>PowerToys.GrabAndMove</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<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>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<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|ARM64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>$(RepoRoot)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>
$(RepoRoot)src\common;
$(RepoRoot)src\common\SettingsAPI;
$(RepoRoot)src\;
%(AdditionalIncludeDirectories)
</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>WindowsApp.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;UNICODE;_UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>
<AdditionalDependencies>comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</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;UNICODE;_UNICODE;%(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>
<EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>
<AdditionalDependencies>comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;UNICODE;_UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>
<AdditionalDependencies>comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;UNICODE;_UNICODE;%(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>
<EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>
<AdditionalDependencies>comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="GrabAndMove.rc" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(RepoRoot)src\common\SettingsAPI\SettingsAPI.vcxproj">
<Project>{6955446D-23F7-4023-9BB3-8657F904AF99}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Image Include="GrabAndMove.ico" />
</ItemGroup>
<ItemGroup>
<Manifest Include="GrabAndMove.manifest" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClInclude Include="resource.h" />
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Resource Files">
<UniqueIdentifier>{195243ad-53ca-40c9-8879-b9efef4fc26d}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{9bdf974b-a58f-4af8-aed8-4882381f7172}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{0e19fd51-9939-4511-b8cb-d144c0e2a670}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<Image Include="GrabAndMove.ico">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="GrabAndMove.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
#include "pch.h"

View File

@@ -1,14 +0,0 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#include <commctrl.h>
#include <TraceLoggingProvider.h>
#include <limits>
#include <mutex>
#include <string>
#include <thread>
#include <vector>

View File

@@ -1,21 +0,0 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by GrabAndMove.rc
//
#pragma once
#define IDI_APP_ICON 101
#define IDR_TRAY_MENU 102
#define IDM_EXIT 1001
#define WM_TRAY_ICON (WM_USER + 1)
//////////////////////////////
// Non-localizable
#define FILE_DESCRIPTION "PowerToys GrabAndMove"
#define INTERNAL_NAME "PowerToys.GrabAndMove"
#define ORIGINAL_FILENAME "PowerToys.GrabAndMove.exe"
// Non-localizable
//////////////////////////////

View File

@@ -1,36 +0,0 @@
#include <windows.h>
#include "resource.h"
#include "../../../common/version/version.h"
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

View File

@@ -1,208 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\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>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{2c3f7770-4e57-46b7-8dc1-7428a383d0db}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>GrabAndMoveModuleInterface</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>GrabAndMoveModuleInterface</ProjectName>
<TargetName>PowerToys.GrabAndMoveModuleInterface</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<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>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<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|ARM64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>$(RepoRoot)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;GRABANDMOVEMODULEINTERFACE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<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>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;GRABANDMOVEMODULEINTERFACE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<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 Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;GRABANDMOVEMODULEINTERFACE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<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|ARM64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;GRABANDMOVEMODULEINTERFACE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<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>$(RepoRoot)src\common\inc;$(RepoRoot)src\common\Telemetry;..\..\;$(RepoRoot)src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="trace.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">pch.h</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="trace.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="GrabAndMoveModuleInterface.rc" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(RepoRoot)src\common\logger\logger.vcxproj">
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
</ProjectReference>
<ProjectReference Include="$(RepoRoot)src\common\SettingsAPI\SettingsAPI.vcxproj">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="$(RepoRoot)deps\spdlog.props" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\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('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View File

@@ -1,216 +0,0 @@
#include "pch.h"
#include <interface/powertoy_module_interface.h>
#include "trace.h"
#include <common/logger/logger.h>
#include <common/SettingsAPI/settings_objects.h>
#include <common/SettingsAPI/settings_helpers.h>
#include <common/utils/logger_helper.h>
#include <common/interop/shared_constants.h>
extern "C" IMAGE_DOS_HEADER __ImageBase;
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
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"GrabAndMove";
// Add a description that will be shown in the module settings page.
const static wchar_t* MODULE_DESC = L"Move and resize windows with Alt+Drag (left button to move, right button to resize).";
class GrabAndMoveInterface : public PowertoyModuleIface
{
private:
bool m_enabled = false;
HANDLE m_process{ nullptr };
HANDLE m_reload_settings_event_handle{ nullptr };
HANDLE m_exit_event_handle{ nullptr };
public:
GrabAndMoveInterface()
{
LoggerHelpers::init_logger(L"GrabAndMove", L"ModuleInterface", LogSettings::grabAndMoveLoggerName);
m_reload_settings_event_handle = CreateDefaultEvent(CommonSharedConstants::GRABANDMOVE_REFRESH_SETTINGS_EVENT);
m_exit_event_handle = CreateDefaultEvent(CommonSharedConstants::GRABANDMOVE_EXIT_EVENT);
}
virtual const wchar_t* get_key() override
{
return L"GrabAndMove";
}
virtual void destroy() override
{
disable();
delete this;
}
virtual const wchar_t* get_name() override
{
return MODULE_NAME;
}
virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override
{
return powertoys_gpo::getConfiguredGrabAndMoveEnabledValue();
}
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
{
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
PowerToysSettings::Settings settings(hinstance, get_name());
settings.set_description(MODULE_DESC);
settings.set_overview_link(L"https://aka.ms/powertoys");
return settings.serialize_to_buffer(buffer, buffer_size);
}
virtual void set_config(const wchar_t* config) override
{
try
{
auto values = PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
values.save_to_settings_file();
// Signal the GrabAndMove process to reload settings
if (m_reload_settings_event_handle)
{
SetEvent(m_reload_settings_event_handle);
}
}
catch (const std::exception&)
{
Logger::error("[GrabAndMove] set_config: Failed to parse or apply config.");
}
}
virtual void enable()
{
Logger::info(L"Enabling GrabAndMove module...");
if (m_process && WaitForSingleObject(m_process, 0) == WAIT_TIMEOUT)
{
m_enabled = true;
Trace::Enable(true);
Logger::debug(L"GrabAndMove process already running.");
return;
}
if (m_process)
{
CloseHandle(m_process);
m_process = nullptr;
}
m_enabled = false;
unsigned long powertoys_pid = GetCurrentProcessId();
std::wstring args = std::to_wstring(powertoys_pid);
std::wstring exe_name = L"PowerToys.GrabAndMove.exe";
std::wstring resolved_path(MAX_PATH, L'\0');
DWORD result = SearchPathW(
nullptr,
exe_name.c_str(),
nullptr,
static_cast<DWORD>(resolved_path.size()),
resolved_path.data(),
nullptr);
if (result == 0 || result >= resolved_path.size())
{
Logger::error(
L"Failed to locate GrabAndMove executable named '{}' at location '{}'",
exe_name,
resolved_path.c_str());
return;
}
resolved_path.resize(result);
Logger::debug(L"Resolved executable path: {}", resolved_path);
std::wstring command_line = L"\"" + resolved_path + L"\" " + args;
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
if (!CreateProcessW(
resolved_path.c_str(),
command_line.data(),
nullptr,
nullptr,
TRUE,
0,
nullptr,
nullptr,
&si,
&pi))
{
Logger::error(L"Failed to launch GrabAndMove process. {}", get_last_error_or_default(GetLastError()));
return;
}
Logger::info(L"GrabAndMove process launched successfully (PID: {}).", pi.dwProcessId);
m_process = pi.hProcess;
m_enabled = true;
Trace::Enable(true);
CloseHandle(pi.hThread);
}
virtual void disable()
{
Logger::info("GrabAndMove disabling");
m_enabled = false;
if (m_exit_event_handle)
{
SetEvent(m_exit_event_handle);
}
if (m_process)
{
constexpr DWORD timeout_ms = 1500;
DWORD result = WaitForSingleObject(m_process, timeout_ms);
if (result == WAIT_TIMEOUT)
{
Logger::warn("GrabAndMove: Process didn't exit in time. Forcing termination.");
TerminateProcess(m_process, 0);
}
CloseHandle(m_process);
m_process = nullptr;
}
Trace::Enable(false);
}
virtual bool is_enabled() override
{
return m_enabled;
}
virtual bool is_enabled_by_default() const override
{
return false;
}
};
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
{
return new GrabAndMoveInterface();
}

View File

@@ -1 +0,0 @@
#include "pch.h"

View File

@@ -1,9 +0,0 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <common/SettingsAPI/settings_helpers.h>
#include <common/utils/gpo.h>
#include <common/utils/winapi_error.h>
#include <shlwapi.h>
#include <shellapi.h>

View File

@@ -1,12 +0,0 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
//////////////////////////////
// Non-localizable
#define FILE_DESCRIPTION "GrabAndMove Module"
#define INTERNAL_NAME "GrabAndMove"
#define ORIGINAL_FILENAME "PowerToys.GrabAndMoveModuleInterface.dll"
// Non-localizable
//////////////////////////////

View File

@@ -1,30 +0,0 @@
#include "pch.h"
#include "trace.h"
#include <TraceLoggingProvider.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()
{
TraceLoggingRegister(g_hProvider);
}
void Trace::UnregisterProvider()
{
TraceLoggingUnregister(g_hProvider);
}
void Trace::Enable(bool enabled) noexcept
{
TraceLoggingWrite(
g_hProvider,
"GrabAndMove_EnableGrabAndMove",
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
TraceLoggingBoolean(enabled, "Enabled"));
}

View File

@@ -1,15 +0,0 @@
#pragma once
#include <windows.h>
#include <TraceLoggingActivity.h>
#include <common/telemetry/ProjectTelemetry.h>
TRACELOGGING_DECLARE_PROVIDER(g_hProvider);
class Trace
{
public:
static void RegisterProvider();
static void UnregisterProvider();
static void Enable(bool enabled) noexcept;
};

View File

@@ -3,101 +3,16 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PowerOCR"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
Exit="Application_Exit"
ShutdownMode="OnExplicitShutdown"
Startup="Application_Startup"
ThemeMode="System">
Startup="Application_Startup">
<Application.Resources>
<ResourceDictionary>
<FontFamily x:Key="SymbolThemeFontFamily">Segoe Fluent Icons, Segoe MDL2 Assets</FontFamily>
<Style
x:Key="SubtleButtonStyle"
BasedOn="{StaticResource {x:Type Button}}"
TargetType="Button">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border
x:Name="Border"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="4"
SnapsToDevicePixels="True">
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Focusable="False"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource SubtleFillColorSecondaryBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{DynamicResource SubtleFillColorSecondaryBrush}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource SubtleFillColorTertiaryBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{DynamicResource SubtleFillColorTertiaryBrush}" />
<Setter Property="Foreground" Value="{DynamicResource TextFillColorSecondaryBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource TextFillColorDisabledBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="SubtleToggleButtonStyle"
BasedOn="{StaticResource {x:Type ToggleButton}}"
TargetType="ToggleButton">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border
x:Name="Border"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="4"
SnapsToDevicePixels="True">
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Focusable="False"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource SubtleFillColorSecondaryBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{DynamicResource SubtleFillColorSecondaryBrush}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource SubtleFillColorTertiaryBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{DynamicResource SubtleFillColorTertiaryBrush}" />
<Setter Property="Foreground" Value="{DynamicResource TextFillColorSecondaryBrush}" />
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource AccentFillColorDefaultBrush}" />
<Setter Property="Foreground" Value="{DynamicResource TextOnAccentFillColorPrimaryBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource TextFillColorDisabledBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ResourceDictionary.MergedDictionaries>
<ui:ThemesDictionary Theme="Dark" />
<ui:ControlsDictionary />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@@ -1,12 +1,14 @@
<Window
<Window
x:Class="PowerOCR.OCROverlay"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:p="clr-namespace:PowerOCR.Properties"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
x:Name="TextExtractorWindow"
Title="TextExtractor"
ui:Design.Background="Transparent"
AllowsTransparency="True"
Background="Transparent"
Loaded="Window_Loaded"
@@ -20,6 +22,26 @@
WindowStyle="None"
mc:Ignorable="d">
<Window.Resources>
<Style BasedOn="{StaticResource DefaultToggleButtonStyle}" TargetType="{x:Type ToggleButton}">
<Setter Property="Margin" Value="4,0" />
<Setter Property="Padding" Value="0" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" />
<Setter Property="Background" Value="Transparent" />
</Style>
<Style BasedOn="{StaticResource DefaultButtonStyle}" TargetType="{x:Type Button}">
<Setter Property="Margin" Value="4,0" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Padding" Value="0" />
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" />
<Setter Property="Background" Value="Transparent" />
</Style>
</Window.Resources>
<Grid>
<Viewbox>
<Image x:Name="BackgroundImage" Stretch="UniformToFill" />
@@ -79,11 +101,17 @@
HorizontalAlignment="Center"
VerticalAlignment="Top"
d:Visibility="Visible"
Background="{DynamicResource SolidBackgroundFillColorBaseBrush}"
BorderBrush="{DynamicResource SurfaceStrokeColorDefaultBrush}"
BorderThickness="1"
Background="{DynamicResource ApplicationBackgroundBrush}"
CornerRadius="8"
Visibility="Collapsed">
<Border.Effect>
<DropShadowEffect
BlurRadius="32"
Opacity="0.28"
RenderingBias="Performance"
ShadowDepth="1" />
</Border.Effect>
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Top"
@@ -105,67 +133,35 @@
</ComboBox>
<ToggleButton
x:Name="SingleLineToggleButton"
Width="32"
Height="32"
Margin="4,0"
Padding="0"
d:IsChecked="True"
AutomationProperties.Name="{x:Static p:Resources.ResultTextSingleLine}"
Click="SingleLineMenuItem_Click"
IsChecked="{Binding IsChecked, ElementName=SingleLineMenuItem, Mode=TwoWay}"
Style="{DynamicResource SubtleToggleButtonStyle}"
ToolTip="{x:Static p:Resources.ResultTextSingleLineShortcut}">
<TextBlock
FontFamily="{DynamicResource SymbolThemeFontFamily}"
FontSize="16"
Text="&#xF16E;" />
<ui:SymbolIcon FontSize="18" Symbol="SubtractSquare24" />
</ToggleButton>
<ToggleButton
x:Name="TableToggleButton"
Width="32"
Height="32"
Margin="4,0"
Padding="0"
d:IsChecked="True"
AutomationProperties.Name="{x:Static p:Resources.ResultTextTable}"
Click="TableToggleButton_Click"
IsChecked="{Binding IsChecked, ElementName=TableMenuItem, Mode=TwoWay}"
Style="{DynamicResource SubtleToggleButtonStyle}"
ToolTip="{x:Static p:Resources.ResultTextTableShortcut}">
<TextBlock
FontFamily="{DynamicResource SymbolThemeFontFamily}"
FontSize="16"
Text="&#xE80A;" />
<ui:SymbolIcon FontSize="18" Symbol="Table24" />
</ToggleButton>
<Button
x:Name="SettingsButton"
Width="32"
Height="32"
Margin="4,0"
Padding="0"
AutomationProperties.Name="{x:Static p:Resources.Settings}"
Click="SettingsMenuItem_Click"
Style="{DynamicResource SubtleButtonStyle}"
ToolTip="{x:Static p:Resources.Settings}">
<TextBlock
FontFamily="{DynamicResource SymbolThemeFontFamily}"
FontSize="16"
Text="&#xE713;" />
<ui:SymbolIcon FontSize="18" Symbol="Settings24" />
</Button>
<Button
x:Name="CancelButton"
Width="32"
Height="32"
Margin="4,0"
Padding="0"
AutomationProperties.Name="{x:Static p:Resources.Cancel}"
Click="CancelMenuItem_Click"
Style="{DynamicResource SubtleButtonStyle}"
ToolTip="{x:Static p:Resources.CancelShortcut}">
<TextBlock
FontFamily="{DynamicResource SymbolThemeFontFamily}"
FontSize="16"
Text="&#xE711;" />
<ui:SymbolIcon FontSize="18" Symbol="Dismiss24" />
</Button>
</StackPanel>
</Border>

View File

@@ -64,6 +64,8 @@ public partial class OCROverlay : Window
InitializeComponent();
Wpf.Ui.Appearance.SystemThemeWatcher.Watch(this, Wpf.Ui.Controls.WindowBackdropType.None);
PopulateLanguageMenu();
}

View File

@@ -31,6 +31,7 @@
<ItemGroup>
<PackageReference Include="System.ComponentModel.Composition" />
<PackageReference Include="System.Drawing.Common" />
<PackageReference Include="WPF-UI" />
</ItemGroup>
<ItemGroup>

View File

@@ -252,13 +252,11 @@ void AlwaysOnTop::ProcessCommand(HWND window)
}
Sound::Type soundType = Sound::Type::Off;
bool stateChanged = false;
bool topmost = IsTopmost(window);
if (topmost)
{
if (UnpinTopmostWindow(window))
{
stateChanged = true;
auto iter = m_topmostWindows.find(window);
if (iter != m_topmostWindows.end())
{
@@ -276,7 +274,6 @@ void AlwaysOnTop::ProcessCommand(HWND window)
{
if (PinTopmostWindow(window))
{
stateChanged = true;
soundType = Sound::Type::On;
AssignBorder(window);
@@ -284,7 +281,7 @@ void AlwaysOnTop::ProcessCommand(HWND window)
}
}
if (stateChanged && AlwaysOnTopSettings::settings()->enableSound)
if (AlwaysOnTopSettings::settings()->enableSound)
{
m_sound.Play(soundType);
}

View File

@@ -19,7 +19,6 @@ using Awake.Core;
using Awake.Core.Models;
using Awake.Core.Native;
using Awake.Properties;
using Awake.Telemetry;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Telemetry;
@@ -69,7 +68,6 @@ namespace Awake
if (parseResult.Errors.Count > 0)
{
// Shows errors and returns non-zero.
LogCLITelemetry(successful: false);
return rootCommand.Invoke(args);
}
@@ -98,7 +96,6 @@ namespace Awake
{
// Awake is already running - there is no need for us to process
// anything further
LogCLITelemetry(successful: false);
Exit(Core.Constants.AppName + " is already running! Exiting the application.", 1);
return 1;
}
@@ -106,7 +103,6 @@ namespace Awake
{
if (PowerToys.GPOWrapper.GPOWrapper.GetConfiguredAwakeEnabledValue() == PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
{
LogCLITelemetry(successful: false);
Exit("PowerToys.Awake tried to start with a group policy setting that disables the tool. Please contact your system administrator.", 1);
return 1;
}
@@ -129,9 +125,7 @@ namespace Awake
Bridge.GetPwrCapabilities(out _powerCapabilities);
Logger.LogInfo(JsonSerializer.Serialize(_powerCapabilities, _serializerOptions));
var result = await rootCommand.InvokeAsync(args);
LogCLITelemetry(successful: result == 0);
return result;
return await rootCommand.InvokeAsync(args);
}
}
}
@@ -222,22 +216,6 @@ namespace Awake
return rootCommand;
}
private static void LogCLITelemetry(bool successful)
{
try
{
PowerToysTelemetry.Log.WriteEvent(new AwakeCLICommandEvent
{
CommandName = "awake",
Successful = successful,
});
}
catch (Exception ex)
{
Logger.LogError($"Failed to log CLI telemetry: {ex.Message}");
}
}
private static void AwakeUnhandledExceptionCatcher(object sender, UnhandledExceptionEventArgs e)
{
if (e.ExceptionObject is Exception exception)

View File

@@ -1,37 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Awake.Telemetry
{
/// <summary>
/// Telemetry event for Awake CLI command execution.
/// </summary>
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class AwakeCLICommandEvent : EventBase, IEvent
{
public AwakeCLICommandEvent()
{
EventName = "Awake_CLICommand";
CommandName = string.Empty;
}
/// <summary>
/// Gets or sets the name of the CLI command that was executed.
/// </summary>
public string CommandName { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the command executed successfully.
/// </summary>
public bool Successful { get; set; }
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}
}

View File

@@ -1,57 +0,0 @@
{
"solution": {
"path": "..\\..\\..\\PowerToys.slnx",
"projects": [
"src\\common\\CalculatorEngineCommon\\CalculatorEngineCommon.vcxproj",
"src\\common\\Common.UI.Controls\\Common.UI.Controls.csproj",
"src\\common\\ManagedCommon\\ManagedCommon.csproj",
"src\\common\\ManagedCsWin32\\ManagedCsWin32.csproj",
"src\\common\\ManagedTelemetry\\Telemetry\\ManagedTelemetry.csproj",
"src\\common\\interop\\PowerToys.Interop.vcxproj",
"src\\common\\version\\version.vcxproj",
"src\\modules\\cmdpal\\CmdPalKeyboardService\\CmdPalKeyboardService.vcxproj",
"src\\modules\\cmdpal\\CmdPalModuleInterface\\CmdPalModuleInterface.vcxproj",
"src\\modules\\cmdpal\\Microsoft.CmdPal.Common\\Microsoft.CmdPal.Common.csproj",
"src\\modules\\cmdpal\\Microsoft.CmdPal.UI.ViewModels\\Microsoft.CmdPal.UI.ViewModels.csproj",
"src\\modules\\cmdpal\\Microsoft.CmdPal.UI\\Microsoft.CmdPal.UI.csproj",
"src\\modules\\cmdpal\\Microsoft.Terminal.UI\\Microsoft.Terminal.UI.vcxproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Common.UnitTests\\Microsoft.CmdPal.Common.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.Apps.UnitTests\\Microsoft.CmdPal.Ext.Apps.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.Bookmarks.UnitTests\\Microsoft.CmdPal.Ext.Bookmarks.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.Calc.UnitTests\\Microsoft.CmdPal.Ext.Calc.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.ClipboardHistory.UnitTests\\Microsoft.CmdPal.Ext.ClipboardHistory.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.Registry.UnitTests\\Microsoft.CmdPal.Ext.Registry.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.RemoteDesktop.UnitTests\\Microsoft.CmdPal.Ext.RemoteDesktop.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.Shell.UnitTests\\Microsoft.CmdPal.Ext.Shell.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.System.UnitTests\\Microsoft.CmdPal.Ext.System.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.TimeDate.UnitTests\\Microsoft.CmdPal.Ext.TimeDate.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.UnitTestsBase\\Microsoft.CmdPal.Ext.UnitTestBase.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.WebSearch.UnitTests\\Microsoft.CmdPal.Ext.WebSearch.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.Ext.WindowWalker.UnitTests\\Microsoft.CmdPal.Ext.WindowWalker.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.UI.ViewModels.UnitTests\\Microsoft.CmdPal.UI.ViewModels.UnitTests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CmdPal.UITests\\Microsoft.CmdPal.UITests.csproj",
"src\\modules\\cmdpal\\Tests\\Microsoft.CommandPalette.Extensions.Toolkit.UnitTests\\Microsoft.CommandPalette.Extensions.Toolkit.UnitTests.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.Apps\\Microsoft.CmdPal.Ext.Apps.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.Bookmark\\Microsoft.CmdPal.Ext.Bookmarks.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.Calc\\Microsoft.CmdPal.Ext.Calc.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.ClipboardHistory\\Microsoft.CmdPal.Ext.ClipboardHistory.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.Indexer\\Microsoft.CmdPal.Ext.Indexer.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.PerformanceMonitor\\Microsoft.CmdPal.Ext.PerformanceMonitor.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.Registry\\Microsoft.CmdPal.Ext.Registry.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.RemoteDesktop\\Microsoft.CmdPal.Ext.RemoteDesktop.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.Shell\\Microsoft.CmdPal.Ext.Shell.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.System\\Microsoft.CmdPal.Ext.System.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.TimeDate\\Microsoft.CmdPal.Ext.TimeDate.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.WebSearch\\Microsoft.CmdPal.Ext.WebSearch.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.WinGet\\Microsoft.CmdPal.Ext.WinGet.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.WindowWalker\\Microsoft.CmdPal.Ext.WindowWalker.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.WindowsServices\\Microsoft.CmdPal.Ext.WindowsServices.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.WindowsSettings\\Microsoft.CmdPal.Ext.WindowsSettings.csproj",
"src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.WindowsTerminal\\Microsoft.CmdPal.Ext.WindowsTerminal.csproj",
"src\\modules\\cmdpal\\ext\\ProcessMonitorExtension\\ProcessMonitorExtension.csproj",
"src\\modules\\cmdpal\\ext\\SamplePagesExtension\\SamplePagesExtension.csproj",
"src\\modules\\cmdpal\\extensionsdk\\Microsoft.CommandPalette.Extensions.Toolkit\\Microsoft.CommandPalette.Extensions.Toolkit.csproj",
"src\\modules\\cmdpal\\extensionsdk\\Microsoft.CommandPalette.Extensions\\Microsoft.CommandPalette.Extensions.vcxproj"
]
}
}

View File

@@ -7,14 +7,8 @@
"src\\common\\ManagedCommon\\ManagedCommon.csproj",
"src\\common\\ManagedCsWin32\\ManagedCsWin32.csproj",
"src\\common\\ManagedTelemetry\\Telemetry\\ManagedTelemetry.csproj",
"src\\common\\SettingsAPI\\SettingsAPI.vcxproj",
"src\\common\\UITestAutomation\\UITestAutomation.csproj",
"src\\common\\interop\\PowerToys.Interop.vcxproj",
"src\\common\\logger\\logger.vcxproj",
"src\\common\\version\\version.vcxproj",
"src\\logging\\logging.vcxproj",
"src\\modules\\MouseUtils\\MouseJump.Common\\MouseJump.Common.csproj",
"src\\modules\\ZoomIt\\ZoomItSettingsInterop\\ZoomItSettingsInterop.vcxproj",
"src\\modules\\cmdpal\\CmdPalKeyboardService\\CmdPalKeyboardService.vcxproj",
"src\\modules\\cmdpal\\CmdPalModuleInterface\\CmdPalModuleInterface.vcxproj",
"src\\modules\\cmdpal\\Microsoft.CmdPal.Common\\Microsoft.CmdPal.Common.csproj",
@@ -57,9 +51,7 @@
"src\\modules\\cmdpal\\ext\\ProcessMonitorExtension\\ProcessMonitorExtension.csproj",
"src\\modules\\cmdpal\\ext\\SamplePagesExtension\\SamplePagesExtension.csproj",
"src\\modules\\cmdpal\\extensionsdk\\Microsoft.CommandPalette.Extensions.Toolkit\\Microsoft.CommandPalette.Extensions.Toolkit.csproj",
"src\\modules\\cmdpal\\extensionsdk\\Microsoft.CommandPalette.Extensions\\Microsoft.CommandPalette.Extensions.vcxproj",
"src\\modules\\powerdisplay\\PowerDisplay.Models\\PowerDisplay.Models.csproj",
"src\\settings-ui\\Settings.UI.Library\\Settings.UI.Library.csproj"
"src\\modules\\cmdpal\\extensionsdk\\Microsoft.CommandPalette.Extensions\\Microsoft.CommandPalette.Extensions.vcxproj"
]
}
}

View File

@@ -2,7 +2,6 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Globalization;
using Microsoft.CmdPal.Ext.Calc.Helper;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -11,25 +10,6 @@ namespace Microsoft.CmdPal.Ext.Calc.UnitTests;
[TestClass]
public class QueryHelperTests
{
private CultureInfo originalCulture;
private CultureInfo originalUiCulture;
[TestInitialize]
public void Setup()
{
originalCulture = CultureInfo.CurrentCulture;
CultureInfo.CurrentCulture = new CultureInfo("en-us", false);
originalUiCulture = CultureInfo.CurrentUICulture;
CultureInfo.CurrentUICulture = new CultureInfo("en-us", false);
}
[TestCleanup]
public void CleanUp()
{
CultureInfo.CurrentCulture = originalCulture;
CultureInfo.CurrentUICulture = originalUiCulture;
}
[DataTestMethod]
[DataRow("2²", "4")]
[DataRow("2³", "8")]

View File

@@ -2,7 +2,6 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Globalization;
using System.Linq;
using Microsoft.CmdPal.Ext.Calc.Helper;
using Microsoft.CmdPal.Ext.Calc.Pages;
@@ -15,25 +14,6 @@ namespace Microsoft.CmdPal.Ext.Calc.UnitTests;
[TestClass]
public class QueryTests : CommandPaletteUnitTestBase
{
private CultureInfo originalCulture;
private CultureInfo originalUiCulture;
[TestInitialize]
public void Setup()
{
originalCulture = CultureInfo.CurrentCulture;
CultureInfo.CurrentCulture = new CultureInfo("en-us", false);
originalUiCulture = CultureInfo.CurrentUICulture;
CultureInfo.CurrentUICulture = new CultureInfo("en-us", false);
}
[TestCleanup]
public void CleanUp()
{
CultureInfo.CurrentCulture = originalCulture;
CultureInfo.CurrentUICulture = originalUiCulture;
}
[DataTestMethod]
[DataRow("2+2", "4")]
[DataRow("5*3", "15")]
@@ -104,40 +84,6 @@ public class QueryTests : CommandPaletteUnitTestBase
Assert.IsTrue(result.Title.Contains(expected, System.StringComparison.Ordinal), $"Calc trigMode convert result isn't correct. Current result: {result.Title}");
}
[DataTestMethod]
[DataRow("sin(60)", "-0.30481", CalculateEngine.TrigMode.Radians, "de-DE")]
[DataRow("sin(60)", "0.866025", CalculateEngine.TrigMode.Degrees, "de-DE")]
[DataRow("sin(60)", "0.809016", CalculateEngine.TrigMode.Gradians, "de-DE")]
[DataRow("sin(60)", "-0.30481", CalculateEngine.TrigMode.Radians, "fr-FR")]
[DataRow("sin(60)", "0.866025", CalculateEngine.TrigMode.Degrees, "fr-FR")]
[DataRow("sin(60)", "0.809016", CalculateEngine.TrigMode.Gradians, "fr-FR")]
public void TrigModeSettingsTest_NonEnglishCulture(string input, string expected, CalculateEngine.TrigMode trigMode, string cultureName)
{
var previousCulture = CultureInfo.CurrentCulture;
var previousUiCulture = CultureInfo.CurrentUICulture;
try
{
CultureInfo.CurrentCulture = new CultureInfo(cultureName, false);
CultureInfo.CurrentUICulture = new CultureInfo(cultureName, false);
var settings = new Settings(trigUnit: trigMode, outputUseEnglishFormat: true);
var page = new CalculatorListPage(settings);
page.UpdateSearchText(string.Empty, input);
var result = page.GetItems().FirstOrDefault();
Assert.IsNotNull(result);
Assert.IsTrue(result.Title.Contains(expected, System.StringComparison.Ordinal), $"Calc trigMode convert result isn't correct for culture '{cultureName}'. Current result: {result.Title}");
}
finally
{
CultureInfo.CurrentCulture = previousCulture;
CultureInfo.CurrentUICulture = previousUiCulture;
}
}
[DataTestMethod]
[DataRow("2^64", "18446744073709551616", "0x10000000000000000")]
[DataRow("0-(2^64)", "-18446744073709551616", "-0x10000000000000000")]

View File

Before

Width:  |  Height:  |  Size: 497 KiB

After

Width:  |  Height:  |  Size: 497 KiB

View File

Before

Width:  |  Height:  |  Size: 276 KiB

After

Width:  |  Height:  |  Size: 276 KiB

View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View File

Before

Width:  |  Height:  |  Size: 269 KiB

After

Width:  |  Height:  |  Size: 269 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

Before

Width:  |  Height:  |  Size: 228 KiB

After

Width:  |  Height:  |  Size: 228 KiB

View File

Before

Width:  |  Height:  |  Size: 491 KiB

After

Width:  |  Height:  |  Size: 491 KiB

View File

Before

Width:  |  Height:  |  Size: 706 KiB

After

Width:  |  Height:  |  Size: 706 KiB

View File

Before

Width:  |  Height:  |  Size: 408 KiB

After

Width:  |  Height:  |  Size: 408 KiB

View File

Before

Width:  |  Height:  |  Size: 384 KiB

After

Width:  |  Height:  |  Size: 384 KiB

View File

Before

Width:  |  Height:  |  Size: 493 KiB

After

Width:  |  Height:  |  Size: 493 KiB

View File

Before

Width:  |  Height:  |  Size: 492 KiB

After

Width:  |  Height:  |  Size: 492 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 106 KiB

View File

Before

Width:  |  Height:  |  Size: 311 KiB

After

Width:  |  Height:  |  Size: 311 KiB

View File

Before

Width:  |  Height:  |  Size: 297 KiB

After

Width:  |  Height:  |  Size: 297 KiB

View File

Before

Width:  |  Height:  |  Size: 284 KiB

After

Width:  |  Height:  |  Size: 284 KiB

View File

Before

Width:  |  Height:  |  Size: 225 KiB

After

Width:  |  Height:  |  Size: 225 KiB

View File

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 111 KiB

View File

Before

Width:  |  Height:  |  Size: 890 KiB

After

Width:  |  Height:  |  Size: 890 KiB

View File

Before

Width:  |  Height:  |  Size: 858 KiB

After

Width:  |  Height:  |  Size: 858 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

View File

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 84 KiB

View File

@@ -108,6 +108,7 @@ internal static class ResultHelper
tags.Add(new Tag
{
Text = Resources.windowwalker_NotResponding,
Foreground = ColorHelpers.FromRgb(220, 20, 60),
});
}

View File

@@ -418,6 +418,16 @@ namespace ColorPicker.UnitTests.Helpers
Assert.AreEqual(expected, result);
}
[TestMethod]
public void GetStringRepresentation_VEC4_NonTrivialColor_HasSufficientPrecision()
{
// Color (237, 41, 57) should produce float values that round-trip back to the original byte values.
// With only 2 decimal places, 57/255 = 0.22 and 0.22*255 = 56.1, which is wrong.
// With 4 decimal places, 57/255 = 0.2235 and 0.2235*255 = 56.9925, which rounds to 57 correctly.
var result = ColorRepresentationHelper.GetStringRepresentation(Color.FromArgb(255, 237, 41, 57), "VEC4", ColorFormatHelper.GetDefaultFormat("VEC4"));
Assert.AreEqual("(0.9294f, 0.1608f, 0.2235f, 1f)", result);
}
[TestMethod]
public void GetStringRepresentation_EmptyFormat_ReturnsHex()
{

View File

@@ -107,8 +107,8 @@ namespace ColorPicker.Helpers
private static string ColorToFloat(Color color)
{
var (red, green, blue) = ColorHelper.ConvertToDouble(color);
const int precision = 2;
const string floatFormat = "0.##";
const int precision = 4;
const string floatFormat = "0.####";
return $"({Math.Round(red, precision).ToString(floatFormat, CultureInfo.InvariantCulture)}f"
+ $", {Math.Round(green, precision).ToString(floatFormat, CultureInfo.InvariantCulture)}f"

View File

@@ -7,9 +7,7 @@ using System.Globalization;
using System.Text;
using ImageResizer.Cli;
using ImageResizer.Cli.Telemetry;
using ManagedCommon;
using Microsoft.PowerToys.Telemetry;
namespace ImageResizerCLI;
@@ -39,33 +37,14 @@ internal static class Program
try
{
var executor = new ImageResizerCliExecutor();
int result = executor.Run(args);
LogCLITelemetry(executor.CommandName, result == 0);
return result;
return executor.Run(args);
}
catch (Exception ex)
{
CliLogger.Error($"Unhandled exception: {ex.Message}");
CliLogger.Error($"Stack trace: {ex.StackTrace}");
Console.Error.WriteLine($"Fatal error: {ex.Message}");
LogCLITelemetry("resize", successful: false);
return 1;
}
}
private static void LogCLITelemetry(string commandName, bool successful)
{
try
{
PowerToysTelemetry.Log.WriteEvent(new ImageResizerCLICommandEvent
{
CommandName = commandName,
Successful = successful,
});
}
catch (Exception ex)
{
CliLogger.Error($"Failed to log CLI telemetry: {ex.Message}");
}
}
}

View File

@@ -19,11 +19,6 @@ namespace ImageResizer.Cli
/// </summary>
public class ImageResizerCliExecutor
{
/// <summary>
/// Gets the name of the last CLI operation that was executed.
/// </summary>
public string CommandName { get; private set; } = "resize";
/// <summary>
/// Runs the CLI executor with the provided command-line arguments.
/// </summary>
@@ -42,21 +37,18 @@ namespace ImageResizer.Cli
}
CliOptions.PrintUsage();
CommandName = "error";
return 1;
}
if (cliOptions.ShowHelp)
{
CliOptions.PrintUsage();
CommandName = "help";
return 0;
}
if (cliOptions.ShowConfig)
{
CliOptions.PrintConfig(Settings.Default);
CommandName = "show-config";
return 0;
}
@@ -64,7 +56,6 @@ namespace ImageResizer.Cli
{
Console.WriteLine(Resources.CLI_NoInputFiles);
CliOptions.PrintUsage();
CommandName = "error";
return 1;
}

View File

@@ -1,37 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace ImageResizer.Cli.Telemetry
{
/// <summary>
/// Telemetry event for Image Resizer CLI command execution.
/// </summary>
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class ImageResizerCLICommandEvent : EventBase, IEvent
{
public ImageResizerCLICommandEvent()
{
EventName = "ImageResizer_CLICommand";
CommandName = string.Empty;
}
/// <summary>
/// Gets or sets the name of the CLI command that was executed.
/// </summary>
public string CommandName { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the command executed successfully.
/// </summary>
public bool Successful { get; set; }
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}
}

View File

@@ -18,7 +18,7 @@ namespace ImageResizer.Models
_scaleFormat ??= CompositeFormat.Parse(ResourceLoaderInstance.GetString("Input_AiScaleFormat"));
[ObservableProperty]
[property: JsonPropertyName("scale")]
[JsonPropertyName("scale")]
private int _scale = 2;
/// <summary>

View File

@@ -26,26 +26,26 @@ namespace ImageResizer.Models
};
[ObservableProperty]
[property: JsonPropertyName("Id")]
[JsonPropertyName("Id")]
private int _id;
private string _name;
[ObservableProperty]
[property: JsonPropertyName("fit")]
[JsonPropertyName("fit")]
[NotifyPropertyChangedFor(nameof(ShowHeight))]
private ResizeFit _fit = ResizeFit.Fit;
[ObservableProperty]
[property: JsonPropertyName("width")]
[JsonPropertyName("width")]
private double _width;
[ObservableProperty]
[property: JsonPropertyName("height")]
[JsonPropertyName("height")]
private double _height;
[ObservableProperty]
[property: JsonPropertyName("unit")]
[JsonPropertyName("unit")]
[NotifyPropertyChangedFor(nameof(ShowHeight))]
private ResizeUnit _unit = ResizeUnit.Pixel;

View File

@@ -5,7 +5,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using ManagedCommon;
@@ -471,19 +470,10 @@ namespace PowerDisplay.Common.Drivers.DDC
{
InitializeContrast(monitor, candidate.Handle);
}
// Initialize volume if supported
if (monitor.SupportsVolume)
{
InitializeVolume(monitor, candidate.Handle);
}
}
// Initialize brightness if supported
if (monitor.SupportsBrightness)
{
InitializeBrightness(monitor, candidate.Handle);
}
// Initialize brightness (always supported for DDC/CI monitors)
InitializeBrightness(monitor, candidate.Handle);
monitors.Add(monitor);
newHandleMap[monitor.Id] = candidate.Handle;
@@ -550,18 +540,6 @@ namespace PowerDisplay.Common.Drivers.DDC
}
}
/// <summary>
/// Initialize volume value for a monitor using VCP 0x62.
/// </summary>
private static void InitializeVolume(Monitor monitor, IntPtr handle)
{
if (TryGetVcpFeature(handle, VcpCodeVolume, monitor.Id, out uint current, out uint max))
{
var volumeInfo = new VcpFeatureValue((int)current, 0, (int)max);
monitor.CurrentVolume = volumeInfo.ToPercentage();
}
}
/// <summary>
/// Wrapper for GetVCPFeatureAndVCPFeatureReply that logs errors on failure.
/// </summary>
@@ -578,7 +556,7 @@ namespace PowerDisplay.Common.Drivers.DDC
return true;
}
var lastError = Marshal.GetLastWin32Error();
var lastError = GetLastError();
var monitorPrefix = string.IsNullOrEmpty(monitorId) ? string.Empty : $"[{monitorId}] ";
Logger.LogError($"{monitorPrefix}Failed to read VCP 0x{vcpCode:X2}, error code: {lastError}");
return false;
@@ -589,12 +567,6 @@ namespace PowerDisplay.Common.Drivers.DDC
/// </summary>
private static void UpdateMonitorCapabilitiesFromVcp(Monitor monitor, VcpCapabilities vcpCaps)
{
// Check for Brightness support (VCP 0x10)
if (vcpCaps.SupportsVcpCode(VcpCodeBrightness))
{
monitor.Capabilities |= MonitorCapabilities.Brightness;
}
// Check for Contrast support (VCP 0x12)
if (vcpCaps.SupportsVcpCode(VcpCodeContrast))
{
@@ -724,8 +696,8 @@ namespace PowerDisplay.Common.Drivers.DDC
return MonitorOperationResult.Success();
}
var lastError = Marshal.GetLastWin32Error();
return MonitorOperationResult.Failure($"Failed to set VCP 0x{vcpCode:X2}", lastError);
var lastError = GetLastError();
return MonitorOperationResult.Failure($"Failed to set VCP 0x{vcpCode:X2}", (int)lastError);
}
catch (Exception ex)
{

Some files were not shown because too many files have changed in this diff Show More