Skip to content

Conversation

@zateutsch
Copy link

@zateutsch zateutsch commented Dec 16, 2025

Validation Steps

Running the Project

Option 1: Test via runner

  1. Check out branch zt/new-kbm-localization
  2. Build PowerToys project
  3. Manually build Modules/KeyboardManagerEditorUI project separately
  4. Run runner project
  5. Ensure experimental features are enabled in general settings (should be on by default)
  6. Launch keyboard manager via settings app

Option 2: Test via installer
Pending installer build is successful on this PR,

  1. Install PowerToys via installer
  2. Launch keyboard manager

Validation

For each page (Text, Remappings, Programs, URLs):

  • Create shortcuts with variable options and ensure they run as expected
  • Delete shortcuts and ensure they no longer execute
  • Try to create invalid shorcuts to check for proper validation
  • Ensure created shortcuts appear in Power Toys Settings Keyboard manager page
  • Any feedback on UI design appreciated as well

haoliuu and others added 30 commits February 27, 2025 15:42
* Implement a dev version ui which is copy of current WinUI2 UX

* Implement WinUI3 dropdown and P/Invoke the key list from existing C++ Library

* Update Dllimport path
* Set up static new UX for Keyboard Manager Editor

* Improve the formatting and performance

* fix spelling
)

* Load remapping config and data

* display single key to shortcuts mapping properly

* get remapping with operation type so we can display them in different tabs

* clean up the xaml
* load URL remapping

* Save Remapping Config and Data

* update mock data for testing

* fix app mapping

* update xaml
* add press button

* add right press button

* add right press button by original button

* change toggle button position

* fix type error

* merge

* add link

* brush blue in new keys

* remove unuse annotations

* remove unuse keyvisual
* Make Disable toggle button functional in Shortcuts page

* Clean up main window and aggregate Constants

* Update key remapping naming

* Fix the key visual stretch out issue when the shortcut contains too many keys

* Refactor code structure

* fix wrapping in dialog

* update naming

* Implement Keyboard hook to get the user input of remappings

