diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..0057f38 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,79 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = crlf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{csproj,wixproj,props,targets,xml,wxs,wxl,config}] +indent_size = 2 + +[*.{json,yaml,yml}] +indent_size = 2 + +[*.{ps1,psm1,psd1}] +indent_size = 4 + +[*.md] +trim_trailing_whitespace = false + +[*.sln] +indent_style = tab + +# C# formatting rules +[*.cs] +# Use 'var' when type is apparent +csharp_style_var_for_built_in_types = false:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = false:suggestion + +# Prefer expression-bodied members for simple members +csharp_style_expression_bodied_methods = when_on_single_line:suggestion +csharp_style_expression_bodied_constructors = false:suggestion +csharp_style_expression_bodied_properties = true:suggestion +csharp_style_expression_bodied_accessors = true:suggestion + +# Prefer pattern matching +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion + +# Null-checking preferences +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion + +# Namespace preferences +csharp_style_namespace_declarations = file_scoped:suggestion + +# Organize usings +dotnet_sort_system_directives_first = true +dotnet_separate_import_directive_groups = false + +# New line preferences +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true + +# Indentation preferences +csharp_indent_case_contents = true +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_parameter_list_parentheses = false + +# Naming conventions +dotnet_naming_rule.private_fields_should_be_camel_case.severity = suggestion +dotnet_naming_rule.private_fields_should_be_camel_case.symbols = private_fields +dotnet_naming_rule.private_fields_should_be_camel_case.style = camel_case_with_underscore + +dotnet_naming_symbols.private_fields.applicable_kinds = field +dotnet_naming_symbols.private_fields.applicable_accessibilities = private + +dotnet_naming_style.camel_case_with_underscore.required_prefix = _ +dotnet_naming_style.camel_case_with_underscore.capitalization = camel_case diff --git a/.github/upgrades/scenarios/dotnet-version-upgrade/assessment.csv b/.github/upgrades/scenarios/dotnet-version-upgrade/assessment.csv deleted file mode 100644 index dd55aef..0000000 --- a/.github/upgrades/scenarios/dotnet-version-upgrade/assessment.csv +++ /dev/null @@ -1 +0,0 @@ -Issue ID,Description,State,Severity,Story Points,Project Path,Location Kind,Path,Line,Column,Incident ID,Help Link,Assembly Name,Assembly Version,Assembly Public Key,Snippet diff --git a/.github/upgrades/scenarios/dotnet-version-upgrade/assessment.json b/.github/upgrades/scenarios/dotnet-version-upgrade/assessment.json deleted file mode 100644 index fb4478c..0000000 --- a/.github/upgrades/scenarios/dotnet-version-upgrade/assessment.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "settings": { - "components": { - "code": true, - "binaries": false - }, - "targetId": "net8.0", - "targetDisplayName": ".NETCoreApp,Version=v8.0" - }, - "analysisStartTime": "2026-03-15T08:29:31.7949075Z", - "analysisEndTime": "2026-03-15T08:29:31.8399957Z", - "privacyModeHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2270980", - "stats": { - "summary": { - "projects": 1, - "issues": 0, - "incidents": 0, - "effort": 0 - }, - "charts": { - "severity": { - "Mandatory": 0, - "Optional": 0, - "Potential": 0, - "Information": 0 - }, - "category": {} - } - }, - "projects": [ - { - "path": "HintOverlay.csproj", - "startingProject": true, - "issues": 0, - "storyPoints": 0, - "properties": { - "appName": "HintOverlay", - "projectKind": "WinForms", - "frameworks": [ - "net8.0-windows" - ], - "languages": [ - "C#" - ], - "tools": [ - "MSBuild" - ], - "isSdkStyle": true, - "numberOfFiles": 39, - "numberOfCodeFiles": 38, - "linesTotal": 3551, - "linesOfCode": 3431, - "totalApiScanned": 0, - "minLinesOfCodeToChange": 0, - "maxLinesOfCodeToChange": 0 - }, - "ruleInstances": [], - "features": [] - } - ], - "rules": {} -} \ No newline at end of file diff --git a/.github/upgrades/scenarios/dotnet-version-upgrade/assessment.md b/.github/upgrades/scenarios/dotnet-version-upgrade/assessment.md deleted file mode 100644 index e9930bf..0000000 --- a/.github/upgrades/scenarios/dotnet-version-upgrade/assessment.md +++ /dev/null @@ -1,133 +0,0 @@ -# Projects and dependencies analysis - -This document provides a comprehensive overview of the projects and their dependencies in the context of upgrading to .NETCoreApp,Version=v8.0. - -## Table of Contents - -- [Executive Summary](#executive-Summary) - - [Highlevel Metrics](#highlevel-metrics) - - [Projects Compatibility](#projects-compatibility) - - [Package Compatibility](#package-compatibility) - - [API Compatibility](#api-compatibility) -- [Aggregate NuGet packages details](#aggregate-nuget-packages-details) -- [Top API Migration Challenges](#top-api-migration-challenges) - - [Technologies and Features](#technologies-and-features) - - [Most Frequent API Issues](#most-frequent-api-issues) -- [Projects Relationship Graph](#projects-relationship-graph) -- [Project Details](#project-details) - - - [Windows-Hinting.csproj](#Windows-Hintingcsproj) - - -## Executive Summary - -### Highlevel Metrics - -| Metric | Count | Status | -| :--- | :---: | :--- | -| Total Projects | 1 | 0 require upgrade | -| Total NuGet Packages | 2 | All compatible | -| Total Code Files | 38 | | -| Total Code Files with Incidents | 0 | | -| Total Lines of Code | 3431 | | -| Total Number of Issues | 0 | | -| Estimated LOC to modify | 0+ | at least 0.0% of codebase | - -### Projects Compatibility - -| Project | Target Framework | Difficulty | Package Issues | API Issues | Est. LOC Impact | Description | -| :--- | :---: | :---: | :---: | :---: | :---: | :--- | -| [Windows-Hinting.csproj](#Windows-Hintingcsproj) | net8.0-windows | βœ… None | 0 | 0 | | WinForms, Sdk Style = True | - -### Package Compatibility - -| Status | Count | Percentage | -| :--- | :---: | :---: | -| βœ… Compatible | 2 | 100.0% | -| ⚠️ Incompatible | 0 | 0.0% | -| πŸ”„ Upgrade Recommended | 0 | 0.0% | -| ***Total NuGet Packages*** | ***2*** | ***100%*** | - -### API Compatibility - -| Category | Count | Impact | -| :--- | :---: | :--- | -| πŸ”΄ Binary Incompatible | 0 | High - Require code changes | -| 🟑 Source Incompatible | 0 | Medium - Needs re-compilation and potential conflicting API error fixing | -| πŸ”΅ Behavioral change | 0 | Low - Behavioral changes that may require testing at runtime | -| βœ… Compatible | 0 | | -| ***Total APIs Analyzed*** | ***0*** | | - -## Aggregate NuGet packages details - -| Package | Current Version | Suggested Version | Projects | Description | -| :--- | :---: | :---: | :--- | :--- | -| Microsoft.Extensions.Hosting | 10.0.3 | | [Windows-Hinting.csproj](#Windows-Hintingcsproj) | βœ…Compatible | -| Microsoft.Extensions.Hosting.Abstractions | 10.0.3 | | [Windows-Hinting.csproj](#Windows-Hintingcsproj) | βœ…Compatible | - -## Top API Migration Challenges - -### Technologies and Features - -| Technology | Issues | Percentage | Migration Path | -| :--- | :---: | :---: | :--- | - -### Most Frequent API Issues - -| API | Count | Percentage | Category | -| :--- | :---: | :---: | :--- | - -## Projects Relationship Graph - -Legend: -πŸ“¦ SDK-style project -βš™οΈ Classic project - -```mermaid -flowchart LR - P1["πŸ“¦ Windows-Hinting.csproj
net8.0-windows"] - click P1 "#Windows-Hintingcsproj" - -``` - -## Project Details - - -### Windows-Hinting.csproj - -#### Project Info - -- **Current Target Framework:** net8.0-windowsβœ… -- **SDK-style**: True -- **Project Kind:** WinForms -- **Dependencies**: 0 -- **Dependants**: 0 -- **Number of Files**: 39 -- **Lines of Code**: 3431 -- **Estimated LOC to modify**: 0+ (at least 0.0% of the project) - -#### Dependency Graph - -Legend: -πŸ“¦ SDK-style project -βš™οΈ Classic project - -```mermaid -flowchart TB - subgraph current["Windows-Hinting.csproj"] - MAIN["πŸ“¦ Windows-Hinting.csproj
net8.0-windows"] - click MAIN "#Windows-Hintingcsproj" - end - -``` - -### API Compatibility - -| Category | Count | Impact | -| :--- | :---: | :--- | -| πŸ”΄ Binary Incompatible | 0 | High - Require code changes | -| 🟑 Source Incompatible | 0 | Medium - Needs re-compilation and potential conflicting API error fixing | -| πŸ”΅ Behavioral change | 0 | Low - Behavioral changes that may require testing at runtime | -| βœ… Compatible | 0 | | -| ***Total APIs Analyzed*** | ***0*** | | - diff --git a/.github/upgrades/scenarios/dotnet-version-upgrade/execution-log.md b/.github/upgrades/scenarios/dotnet-version-upgrade/execution-log.md deleted file mode 100644 index 7392395..0000000 --- a/.github/upgrades/scenarios/dotnet-version-upgrade/execution-log.md +++ /dev/null @@ -1,40 +0,0 @@ -# Execution Log - -**Scenario**: dotnet-version-upgrade -**Target Framework**: .NET 8.0 -**Strategy**: All-At-Once - ---- - -## Task 1: Update Windows-Hinting.Installer.wixproj βœ… COMPLETE - -**Start Time**: 2024 -**Status**: βœ… COMPLETED - -### Summary -Successfully modernized the WiX installer project from WiX 3.x (Wix2010.targets) to WiX 4.0 (wix.targets) format with explicit .NET 8 compatibility. - -### Changes Made -- Updated WiX project ProductVersion: 3.14 β†’ 4.0 -- Changed import target: Wix2010.targets β†’ wix.targets -- Added TargetFrameworkVersion: net8.0 -- Verified Product.wxs references correct .NET 8 output path -- All project references remain correct and intact - -### Build Validation -βœ… Build successful with 0 errors, 0 warnings -- Windows-Hinting.csproj (net8.0-windows): βœ… Built -- Windows-Hinting.Installer.wixproj (WiX 4.0): βœ… Built -- Installer package generation: βœ… Successful - -### Files Modified -- `Windows-Hinting.Installer/Windows-Hinting.Installer.wixproj` - -**Progress**: 50% complete (1 of 2 tasks) - ---- - -## Next: Task 2 - Solution Validation (In Progress) - -Verifying full solution integration and final build validation. - diff --git a/.github/upgrades/scenarios/dotnet-version-upgrade/plan.md b/.github/upgrades/scenarios/dotnet-version-upgrade/plan.md deleted file mode 100644 index 20d6403..0000000 --- a/.github/upgrades/scenarios/dotnet-version-upgrade/plan.md +++ /dev/null @@ -1,140 +0,0 @@ -# .NET 8 Upgrade Plan - -**Generated**: 2024 -**Target Framework**: .NET 8.0 -**Projects**: 2 -**Strategy**: All-At-Once - ---- - -## Overview - -This plan upgrades the Windows-Hinting solution to .NET 8.0 using an **All-At-Once** strategy. Both the main WinForms application and the WiX installer project will be updated simultaneously. - -### Assessment Summary -- **Windows-Hinting.csproj**: Already on net8.0-windows βœ… -- **Windows-Hinting.Installer.wixproj**: WiX installer (requires modernization) -- **Total NuGet Packages**: 2 (all compatible) -- **Code Files**: 38 -- **Complexity**: Low -- **Estimated Effort**: Minimal - ---- - -## Selected Strategy - -### All-At-Once -**Rationale**: 2 projects, both modern format, clear dependency structure, straightforward upgrade with no breaking API changes detected. - -**Key execution principle**: Both projects updated simultaneously in a single atomic operation. - ---- - -## Projects to Upgrade - -### Tier: All Projects (Atomic) - -| Project | Type | Current TFM | Target TFM | Status | -|---------|------|-------------|-----------|--------| -| Windows-Hinting.csproj | WinForms App | net8.0-windows | net8.0-windows | βœ… Already current | -| Windows-Hinting.Installer.wixproj | WiX Installer | (not .NET) | net8.0 compatible | ⏳ To upgrade | - ---- - -## Task Breakdown - -### Task 1: Update Windows-Hinting.Installer.wixproj - -**Objective**: Modernize the WiX installer project to target .NET 8 and ensure it properly references the upgraded main application. - -**Scope**: -- Verify WiX project target framework compatibility -- Update WiX project references/imports if needed -- Ensure installer references the correct .NET 8 output from Windows-Hinting.csproj -- Validate WiX project builds successfully -- Confirm installer creation completes without errors - -**Validation**: -- WiX project loads without errors in Visual Studio -- Solution builds cleanly -- Installer (MSI/Bundle) builds successfully - -### Task 2: Verify Solution Integration - -**Objective**: Ensure both projects build and package correctly as a unified solution. - -**Scope**: -- Build full solution (both projects together) -- Run any existing unit tests -- Verify installer includes correct application binaries -- Test installer functionality (basic smoke test) - -**Validation**: -- Solution builds with 0 errors -- All tests pass -- Installer package is created successfully - ---- - -## Execution Constraints - -Based on All-At-Once strategy: - -1. **Single atomic operation** β€” Both projects updated together; full solution validated after changes -2. **No tier ordering** β€” All projects treated as one group -3. **Build-and-fix pass** β€” Single bounded compilation pass; fix all errors at once, not iteratively -4. **Validation** β€” Full solution must build with 0 errors before moving to testing - ---- - -## NuGet Packages - -All existing packages are compatible with .NET 8.0: - -| Package | Current | Target | Projects | -|---------|---------|--------|----------| -| Microsoft.Extensions.Hosting | 10.0.3 | 10.0.3 | Windows-Hinting.csproj | -| Microsoft.Extensions.Hosting.Abstractions | 10.0.3 | 10.0.3 | Windows-Hinting.csproj | - -No package version updates required. - ---- - -## Success Criteria - -- [ ] Windows-Hinting.csproj confirms .NET 8.0-windows targeting -- [ ] Windows-Hinting.Installer.wixproj loads without errors -- [ ] Solution builds successfully with 0 errors -- [ ] Installer package is created and validated -- [ ] All tests pass -- [ ] Working branch contains all upgrade changes - ---- - -## Next Steps - -1. **Review this plan** β€” confirm the approach and tasks -2. **Execute tasks** β€” follow the task-execution workflow -3. **Validate** β€” build and test each change -4. **Complete** β€” merge working branch back to main development branch - ---- - -## Appendix: Project Dependency Graph - -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Windows-Hinting.csproj (net8.0) β”‚ -β”‚ WinForms Application β”‚ -β”‚ - Microsoft.Extensions.Hosting β”‚ -β”‚ - Abstractions (10.0.3) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ - β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Windows-Hinting.Installer.wixproj β”‚ -β”‚ WiX Setup Package β”‚ -β”‚ (References Windows-Hinting.csproj) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - diff --git a/.github/upgrades/scenarios/dotnet-version-upgrade/scenario-instructions.md b/.github/upgrades/scenarios/dotnet-version-upgrade/scenario-instructions.md deleted file mode 100644 index 6ecc718..0000000 --- a/.github/upgrades/scenarios/dotnet-version-upgrade/scenario-instructions.md +++ /dev/null @@ -1,96 +0,0 @@ -# Scenario Instructions - -## Scenario Context -- **Scenario ID**: dotnet-version-upgrade -- **Description**: Upgrade Windows-Hinting and WiX installer project to .NET 8 -- **Target Framework**: .NET 8.0 (net8.0 / net8.0-windows) -- **Date Initialized**: 2024 - ---- - -## Preferences - -### Flow Mode -**Mode**: Automatic - -The agent will run end-to-end, only pausing when: -- Blocked (missing information, conflicting decisions) -- Requiring explicit user input (important choices) -- Critical validation fails - -### Technical Preferences -- **Target Framework**: .NET 8.0 (LTS) -- **Package Update Strategy**: Compatible versions only β€” no breaking changes -- **WiX Toolset**: Installed (v4.0+) - -### Execution Style -- **Commit Strategy**: After Each Task -- **Validation**: Build after each task completion -- **Testing**: Run full solution validation after all changes - ---- - -## Strategy - -**Selected**: All-At-Once - -**Rationale**: -- 2 projects (well under 30 project threshold) -- Main application already on .NET 8.0 -- Clear, straightforward upgrade with no breaking API changes -- All dependencies compatible with target framework -- Modern SDK-style project format - -### Execution Constraints - -1. **Single atomic upgrade** β€” Both Windows-Hinting.csproj and Windows-Hinting.Installer.wixproj updated together -2. **No tier ordering** β€” All projects treated as one group; no phased rollout needed -3. **Build-and-fix pass** β€” Single comprehensive compilation pass; fix all errors at once -4. **Full solution validation** β€” Entire solution must build with 0 errors before testing -5. **Installer verification** β€” Confirm WiX project builds MSI/Bundle successfully after upgrade - ---- - -## Source Control - -- **Repository**: C:\Users\knausj\git\Windows-Hinting (Git) -- **Source Branch**: expiremental-refactor -- **Working Branch**: upgrade-to-NET8 -- **Pending Changes**: Committed before workflow start - ---- - -## Key Decisions Log - -| Date | Decision | Context | -|------|----------|---------| -| 2024 | Install WiX Toolset 4.0 | Required for WiX project analysis and modernization | -| 2024 | Select All-At-Once strategy | Straightforward upgrade, small project count, clear dependencies | -| 2024 | Include WiX installer in upgrade | User preference to modernize both projects together | - ---- - -## Task Execution Notes - -- **Total Tasks**: 2 -- **Task 1**: Update Windows-Hinting.Installer.wixproj for .NET 8 compatibility -- **Task 2**: Verify solution integration and build validation - ---- - -## Known Issues & Notes - -- WiX Toolset must remain installed throughout upgrade -- WiX project references Windows-Hinting.csproj; ensure updatedpaths/references after any file reorganization -- Installer package creation depends on successful Windows-Hinting.csproj build -- No security vulnerabilities detected in dependencies - ---- - -## Related Artifacts - -- `assessment.md` β€” Full project analysis and compatibility assessment -- `plan.md` β€” Detailed upgrade plan with task breakdown -- `tasks.md` β€” Real-time task status and execution tracker -- `execution-log.md` β€” Chronological log of all completed work - diff --git a/.github/upgrades/scenarios/dotnet-version-upgrade/scenario.json b/.github/upgrades/scenarios/dotnet-version-upgrade/scenario.json deleted file mode 100644 index bbd273e..0000000 --- a/.github/upgrades/scenarios/dotnet-version-upgrade/scenario.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "scenarioId": "dotnet-version-upgrade", - "operationId": "dc5fd04c-0745-49f1-b5f3-7c3526acb5f6", - "description": "Upgrade .NET projects to newer .NET versions", - "startTime": "2026-03-15T08:27:12.0435109Z", - "lastUpdateTime": "2026-03-15T08:32:32.2071286Z", - "stage": "Assessment", - "properties": { - "currentTask": "02-verify-solution-integration", - "task:01-update-hintoverlay-installer-wixproj:startedAt": "2026-03-15T08:31:06.2143887Z", - "UpgradeTargetFramework": "net8.0", - "task:02-verify-solution-integration:startedAt": "2026-03-15T08:32:32.2071286Z" - }, - "folderPath": "" -} \ No newline at end of file diff --git a/.github/upgrades/scenarios/dotnet-version-upgrade/tasks.md b/.github/upgrades/scenarios/dotnet-version-upgrade/tasks.md deleted file mode 100644 index fc4884c..0000000 --- a/.github/upgrades/scenarios/dotnet-version-upgrade/tasks.md +++ /dev/null @@ -1,37 +0,0 @@ -# Task Execution Tracker - -**Scenario**: dotnet-version-upgrade -**Strategy**: All-At-Once -**Total Tasks**: 2 - ---- - -## Task 1: Update WiX Installer - -**Status**: βœ… COMPLETE - -### 01-update-Windows-Hinting-installer-wixproj -- Modernize the Windows-Hinting.Installer.wixproj to ensure .NET 8 compatibility and proper project references. -- **Completed**: Updated WiX project to v4.0 format, verified .NET 8 references -- **Files Modified**: Windows-Hinting.Installer/Windows-Hinting.Installer.wixproj - ---- - -## Task 2: Solution Validation - -**Status**: ⏳ IN PROGRESS - -### 02-verify-solution-integration -- Verify both projects build together and the installer package is created successfully. -- **Status**: Ready to execute -- **Depends On**: Task 1 complete βœ… - ---- - -## Execution Progress - -| Task | Status | Files Modified | Notes | -|------|--------|-----------------|-------| -| 01-update-Windows-Hinting-installer-wixproj | βœ… COMPLETE | Windows-Hinting.Installer.wixproj | WiX upgraded to v4.0, build validated | -| 02-verify-solution-integration | ⏳ IN PROGRESS | β€” | Next task | - diff --git a/.github/upgrades/scenarios/dotnet-version-upgrade/tasks/01-update-hintoverlay-installer-wixproj/progress-detail.md b/.github/upgrades/scenarios/dotnet-version-upgrade/tasks/01-update-hintoverlay-installer-wixproj/progress-detail.md deleted file mode 100644 index 120d4a0..0000000 --- a/.github/upgrades/scenarios/dotnet-version-upgrade/tasks/01-update-hintoverlay-installer-wixproj/progress-detail.md +++ /dev/null @@ -1,74 +0,0 @@ -# Progress Detail - Task 01 - -**Task**: Update Windows-Hinting.Installer.wixproj for .NET 8 -**Status**: βœ… COMPLETED -**Date**: 2024 - ---- - -## Summary of Changes - -Successfully modernized the WiX installer project from WiX 3.x to WiX 4.0 format with .NET 8 compatibility. - ---- - -## Files Modified - -### 1. Windows-Hinting.Installer/Windows-Hinting.Installer.wixproj -**Changes**: -- Line 6: Updated `3.14` β†’ `4.0` -- Line 35: Updated `` β†’ `` -- Added new property: `net8.0` (line 10) - -**Rationale**: -- WiX 4.0 uses `wix.targets` instead of `Wix2010.targets` -- ProductVersion updated to reflect toolset version -- Added explicit .NET 8 target framework version for clarity - -### 2. Windows-Hinting.Installer/Product.wxs -**Status**: No changes needed βœ… -- Already correctly configured to reference .NET 8 output path -- Binary reference: `Source="..\bin\Release\net8.0-windows\Windows-Hinting.exe"` - ---- - -## Build Results - -**Build Command**: `dotnet build` - -**Output**: -``` -Build successful -``` - -**Details**: -- βœ… Windows-Hinting.csproj compiled as net8.0-windows -- βœ… Windows-Hinting.Installer.wixproj compiled with WiX 4.0 targets -- βœ… No build warnings or errors -- βœ… Installer package files generated successfully - ---- - -## Validation Checklist - -- βœ… WiX project loads without errors (tested via build) -- βœ… Project references are correct (Windows-Hinting.csproj β†’ .NET 8 binaries) -- βœ… Product.wxs paths match .NET 8 output structure -- βœ… Solution builds cleanly with both projects -- βœ… No dependency conflicts detected - ---- - -## Key Findings - -1. **Main Application**: Already on .NET 8 (net8.0-windows) -2. **WiX Project**: Successfully upgraded to use WiX 4.0 imports -3. **Package Paths**: Correctly aligned with .NET 8 output directory structure -4. **No Breaking Changes**: All references are compatible - ---- - -## Next Steps - -Task 2: Verify solution integration and run full validation tests. - diff --git a/.github/upgrades/scenarios/dotnet-version-upgrade/tasks/01-update-hintoverlay-installer-wixproj/task.md b/.github/upgrades/scenarios/dotnet-version-upgrade/tasks/01-update-hintoverlay-installer-wixproj/task.md deleted file mode 100644 index 10c90e9..0000000 --- a/.github/upgrades/scenarios/dotnet-version-upgrade/tasks/01-update-hintoverlay-installer-wixproj/task.md +++ /dev/null @@ -1,63 +0,0 @@ -# 01-update-Windows-Hinting-installer-wixproj: Update Windows-Hinting.Installer.wixproj - -**Objective**: Modernize the WiX installer project to target .NET 8 and ensure it properly references the upgraded main application. - -**Target Framework**: .NET 8.0 (net8.0-windows) - -**Status**: βœ… COMPLETED - ---- - -## Changes Made - -### 1. Updated WiX Project File (Windows-Hinting.Installer.wixproj) - -**Changes:** -- **ProductVersion**: Updated from 3.14 β†’ 4.0 (aligns with installed WiX Toolset v4.0) -- **WiX Import**: Changed from `Wix2010.targets` β†’ `wix.targets` (WiX 4.0 standard) -- **Added**: `net8.0` (metadata for .NET 8 compatibility) - -### 2. Verified Product.wxs - -**Status**: βœ… Already correct -- Binary path correctly references `net8.0-windows` output: - - `Source="..\bin\Release\net8.0-windows\Windows-Hinting.exe"` -- No changes needed β€” already optimized for .NET 8 - -### 3. Verified ProjectReference - -**Status**: βœ… Correct -- WiX project correctly references main app: `Include="..\Windows-Hinting.csproj"` -- Will pull .NET 8 binaries at build time - ---- - -## Build Validation - -βœ… **Solution Build**: Successful -- Windows-Hinting.csproj: Built as net8.0-windows -- Windows-Hinting.Installer.wixproj: Built successfully with WiX 4.0 -- No errors or warnings - ---- - -## What Was Accomplished - -βœ… WiX installer project upgraded to WiX 4.0 format -βœ… Project references .NET 8 binaries correctly -βœ… Build completed without errors -βœ… Installer configuration ready for .NET 8 - ---- - -## Scope**: -- Verify WiX project target framework compatibility -- Update WiX project references/imports if needed -- Ensure installer references the correct .NET 8 output from Windows-Hinting.csproj -- Validate WiX project builds successfully -- Confirm installer creation completes without errors - -**Validation**: -- WiX project loads without errors in Visual Studio -- Solution builds cleanly -- Installer (MSI/Bundle) builds successfully diff --git a/.github/upgrades/scenarios/dotnet-version-upgrade/tasks/02-verify-solution-integration/task.md b/.github/upgrades/scenarios/dotnet-version-upgrade/tasks/02-verify-solution-integration/task.md deleted file mode 100644 index 29b12e7..0000000 --- a/.github/upgrades/scenarios/dotnet-version-upgrade/tasks/02-verify-solution-integration/task.md +++ /dev/null @@ -1,14 +0,0 @@ -# 02-verify-solution-integration: Verify Solution Integration - -**Objective**: Ensure both projects build and package correctly as a unified solution. - -**Scope**: -- Build full solution (both projects together) -- Run any existing unit tests -- Verify installer includes correct application binaries -- Test installer functionality (basic smoke test) - -**Validation**: -- Solution builds with 0 errors -- All tests pass -- Installer package is created successfully diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 48053f8..ca7e723 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -51,4 +51,4 @@ Update the `DOTNET_VERSION` environment variable in each workflow file. Add additional steps in the respective jobs as needed for your deployment process. ### Modify Build Configuration -Update the `BUILD_CONFIGURATION` environment variable to change between Debug/Release builds. \ No newline at end of file +Update the `BUILD_CONFIGURATION` environment variable to change between Debug/Release builds. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index abd3c72..02bb0f8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,12 +7,53 @@ on: branches: [ "**" ] workflow_dispatch: +permissions: + contents: write + env: BUILD_VERSION: 0.1.${{ github.run_number }} +defaults: + run: + shell: pwsh + jobs: + lint: + name: Pre-commit Lint + runs-on: windows-latest + + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + ref: ${{ github.head_ref || github.ref_name }} + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '8.0.x' + + - name: Install PSScriptAnalyzer + run: Install-Module -Name PSScriptAnalyzer -Force -Scope CurrentUser + + - name: Run pre-commit + uses: pre-commit/action@v3.0.1 + + - name: Auto-fix and commit + if: failure() && github.event_name == 'pull_request' + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "style: auto-fix pre-commit hook violations" + build-debug: name: Debug Build + needs: lint runs-on: windows-latest steps: @@ -34,7 +75,6 @@ jobs: run: build\build-complete.bat Debug --exe-only - name: Clean Debug output - shell: pwsh run: | $outDir = "Windows-Hinting\bin\Debug\net8.0-windows" Remove-Item "$outDir\xunit.*" -Force -ErrorAction SilentlyContinue @@ -48,6 +88,7 @@ jobs: build-release: name: Release Build + MSI + needs: lint runs-on: windows-latest steps: @@ -70,7 +111,6 @@ jobs: run: dotnet restore Windows-Hinting\Windows-Hinting.csproj - name: Decode signing certificate - shell: pwsh env: CERT_BASE64: ${{ secrets.SIGNING_CERT_BASE64 }} run: | @@ -84,7 +124,6 @@ jobs: } - name: Build Release + MSI - shell: pwsh env: CERT_PASSWORD: ${{ secrets.SIGNING_CERT_PASSWORD }} run: | @@ -102,7 +141,6 @@ jobs: - name: Clean up signing certificate if: always() - shell: pwsh run: | if ($env:CERT_PATH -and (Test-Path $env:CERT_PATH)) { Remove-Item $env:CERT_PATH -Force @@ -110,7 +148,6 @@ jobs: } - name: Verify exe signature - shell: pwsh run: | $exePath = "Windows-Hinting\bin\Release\net8.0-windows\Windows-Hinting.exe" Write-Host "--- Signature verification ---" @@ -149,8 +186,6 @@ jobs: needs: [build-debug, build-release] # Only publish a release on direct pushes to main β€” not PRs or other branches if: github.ref == 'refs/heads/main' && github.event_name == 'push' - permissions: - contents: write steps: - name: Download Debug build diff --git a/.gitignore b/.gitignore index 815afc4..f23790a 100644 --- a/.gitignore +++ b/.gitignore @@ -398,6 +398,16 @@ MSBuild_Logs/ # BeatPulse healthcheck temp database healthchecksdb +# WiX Toolset +*.msi +*.msm +*.msp +*.wixpdb +*.wixobj + +# .NET Upgrade Assistant / Copilot modernization working files +.github/upgrades/ + # Backup folder for Package Reference Convert tool in Visual Studio 2017 MigrationBackup/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..d04d9a3 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,34 @@ +repos: + # General hygiene hooks + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-xml + - id: check-merge-conflict + - id: check-added-large-files + args: ['--maxkb=500'] + - id: mixed-line-ending + args: ['--fix=crlf'] + + # C# formatting via dotnet format + - repo: local + hooks: + - id: dotnet-format + name: dotnet format + entry: dotnet format --include + language: system + types_or: [c#] + pass_filenames: true + + # PowerShell linting via PSScriptAnalyzer + - repo: local + hooks: + - id: psscriptanalyzer + name: PSScriptAnalyzer + entry: pwsh -NoProfile -Command "$settings = Join-Path $PWD 'build/PSScriptAnalyzerSettings.psd1'; Get-ChildItem -Filter *.ps1 -Recurse build/ | ForEach-Object { Invoke-ScriptAnalyzer -Path $_.FullName -Fix -Settings $settings -Severity Warning,Error | Out-Null; $results = Invoke-ScriptAnalyzer -Path $_.FullName -Settings $settings -Severity Warning,Error; if ($results) { $results | Format-Table -AutoSize; $global:failed = $true } }; if ($global:failed) { exit 1 }" + language: system + files: '\.ps1$' + pass_filenames: false diff --git a/README.md b/README.md index f417c17..28eebb7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Windows Hinting -Initial prototype of a fast hinting program for windows +Initial prototype of a fast hinting program for windows Ctrl + T -> Toggles hints on taskbar diff --git a/Windows-Hinting.Installer/FIX_SUMMARY.md b/Windows-Hinting.Installer/FIX_SUMMARY.md index 7c7c3ad..68e20e0 100644 --- a/Windows-Hinting.Installer/FIX_SUMMARY.md +++ b/Windows-Hinting.Installer/FIX_SUMMARY.md @@ -6,7 +6,7 @@ **Root Cause**: The WiX configuration was using `$(var.Windows_Hinting.TargetPath)` which pointed to the DLL output instead of the EXE, and dependencies were not being bundled. -**Solution**: +**Solution**: 1. Changed file reference from `$(var.Windows_Hinting.TargetPath)` to `$(var.Windows_Hinting.TargetDir)Windows-Hinting.exe` 2. Added Windows-Hinting.dll, configuration files, and all .NET runtime dependencies 3. Properly configured components with explicit GUIDs for multiple-file components @@ -46,7 +46,7 @@ - Added RuntimeRegistry component for dependency tracking - Assigned explicit GUIDs for proper component handling -### Package.wxs +### Package.wxs - Added ComponentRef for DotNetRuntimeLibraries - Added ComponentRef for RuntimeRegistry - Ensures all components are included in the Feature diff --git a/Windows-Hinting.Installer/INSTALLATION_GUIDE.md b/Windows-Hinting.Installer/INSTALLATION_GUIDE.md index 18fa88e..ab9c138 100644 --- a/Windows-Hinting.Installer/INSTALLATION_GUIDE.md +++ b/Windows-Hinting.Installer/INSTALLATION_GUIDE.md @@ -18,7 +18,7 @@ The Windows-Hinting.Installer project has been successfully configured and built **Shortcuts Created**: - βœ… Desktop shortcut: "Windows-Hinting" -- βœ… Start Menu folder: "Windows-Hinting" +- βœ… Start Menu folder: "Windows-Hinting" - βœ… Start Menu shortcut: "Windows-Hinting" ### Registry Configuration diff --git a/Windows-Hinting.Installer/QUICK_START.md b/Windows-Hinting.Installer/QUICK_START.md index 48bf353..aeaa8b1 100644 --- a/Windows-Hinting.Installer/QUICK_START.md +++ b/Windows-Hinting.Installer/QUICK_START.md @@ -70,7 +70,7 @@ signtool verify /pa bin\Release\net8.0-windows\Windows-Hinting.exe Windows-Hinting.Installer/ β”œβ”€β”€ Package.wxs # Main installer definition β”œβ”€β”€ ExampleComponents.wxs # Application files & shortcuts -β”œβ”€β”€ UI.wxs # Installer UI configuration +β”œβ”€β”€ UI.wxs # Installer UI configuration β”œβ”€β”€ Folders.wxs # Directory structure β”œβ”€β”€ License.rtf # EULA displayed to users β”œβ”€β”€ INSTALLATION_GUIDE.md # Detailed setup guide diff --git a/Windows-Hinting.Installer/RUNTIMES_FOLDER_FIX.md b/Windows-Hinting.Installer/RUNTIMES_FOLDER_FIX.md index 8c3745c..b193d99 100644 --- a/Windows-Hinting.Installer/RUNTIMES_FOLDER_FIX.md +++ b/Windows-Hinting.Installer/RUNTIMES_FOLDER_FIX.md @@ -15,7 +15,7 @@ - βœ… `System.Diagnostics.EventLog.dll` (native interop for Windows Event Log) - βœ… `System.Diagnostics.EventLog.Messages.dll` (localized messages for Event Log) -### Browser/WASM Runtime Files +### Browser/WASM Runtime Files **Location**: `runtimes\browser\lib\net8.0\` - βœ… `System.Text.Encodings.Web.dll` (WebAssembly optimized version) @@ -35,7 +35,7 @@ Added two new components in the DirectoryRef section: ```xml - diff --git a/Windows-Hinting.Installer/UIACCESS_SETUP.md b/Windows-Hinting.Installer/UIACCESS_SETUP.md index f81379d..df7b114 100644 --- a/Windows-Hinting.Installer/UIACCESS_SETUP.md +++ b/Windows-Hinting.Installer/UIACCESS_SETUP.md @@ -121,7 +121,7 @@ Get-ItemProperty -Path "HKLM:\Software\Windows-Hinting\Windows-Hinting" #### "Access is denied" when accessing privileged UI - **Cause**: UIAccess may be disabled or not working properly -- **Check**: +- **Check**: - Verify executable is signed: `signtool verify /pa Windows-Hinting.exe` - Check Event Viewer (System) for code integrity warnings - Verify manifest is embedded: `ExifTool.exe -ALL Windows-Hinting.exe | grep -i manifest` diff --git a/Windows-Hinting.Installer/Windows-Hinting.Installer.wixproj b/Windows-Hinting.Installer/Windows-Hinting.Installer.wixproj index bc872a6..59091fb 100644 --- a/Windows-Hinting.Installer/Windows-Hinting.Installer.wixproj +++ b/Windows-Hinting.Installer/Windows-Hinting.Installer.wixproj @@ -27,7 +27,6 @@ - - \ No newline at end of file + diff --git a/Windows-Hinting.sln b/Windows-Hinting.sln index 080fb02..798367a 100644 --- a/Windows-Hinting.sln +++ b/Windows-Hinting.sln @@ -27,6 +27,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{A1B2 .github\workflows\README.md = .github\workflows\README.md EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "config", "config", "{C1D2E3F4-5678-9ABC-DEF0-ABCDEF123456}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + .gitignore = .gitignore + .pre-commit-config.yaml = .pre-commit-config.yaml + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/Windows-Hinting/Configuration/HintOverlaySettings.cs b/Windows-Hinting/Configuration/HintOverlaySettings.cs index 924bf9a..22e2acf 100644 --- a/Windows-Hinting/Configuration/HintOverlaySettings.cs +++ b/Windows-Hinting/Configuration/HintOverlaySettings.cs @@ -3,8 +3,8 @@ namespace WindowsHinting.Configuration internal sealed class HintOverlaySettings { public const string SectionName = "Windows-Hinting"; - + public string LogLevel { get; set; } = "Debug"; public bool EnablePerformanceMetrics { get; set; } = true; } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Forms/OverlayForm.cs b/Windows-Hinting/Forms/OverlayForm.cs index a399559..ef941a5 100644 --- a/Windows-Hinting/Forms/OverlayForm.cs +++ b/Windows-Hinting/Forms/OverlayForm.cs @@ -218,7 +218,7 @@ protected override void OnPaint(PaintEventArgs e) private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); private static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2); - + private const uint SWP_NOSIZE = 0x0001; private const uint SWP_NOMOVE = 0x0002; private const uint SWP_NOACTIVATE = 0x0010; @@ -256,7 +256,7 @@ protected override CreateParams CreateParams return cp; } } - + protected override void OnShown(EventArgs e) { base.OnShown(e); diff --git a/Windows-Hinting/Forms/OverlayForm.resx b/Windows-Hinting/Forms/OverlayForm.resx index 1af7de1..58a9e20 100644 --- a/Windows-Hinting/Forms/OverlayForm.resx +++ b/Windows-Hinting/Forms/OverlayForm.resx @@ -1,17 +1,17 @@ ο»Ώ - @@ -117,4 +117,4 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - \ No newline at end of file + diff --git a/Windows-Hinting/HintController.cs b/Windows-Hinting/HintController.cs index 22846cd..d8799f4 100644 --- a/Windows-Hinting/HintController.cs +++ b/Windows-Hinting/HintController.cs @@ -1,4 +1,4 @@ -ο»Ώusing System; +using System; using System.Diagnostics; using System.Linq; using System.Windows.Forms; @@ -162,7 +162,7 @@ private void SelectHintByLabel(string label, ClickAction action = ClickAction.De { _logger.Info($"Attempting to select hint with label: {label}, action: {action}"); - var hint = _stateManager.CurrentHints.FirstOrDefault(h => + var hint = _stateManager.CurrentHints.FirstOrDefault(h => h.Label.Equals(label, StringComparison.OrdinalIgnoreCase)); if (hint == null) @@ -288,18 +288,18 @@ private void ScanForHints() _stateManager.Deactivate(); return; } - + _logger.Debug($"Scanning window: {hwnd}"); - + // Ensure overlay is topmost before scanning _overlay.EnsureTopmost(); - + var elements = PerformanceMetricsExtensions.MeasureExecution( "FindClickableElements", () => _uiaService.FindClickableElements(hwnd), _logger, LogLevel.Info); - + _logger.Info($"Found {elements.Count} clickable elements"); if (elements.Count == 0) @@ -343,7 +343,7 @@ private void ScanForHints() }).ToList(), _logger, LogLevel.Debug); - + _logger.Debug($"Created {hints.Count} hint items"); _stateManager.SetHints(hints); } @@ -505,15 +505,15 @@ private bool CheckModifiersMatch(int expectedWin32Mods, KeyModifiers actualMods) const int MOD_CONTROL = 0x0002; const int MOD_ALT = 0x0001; const int MOD_SHIFT = 0x0004; - + bool expectCtrl = (expectedWin32Mods & MOD_CONTROL) != 0; bool expectAlt = (expectedWin32Mods & MOD_ALT) != 0; bool expectShift = (expectedWin32Mods & MOD_SHIFT) != 0; - + bool hasCtrl = (actualMods & KeyModifiers.Control) != 0; bool hasAlt = (actualMods & KeyModifiers.Alt) != 0; bool hasShift = (actualMods & KeyModifiers.Shift) != 0; - + return expectCtrl == hasCtrl && expectAlt == hasAlt && expectShift == hasShift; } diff --git a/Windows-Hinting/Logging/DebugLogger.cs b/Windows-Hinting/Logging/DebugLogger.cs index 9df3e9f..c21cd05 100644 --- a/Windows-Hinting/Logging/DebugLogger.cs +++ b/Windows-Hinting/Logging/DebugLogger.cs @@ -138,4 +138,4 @@ public void Dispose() CloseLogFile(); } } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Logging/ILogger.cs b/Windows-Hinting/Logging/ILogger.cs index 3516f95..34cd929 100644 --- a/Windows-Hinting/Logging/ILogger.cs +++ b/Windows-Hinting/Logging/ILogger.cs @@ -11,4 +11,4 @@ public interface ILogger void Warning(string message, [CallerMemberName] string memberName = "", [CallerFilePath] string filePath = ""); void Error(string message, Exception? ex = null, [CallerMemberName] string memberName = "", [CallerFilePath] string filePath = ""); } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Logging/LogLevel.cs b/Windows-Hinting/Logging/LogLevel.cs index dfcf64c..2424034 100644 --- a/Windows-Hinting/Logging/LogLevel.cs +++ b/Windows-Hinting/Logging/LogLevel.cs @@ -7,4 +7,4 @@ public enum LogLevel Warning = 2, Error = 3 } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Models/HintOverlayOptions.cs b/Windows-Hinting/Models/HintOverlayOptions.cs index 0d415e7..12e685c 100644 --- a/Windows-Hinting/Models/HintOverlayOptions.cs +++ b/Windows-Hinting/Models/HintOverlayOptions.cs @@ -40,7 +40,7 @@ internal sealed class ClickActionShortcutOptions public int DoubleClickKey { get; set; } = 0x44; // D key public int MouseMoveKey { get; set; } = 0x4D; // M key } - + internal sealed class AnimationOptions { public int FadeDurationMs { get; set; } = 150; @@ -69,4 +69,4 @@ internal enum HintPosition LowerCenter, LowerRight } -} \ No newline at end of file +} diff --git a/Windows-Hinting/NativeInterop/KeyboardHook.cs b/Windows-Hinting/NativeInterop/KeyboardHook.cs index c4fb8e2..f65a98a 100644 --- a/Windows-Hinting/NativeInterop/KeyboardHook.cs +++ b/Windows-Hinting/NativeInterop/KeyboardHook.cs @@ -1,4 +1,4 @@ -ο»Ώusing System; +using System; using System.Runtime.InteropServices; using WindowsHinting.Models; using WindowsHinting.Services; @@ -11,32 +11,32 @@ internal sealed class KeyboardHook : IDisposable private IntPtr _hookHandle; private readonly NativeMethods.LowLevelKeyboardProc _hookProc; private bool _disposed; - + public event EventHandler? KeyPressed; public event EventHandler? KeyReleased; - + public KeyboardHook() { _hookProc = HookCallback; } - + public void Install() { if (_hookHandle != IntPtr.Zero) return; - + _hookHandle = NativeMethods.SetWindowsHookEx( - WindowsConstants.WH_KEYBOARD_LL, - _hookProc, - NativeMethods.GetModuleHandle(null), + WindowsConstants.WH_KEYBOARD_LL, + _hookProc, + NativeMethods.GetModuleHandle(null), 0); - + if (_hookHandle == IntPtr.Zero) { throw new InvalidOperationException("Failed to install keyboard hook"); } } - + public void Uninstall() { if (_hookHandle != IntPtr.Zero) @@ -45,18 +45,18 @@ public void Uninstall() _hookHandle = IntPtr.Zero; } } - + private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) { if (nCode >= 0) { int vkCode = Marshal.ReadInt32(lParam); - - bool isKeyDown = wParam == (IntPtr)WindowsConstants.WM_KEYDOWN || + + bool isKeyDown = wParam == (IntPtr)WindowsConstants.WM_KEYDOWN || wParam == (IntPtr)WindowsConstants.WM_SYSKEYDOWN; - bool isKeyUp = wParam == (IntPtr)WindowsConstants.WM_KEYUP || + bool isKeyUp = wParam == (IntPtr)WindowsConstants.WM_KEYUP || wParam == (IntPtr)WindowsConstants.WM_SYSKEYUP; - + if (isKeyDown || isKeyUp) { var modifiers = GetCurrentModifiers(); @@ -66,45 +66,45 @@ private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) Modifiers = modifiers, Handled = false }; - + if (isKeyDown) KeyPressed?.Invoke(this, args); else KeyReleased?.Invoke(this, args); - + if (args.Handled) return (IntPtr)1; // Suppress the key } } - + return NativeMethods.CallNextHookEx(_hookHandle, nCode, wParam, lParam); } - + private KeyModifiers GetCurrentModifiers() { var mods = KeyModifiers.None; - + if ((NativeMethods.GetAsyncKeyState(WindowsConstants.VK_CONTROL) & WindowsConstants.KEY_PRESSED) != 0) mods |= KeyModifiers.Control; - + if ((NativeMethods.GetAsyncKeyState(WindowsConstants.VK_MENU) & WindowsConstants.KEY_PRESSED) != 0) mods |= KeyModifiers.Alt; - + if ((NativeMethods.GetAsyncKeyState(WindowsConstants.VK_SHIFT) & WindowsConstants.KEY_PRESSED) != 0) mods |= KeyModifiers.Shift; - + if ((NativeMethods.GetAsyncKeyState(WindowsConstants.VK_LWIN) & WindowsConstants.KEY_PRESSED) != 0 || (NativeMethods.GetAsyncKeyState(WindowsConstants.VK_RWIN) & WindowsConstants.KEY_PRESSED) != 0) mods |= KeyModifiers.Win; - + return mods; } - + public void Dispose() { if (_disposed) return; - + Uninstall(); _disposed = true; } diff --git a/Windows-Hinting/NativeInterop/UIAutomationWrapper.cs b/Windows-Hinting/NativeInterop/UIAutomationWrapper.cs index a4a1361..0502cfb 100644 --- a/Windows-Hinting/NativeInterop/UIAutomationWrapper.cs +++ b/Windows-Hinting/NativeInterop/UIAutomationWrapper.cs @@ -20,11 +20,11 @@ public void Dispose() Marshal.ReleaseComObject(_automation); } } - + public IEnumerable FindClickableElements(IntPtr windowHandle) { var results = new List(); - + try { var rootElement = _automation.ElementFromHandle(windowHandle); @@ -35,9 +35,9 @@ public IEnumerable FindClickableElements(IntPtr windowHandle) var condition = _automation.CreateTrueCondition(); var walker = _automation.CreateTreeWalker(condition); - + TraverseElements(rootElement, walker, results); - + Marshal.ReleaseComObject(rootElement); Marshal.ReleaseComObject(condition); Marshal.ReleaseComObject(walker); @@ -90,6 +90,6 @@ private void TraverseElements(IUIAutomationElement element, IUIAutomationTreeWal } } } - + internal record ClickableElement(Rectangle Bounds, IUIAutomationElement Element); -} \ No newline at end of file +} diff --git a/Windows-Hinting/Preferences/Preferences.cs b/Windows-Hinting/Preferences/Preferences.cs index 0376219..3d58b2b 100644 --- a/Windows-Hinting/Preferences/Preferences.cs +++ b/Windows-Hinting/Preferences/Preferences.cs @@ -44,4 +44,4 @@ public void Save() catch { } } } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Preferences/PreferencesDialog.cs b/Windows-Hinting/Preferences/PreferencesDialog.cs index 3a36ac0..59b6565 100644 --- a/Windows-Hinting/Preferences/PreferencesDialog.cs +++ b/Windows-Hinting/Preferences/PreferencesDialog.cs @@ -608,4 +608,4 @@ private void BtnOk_Click(object? sender, EventArgs e) prefsService.Save(_options); } } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Program.cs b/Windows-Hinting/Program.cs index 22f38ff..fb73392 100644 --- a/Windows-Hinting/Program.cs +++ b/Windows-Hinting/Program.cs @@ -13,20 +13,20 @@ static void Main() Application.SetHighDpiMode(HighDpiMode.SystemAware); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); - + var host = Host.CreateDefaultBuilder() .ConfigureServices((context, services) => { services.AddHintOverlayServices(); }) .Build(); - + using (var scope = host.Services.CreateScope()) { var controller = scope.ServiceProvider.GetRequiredService(); Application.Run(); } - + host.Dispose(); } } diff --git a/Windows-Hinting/ServiceCollectionExtensions.cs b/Windows-Hinting/ServiceCollectionExtensions.cs index 292ecd9..5f6c2b1 100644 --- a/Windows-Hinting/ServiceCollectionExtensions.cs +++ b/Windows-Hinting/ServiceCollectionExtensions.cs @@ -11,9 +11,9 @@ internal static class ServiceCollectionExtensions public static IServiceCollection AddHintOverlayServices(this IServiceCollection services) { // Logging - services.AddSingleton(sp => new DebugLogger - { - MinimumLevel = LogLevel.Info + services.AddSingleton(sp => new DebugLogger + { + MinimumLevel = LogLevel.Info }); // Configuration @@ -29,15 +29,15 @@ public static IServiceCollection AddHintOverlayServices(this IServiceCollection services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - + // UI Components services.AddSingleton(); services.AddSingleton(); - + // Application Controller services.AddSingleton(); - + return services; } } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Services/ElementActivatorChain.cs b/Windows-Hinting/Services/ElementActivatorChain.cs index 5411267..5c8d98c 100644 --- a/Windows-Hinting/Services/ElementActivatorChain.cs +++ b/Windows-Hinting/Services/ElementActivatorChain.cs @@ -36,7 +36,7 @@ public bool TryActivate(IUIAutomationElement element) return true; } } - + _logger.Warning("No interaction pattern succeeded for element"); return false; } @@ -65,4 +65,4 @@ private void LogCachedPatterns(IUIAutomationElement element) } } } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Services/ElementActivators/ExpandCollapsePatternActivator.cs b/Windows-Hinting/Services/ElementActivators/ExpandCollapsePatternActivator.cs index d8eb0ba..559ac59 100644 --- a/Windows-Hinting/Services/ElementActivators/ExpandCollapsePatternActivator.cs +++ b/Windows-Hinting/Services/ElementActivators/ExpandCollapsePatternActivator.cs @@ -49,4 +49,4 @@ public bool TryActivate(IUIAutomationElement element) return false; } } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Services/ElementActivators/InvokePatternActivator.cs b/Windows-Hinting/Services/ElementActivators/InvokePatternActivator.cs index a428612..82fa191 100644 --- a/Windows-Hinting/Services/ElementActivators/InvokePatternActivator.cs +++ b/Windows-Hinting/Services/ElementActivators/InvokePatternActivator.cs @@ -20,7 +20,7 @@ public bool TryActivate(IUIAutomationElement element) IUIAutomationInvokePattern? pattern = null; bool isAvailable = element.GetCachedPropertyValue(UIA_PropertyIds.UIA_IsInvokePatternAvailablePropertyId); - if (isAvailable) + if (isAvailable) { try { @@ -44,8 +44,8 @@ public bool TryActivate(IUIAutomationElement element) } } } - + return false; } } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Services/ElementActivators/SelectionItemPatternActivator.cs b/Windows-Hinting/Services/ElementActivators/SelectionItemPatternActivator.cs index ef5e284..d87fc9a 100644 --- a/Windows-Hinting/Services/ElementActivators/SelectionItemPatternActivator.cs +++ b/Windows-Hinting/Services/ElementActivators/SelectionItemPatternActivator.cs @@ -48,4 +48,4 @@ public bool TryActivate(IUIAutomationElement element) return false; } } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Services/ElementActivators/SetFocusActivator.cs b/Windows-Hinting/Services/ElementActivators/SetFocusActivator.cs index d183e19..0a0474c 100644 --- a/Windows-Hinting/Services/ElementActivators/SetFocusActivator.cs +++ b/Windows-Hinting/Services/ElementActivators/SetFocusActivator.cs @@ -35,4 +35,4 @@ public bool TryActivate(IUIAutomationElement element) return false; } } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Services/ElementActivators/TogglePatternActivator.cs b/Windows-Hinting/Services/ElementActivators/TogglePatternActivator.cs index c4463a7..d351054 100644 --- a/Windows-Hinting/Services/ElementActivators/TogglePatternActivator.cs +++ b/Windows-Hinting/Services/ElementActivators/TogglePatternActivator.cs @@ -49,4 +49,4 @@ public bool TryActivate(IUIAutomationElement element) return false; } } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Services/HintInputHandler.cs b/Windows-Hinting/Services/HintInputHandler.cs index 64103e3..d6b0646 100644 --- a/Windows-Hinting/Services/HintInputHandler.cs +++ b/Windows-Hinting/Services/HintInputHandler.cs @@ -141,4 +141,4 @@ private void ToggleAction(ClickAction action) _stateManager.SetPendingAction(action); } } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Services/HintState.cs b/Windows-Hinting/Services/HintState.cs index d1d0c55..1297474 100644 --- a/Windows-Hinting/Services/HintState.cs +++ b/Windows-Hinting/Services/HintState.cs @@ -45,7 +45,7 @@ public void SetPendingAction(ClickAction action) ClickActionChanged?.Invoke(this, action); } } - + public void Activate(HintSource source = HintSource.ForegroundWindow) { if (_mode == HintMode.Inactive) @@ -68,7 +68,7 @@ public void Deactivate() HintsChanged?.Invoke(this, _currentHints); } } - + public void SetHints(IReadOnlyList hints) { _currentHints = hints.ToList(); @@ -78,14 +78,14 @@ public void SetHints(IReadOnlyList hints) } HintsChanged?.Invoke(this, _currentHints); } - + public void AppendToFilter(char c) { _filterText += c; UpdateHintOpacity(); FilterChanged?.Invoke(this, _filterText); } - + public void RemoveLastFilterChar() { if (_filterText.Length > 0) @@ -95,7 +95,7 @@ public void RemoveLastFilterChar() FilterChanged?.Invoke(this, _filterText); } } - + public void ClearFilter() { if (_filterText.Length > 0) @@ -105,22 +105,22 @@ public void ClearFilter() FilterChanged?.Invoke(this, _filterText); } } - + public HintItem? GetExactMatch() { if (string.IsNullOrEmpty(_filterText)) return null; - + return _currentHints.FirstOrDefault(h => h.Label.Equals(_filterText, StringComparison.OrdinalIgnoreCase)); } - + public bool HasMatchingHint(string text) { return _currentHints.Any(h => h.Label.StartsWith(text, StringComparison.OrdinalIgnoreCase)); } - + private void UpdateHintOpacity() { foreach (var hint in _currentHints) @@ -131,7 +131,7 @@ private void UpdateHintOpacity() } HintsChanged?.Invoke(this, _currentHints); } - + private void SetMode(HintMode mode) { if (_mode != mode) @@ -141,4 +141,4 @@ private void SetMode(HintMode mode) } } } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Services/IElementActivator.cs b/Windows-Hinting/Services/IElementActivator.cs index 254bdff..aa630d2 100644 --- a/Windows-Hinting/Services/IElementActivator.cs +++ b/Windows-Hinting/Services/IElementActivator.cs @@ -6,4 +6,4 @@ public interface IElementActivator { bool TryActivate(IUIAutomationElement element); } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Services/IUIAutomationService.cs b/Windows-Hinting/Services/IUIAutomationService.cs index acb2456..d4aabef 100644 --- a/Windows-Hinting/Services/IUIAutomationService.cs +++ b/Windows-Hinting/Services/IUIAutomationService.cs @@ -18,7 +18,7 @@ public class ClickableElement public IUIAutomationElement Element { get; set; } = null!; public Rectangle Bounds { get; set; } } - + internal interface IKeyboardHookService { event EventHandler? KeyPressed; @@ -27,7 +27,7 @@ internal interface IKeyboardHookService void Stop(); bool IsActive { get; } } - + internal interface IPreferencesService { HintOverlayOptions Load(); @@ -40,4 +40,4 @@ internal sealed class KeyboardEventArgs : EventArgs public KeyModifiers Modifiers { get; init; } public bool Handled { get; set; } } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Services/IWindowManager.cs b/Windows-Hinting/Services/IWindowManager.cs index fc2253d..8ef63b8 100644 --- a/Windows-Hinting/Services/IWindowManager.cs +++ b/Windows-Hinting/Services/IWindowManager.cs @@ -8,4 +8,4 @@ public interface IWindowManager IntPtr GetTaskbarWindow(); bool IsWindowValid(IntPtr hwnd); } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Services/MouseClickService.cs b/Windows-Hinting/Services/MouseClickService.cs index 26adfd4..2aa86db 100644 --- a/Windows-Hinting/Services/MouseClickService.cs +++ b/Windows-Hinting/Services/MouseClickService.cs @@ -35,30 +35,30 @@ public bool PerformClick(Rectangle elementBounds, ClickAction action) Thread.Sleep(10); switch (action) - { - case ClickAction.Default: - case ClickAction.LeftClick: - SendClick(WindowsConstants.MOUSEEVENTF_LEFTDOWN, WindowsConstants.MOUSEEVENTF_LEFTUP); - break; - - case ClickAction.RightClick: - SendClick(WindowsConstants.MOUSEEVENTF_RIGHTDOWN, WindowsConstants.MOUSEEVENTF_RIGHTUP); - break; - - case ClickAction.DoubleClick: - SendClick(WindowsConstants.MOUSEEVENTF_LEFTDOWN, WindowsConstants.MOUSEEVENTF_LEFTUP); - Thread.Sleep(30); - SendClick(WindowsConstants.MOUSEEVENTF_LEFTDOWN, WindowsConstants.MOUSEEVENTF_LEFTUP); - break; - - case ClickAction.MouseMove: - SendMove(x, y); - break; - - default: - _logger.Warning($"Unsupported click action: {action}"); - return false; - } + { + case ClickAction.Default: + case ClickAction.LeftClick: + SendClick(WindowsConstants.MOUSEEVENTF_LEFTDOWN, WindowsConstants.MOUSEEVENTF_LEFTUP); + break; + + case ClickAction.RightClick: + SendClick(WindowsConstants.MOUSEEVENTF_RIGHTDOWN, WindowsConstants.MOUSEEVENTF_RIGHTUP); + break; + + case ClickAction.DoubleClick: + SendClick(WindowsConstants.MOUSEEVENTF_LEFTDOWN, WindowsConstants.MOUSEEVENTF_LEFTUP); + Thread.Sleep(30); + SendClick(WindowsConstants.MOUSEEVENTF_LEFTDOWN, WindowsConstants.MOUSEEVENTF_LEFTUP); + break; + + case ClickAction.MouseMove: + SendMove(x, y); + break; + + default: + _logger.Warning($"Unsupported click action: {action}"); + return false; + } _logger.Info($"{action} performed successfully at ({x}, {y})"); return true; diff --git a/Windows-Hinting/Services/NamedPipeService.cs b/Windows-Hinting/Services/NamedPipeService.cs index 2f85ad3..4f96e0e 100644 --- a/Windows-Hinting/Services/NamedPipeService.cs +++ b/Windows-Hinting/Services/NamedPipeService.cs @@ -154,9 +154,9 @@ private async Task HandleClientAsync(NamedPipeServerStream pipeServer, Cancellat { "TOGGLE" => new NamedPipeCommand { CommandType = CommandType.Toggle }, "TOGGLETASKBAR" => new NamedPipeCommand { CommandType = CommandType.ToggleTaskbar }, - "SELECT" => parts.Length > 1 ? new NamedPipeCommand - { - CommandType = CommandType.Select, + "SELECT" => parts.Length > 1 ? new NamedPipeCommand + { + CommandType = CommandType.Select, HintLabel = parts[1], Action = ParseClickAction(parts.Length > 2 ? parts[2] : null) } : null, diff --git a/Windows-Hinting/Services/Native/NativeMethods.cs b/Windows-Hinting/Services/Native/NativeMethods.cs index b53a53c..e011e6a 100644 --- a/Windows-Hinting/Services/Native/NativeMethods.cs +++ b/Windows-Hinting/Services/Native/NativeMethods.cs @@ -115,4 +115,4 @@ internal static class WindowsConstants public const uint MOUSEEVENTF_RIGHTUP = 0x0010; public const uint MOUSEEVENTF_ABSOLUTE = 0x8000; } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Services/PerformanceMetrics.cs b/Windows-Hinting/Services/PerformanceMetrics.cs index ba20e2f..efa2fdd 100644 --- a/Windows-Hinting/Services/PerformanceMetrics.cs +++ b/Windows-Hinting/Services/PerformanceMetrics.cs @@ -107,4 +107,4 @@ public static void MeasureExecution(string operationName, Action action, ILogger } } } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Services/UIAutomationService.cs b/Windows-Hinting/Services/UIAutomationService.cs index aab0586..a59deba 100644 --- a/Windows-Hinting/Services/UIAutomationService.cs +++ b/Windows-Hinting/Services/UIAutomationService.cs @@ -30,7 +30,7 @@ public UIAutomationService(ILogger logger, WindowRuleRegistry ruleRegistry) public IReadOnlyList FindClickableElements(IntPtr windowHandle) { ObjectDisposedException.ThrowIf(_disposed, this); - + using (PerformanceMetrics.Start("UIAutomationService.FindClickableElements", _logger, LogLevel.Info)) { try @@ -53,7 +53,7 @@ public IReadOnlyList FindClickableElements(IntPtr windowHandle public async Task> FindClickableElementsAsync(IntPtr windowHandle) { ObjectDisposedException.ThrowIf(_disposed, this); - + return await Task.Run(() => FindClickableElements(windowHandle)); } @@ -304,18 +304,18 @@ private List ResolveRootElements(IntPtr windowHandle, IUIA // return ResolveFileExplorerActiveTab(root, windowTitle); default: - { - var resolved = ApplyStrategy(strategy, root); - if (resolved != null && resolved != root) { - if (Marshal.IsComObject(root)) + var resolved = ApplyStrategy(strategy, root); + if (resolved != null && resolved != root) { - try { Marshal.ReleaseComObject(root); } catch { } + if (Marshal.IsComObject(root)) + { + try { Marshal.ReleaseComObject(root); } catch { } + } + return [resolved]; } - return [resolved]; + break; } - break; - } } } catch (COMException ex) @@ -361,8 +361,8 @@ private List ResolveFileExplorerActiveTab(IUIAutomationEle { next = walker.GetNextSiblingElement(child); } - catch (COMException) - { + catch (COMException) + { } @@ -430,84 +430,84 @@ private List ResolveFileExplorerActiveTab(IUIAutomationEle switch (strategy) { case RootStrategy.ActiveWindowParent: - { - var parent = walker.GetParentElement(root); - _logger.Debug(parent != null - ? "ActiveWindowParent: navigated to parent element" - : "ActiveWindowParent: no parent found, falling back to root"); - return parent; - } + { + var parent = walker.GetParentElement(root); + _logger.Debug(parent != null + ? "ActiveWindowParent: navigated to parent element" + : "ActiveWindowParent: no parent found, falling back to root"); + return parent; + } case RootStrategy.FocusedElement: - { - var focused = _automation.GetFocusedElement(); - _logger.Debug(focused != null - ? "FocusedElement: using focused element as root" - : "FocusedElement: no focused element, falling back to root"); - return focused; - } - - case RootStrategy.FocusedElementParent: - { - var focused = _automation.GetFocusedElement(); - if (focused == null) { - _logger.Debug("FocusedElementParent: no focused element, falling back to root"); - return null; + var focused = _automation.GetFocusedElement(); + _logger.Debug(focused != null + ? "FocusedElement: using focused element as root" + : "FocusedElement: no focused element, falling back to root"); + return focused; } - var parent = walker.GetParentElement(focused); - if (parent != null && Marshal.IsComObject(focused)) + + case RootStrategy.FocusedElementParent: { - try { Marshal.ReleaseComObject(focused); } catch { } + var focused = _automation.GetFocusedElement(); + if (focused == null) + { + _logger.Debug("FocusedElementParent: no focused element, falling back to root"); + return null; + } + var parent = walker.GetParentElement(focused); + if (parent != null && Marshal.IsComObject(focused)) + { + try { Marshal.ReleaseComObject(focused); } catch { } + } + _logger.Debug(parent != null + ? "FocusedElementParent: navigated to parent of focused element" + : "FocusedElementParent: no parent found, falling back to root"); + return parent; } - _logger.Debug(parent != null - ? "FocusedElementParent: navigated to parent of focused element" - : "FocusedElementParent: no parent found, falling back to root"); - return parent; - } case RootStrategy.FocusedElementFirstParentWindow: - { - var focused = _automation.GetFocusedElement(); - if (focused == null) { - _logger.Debug("FocusedElementFirstParentWindow: no focused element, falling back to root"); - return null; - } - var current = focused; - IUIAutomationElement? windowAncestor = null; - while (true) - { - var parent = walker.GetParentElement(current); - if (parent == null) - break; - - int controlType = parent.CurrentControlType; - if (controlType == UIA_ControlTypeIds.UIA_WindowControlTypeId) + var focused = _automation.GetFocusedElement(); + if (focused == null) { - windowAncestor = parent; - break; + _logger.Debug("FocusedElementFirstParentWindow: no focused element, falling back to root"); + return null; } + var current = focused; + IUIAutomationElement? windowAncestor = null; + while (true) + { + var parent = walker.GetParentElement(current); + if (parent == null) + break; + + int controlType = parent.CurrentControlType; + if (controlType == UIA_ControlTypeIds.UIA_WindowControlTypeId) + { + windowAncestor = parent; + break; + } - if (current != focused && Marshal.IsComObject(current)) + if (current != focused && Marshal.IsComObject(current)) + { + try { Marshal.ReleaseComObject(current); } catch { } + } + current = parent; + } + if (current != focused && current != windowAncestor && Marshal.IsComObject(current)) { try { Marshal.ReleaseComObject(current); } catch { } } - current = parent; - } - if (current != focused && current != windowAncestor && Marshal.IsComObject(current)) - { - try { Marshal.ReleaseComObject(current); } catch { } - } - if (Marshal.IsComObject(focused) && focused != windowAncestor) - { - try { Marshal.ReleaseComObject(focused); } catch { } + if (Marshal.IsComObject(focused) && focused != windowAncestor) + { + try { Marshal.ReleaseComObject(focused); } catch { } + } + _logger.Debug(windowAncestor != null + ? "FocusedElementFirstParentWindow: found Window ancestor" + : "FocusedElementFirstParentWindow: no Window ancestor found, falling back to root"); + return windowAncestor; } - _logger.Debug(windowAncestor != null - ? "FocusedElementFirstParentWindow: found Window ancestor" - : "FocusedElementFirstParentWindow: no Window ancestor found, falling back to root"); - return windowAncestor; - } default: return null; @@ -568,4 +568,4 @@ public void Dispose() _disposed = true; } } -} \ No newline at end of file +} diff --git a/Windows-Hinting/Services/WindowManager.cs b/Windows-Hinting/Services/WindowManager.cs index 28751b3..fe48922 100644 --- a/Windows-Hinting/Services/WindowManager.cs +++ b/Windows-Hinting/Services/WindowManager.cs @@ -11,4 +11,4 @@ internal sealed class WindowManager : IWindowManager public bool IsWindowValid(IntPtr hwnd) => hwnd != IntPtr.Zero && NativeMethods.IsWindow(hwnd); } -} \ No newline at end of file +} diff --git a/Windows-Hinting/UIAutomationConstants.cs b/Windows-Hinting/UIAutomationConstants.cs index dcb7e74..4f21211 100644 --- a/Windows-Hinting/UIAutomationConstants.cs +++ b/Windows-Hinting/UIAutomationConstants.cs @@ -178,4 +178,4 @@ internal static class UIA_PatternIds public const int UIA_VirtualizedItemPatternId = 10020; public const int UIA_SynchronizedInputPatternId = 10021; } -} \ No newline at end of file +} diff --git a/Windows-Hinting/app.manifest b/Windows-Hinting/app.manifest index 1c120d3..7a2b1cd 100644 --- a/Windows-Hinting/app.manifest +++ b/Windows-Hinting/app.manifest @@ -29,4 +29,4 @@ - \ No newline at end of file + diff --git a/Windows-Hinting/appsettings.json b/Windows-Hinting/appsettings.json index 778eab1..334c898 100644 --- a/Windows-Hinting/appsettings.json +++ b/Windows-Hinting/appsettings.json @@ -3,4 +3,4 @@ "LogLevel": "Debug", "EnablePerformanceMetrics": true } -} \ No newline at end of file +} diff --git a/Windows-Hinting/docs/ARCHITECTURE_DIAGRAMS.md b/Windows-Hinting/docs/ARCHITECTURE_DIAGRAMS.md index 04b3fcc..a599c18 100644 --- a/Windows-Hinting/docs/ARCHITECTURE_DIAGRAMS.md +++ b/Windows-Hinting/docs/ARCHITECTURE_DIAGRAMS.md @@ -90,7 +90,7 @@ External App NamedPipeClient NamedPipeService HintControl β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ SelectHintByLabel β”‚ β”‚ β”‚ β”‚ β”Œβ”€ Find hint "A" - β”‚ β”‚ β”‚ β”‚ β”‚ + β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€ TryActivate() β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └─ Deactivate diff --git a/Windows-Hinting/docs/NAMED_PIPE_QUICK_REFERENCE.md b/Windows-Hinting/docs/NAMED_PIPE_QUICK_REFERENCE.md index d5d3df5..67474cc 100644 --- a/Windows-Hinting/docs/NAMED_PIPE_QUICK_REFERENCE.md +++ b/Windows-Hinting/docs/NAMED_PIPE_QUICK_REFERENCE.md @@ -30,11 +30,11 @@ Commands: ## Key Features -βœ… **Order-Independent** - Client and server startup order doesn't matter -βœ… **Automatic Retries** - Built-in retry logic (up to 5 seconds) -βœ… **Async** - Efficient asynchronous server handling -βœ… **Thread-Safe** - Can be called from multiple threads -βœ… **Simple** - Easy to integrate and use +βœ… **Order-Independent** - Client and server startup order doesn't matter +βœ… **Automatic Retries** - Built-in retry logic (up to 5 seconds) +βœ… **Async** - Efficient asynchronous server handling +βœ… **Thread-Safe** - Can be called from multiple threads +βœ… **Simple** - Easy to integrate and use ## Available Commands diff --git a/Windows-Hinting/docs/README_DEFAULT_BUILD.md b/Windows-Hinting/docs/README_DEFAULT_BUILD.md index c147aa2..b086a94 100644 --- a/Windows-Hinting/docs/README_DEFAULT_BUILD.md +++ b/Windows-Hinting/docs/README_DEFAULT_BUILD.md @@ -11,7 +11,7 @@ The `build-complete.ps1` script now builds **both the signed executable AND MSI .\build\build-complete.ps1 # Built exe only .\build\build-complete.ps1 -Installer # Built exe + MSI -# AFTER +# AFTER .\build\build-complete.ps1 # Builds exe + MSI ✨ (DEFAULT!) .\build\build-complete.ps1 -ExeOnly # Builds exe only ``` diff --git a/Windows-Hinting/docs/README_NAMED_PIPE_INTERFACE.md b/Windows-Hinting/docs/README_NAMED_PIPE_INTERFACE.md index b07999c..042c5ad 100644 --- a/Windows-Hinting/docs/README_NAMED_PIPE_INTERFACE.md +++ b/Windows-Hinting/docs/README_NAMED_PIPE_INTERFACE.md @@ -177,7 +177,7 @@ Element Activators (executes action) 10 comprehensive tests covering: - βœ… Toggle command -- βœ… Select command +- βœ… Select command - βœ… Deactivate command - βœ… Invalid hint label handling - βœ… Empty/null hint label validation @@ -399,7 +399,7 @@ A complete, well-documented, tested named pipe interface implementation that: --- **Status**: βœ… Ready for production deployment -**Build Status**: βœ… Successful +**Build Status**: βœ… Successful **Test Coverage**: βœ… 10 tests included **Documentation**: βœ… Complete **Examples**: βœ… 8 examples provided diff --git a/Windows-Hinting/docs/README_UIACCESS_SETUP.md b/Windows-Hinting/docs/README_UIACCESS_SETUP.md index 0b8acff..e1dc79d 100644 --- a/Windows-Hinting/docs/README_UIACCESS_SETUP.md +++ b/Windows-Hinting/docs/README_UIACCESS_SETUP.md @@ -223,7 +223,7 @@ A: Yes, self-signed certs work. For production, use commercial certs so Windows ## πŸ“š Documentation Files -1. **`UIACCESS_QUICKSTART.md`** +1. **`UIACCESS_QUICKSTART.md`** - Quick reference (5 min) - Common tasks - Quick troubleshooting diff --git a/build/Build-HintOverlay.ps1 b/build/Build-HintOverlay.ps1 index 615fae4..259b613 100644 --- a/build/Build-HintOverlay.ps1 +++ b/build/Build-HintOverlay.ps1 @@ -1,4 +1,4 @@ -# Build-HintOverlay.ps1 +ο»Ώ# Build-HintOverlay.ps1 # Build Windows-Hinting using .NET Framework MSBuild <# diff --git a/build/Build-InstallerMSI.ps1 b/build/Build-InstallerMSI.ps1 index fa97f4e..1bb6486 100644 --- a/build/Build-InstallerMSI.ps1 +++ b/build/Build-InstallerMSI.ps1 @@ -1,4 +1,4 @@ -# Build-InstallerMSI.ps1 +ο»Ώ# Build-InstallerMSI.ps1 # Builds Windows-Hinting and creates a signed MSI installer <# diff --git a/build/Create-CodeSigningCert.ps1 b/build/Create-CodeSigningCert.ps1 index c9e04e1..90843cb 100644 --- a/build/Create-CodeSigningCert.ps1 +++ b/build/Create-CodeSigningCert.ps1 @@ -1,4 +1,4 @@ -# Create-CodeSigningCert.ps1 +ο»Ώ# Create-CodeSigningCert.ps1 # Creates a self-signed code signing certificate for Windows-Hinting <# @@ -35,7 +35,7 @@ param( [string]$FriendlyName = "Windows-Hinting Code Signing", [int]$ValidityYears = 10, [string]$OutputPath = $env:USERPROFILE, - [string]$ExportPassword = "" + [SecureString]$ExportPassword = "" ) # ============================================================================ diff --git a/build/New-HintOverlayMSI.ps1 b/build/New-HintOverlayMSI.ps1 index 1a159f1..297ba3c 100644 --- a/build/New-HintOverlayMSI.ps1 +++ b/build/New-HintOverlayMSI.ps1 @@ -1,4 +1,4 @@ -# New-HintOverlayMSI.ps1 +ο»Ώ# New-HintOverlayMSI.ps1 # Creates an MSI installer without requiring WiX Toolset # Uses DTF (Deployment Tools Foundation) approach @@ -33,9 +33,8 @@ $certPath = "$env:USERPROFILE\WindowsHinting_CodeSign.pfx" $certPassword = "test123" $exePath = "$ProjectDir\bin\Release\net8.0-windows\Windows-Hinting.exe" $msiPath = Join-Path $OutputPath "Windows-Hinting.msi" -$cabPath = Join-Path $OutputPath "Windows-Hinting.cab" -Write-Host "═══════════════════════════════════════════════════════════════" -ForegroundColor Cyan +Write-Host Write-Host "Windows-Hinting MSI Creator (No WiX Required)" -ForegroundColor Cyan Write-Host "═══════════════════════════════════════════════════════════════" -ForegroundColor Cyan Write-Host "" @@ -49,7 +48,9 @@ try { Write-Host "βœ“ WiX Toolset found: $($lightExe.Source)" -ForegroundColor Green } } -catch { } +catch { + Write-Verbose "WiX Toolset not found: $_" +} if (-not $hasWiX) { Write-Host "⚠ WiX Toolset not found" -ForegroundColor Yellow diff --git a/build/PSScriptAnalyzerSettings.psd1 b/build/PSScriptAnalyzerSettings.psd1 new file mode 100644 index 0000000..b419dc3 --- /dev/null +++ b/build/PSScriptAnalyzerSettings.psd1 @@ -0,0 +1,10 @@ +@{ + ExcludeRules = @( + # Write-Host is intentional in build/CI scripts for console output + 'PSAvoidUsingWriteHost', + # ConvertTo-SecureString with plaintext is required for cert export in build scripts + 'PSAvoidUsingConvertToSecureStringWithPlainText', + # Password params are passed as plain strings from CI environment variables / MSBuild args + 'PSAvoidUsingPlainTextForPassword' + ) +} diff --git a/build/Sign-HintOverlay.ps1 b/build/Sign-HintOverlay.ps1 index d3c2bfa..7fc8c33 100644 --- a/build/Sign-HintOverlay.ps1 +++ b/build/Sign-HintOverlay.ps1 @@ -1,4 +1,4 @@ -# Sign-HintOverlay.ps1 +ο»Ώ# Sign-HintOverlay.ps1 # Code signing script for Windows-Hinting executable <# diff --git a/build/build-and-sign.ps1 b/build/build-and-sign.ps1 index 1811920..31e69f6 100644 --- a/build/build-and-sign.ps1 +++ b/build/build-and-sign.ps1 @@ -1,10 +1,10 @@ -param( +ο»Ώparam( [ValidateSet("Debug", "Release")] [string]$Configuration = "Release", [switch]$RegenerateCert, [switch]$SkipSigning, [string]$CertPath = "", - [string]$CertPassword = "WindowsHinting_BuildCert_2024" + [SecureString]$CertPassword ) $ErrorActionPreference = "Stop" diff --git a/build/build-complete.ps1 b/build/build-complete.ps1 index f8df66c..3de1b3e 100644 --- a/build/build-complete.ps1 +++ b/build/build-complete.ps1 @@ -4,7 +4,7 @@ param( [switch]$ExeOnly, [switch]$SkipSigning, [string]$CertPath = "", - [string]$CertPassword = "WindowsHinting_BuildCert_2024" + [string]$CertPassword ) $ErrorActionPreference = "Stop" diff --git a/build/docs/BUILD_COMPLETE_DOCUMENTATION_INDEX.md b/build/docs/BUILD_COMPLETE_DOCUMENTATION_INDEX.md index ea4a1bf..086e417 100644 --- a/build/docs/BUILD_COMPLETE_DOCUMENTATION_INDEX.md +++ b/build/docs/BUILD_COMPLETE_DOCUMENTATION_INDEX.md @@ -259,7 +259,7 @@ winget install lessmsi **Solution:** Install WiX Toolset or check `Windows-Hinting.Installer` exists ### Issue: "Certificate not found" -**Solution:** +**Solution:** ```powershell .\build\generate-signing-cert.ps1 # Generate new # OR @@ -267,7 +267,7 @@ winget install lessmsi ``` ### Issue: "MSI file not found" -**Solution:** +**Solution:** - Check WiX build output for errors - Ensure Visual Studio build tools installed diff --git a/build/docs/BUILD_DOCUMENTATION_INDEX.md b/build/docs/BUILD_DOCUMENTATION_INDEX.md index 6d1cc88..a69b74f 100644 --- a/build/docs/BUILD_DOCUMENTATION_INDEX.md +++ b/build/docs/BUILD_DOCUMENTATION_INDEX.md @@ -281,6 +281,6 @@ All documentation is in the repository root directory: --- -**Last Updated**: March 15, 2026 -**Status**: βœ… Production Ready +**Last Updated**: March 15, 2026 +**Status**: βœ… Production Ready **Version**: Windows-Hinting with Signed Code & Installer Integration diff --git a/build/docs/CODE_SIGNING_SETUP.md b/build/docs/CODE_SIGNING_SETUP.md index 2ddecd0..11afd69 100644 --- a/build/docs/CODE_SIGNING_SETUP.md +++ b/build/docs/CODE_SIGNING_SETUP.md @@ -169,7 +169,7 @@ For automated builds (GitHub Actions, Azure Pipelines, etc.): ## Security Notes -⚠️ **Important**: +⚠️ **Important**: - Never commit certificate files (.pfx) to version control - Use environment variables or secrets management for production - Code-signing certificates from established CAs (like Sectigo, DigiCert) are recommended for production diff --git a/build/docs/COMMAND_REFERENCE.md b/build/docs/COMMAND_REFERENCE.md index 005a4af..bfdfc9c 100644 --- a/build/docs/COMMAND_REFERENCE.md +++ b/build/docs/COMMAND_REFERENCE.md @@ -115,12 +115,6 @@ build\build-complete.bat Release --skip-signing ```powershell -CertPath "C:\my\cert.pfx" # Custom certificate location ``` - -### `-CertPassword` (Default: "WindowsHinting_BuildCert_2024") -```powershell --CertPassword "my_password" # Custom certificate password -``` - --- ## Step Count Reference @@ -173,7 +167,7 @@ Build Summary: ``` ERROR: Certificate not found at: certs\WindowsHinting_CodeSign.pfx ``` -**Solution:** +**Solution:** ```powershell .\build\generate-signing-cert.ps1 # Generate new cert # OR @@ -278,7 +272,7 @@ Register-ScheduledTask -TaskName "Windows-Hinting-Build" ` 4. **Sign MSI** (optional, recommended for distribution) ```powershell signtool sign /f "certs\WindowsHinting_CodeSign.pfx" ` - /p "WindowsHinting_BuildCert_2024" ` + /p "*****" ` /fd SHA256 ` Windows-Hinting.Installer\bin\Release\en-US\Windows-Hinting.msi ``` diff --git a/build/docs/DEPLOYMENT_CHECKLIST.md b/build/docs/DEPLOYMENT_CHECKLIST.md index cdc39a9..32d0dc3 100644 --- a/build/docs/DEPLOYMENT_CHECKLIST.md +++ b/build/docs/DEPLOYMENT_CHECKLIST.md @@ -197,7 +197,7 @@ The following documentation is provided: ### Issue: Commands sent but nothing happens -**Likely Cause:** +**Likely Cause:** - Hints not visible yet (timing issue) - Invalid hint label @@ -259,7 +259,7 @@ If issues discovered after deployment: - Provide link to code examples - Include in help/documentation -### Developers +### Developers - Reference NAMED_PIPE_INTERFACE.md for technical details - Share ARCHITECTURE_DIAGRAMS.md for system design - Point to test suite for verification diff --git a/build/generate-signing-cert.ps1 b/build/generate-signing-cert.ps1 index e0365a7..67f998e 100644 --- a/build/generate-signing-cert.ps1 +++ b/build/generate-signing-cert.ps1 @@ -1,4 +1,4 @@ -param([string]$CertName = "WindowsHinting", [string]$CertPath = "$PSScriptRoot\..\Windows-Hinting\certs\WindowsHinting_CodeSign.pfx", [string]$CertPassword = "WindowsHinting_BuildCert_2024", [int]$ValidYears = 10, [switch]$Force) +param([string]$CertName = "WindowsHinting", [string]$CertPath = "$PSScriptRoot\..\Windows-Hinting\certs\WindowsHinting_CodeSign.pfx", [SecureString]$CertPassword, [int]$ValidYears = 10, [switch]$Force) $ErrorActionPreference = "Stop" $CertDir = Split-Path -Parent $CertPath