* Implement Reset for InputControl to make sure InputControl can have correct status for various dialog
…oard Hook and Input Validator (#39081)

* Add delete remapping function

* Fix the problem that Keyboard Hook is not cleaned properly when the toggle button lost focus (user clicked other checkbox or switched to another app)

* Make sure original toggle button is checked for InputControl

* Disable app setting for single key remapping

* Update KBM Editor UI Signing

* Ensuring Modifier Keys Don't Repeat

* Make sure the shortcut takes at most 4 modifier keys and show notification to the user

* Show teaching tip for reserved illegal shortcuts - Win+L and Ctrl+Alt+Delete

* Add validation to check if the user is trying to remap a key or shortcut that's already mapped for the same app context

* Add validation to make sure key/shortcut cannot be mapped to itself

* Add validation to check the original/new keys are not empty. Application name must be entered if the specific app checkbox is checked.

* Add validation to check shortcuts must contain at least one action key in addition to modifier keys

* Add validation to warn orphaned key to user

* Unify and consolidate the validation code

* Refactor the validation mechanism

* Delete the existing remapping when user modified the content
…e-behind functionalities (#39888)

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

> [Target feature branch ``feature/KeyboardManagerWinUI3``]

Refactor the New Keyboard Manager code to generalize functions (like
Keyboard Hook) for use across pages. Implement Code-behind and the Text
Remapping Page.

- Implement the Text Remapping page
- Restructure the Key Remappings code
- Implement unified Keyboard Hook for all Pages
- Implement Save and Delete for Text Page
- Adjust the Text Page list UI
- Create Input Control for Text Page
- Validate the user input in Text Page and show teaching tip for the
validation error
- Move Remapping Saving into Helper
- Move Remapping Delete into Helper
- Don't check for duplicates if the original keys are the same as the
remapping being edited
- Use InputMode to indicate the active toggle for Original Keys/Remapped
Keys
- Add Rectangle for all pages


![image](https://github.com/user-attachments/assets/e109d82f-01c5-4da7-9efb-facea4070808)

![image](https://github.com/user-attachments/assets/09cc4462-43eb-4823-9b01-ab630a0bf9ed)

![image](https://github.com/user-attachments/assets/9b85c0f6-cbce-40cc-8e65-b755cb852eae)

![image](https://github.com/user-attachments/assets/ff7945cc-6535-4697-812e-93c2effab14e)

![image](https://github.com/user-attachments/assets/7cf887c8-24f3-45bd-956f-b3d655844974)

![image](https://github.com/user-attachments/assets/d958bb16-66b9-44e0-8918-32ddcc780f02)
@zateutsch zateutsch added the Product-Keyboard Shortcut Manager Issues regarding Keyboard Shortcut Manager label Dec 16, 2025
return ValidationErrorType.NoError;
}

// Temporary program shorctut validation

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error

shorctut is not a recognized word. (unrecognized-spelling)
return KeyboardManagerInterop.AddShortcutRemap(_configHandle, originalKeys, targetKeys, targetApp, (int)operationType);
}

public bool AddShorcutMapping(ShortcutKeyMapping shortcutKeyMapping)

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error

Shorcut is not a recognized word. (unrecognized-spelling)
try
{
_mappingService = new KeyboardMappingService();
LoadProgramShrotcuts();

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error

Shrotcuts is not a recognized word. (unrecognized-spelling)
Dispose();
}

private void LoadProgramShrotcuts()

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error

Shrotcuts is not a recognized word. (unrecognized-spelling)
Elevation = elevationLevel,
};

saved = _mappingService.AddShorcutMapping(shortcutKeyMapping);

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error

Shorcut is not a recognized word. (unrecognized-spelling)
<data name="RemappingsPageOriginalKeysTextBlock.Text" xml:space="preserve">
<value>Original key(s)</value>
</data>
<data name="RemmapingsPageOrphanedKeysTeachingTip.ActionButtonContent" xml:space="preserve">

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error

Remmapings is not a recognized word. (unrecognized-spelling)
<data name="RemmapingsPageOrphanedKeysTeachingTip.ActionButtonContent" xml:space="preserve">
<value>Continue anyway</value>
</data>
<data name="RemmapingsPageOrphanedKeysTeachingTip.CloseButtonContent" xml:space="preserve">

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error

Remmapings is not a recognized word. (unrecognized-spelling)
<data name="RemmapingsPageOrphanedKeysTeachingTip.CloseButtonContent" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="RemmapingsPageOrphanedKeysTeachingTip.Title" xml:space="preserve">

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error

Remmapings is not a recognized word. (unrecognized-spelling)
<data name="TextPageInputControlTextContentTextBox.Header" xml:space="preserve">
<value>Text to insert</value>
</data>
<data name="TextPageDeleteButton.ToolTipSevice.ToolTip" xml:space="preserve">

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error

Sevice is not a recognized word. (unrecognized-spelling)
ProcessStartInfo startInfo = new ProcessStartInfo(path);
startInfo.UseShellExecute = true; // LOAD BEARING
startInfo.Arguments = $"{type.ToString(CultureInfo.InvariantCulture)} {Environment.ProcessId}";
System.Environment.SetEnvironmentVariable("MICROSOFT_WINDOWSAPPRUNTIME_BASE_DIRECTORY", null);

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error

WINDOWSAPPRUNTIME is not a recognized word. (unrecognized-spelling)
@github-actions
Copy link

@check-spelling-bot Report

🔴 Please review

See the 📂 files view, the 📜action log, or 📝 job summary for details.

Unrecognized words (6)

Remmapings
Sevice
shorctut
Shorcut
Shrotcuts
WINDOWSAPPRUNTIME

These words are not needed and should be removed CLITo CVS Notavailable toolgood Uninitializes

To accept these unrecognized words as correct and remove the previously acknowledged and now absent words, you could run the following commands

... in a clone of the git@github.com:microsoft/PowerToys.git repository
on the zt/new-kbm-localization branch (ℹ️ how do I use this?):

curl -s -S -L 'https://raw.githubusercontent.com/check-spelling/check-spelling/c635c2f3f714eec2fcf27b643a1919b9a811ef2e/apply.pl' |
perl - 'https://github.com/microsoft/PowerToys/actions/runs/20256621830/attempts/1' &&
git commit -m 'Update check-spelling metadata'
If the flagged items are 🤯 false positives

If items relate to a ...

  • binary file (or some other file you wouldn't want to check at all).

    Please add a file path to the excludes.txt file matching the containing file.

    File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.

    ^ refers to the file's path from the root of the repository, so ^README\.md$ would exclude README.md (on whichever branch you're using).

  • well-formed pattern.

    If you can write a pattern that would match it,
    try adding it to the patterns.txt file.

    Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.

    Note that patterns can't match multiline strings.

@diffray-bot
Copy link

Changes Summary

This PR introduces a new WinUI 3-based Keyboard Manager Editor UI application with full CRUD functionality for keyboard remappings, text shortcuts, program shortcuts, and URL shortcuts. It replaces a placeholder implementation with a complete C#/XAML UI that interoperates with C++ backend through P/Invoke, implementing a modern navigation-based interface with comprehensive validation.

Type: feature

Components Affected: KeyboardManagerEditorUI (new WinUI3 application), KeyboardManagerEditorLibraryWrapper (C++ interop layer), Settings.UI (KeyboardManagerViewModel), Build configuration (Directory.Build.props, Directory.Packages.props), ESRP signing pipeline

Architecture Impact
  • New Patterns: Singleton keyboard hook helper pattern for global keyboard capture, P/Invoke interop layer between C# UI and C++ backend, MVVM-lite pattern with ObservableCollections, IDisposable pattern for resource cleanup across UI components, Interface-based keyboard hook targeting (IKeyboardHookTarget)
  • Dependencies: added: CommunityToolkit.WinUI.UI.Controls.Markdown, added: WinUIEx (for WindowEx features)
  • Coupling: New tight coupling between C# KeyboardMappingService and C++ MappingConfiguration through native interop. The UI now depends on KeyboardManagerEditorLibraryWrapper.dll for all configuration operations.
  • Breaking Changes: Editor path changed from KeyboardManagerEditorUI to WinUI3Apps\PowerToys.KeyboardManagerEditorUI.exe, Registry check for UseNewEditor removed - experimentation toggle now directly uses new editor

Risk Areas: Native interop (P/Invoke) memory management - strings allocated in C++ must be freed properly via FreeString, Keyboard hook lifecycle management - improper cleanup could leave hooks active, Race conditions in keyboard hook activation/deactivation during window focus changes, Resource leaks from IDisposable implementations (KeyboardMappingService, KeyboardHookHelper), Validation logic correctness for illegal shortcuts (Win+L, Ctrl+Alt+Del), Process startup changes in KeyboardManagerViewModel (UseShellExecute=true, environment variable clearing)

Suggestions
  • Add unit tests for ValidationHelper methods especially for edge cases in duplicate and self-mapping detection
  • Consider adding defensive null checks in GetStringAndFree for edge cases
  • Review thread safety of KeyboardHookHelper singleton pattern
  • Ensure proper cleanup paths when window is closed unexpectedly
  • Add telemetry/logging for tracking editor usage and errors

Full review in progress... | Powered by diffray

/// </summary>
public App()
{
global::System.Diagnostics.Debugger.Break();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 CRITICAL - Debug code left in production
Category: bug

Description:
Debugger.Break() is called unconditionally in the App constructor, which will break into the debugger on every application launch. This should never be in production code.

Suggestion:
Remove the Debugger.Break() call or wrap it in #if DEBUG preprocessor directive:
#if DEBUG
global::System.Diagnostics.Debugger.Break();
#endif

Confidence: 100%
Rule: cs_remove_debug_code_from_production

Comment on lines +240 to +249
private void ShowValidationError(ValidationErrorType errorType, ContentDialogButtonClickEventArgs args)
{
// if (ValidationHelper.ValidationMessages.TryGetValue(errorType, out (string Title, string Message) error))
// {
// ValidationTip.Title = error.Title;
// ValidationTip.Subtitle = error.Message;
// ValidationTip.IsOpen = true;
// args.Cancel = true;
// }
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 HIGH - Empty validation error handler silently fails
Category: bug

Description:
The ShowValidationError method is completely commented out (lines 242-248), meaning validation errors are silently ignored. The dialog provides no feedback when validation fails.

Suggestion:
Implement the validation error display logic or remove the commented code:

private void ShowValidationError(ValidationErrorType errorType, ContentDialogButtonClickEventArgs args)
{
    if (ValidationHelper.ValidationMessages.TryGetValue(errorType, out (string Title, string Message) error))
    {
        ValidationTip.Title = error.Title;
        ValidationTip.Subtitle = error.Message;
        ValidationTip.IsOpen = true;
        args.Cancel = true;
    }
}

Confidence: 100%
Rule: cs_avoid_empty_catch_blocks

Comment on lines +211 to +220
private void ShowValidationError(ValidationErrorType errorType, ContentDialogButtonClickEventArgs args)
{
// if (ValidationHelper.ValidationMessages.TryGetValue(errorType, out (string Title, string Message) error))
// {
// ValidationTip.Title = error.Title;
// ValidationTip.Subtitle = error.Message;
// ValidationTip.IsOpen = true;
// args.Cancel = true;
// }
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 HIGH - Empty validation error handler silently fails
Category: bug

Description:
The ShowValidationError method is completely commented out (lines 213-219), meaning validation errors are silently ignored. The dialog provides no feedback when validation fails.

Suggestion:
Implement the validation error display logic or remove the commented code:

private void ShowValidationError(ValidationErrorType errorType, ContentDialogButtonClickEventArgs args)
{
    if (ValidationHelper.ValidationMessages.TryGetValue(errorType, out (string Title, string Message) error))
    {
        ValidationTip.Title = error.Title;
        ValidationTip.Subtitle = error.Message;
        ValidationTip.IsOpen = true;
        args.Cancel = true;
    }
}

Confidence: 100%
Rule: cs_avoid_empty_catch_blocks

try
{
_mappingService = new KeyboardMappingService();
LoadProgramShrotcuts();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 LOW - Typo in method name: LoadProgramShrotcuts
Category: quality

Description:
The method 'LoadProgramShrotcuts' appears to be misspelled. It should be 'LoadProgramShortcuts'.

Suggestion:
Rename the method from 'LoadProgramShrotcuts' to 'LoadProgramShortcuts'. Update all references.

Confidence: 100%
Rule: cs_use_pascalcase_for_type_names

return KeyboardManagerInterop.AddShortcutRemap(_configHandle, originalKeys, targetKeys, targetApp, (int)operationType);
}

public bool AddShorcutMapping(ShortcutKeyMapping shortcutKeyMapping)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 LOW - Typo in method name
Category: quality

Description:
Method name 'AddShorcutMapping' contains a typo - 'Shorcut' should be 'Shortcut'.

Suggestion:
Rename the method to 'AddShortcutMapping' for consistency.

Confidence: 100%
Rule: qual_semantic_naming_csharp

Comment on lines +240 to +249
private void ShowValidationError(ValidationErrorType errorType, ContentDialogButtonClickEventArgs args)
{
// if (ValidationHelper.ValidationMessages.TryGetValue(errorType, out (string Title, string Message) error))
// {
// ValidationTip.Title = error.Title;
// ValidationTip.Subtitle = error.Message;
// ValidationTip.IsOpen = true;
// args.Cancel = true;
// }
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 HIGH - ShowValidationError implementation is commented out
Category: bug

Description:
The entire ShowValidationError method body is commented out, meaning validation errors are silently ignored. Users won't see any feedback when validation fails.

Suggestion:
Implement the validation error display or add a clear comment explaining why validation is disabled. Compare with Text.xaml.cs which has a working implementation.

Confidence: 95%
Rule: quality_commented_code

Comment on lines +182 to +187
// if (isAppSpecific && !string.IsNullOrEmpty(appName))
// {
// saved = _mappingService.AddShortcutMapping(originalKeysString, programPath, appName, ShortcutOperationType.RemapText);
// }
// else
// {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MEDIUM - Commented out code block without explanation
Category: quality

Description:
6 consecutive lines of commented-out code containing if-else statements with no accompanying TODO or explanation. Same pattern as in Programs.xaml.cs.

Suggestion:
Either remove this commented code and rely on git history for recovery, or add a clear TODO/NOTE explaining why it's temporarily disabled.

Confidence: 90%
Rule: quality_commented_code

Comment on lines +211 to +220
private void ShowValidationError(ValidationErrorType errorType, ContentDialogButtonClickEventArgs args)
{
// if (ValidationHelper.ValidationMessages.TryGetValue(errorType, out (string Title, string Message) error))
// {
// ValidationTip.Title = error.Title;
// ValidationTip.Subtitle = error.Message;
// ValidationTip.IsOpen = true;
// args.Cancel = true;
// }
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 HIGH - ShowValidationError implementation is commented out
Category: bug

Description:
The entire ShowValidationError method body is commented out, meaning validation errors are silently ignored. Users won't see any feedback when validation fails.

Suggestion:
Implement the validation error display or add a clear comment explaining why validation is disabled. Compare with Text.xaml.cs which has a working implementation.

Confidence: 95%
Rule: quality_commented_code

Comment on lines +195 to +244
else
{
string originalKeysString = string.Join(";", originalKeys.Select(
k => mappingService.GetKeyCodeFromName(k).ToString(CultureInfo.InvariantCulture)));

// Don't check for duplicates if the original keys are the same as the remapping being edited
bool isEditingExistingRemapping = false;
if (isEditMode && editingRemapping != null)
{
string editingOriginalKeysString = string.Join(";", editingRemapping.OriginalKeys.Select(k =>
mappingService.GetKeyCodeFromName(k).ToString(CultureInfo.InvariantCulture)));

if (KeyboardManagerInterop.AreShortcutsEqual(originalKeysString, editingOriginalKeysString))
{
isEditingExistingRemapping = true;
}
}

// Check if the shortcut is already remapped in the same app context
foreach (var mapping in mappingService.GetShortcutMappingsByType(ShortcutOperationType.RemapShortcut))
{
if (KeyboardManagerInterop.AreShortcutsEqual(originalKeysString, mapping.OriginalKeys))
{
// If both are global (all apps)
if (!isAppSpecific && string.IsNullOrEmpty(mapping.TargetApp))
{
// Skip if the remapping is the same as the one being edited
if (editingRemapping != null && editingRemapping.OriginalKeys.Count > 1 && editingRemapping.IsAllApps && isEditingExistingRemapping)
{
continue;
}

return true;
}

// If both are for the same specific app
else if (isAppSpecific && !string.IsNullOrEmpty(mapping.TargetApp)
&& string.Equals(mapping.TargetApp, appName, StringComparison.OrdinalIgnoreCase))
{
// Skip if the remapping is the same as the one being edited
if (editingRemapping != null && editingRemapping.OriginalKeys.Count > 1 && !editingRemapping.IsAllApps &&
string.Equals(editingRemapping.AppName, appName, StringComparison.OrdinalIgnoreCase) && isEditingExistingRemapping)
{
continue;
}

return true;
}
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MEDIUM - Deeply nested if-else blocks instead of guard clauses
Category: quality

Description:
The shortcut remapping validation logic (else block) contains 4-5 levels of nesting with complex conditional logic checking for duplicate mappings.

Suggestion:
Extract the duplicate checking logic into separate helper methods. Use early returns for edge cases. Consider extracting 'CheckGlobalShortcutDuplicate' and 'CheckAppSpecificShortcutDuplicate' methods.

Confidence: 70%
Rule: quality_guard_clauses

Comment on lines +29 to +87
public static ValidationErrorType ValidateKeyMapping(
List<string> originalKeys,
List<string> remappedKeys,
bool isAppSpecific,
string appName,
KeyboardMappingService mappingService,
bool isEditMode = false,
Remapping? editingRemapping = null)
{
// Check if original keys are empty
if (originalKeys == null || originalKeys.Count == 0)
{
return ValidationErrorType.EmptyOriginalKeys;
}

// Check if remapped keys are empty
if (remappedKeys == null || remappedKeys.Count == 0)
{
return ValidationErrorType.EmptyRemappedKeys;
}

// Check if shortcut contains only modifier keys
if ((originalKeys.Count > 1 && ContainsOnlyModifierKeys(originalKeys)) ||
(remappedKeys.Count > 1 && ContainsOnlyModifierKeys(remappedKeys)))
{
return ValidationErrorType.ModifierOnly;
}

// Check if app specific is checked but no app name is provided
if (isAppSpecific && string.IsNullOrWhiteSpace(appName))
{
return ValidationErrorType.EmptyAppName;
}

// Check if this is a shortcut (multiple keys) and if it's an illegal combination
if (originalKeys.Count > 1)
{
string shortcutKeysString = string.Join(";", originalKeys.Select(k => mappingService.GetKeyCodeFromName(k).ToString(CultureInfo.InvariantCulture)));

if (KeyboardManagerInterop.IsShortcutIllegal(shortcutKeysString))
{
return ValidationErrorType.IllegalShortcut;
}
}

// Check for duplicate mappings
if (IsDuplicateMapping(originalKeys, isAppSpecific, appName, mappingService, isEditMode, editingRemapping))
{
return ValidationErrorType.DuplicateMapping;
}

// Check for self-mapping
if (IsSelfMapping(originalKeys, remappedKeys, mappingService))
{
return ValidationErrorType.SelfMapping;
}

return ValidationErrorType.NoError;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MEDIUM - Method with 7 parameters - consider parameter object
Category: quality

Description:
The method 'ValidateKeyMapping' has 7 parameters (5 required + 2 optional). This makes call sites verbose and harder to maintain.

Suggestion:
Create a parameter object like 'KeyMappingValidationContext' that groups the logically related parameters (originalKeys, remappedKeys, isAppSpecific, appName, mappingService, isEditMode, editingRemapping).

Confidence: 65%
Rule: cs_group_related_parameters_in_objects

@diffray-bot
Copy link

Review Summary

Free public review - Want AI code reviews on your PRs? Check out diffray.ai

Validated 76 issues: 33 kept, 43 filtered

Issues Found: 33

See 33 individual line comment(s) for details.

📊 16 unique issue type(s) across 33 location(s)

📋 Full issue list (click to expand)

🔴 CRITICAL - Debug code left in production

Category: bug

File: src/modules/keyboardmanager/KeyboardManagerEditorUI/App.xaml.cs:42

Description: Debugger.Break() is called unconditionally in the App constructor, which will break into the debugger on every application launch. This should never be in production code.

Suggestion: Remove the Debugger.Break() call or wrap it in #if DEBUG preprocessor directive:
#if DEBUG
global::System.Diagnostics.Debugger.Break();
#endif

Confidence: 100%

Rule: cs_remove_debug_code_from_production


🟠 HIGH - Empty validation error handler silently fails (2 occurrences)

Category: bug

📍 View all locations
File Description Suggestion Confidence
src/modules/keyboardmanager/KeyboardManagerEditorUI/Pages/Programs.xaml.cs:240-249 The ShowValidationError method is completely commented out (lines 242-248), meaning validation error... Implement the validation error display logic or remove the commented code:
private void Sh... | 100% |
| `src/modules/keyboardmanager/KeyboardManagerEditorUI/Pages/URLs.xaml.cs:211-220` | The ShowValidationError method is completely commented out (lines 213-219), meaning validation error... | Implement the validation error display logic or remove the commented code:
```csharp
private void Sh... | 100% |

</details>

**Rule:** `cs_avoid_empty_catch_blocks`

---

#### 🟠 HIGH - Memory leak: Raw pointer allocations without cleanup path (5 occurrences)

**Category:** bug

<details>
<summary>📍 View all locations</summary>

| File | Description | Suggestion | Confidence |
|------|-------------|------------|------------|
| `src/modules/keyboardmanager/KeyboardManagerEditorLibraryWrapper/KeyboardManagerEditorLibraryWrapper.cpp:50-88` | In GetSingleKeyRemap(), AllocateAndCopyString() allocates memory for mapping->targetKey in multiple ... | Document that callers MUST call FreeString(mapping->targetKey) after use. Consider adding a cleanup ... | 75% |
| `src/modules/keyboardmanager/KeyboardManagerEditorLibraryWrapper/KeyboardManagerEditorLibraryWrapper.cpp:96-113` | In GetSingleKeyToTextRemap(), AllocateAndCopyString() allocates memory for mapping->targetText. If t... | Document that callers MUST call FreeString(mapping->targetText) after use. Add null check for mappin... | 75% |
| `src/modules/keyboardmanager/KeyboardManagerEditorLibraryWrapper/KeyboardManagerEditorLibraryWrapper.cpp:214-375` | In GetShortcutRemapByType(), the function allocates up to 7 raw pointers per call using AllocateAndC... | Provide a helper function like 'FreeShortcutMapping(ShortcutMapping* mapping)' that frees all pointe... | 75% |
| `src/modules/keyboardmanager/KeyboardManagerEditorLibraryWrapper/KeyboardManagerEditorLibraryWrapper.cpp:390-476` | In GetShortcutRemap(), the function allocates up to 7 raw pointers per call using AllocateAndCopyStr... | Document that callers MUST call FreeString() on all allocated pointers. Provide a helper function to... | 75% |
| `src/modules/keyboardmanager/KeyboardManagerEditorLibraryWrapper/KeyboardManagerEditorLibraryWrapper.cpp:16-24` | CreateMappingConfiguration() uses 'new MappingConfiguration()' which could throw std::bad_alloc. In ... | Wrap the allocation in a try-catch block and return nullptr on allocation failure, or use std::nothr... | 60% |

</details>

**Rule:** `cpp_raw_pointer_delete`

---

#### 🟠 HIGH - Placeholder implementation returns hardcoded value

**Category:** quality

**File:** `src/modules/keyboardmanager/KeyboardManagerEditorUI/Helpers/ResourceLoaderInstance.cs:17`

**Description:** The GetString method always returns 'Hello' instead of actually loading the resource, indicating incomplete implementation that will cause all localized strings to display 'Hello'.

**Suggestion:** Implement the method properly: 'internal static string GetString(string resourceId) => ResourceLoader.GetString(resourceId);'

**Confidence:** 98%

**Rule:** `cs_extract_duplicated_business_logic`

---

#### 🟡 MEDIUM - Missing null pointer check for output parameter (5 occurrences)

**Category:** bug

<details>
<summary>📍 View all locations</summary>

| File | Description | Suggestion | Confidence |
|------|-------------|------------|------------|
| `src/modules/keyboardmanager/KeyboardManagerEditorLibraryWrapper/KeyboardManagerEditorLibraryWrapper.cpp:50-88` | In GetSingleKeyRemap(), the 'mapping' parameter is dereferenced without checking if it's null. If a ... | Add a null check at the beginning: if (mapping == nullptr) { return false; } | 85% |
| `src/modules/keyboardmanager/KeyboardManagerEditorLibraryWrapper/KeyboardManagerEditorLibraryWrapper.cpp:96-113` | In GetSingleKeyToTextRemap(), the 'mapping' parameter is dereferenced without checking if it's null.... | Add a null check at the beginning: if (mapping == nullptr) { return false; } | 85% |
| `src/modules/keyboardmanager/KeyboardManagerEditorLibraryWrapper/KeyboardManagerEditorLibraryWrapper.cpp:214-375` | In GetShortcutRemapByType(), the 'mapping' parameter is dereferenced without checking if it's null. ... | Add a null check at the beginning: if (mapping == nullptr) { return false; } | 85% |
| `src/modules/keyboardmanager/KeyboardManagerEditorLibraryWrapper/KeyboardManagerEditorLibraryWrapper.cpp:390-476` | In GetShortcutRemap(), the 'mapping' parameter is dereferenced without checking if it's null. This w... | Add a null check at the beginning: if (mapping == nullptr) { return false; } | 85% |
| `src/modules/keyboardmanager/KeyboardManagerEditorLibraryWrapper/KeyboardManagerEditorLibraryWrapper.cpp:515-575` | In AddShortcutRemap(), the function doesn't check if 'originalKeys', 'targetKeys', or 'appPathOrUri'... | Add null checks: if (!originalKeys \|\| !targetKeys) { return false; }. Also check appPathOrUri when... | 80% |

</details>

**Rule:** `cpp_use_after_free`

---

#### 🟡 MEDIUM - Potential NullReferenceException in event handler

**Category:** bug

**File:** `src/modules/keyboardmanager/KeyboardManagerEditorUI/Pages/Remappings.xaml.cs:243`

**Description:** OrphanedKeysTeachingTip_ActionButtonClick uses null-forgiving operator on _mappingService without null check. While unlikely, _mappingService could be null if Dispose() was called.

**Suggestion:** Add a null check for _mappingService at the beginning of the method: if (_mappingService == null) { return; }

**Confidence:** 65%

**Rule:** `bug_null_pointer_csharp`

---

#### 🟡 MEDIUM - Magic numbers for key count limits

**Category:** quality

**File:** `src/modules/keyboardmanager/KeyboardManagerEditorUI/Helpers/KeyboardHookHelper.cs:94-95`

**Description:** The numeric literals 4 and 5 represent maximum modifier key count and total key count but are hardcoded without named constants. The comment on line 93 explains the meaning but named constants would be clearer.

**Suggestion:** Extract these magic numbers into named constants: 'private const int MaxModifierKeys = 4;' and 'private const int MaxTotalKeysInShortcut = 5;'

**Confidence:** 75%

**Rule:** `cs_replace_magic_numbers_with_named_constan`

---

#### 🟡 MEDIUM - Magic numbers for VirtualKey values

**Category:** quality

**File:** `src/modules/keyboardmanager/KeyboardManagerEditorUI/Controls/KeyVisual/KeyVisual.xaml.cs:120-122`

**Description:** The numeric literals 160 and 161 represent Left Shift and Right Shift key codes. While there are inline comments, named constants would improve maintainability.

**Suggestion:** Define named constants: 'private const int VK_LSHIFT = 160;' and 'private const int VK_RSHIFT = 161;' or use Windows.System.VirtualKey enum values if available.

**Confidence:** 70%

**Rule:** `qual_magic_numbers_csharp`

---

#### 🟡 MEDIUM - O(N) linear search in duplicate detection (5 occurrences)

**Category:** performance

<details>
<summary>📍 View all locations</summary>

| File | Description | Suggestion | Confidence |
|------|-------------|------------|------------|
| `src/modules/keyboardmanager/KeyboardManagerEditorUI/Helpers/ValidationHelper.cs:177-191` | IsDuplicateMapping performs a foreach loop over all single key mappings to check for duplicates. Cal... | Pre-index single key mappings using a HashSet<int> or Dictionary<int, KeyMapping> by originalKey. Ch... | 65% |
| `src/modules/keyboardmanager/KeyboardManagerEditorUI/Helpers/ValidationHelper.cs:214-244` | IsDuplicateMapping performs foreach over all shortcut mappings, calling KeyboardManagerInterop.AreSh... | Create an index using normalized shortcut strings as keys: Dictionary<string, ShortcutKeyMapping>. C... | 70% |
| `src/modules/keyboardmanager/KeyboardManagerEditorLibraryWrapper/KeyboardManagerEditorLibraryWrapper.cpp:115-212` | Contains nested loops iterating over osLevelShortcutReMap and appSpecificShortcutReMap to count by o... | Pre-filter and cache the counts by operation type when mappings are loaded or modified, rather than ... | 70% |
| `src/modules/keyboardmanager/KeyboardManagerEditorLibraryWrapper/KeyboardManagerEditorLibraryWrapper.cpp:214-309` | Iterates through all mappings with nested loops, filtering by operation type and building a vector. ... | Maintain filtered collections by operation type and invalidate cache when mappings change. | 70% |
| `src/modules/keyboardmanager/KeyboardManagerEditorUI/Helpers/ValidationHelper.cs:295-312` | IsKeyOrphaned iterates over all single key and shortcut mappings to check if a key is used as a targ... | Pre-build a HashSet<int> of all keys that are used as targets in any mapping. Check orphaned status ... | 65% |

</details>

**Rule:** `perf_quadratic_loops`

---

#### 🟡 MEDIUM - Commented out code block without explanation (4 occurrences)

**Category:** quality

<details>
<summary>📍 View all locations</summary>

| File | Description | Suggestion | Confidence |
|------|-------------|------------|------------|
| `src/modules/keyboardmanager/KeyboardManagerEditorUI/Pages/Programs.xaml.cs:168-173` | 6 consecutive lines of commented-out code containing if-else statements with no accompanying TODO or... | Either remove this commented code and rely on git history for recovery, or add a clear TODO/NOTE exp... | 90% |
| `src/modules/keyboardmanager/KeyboardManagerEditorUI/Pages/Programs.xaml.cs:240-249` | The entire ShowValidationError method body is commented out, meaning validation errors are silently ... | Implement the validation error display or add a clear comment explaining why validation is disabled.... | 95% |
| `src/modules/keyboardmanager/KeyboardManagerEditorUI/Pages/URLs.xaml.cs:182-187` | 6 consecutive lines of commented-out code containing if-else statements with no accompanying TODO or... | Either remove this commented code and rely on git history for recovery, or add a clear TODO/NOTE exp... | 90% |
| `src/modules/keyboardmanager/KeyboardManagerEditorUI/Pages/URLs.xaml.cs:211-220` | The entire ShowValidationError method body is commented out, meaning validation errors are silently ... | Implement the validation error display or add a clear comment explaining why validation is disabled.... | 95% |

</details>

**Rule:** `quality_commented_code`

---

#### 🟡 MEDIUM - Deeply nested if-else blocks instead of guard clauses

**Category:** quality

**File:** `src/modules/keyboardmanager/KeyboardManagerEditorUI/Helpers/ValidationHelper.cs:195-244`

**Description:** The shortcut remapping validation logic (else block) contains 4-5 levels of nesting with complex conditional logic checking for duplicate mappings.

**Suggestion:** Extract the duplicate checking logic into separate helper methods. Use early returns for edge cases. Consider extracting 'CheckGlobalShortcutDuplicate' and 'CheckAppSpecificShortcutDuplicate' methods.

**Confidence:** 70%

**Rule:** `quality_guard_clauses`

---

#### 🟡 MEDIUM - Method with 7 parameters - consider parameter object

**Category:** quality

**File:** `src/modules/keyboardmanager/KeyboardManagerEditorUI/Helpers/ValidationHelper.cs:29-87`

**Description:** The method 'ValidateKeyMapping' has 7 parameters (5 required + 2 optional). This makes call sites verbose and harder to maintain.

**Suggestion:** Create a parameter object like 'KeyMappingValidationContext' that groups the logically related parameters (originalKeys, remappedKeys, isAppSpecific, appName, mappingService, isEditMode, editingRemapping).

**Confidence:** 65%

**Rule:** `cs_group_related_parameters_in_objects`

---

#### 🔵 LOW - Typo in method name: LoadProgramShrotcuts

**Category:** quality

**File:** `src/modules/keyboardmanager/KeyboardManagerEditorUI/Pages/Programs.xaml.cs:48`

**Description:** The method 'LoadProgramShrotcuts' appears to be misspelled. It should be 'LoadProgramShortcuts'.

**Suggestion:** Rename the method from 'LoadProgramShrotcuts' to 'LoadProgramShortcuts'. Update all references.

**Confidence:** 100%

**Rule:** `cs_use_pascalcase_for_type_names`

---

#### 🔵 LOW - Typo in method name

**Category:** quality

**File:** `src/modules/keyboardmanager/KeyboardManagerEditorUI/Interop/KeyboardMappingService.cs:188`

**Description:** Method name 'AddShorcutMapping' contains a typo - 'Shorcut' should be 'Shortcut'.

**Suggestion:** Rename the method to 'AddShortcutMapping' for consistency.

**Confidence:** 100%

**Rule:** `qual_semantic_naming_csharp`

---

#### 🔵 LOW - Missing XML documentation for public static class (2 occurrences)

**Category:** docs

<details>
<summary>📍 View all locations</summary>

| File | Description | Suggestion | Confidence |
|------|-------------|------------|------------|
| `src/modules/keyboardmanager/KeyboardManagerEditorUI/Helpers/ValidationHelper.cs:15` | ValidationHelper lacks XML documentation. Public APIs should be documented for IntelliSense support.... | Add XML documentation: /// <summary>Provides validation methods for keyboard mappings.</summary> | 70% |
| `src/modules/keyboardmanager/KeyboardManagerEditorUI/Interop/KeyboardMappingService.cs:15` | KeyboardMappingService lacks XML documentation. Public APIs should be documented. | Add XML documentation: /// <summary>Provides a managed wrapper for keyboard mapping configuration op... | 70% |

</details>

**Rule:** `cs_xml_documentation_for_public_apis`

---

#### 🔵 LOW - Missing culture specification in ToString

**Category:** quality

**File:** `src/modules/keyboardmanager/KeyboardManagerEditorUI/Pages/URLs.xaml.cs:244`

**Description:** Using ToString() without CultureInfo when converting integer key codes to strings in DeleteButton_Click. While integer ToString() is culture-invariant by default in .NET, explicit specification would be consistent with other code in the file.

**Suggestion:** Specify CultureInfo.InvariantCulture for consistency with line 174 and 180:
string originalKeys = string.Join(";", shortcut.Shortcut.Select(k => _mappingService.GetKeyCodeFromName(k).ToString(CultureInfo.InvariantCulture)));

**Confidence:** 62%

**Rule:** `csharp_string_comparison_culture`

---

</details>

<sub>Powered by [diffray](https://diffray.ai?utm_source=github-public) - Multi-Agent Code Review Agent</sub>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Product-Keyboard Shortcut Manager Issues regarding Keyboard Shortcut Manager

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants