├── .editorconfig ├── .github ├── dependabot.yml └── workflows │ └── codeql-analysis.yml ├── .gitignore ├── GitVersion.yml ├── InputSimulatorStandard.sln ├── InputSimulatorStandard.sln.DotSettings ├── LICENSE ├── README.md ├── azure-pipelines.yml ├── src └── GregsStack.InputSimulatorStandard │ ├── GregsStack.InputSimulatorStandard.csproj │ ├── IInputDeviceStateAdapter.cs │ ├── IInputMessageDispatcher.cs │ ├── IInputSimulator.cs │ ├── IKeyboardSimulator.cs │ ├── IMouseSimulator.cs │ ├── InputBuilder.cs │ ├── InputSimulator.cs │ ├── KeyboardSimulator.cs │ ├── MouseButton.cs │ ├── MouseSimulator.cs │ ├── Native │ ├── HardwareInput.cs │ ├── Input.cs │ ├── InputType.cs │ ├── KeyboardFlag.cs │ ├── KeyboardInput.cs │ ├── MouseFlag.cs │ ├── MouseInput.cs │ ├── MouseKeyboardHardwareInput.cs │ ├── NativeMethods.cs │ ├── Point.cs │ ├── SystemMetric.cs │ ├── VirtualKeyCode.cs │ └── XButton.cs │ ├── WindowsInputDeviceStateAdapter.cs │ └── WindowsInputMessageDispatcher.cs ├── tests └── GregsStack.InputSimulatorStandard.Tests │ ├── GregsStack.InputSimulatorStandard.Tests.csproj │ ├── InputBuilderTests.cs │ ├── InputSimulatorExamples.cs │ ├── InputSimulatorTests.cs │ ├── MouseSimulatorTests.cs │ ├── UnicodeText │ ├── UnicodeRange.cs │ ├── UnicodeTestForm.Designer.cs │ ├── UnicodeTestForm.cs │ ├── UnicodeTestForm.resx │ └── UnicodeTextTests.cs │ └── WindowsInputMessageDispatcherTests.cs └── tools └── NuGet.Tools └── NuGet.Tools.csproj /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | # File adapted from https://github.com/RehanSaeed/EditorConfig/blob/master/.editorconfig 3 | 4 | ################# 5 | # Common Settings 6 | ################# 7 | 8 | # top-most EditorConfig file 9 | root = true 10 | 11 | # All Files 12 | [*] 13 | indent_style = space 14 | insert_final_newline = false 15 | trim_trailing_whitespace = true 16 | 17 | ######################### 18 | # File Extension Settings 19 | ######################### 20 | 21 | # Code files 22 | [*.{cs,csx,vb,vbx}] 23 | indent_size = 4 24 | insert_final_newline = true 25 | max_line_length = 200 26 | 27 | # Solution Files 28 | [*.sln] 29 | indent_style = tab 30 | 31 | # XML Project Files 32 | [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] 33 | indent_size = 2 34 | 35 | # Configuration Files 36 | [*.{json,xml,yml,config,props,targets,nuspec,resx,ruleset,vsixmanifest,vsct}] 37 | indent_size = 2 38 | 39 | # YAML Files 40 | [*.{yml,yaml}] 41 | indent_size = 2 42 | 43 | # Markdown Files 44 | [*.md] 45 | trim_trailing_whitespace = false 46 | 47 | # Web Files 48 | [*.{htm,html,js,ts,css,scss,less}] 49 | indent_size = 2 50 | insert_final_newline = true 51 | 52 | # Bash Files 53 | [*.sh] 54 | end_of_line = lf 55 | 56 | [*.cs] 57 | #### .NET Coding Conventions #### 58 | 59 | # this. and Me. preferences 60 | dotnet_style_qualification_for_event = true:silent 61 | dotnet_style_qualification_for_field = true:silent 62 | dotnet_style_qualification_for_method = true:silent 63 | dotnet_style_qualification_for_property = true:silent 64 | 65 | # Language keywords vs BCL types preferences 66 | dotnet_style_predefined_type_for_locals_parameters_members = true:silent 67 | dotnet_style_predefined_type_for_member_access = true:silent 68 | 69 | # Parentheses preferences 70 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent 71 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent 72 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent 73 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent 74 | 75 | # Modifier preferences 76 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent 77 | 78 | # Expression-level preferences 79 | csharp_style_deconstructed_variable_declaration = true:suggestion 80 | csharp_style_inlined_variable_declaration = true:suggestion 81 | csharp_style_throw_expression = true:suggestion 82 | dotnet_style_coalesce_expression = true:suggestion 83 | dotnet_style_collection_initializer = true:suggestion 84 | dotnet_style_explicit_tuple_names = true:suggestion 85 | dotnet_style_null_propagation = true:suggestion 86 | dotnet_style_object_initializer = true:suggestion 87 | dotnet_style_prefer_auto_properties = true:silent 88 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent 89 | dotnet_style_prefer_conditional_expression_over_return = true:silent 90 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion 91 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 92 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion 93 | 94 | # Field preferences 95 | dotnet_style_readonly_field = true:suggestion 96 | 97 | #### C# Coding Conventions #### 98 | 99 | # var preferences 100 | csharp_style_var_elsewhere = false:silent 101 | csharp_style_var_for_built_in_types = false:silent 102 | csharp_style_var_when_type_is_apparent = false:silent 103 | 104 | # Expression-bodied members 105 | csharp_style_expression_bodied_accessors = true:silent 106 | csharp_style_expression_bodied_constructors = false:silent 107 | csharp_style_expression_bodied_indexers = true:silent 108 | csharp_style_expression_bodied_lambdas = true:silent 109 | csharp_style_expression_bodied_methods = false:silent 110 | csharp_style_expression_bodied_operators = false:silent 111 | csharp_style_expression_bodied_properties = true:silent 112 | 113 | # Pattern matching preferences 114 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 115 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 116 | 117 | # Null-checking preferences 118 | csharp_style_conditional_delegate_call = true:suggestion 119 | 120 | # Modifier preferences 121 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async 122 | 123 | # Code-block preferences 124 | csharp_prefer_braces = true:silent 125 | 126 | # Expression-level preferences 127 | csharp_prefer_simple_default_expression = true:suggestion 128 | csharp_style_pattern_local_over_anonymous_function = true:suggestion 129 | 130 | #### C# Formatting Rules #### 131 | 132 | # New line preferences 133 | csharp_new_line_before_catch = true 134 | csharp_new_line_before_else = true 135 | csharp_new_line_before_finally = true 136 | csharp_new_line_before_members_in_anonymous_types = true 137 | csharp_new_line_before_members_in_object_initializers = true 138 | csharp_new_line_before_open_brace = all 139 | csharp_new_line_between_query_expression_clauses = true 140 | 141 | # Indentation preferences 142 | csharp_indent_block_contents = true 143 | csharp_indent_braces = false 144 | csharp_indent_case_contents = true 145 | csharp_indent_case_contents_when_block = true 146 | csharp_indent_labels = one_less_than_current 147 | csharp_indent_switch_labels = true 148 | 149 | # Space preferences 150 | csharp_space_after_cast = false 151 | csharp_space_after_colon_in_inheritance_clause = true 152 | csharp_space_after_comma = true 153 | csharp_space_after_dot = false 154 | csharp_space_after_keywords_in_control_flow_statements = true 155 | csharp_space_after_semicolon_in_for_statement = true 156 | csharp_space_around_binary_operators = before_and_after 157 | csharp_space_around_declaration_statements = false 158 | csharp_space_before_colon_in_inheritance_clause = true 159 | csharp_space_before_comma = false 160 | csharp_space_before_dot = false 161 | csharp_space_before_open_square_brackets = false 162 | csharp_space_before_semicolon_in_for_statement = false 163 | csharp_space_between_empty_square_brackets = false 164 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 165 | csharp_space_between_method_call_name_and_opening_parenthesis = false 166 | csharp_space_between_method_call_parameter_list_parentheses = false 167 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 168 | csharp_space_between_method_declaration_name_and_open_parenthesis = false 169 | csharp_space_between_method_declaration_parameter_list_parentheses = false 170 | csharp_space_between_parentheses = false 171 | csharp_space_between_square_brackets = false 172 | 173 | # Wrapping preferences 174 | csharp_preserve_single_line_blocks = true 175 | csharp_preserve_single_line_statements = true 176 | 177 | # Organize usings 178 | dotnet_sort_system_directives_first = true 179 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: nuget 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "04:00" 8 | open-pull-requests-limit: 10 9 | ignore: 10 | - dependency-name: altcover 11 | versions: 12 | - 7.6.812 13 | - 8.0.815 14 | - 8.0.816 15 | - 8.1.817 16 | - 8.1.819 17 | - dependency-name: HtmlAgilityPack 18 | versions: 19 | - 1.11.30 20 | - 1.11.31 21 | - 1.11.32 22 | - dependency-name: Microsoft.NET.Test.Sdk 23 | versions: 24 | - 16.8.3 25 | - 16.9.1 26 | - dependency-name: Codecov 27 | versions: 28 | - 1.12.4 29 | - 1.13.0 30 | - dependency-name: Moq 31 | versions: 32 | - 4.16.0 33 | - dependency-name: xunit.runner.visualstudio 34 | versions: 35 | - 2.4.3 36 | - dependency-name: Microsoft.SourceLink.GitHub 37 | versions: 38 | - 1.0.0 39 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "master" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "master" ] 20 | schedule: 21 | - cron: '39 6 * * 4' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'csharp' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v2 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | # - run: | 68 | # echo "Run, Build Application using script" 69 | # ./location_of_script_within_repo/buildscript.sh 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v2 73 | with: 74 | category: "/language:${{matrix.language}}" 75 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | [Aa][Rr][Mm]/ 24 | [Aa][Rr][Mm]64/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio 2015/2017 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # Visual Studio 2017 auto generated files 36 | Generated\ Files/ 37 | 38 | # MSTest test Results 39 | [Tt]est[Rr]esult*/ 40 | [Bb]uild[Ll]og.* 41 | 42 | # NUNIT 43 | *.VisualState.xml 44 | TestResult.xml 45 | 46 | # Build Results of an ATL Project 47 | [Dd]ebugPS/ 48 | [Rr]eleasePS/ 49 | dlldata.c 50 | 51 | # Benchmark Results 52 | BenchmarkDotNet.Artifacts/ 53 | 54 | # .NET Core 55 | project.lock.json 56 | project.fragment.lock.json 57 | artifacts/ 58 | 59 | # StyleCop 60 | StyleCopReport.xml 61 | 62 | # Files built by Visual Studio 63 | *_i.c 64 | *_p.c 65 | *_h.h 66 | *.ilk 67 | *.meta 68 | *.obj 69 | *.iobj 70 | *.pch 71 | *.pdb 72 | *.ipdb 73 | *.pgc 74 | *.pgd 75 | *.rsp 76 | *.sbr 77 | *.tlb 78 | *.tli 79 | *.tlh 80 | *.tmp 81 | *.tmp_proj 82 | *_wpftmp.csproj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Chutzpah Test files 92 | _Chutzpah* 93 | 94 | # Visual C++ cache files 95 | ipch/ 96 | *.aps 97 | *.ncb 98 | *.opendb 99 | *.opensdf 100 | *.sdf 101 | *.cachefile 102 | *.VC.db 103 | *.VC.VC.opendb 104 | 105 | # Visual Studio profiler 106 | *.psess 107 | *.vsp 108 | *.vspx 109 | *.sap 110 | 111 | # Visual Studio Trace Files 112 | *.e2e 113 | 114 | # TFS 2012 Local Workspace 115 | $tf/ 116 | 117 | # Guidance Automation Toolkit 118 | *.gpState 119 | 120 | # ReSharper is a .NET coding add-in 121 | _ReSharper*/ 122 | *.[Rr]e[Ss]harper 123 | *.DotSettings.user 124 | 125 | # JustCode is a .NET coding add-in 126 | .JustCode 127 | 128 | # TeamCity is a build add-in 129 | _TeamCity* 130 | 131 | # DotCover is a Code Coverage Tool 132 | *.dotCover 133 | 134 | # AxoCover is a Code Coverage Tool 135 | .axoCover/* 136 | !.axoCover/settings.json 137 | 138 | # Visual Studio code coverage results 139 | *.coverage 140 | *.coveragexml 141 | 142 | # NCrunch 143 | _NCrunch_* 144 | .*crunch*.local.xml 145 | nCrunchTemp_* 146 | 147 | # MightyMoose 148 | *.mm.* 149 | AutoTest.Net/ 150 | 151 | # Web workbench (sass) 152 | .sass-cache/ 153 | 154 | # Installshield output folder 155 | [Ee]xpress/ 156 | 157 | # DocProject is a documentation generator add-in 158 | DocProject/buildhelp/ 159 | DocProject/Help/*.HxT 160 | DocProject/Help/*.HxC 161 | DocProject/Help/*.hhc 162 | DocProject/Help/*.hhk 163 | DocProject/Help/*.hhp 164 | DocProject/Help/Html2 165 | DocProject/Help/html 166 | 167 | # Click-Once directory 168 | publish/ 169 | 170 | # Publish Web Output 171 | *.[Pp]ublish.xml 172 | *.azurePubxml 173 | # Note: Comment the next line if you want to checkin your web deploy settings, 174 | # but database connection strings (with potential passwords) will be unencrypted 175 | *.pubxml 176 | *.publishproj 177 | 178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 179 | # checkin your Azure Web App publish settings, but sensitive information contained 180 | # in these scripts will be unencrypted 181 | PublishScripts/ 182 | 183 | # NuGet Packages 184 | *.nupkg 185 | # The packages folder can be ignored because of Package Restore 186 | **/[Pp]ackages/* 187 | # except build/, which is used as an MSBuild target. 188 | !**/[Pp]ackages/build/ 189 | # Uncomment if necessary however generally it will be regenerated when needed 190 | #!**/[Pp]ackages/repositories.config 191 | # NuGet v3's project.json files produces more ignorable files 192 | *.nuget.props 193 | *.nuget.targets 194 | 195 | # Microsoft Azure Build Output 196 | csx/ 197 | *.build.csdef 198 | 199 | # Microsoft Azure Emulator 200 | ecf/ 201 | rcf/ 202 | 203 | # Windows Store app package directories and files 204 | AppPackages/ 205 | BundleArtifacts/ 206 | Package.StoreAssociation.xml 207 | _pkginfo.txt 208 | *.appx 209 | 210 | # Visual Studio cache files 211 | # files ending in .cache can be ignored 212 | *.[Cc]ache 213 | # but keep track of directories ending in .cache 214 | !?*.[Cc]ache/ 215 | 216 | # Others 217 | ClientBin/ 218 | ~$* 219 | *~ 220 | *.dbmdl 221 | *.dbproj.schemaview 222 | *.jfm 223 | *.pfx 224 | *.publishsettings 225 | orleans.codegen.cs 226 | 227 | # Including strong name files can present a security risk 228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 229 | #*.snk 230 | 231 | # Since there are multiple workflows, uncomment next line to ignore bower_components 232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 233 | #bower_components/ 234 | # ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true 235 | **/wwwroot/lib/ 236 | 237 | # RIA/Silverlight projects 238 | Generated_Code/ 239 | 240 | # Backup & report files from converting an old project file 241 | # to a newer Visual Studio version. Backup files are not needed, 242 | # because we have git ;-) 243 | _UpgradeReport_Files/ 244 | Backup*/ 245 | UpgradeLog*.XML 246 | UpgradeLog*.htm 247 | ServiceFabricBackup/ 248 | *.rptproj.bak 249 | 250 | # SQL Server files 251 | *.mdf 252 | *.ldf 253 | *.ndf 254 | 255 | # Business Intelligence projects 256 | *.rdl.data 257 | *.bim.layout 258 | *.bim_*.settings 259 | *.rptproj.rsuser 260 | 261 | # Microsoft Fakes 262 | FakesAssemblies/ 263 | 264 | # GhostDoc plugin setting file 265 | *.GhostDoc.xml 266 | 267 | # Node.js Tools for Visual Studio 268 | .ntvs_analysis.dat 269 | node_modules/ 270 | 271 | # Visual Studio 6 build log 272 | *.plg 273 | 274 | # Visual Studio 6 workspace options file 275 | *.opt 276 | 277 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 278 | *.vbw 279 | 280 | # Visual Studio LightSwitch build output 281 | **/*.HTMLClient/GeneratedArtifacts 282 | **/*.DesktopClient/GeneratedArtifacts 283 | **/*.DesktopClient/ModelManifest.xml 284 | **/*.Server/GeneratedArtifacts 285 | **/*.Server/ModelManifest.xml 286 | _Pvt_Extensions 287 | 288 | # Paket dependency manager 289 | .paket/paket.exe 290 | paket-files/ 291 | 292 | # FAKE - F# Make 293 | .fake/ 294 | 295 | # JetBrains Rider 296 | .idea/ 297 | *.sln.iml 298 | 299 | # CodeRush personal settings 300 | .cr/personal 301 | 302 | # Python Tools for Visual Studio (PTVS) 303 | __pycache__/ 304 | *.pyc 305 | 306 | # Cake - Uncomment if you are using it 307 | # tools/** 308 | # !tools/packages.config 309 | 310 | # Tabs Studio 311 | *.tss 312 | 313 | # Telerik's JustMock configuration file 314 | *.jmconfig 315 | 316 | # BizTalk build output 317 | *.btp.cs 318 | *.btm.cs 319 | *.odx.cs 320 | *.xsd.cs 321 | 322 | # OpenCover UI analysis results 323 | OpenCover/ 324 | 325 | # Azure Stream Analytics local run output 326 | ASALocalRun/ 327 | 328 | # MSBuild Binary and Structured Log 329 | *.binlog 330 | 331 | # NVidia Nsight GPU debugger configuration file 332 | *.nvuser 333 | 334 | # MFractors (Xamarin productivity tool) working folder 335 | .mfractor/ 336 | 337 | # Local History for Visual Studio 338 | .localhistory/ 339 | 340 | # BeatPulse healthcheck temp database 341 | healthchecksdb 342 | -------------------------------------------------------------------------------- /GitVersion.yml: -------------------------------------------------------------------------------- 1 | branches: 2 | release: 3 | mode: ContinuousDeployment 4 | tag: rc 5 | develop: 6 | mode: ContinuousDeployment 7 | tag: beta 8 | source-branches: ['master'] 9 | tracks-release-branches: false 10 | -------------------------------------------------------------------------------- /InputSimulatorStandard.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.28407.52 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GregsStack.InputSimulatorStandard", "src\GregsStack.InputSimulatorStandard\GregsStack.InputSimulatorStandard.csproj", "{3549CD6F-80F8-450F-B99E-CF0A736B1F2A}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GregsStack.InputSimulatorStandard.Tests", "tests\GregsStack.InputSimulatorStandard.Tests\GregsStack.InputSimulatorStandard.Tests.csproj", "{93982D2F-BEAD-49F7-86A9-C68159410F28}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C404D6FF-9C4D-4824-B7B6-7CBF2EB29BD9}" 11 | ProjectSection(SolutionItems) = preProject 12 | .editorconfig = .editorconfig 13 | .gitignore = .gitignore 14 | azure-pipelines.yml = azure-pipelines.yml 15 | GitVersion.yml = GitVersion.yml 16 | LICENSE = LICENSE 17 | README.md = README.md 18 | EndProjectSection 19 | EndProject 20 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{D92B7BDD-9E42-4FB7-982A-147D4B333CE4}" 21 | EndProject 22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NuGet.Tools", "tools\NuGet.Tools\NuGet.Tools.csproj", "{52EE0CF0-C85F-4778-A08B-7D15F1E04F9E}" 23 | EndProject 24 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{CBE9D601-852E-40A9-BBE7-F8CFEA094380}" 25 | EndProject 26 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{81B2CA76-388C-41AE-A34B-53B6474AF283}" 27 | EndProject 28 | Global 29 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 30 | Debug|Any CPU = Debug|Any CPU 31 | Release|Any CPU = Release|Any CPU 32 | EndGlobalSection 33 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 34 | {3549CD6F-80F8-450F-B99E-CF0A736B1F2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {3549CD6F-80F8-450F-B99E-CF0A736B1F2A}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {3549CD6F-80F8-450F-B99E-CF0A736B1F2A}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {3549CD6F-80F8-450F-B99E-CF0A736B1F2A}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {93982D2F-BEAD-49F7-86A9-C68159410F28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {93982D2F-BEAD-49F7-86A9-C68159410F28}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {93982D2F-BEAD-49F7-86A9-C68159410F28}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {93982D2F-BEAD-49F7-86A9-C68159410F28}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {52EE0CF0-C85F-4778-A08B-7D15F1E04F9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {52EE0CF0-C85F-4778-A08B-7D15F1E04F9E}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {52EE0CF0-C85F-4778-A08B-7D15F1E04F9E}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {52EE0CF0-C85F-4778-A08B-7D15F1E04F9E}.Release|Any CPU.Build.0 = Release|Any CPU 46 | EndGlobalSection 47 | GlobalSection(SolutionProperties) = preSolution 48 | HideSolutionNode = FALSE 49 | EndGlobalSection 50 | GlobalSection(NestedProjects) = preSolution 51 | {3549CD6F-80F8-450F-B99E-CF0A736B1F2A} = {CBE9D601-852E-40A9-BBE7-F8CFEA094380} 52 | {93982D2F-BEAD-49F7-86A9-C68159410F28} = {81B2CA76-388C-41AE-A34B-53B6474AF283} 53 | {52EE0CF0-C85F-4778-A08B-7D15F1E04F9E} = {D92B7BDD-9E42-4FB7-982A-147D4B333CE4} 54 | EndGlobalSection 55 | GlobalSection(ExtensibilityGlobals) = postSolution 56 | SolutionGuid = {4CF19F51-46F7-4DE1-9BC3-2EEC71EE691A} 57 | EndGlobalSection 58 | EndGlobal 59 | -------------------------------------------------------------------------------- /InputSimulatorStandard.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Michael Noonan, Theodoros Chatzigiannakis, Gregor Sindl 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Input Simulator Standard 2 | This library is a fork of Michael Noonan's *Windows Input Simulator* and Theodoros Chatzigiannakis's *Input Simulator Plus* (a C# wrapper around the `SendInput` functionality of Windows). It can be used as a replacement of the original library with some small source code changes. 3 | 4 | This fork supports scan codes, making it compatible with many applications that the original library does not support. 5 | 6 | The target framework has been changed to .Net Standard to support the usage with .Net Core and .Net Framework projects on Windows. 7 | 8 | [![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/GregsStack.InputSimulatorStandard)](https://www.nuget.org/packages/GregsStack.InputSimulatorStandard) 9 | [![Build Status](https://dev.azure.com/GregsStack/GitHub/_apis/build/status/GregsStack.InputSimulatorStandard?branchName=master)](https://dev.azure.com/GregsStack/GitHub/_build/latest?definitionId=2?branchName=master) 10 | [![codecov](https://codecov.io/gh/GregsStack/InputSimulatorStandard/branch/master/graph/badge.svg)](https://codecov.io/gh/GregsStack/InputSimulatorStandard) 11 | 12 | # Examples 13 | 14 | ## Example: Single key press 15 | ```csharp 16 | public void PressTheSpacebar() 17 | { 18 | var simulator = new InputSimulator(); 19 | simulator.Keyboard.KeyPress(VirtualKeyCode.SPACE); 20 | } 21 | ``` 22 | 23 | ## Example: Key-down and Key-up 24 | ```csharp 25 | public void ShoutHello() 26 | { 27 | var simulator = new InputSimulator(); 28 | 29 | // Simulate each key stroke 30 | simulator.Keyboard.KeyDown(VirtualKeyCode.SHIFT); 31 | simulator.Keyboard.KeyPress(VirtualKeyCode.VK_H); 32 | simulator.Keyboard.KeyPress(VirtualKeyCode.VK_E); 33 | simulator.Keyboard.KeyPress(VirtualKeyCode.VK_L); 34 | simulator.Keyboard.KeyPress(VirtualKeyCode.VK_L); 35 | simulator.Keyboard.KeyPress(VirtualKeyCode.VK_O); 36 | simulator.Keyboard.KeyPress(VirtualKeyCode.VK_1); 37 | simulator.Keyboard.KeyUp(VirtualKeyCode.SHIFT); 38 | 39 | // Alternatively you can simulate text entry to acheive the same end result 40 | simulator.Keyboard.TextEntry("HELLO!"); 41 | } 42 | ``` 43 | 44 | ## Example: Modified keystrokes such as CTRL-C 45 | ```csharp 46 | public void SimulateSomeModifiedKeystrokes() 47 | { 48 | var simulator = new InputSimulator(); 49 | 50 | // CTRL-C (effectively a copy command in many situations) 51 | simulator.Keyboard.ModifiedKeyStroke(VirtualKeyCode.CONTROL, VirtualKeyCode.VK_C); 52 | 53 | // You can simulate chords with multiple modifiers 54 | // For example CTRL-K-C whic is simulated as 55 | // CTRL-down, K, C, CTRL-up 56 | simulator.Keyboard.ModifiedKeyStroke(VirtualKeyCode.CONTROL, new [] {VirtualKeyCode.VK_K, VirtualKeyCode.VK_C}); 57 | 58 | // You can simulate complex chords with multiple modifiers and key presses 59 | // For example CTRL-ALT-SHIFT-ESC-K which is simulated as 60 | // CTRL-down, ALT-down, SHIFT-down, press ESC, press K, SHIFT-up, ALT-up, CTRL-up 61 | simulator.Keyboard.ModifiedKeyStroke( 62 | new[] { VirtualKeyCode.CONTROL, VirtualKeyCode.MENU, VirtualKeyCode.SHIFT }, 63 | new[] { VirtualKeyCode.ESCAPE, VirtualKeyCode.VK_K }); 64 | } 65 | ``` 66 | 67 | ## Example: Simulate text entry 68 | ```csharp 69 | public void SayHello() 70 | { 71 | var simulator = new InputSimulator(); 72 | simulator.Keyboard.TextEntry("Say hello!"); 73 | } 74 | ``` 75 | 76 | ## Example: Determine the state of different types of keys 77 | ```csharp 78 | public void GetKeyStatus() 79 | { 80 | var simulator = new InputSimulator(); 81 | 82 | // Determines if the shift key is currently down 83 | var isShiftKeyDown = simulator.InputDeviceState.IsKeyDown(VirtualKeyCode.SHIFT); 84 | 85 | // Determines if the caps lock key is currently in effect (toggled on) 86 | var isCapsLockOn = simulator.InputDeviceState.IsTogglingKeyInEffect(VirtualKeyCode.CAPITAL); 87 | } 88 | ``` 89 | 90 | ## Example: Get current mouse position 91 | ```csharp 92 | public void GetMousePosition() 93 | { 94 | var simulator = new InputSimulator(); 95 | 96 | // Gets the mouse position as System.Drawing.Point 97 | var position = simulator.Mouse.Position; 98 | } 99 | ``` 100 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # Add steps that publish symbols, save build artifacts, and more: 2 | # https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net 3 | 4 | trigger: 5 | batch: true 6 | branches: 7 | include: 8 | - master 9 | - develop 10 | - release/* 11 | 12 | pr: 13 | branches: 14 | include: 15 | - master 16 | - release/* 17 | 18 | pool: 19 | vmImage: 'windows-2019' 20 | 21 | variables: 22 | Solution: '**/*.sln' 23 | BuildPlatform: 'Any CPU' 24 | BuildConfiguration: 'Release' 25 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 'true' 26 | 27 | steps: 28 | - task: UseDotNet@2 29 | displayName: 'Use .NET Core sdk' 30 | inputs: 31 | packageType: 'sdk' 32 | version: '3.x' 33 | 34 | - script: | 35 | dotnet tool install -g GitVersion.Tool --version 5.10.1 36 | displayName: 'Install global tools' 37 | 38 | - script: dotnet-gitversion /output buildserver 39 | displayName: 'Run GitVersion.Tool' 40 | 41 | - powershell: Write-Output "##vso[task.setvariable variable=informationalVersion]$($env:GITVERSION_INFORMATIONALVERSION)" 42 | displayName: 'Set assembly version variable' 43 | 44 | - bash: printenv | sort 45 | displayName: 'List environment variables' 46 | 47 | - task: DotNetCoreCLI@2 48 | displayName: 'Build source' 49 | inputs: 50 | command: 'build' 51 | projects: '$(Solution)' 52 | arguments: '-c $(BuildConfiguration) /p:Version=$(informationalVersion)' 53 | 54 | - powershell: | 55 | $testsDirectory = Join-Path -Path '$(Build.SourcesDirectory)' -ChildPath 'tests' 56 | $testAssemblies = Get-ChildItem -Path "$testsDirectory" -Recurse -File -Filter '*.Tests.csproj' | Select-Object -ExpandProperty BaseName 57 | Write-Output "##vso[task.setvariable variable=testAssemblies]$($testAssemblies -join '|')" 58 | displayName: 'Set test assembly filter variable' 59 | 60 | - task: DotNetCoreCLI@2 61 | displayName: 'Run tests with coverage' 62 | inputs: 63 | command: test 64 | projects: 'tests/**/*.Tests.csproj' 65 | arguments: '-c $(BuildConfiguration) /p:Version=$(informationalVersion) /p:AltCover=true /p:AltCoverOpenCover=true /p:AltCoverAssemblyExcludeFilter="xunit|$(testAssemblies)"' 66 | 67 | - powershell: | 68 | $testsDirectory = Join-Path -Path '$(Build.SourcesDirectory)' -ChildPath 'tests' 69 | $coverageFile = Get-ChildItem -Path "$testsDirectory" -Recurse -File -Filter 'coverage.xml' | Select-Object -First 1 70 | $codecovExecutable = Get-ChildItem -Path "$ENV:USERPROFILE\.nuget\packages\codecov" -Recurse -File -Filter "codecov.exe" | Sort-Object -Descending -Property FullName | Select-Object -First 1 71 | & "$($codecovExecutable.FullName)" -f "$($coverageFile.FullName)" -t '$(CODECOV_TOKEN)' 72 | displayName: 'Upload coverage to codecov.io' 73 | 74 | - task: DotNetCoreCLI@2 75 | displayName: 'Pack projects' 76 | condition: and(succeeded(), or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(variables['Build.SourceBranch'], 'refs/heads/develop'), startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'))) 77 | inputs: 78 | command: 'pack' 79 | packagesToPack: '$(Solution)' 80 | nobuild: true 81 | includesymbols: true 82 | versioningScheme: 'byEnvVar' 83 | versionEnvVar: 'GITVERSION_NUGETVERSIONV2' 84 | 85 | - task: NuGetToolInstaller@1 86 | condition: and(succeeded(), or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(variables['Build.SourceBranch'], 'refs/heads/develop'), startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'))) 87 | inputs: 88 | versionSpec: '5.1.0' 89 | checkLatest: true 90 | 91 | - task: NuGetCommand@2 92 | displayName: 'Push *.nupkg and *.snupkg to nuget.org' 93 | condition: and(succeeded(), or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(variables['Build.SourceBranch'], 'refs/heads/develop'), startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'))) 94 | inputs: 95 | command: 'push' 96 | packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' 97 | nuGetFeedType: 'external' 98 | publishFeedCredentials: 'NuGet.org' 99 | allowPackageConflicts: true 100 | 101 | - task: GitHubRelease@0 102 | condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master')) 103 | inputs: 104 | gitHubConnection: 'GithubOAuth' 105 | repositoryName: '$(Build.Repository.Name)' 106 | action: 'create' 107 | target: '$(Build.SourceVersion)' 108 | tagSource: 'manual' 109 | tag: 'v$(Build.BuildNumber)' 110 | title: 'v$(Build.BuildNumber)' 111 | 112 | - task: GitHubRelease@0 113 | condition: and(succeeded(), or(eq(variables['Build.SourceBranch'], 'refs/heads/develop'), startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'))) 114 | inputs: 115 | gitHubConnection: 'GithubOAuth' 116 | repositoryName: '$(Build.Repository.Name)' 117 | action: 'create' 118 | target: '$(Build.SourceVersion)' 119 | tagSource: 'manual' 120 | tag: 'v$(Build.BuildNumber)' 121 | title: 'v$(Build.BuildNumber)' 122 | isPreRelease: true 123 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/GregsStack.InputSimulatorStandard.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net40;netstandard2.0 5 | Input Simulator Standard 6 | Michael Noonan, Theodoros Chatzigiannakis, Gregor Sindl 7 | Copyright 2009-2019 8 | LICENSE 9 | true 10 | https://github.com/GregsStack/InputSimulatorStandard 11 | This package is a fork of the Windows Input Simulator Plus package. If you have encountered applications that do not receive input from the original Windows Input Simulator, try replacing it with this package instead. 12 | windows;input;keyboard;mouse 13 | https://github.com/GregsStack/InputSimulatorStandard 14 | true 15 | true 16 | true 17 | snupkg 18 | 19 | 20 | 21 | 22 | <_Parameter1>$(AssemblyName).Tests 23 | 24 | 25 | <_Parameter1>DynamicProxyGenAssembly2 26 | 27 | 28 | 29 | 30 | 31 | all 32 | runtime; build; native; contentfiles; analyzers 33 | 34 | 35 | 36 | 37 | 38 | True 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/IInputDeviceStateAdapter.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard 2 | { 3 | using Native; 4 | 5 | /// 6 | /// The contract for a service that interprets the state of input devices. 7 | /// 8 | public interface IInputDeviceStateAdapter 9 | { 10 | /// 11 | /// Determines whether the specified key is up or down. 12 | /// 13 | /// The for the key. 14 | /// true if the key is down; otherwise, false. 15 | bool IsKeyDown(VirtualKeyCode keyCode); 16 | 17 | /// 18 | /// Determines whether the specified key is up or down. 19 | /// 20 | /// The for the key. 21 | /// true if the key is up; otherwise, false. 22 | bool IsKeyUp(VirtualKeyCode keyCode); 23 | 24 | /// 25 | /// Determines whether the physical key is up or down at the time the function is called regardless of whether the application thread has read the keyboard event from the message pump. 26 | /// 27 | /// The for the key. 28 | /// true if the key is down; otherwise, false. 29 | bool IsHardwareKeyDown(VirtualKeyCode keyCode); 30 | 31 | /// 32 | /// Determines whether the physical key is up or down at the time the function is called regardless of whether the application thread has read the keyboard event from the message pump. 33 | /// 34 | /// The for the key. 35 | /// true if the key is up; otherwise, false. 36 | bool IsHardwareKeyUp(VirtualKeyCode keyCode); 37 | 38 | /// 39 | /// Determines whether the toggling key is toggled on (in-effect) or not. 40 | /// 41 | /// The for the key. 42 | /// true if the toggling key is toggled on (in-effect); otherwise, false. 43 | bool IsTogglingKeyInEffect(VirtualKeyCode keyCode); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/IInputMessageDispatcher.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard 2 | { 3 | using System; 4 | 5 | using Native; 6 | 7 | /// 8 | /// The contract for a service that dispatches messages to the appropriate destination. 9 | /// 10 | internal interface IInputMessageDispatcher 11 | { 12 | /// 13 | /// Dispatches the specified list of messages in their specified order. 14 | /// 15 | /// The list of messages to be dispatched. 16 | /// If the array is empty. 17 | /// If the array is null. 18 | /// If the any of the commands in the array could not be sent successfully. 19 | void DispatchInput(Input[] inputs); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/IInputSimulator.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard 2 | { 3 | /// 4 | /// The contract for a service that simulates Keyboard and Mouse input and Hardware Input Device state detection for the Windows Platform. 5 | /// 6 | public interface IInputSimulator 7 | { 8 | /// 9 | /// Gets the instance for simulating Keyboard input. 10 | /// 11 | /// The instance. 12 | IKeyboardSimulator Keyboard { get; } 13 | 14 | /// 15 | /// Gets the instance for simulating Mouse input. 16 | /// 17 | /// The instance. 18 | IMouseSimulator Mouse { get; } 19 | 20 | /// 21 | /// Gets the instance for determining the state of the various input devices. 22 | /// 23 | /// The instance. 24 | IInputDeviceStateAdapter InputDeviceState { get; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/IKeyboardSimulator.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | using Native; 7 | 8 | /// 9 | /// The service contract for a keyboard simulator for the Windows platform. 10 | /// 11 | public interface IKeyboardSimulator 12 | { 13 | /// 14 | /// Simulates the key down gesture for the specified key. 15 | /// 16 | /// The for the key. 17 | IKeyboardSimulator KeyDown(VirtualKeyCode keyCode); 18 | 19 | /// 20 | /// Simulates the key press gesture for the specified key. 21 | /// 22 | /// The for the key. 23 | IKeyboardSimulator KeyPress(VirtualKeyCode keyCode); 24 | 25 | /// 26 | /// Simulates a key press for each of the specified key codes in the order they are specified. 27 | /// 28 | /// 29 | IKeyboardSimulator KeyPress(params VirtualKeyCode[] keyCodes); 30 | 31 | /// 32 | /// Simulates the key up gesture for the specified key. 33 | /// 34 | /// The for the key. 35 | IKeyboardSimulator KeyUp(VirtualKeyCode keyCode); 36 | 37 | /// 38 | /// Simulates a modified keystroke where there are multiple modifiers and multiple keys like CTRL-ALT-K-C where CTRL and ALT are the modifierKeys and K and C are the keys. 39 | /// The flow is Modifiers KeyDown in order, Keys Press in order, Modifiers KeyUp in reverse order. 40 | /// 41 | /// The list of s for the modifier keys. 42 | /// The list of s for the keys to simulate. 43 | IKeyboardSimulator ModifiedKeyStroke(IEnumerable modifierKeyCodes, IEnumerable keyCodes); 44 | 45 | /// 46 | /// Simulates a modified keystroke where there are multiple modifiers and one key like CTRL-ALT-C where CTRL and ALT are the modifierKeys and C is the key. 47 | /// The flow is Modifiers KeyDown in order, Key Press, Modifiers KeyUp in reverse order. 48 | /// 49 | /// The list of s for the modifier keys. 50 | /// The for the key. 51 | IKeyboardSimulator ModifiedKeyStroke(IEnumerable modifierKeyCodes, VirtualKeyCode keyCode); 52 | 53 | /// 54 | /// Simulates a modified keystroke where there is one modifier and multiple keys like CTRL-K-C where CTRL is the modifierKey and K and C are the keys. 55 | /// The flow is Modifier KeyDown, Keys Press in order, Modifier KeyUp. 56 | /// 57 | /// The for the modifier key. 58 | /// The list of s for the keys to simulate. 59 | IKeyboardSimulator ModifiedKeyStroke(VirtualKeyCode modifierKey, IEnumerable keyCodes); 60 | 61 | /// 62 | /// Simulates a simple modified keystroke like CTRL-C where CTRL is the modifierKey and C is the key. 63 | /// The flow is Modifier KeyDown, Key Press, Modifier KeyUp. 64 | /// 65 | /// The for the modifier key. 66 | /// The for the key. 67 | IKeyboardSimulator ModifiedKeyStroke(VirtualKeyCode modifierKeyCode, VirtualKeyCode keyCode); 68 | 69 | /// 70 | /// Simulates uninterrupted text entry via the keyboard. 71 | /// 72 | /// The text to be simulated. 73 | IKeyboardSimulator TextEntry(string text); 74 | 75 | /// 76 | /// Simulates a single character text entry via the keyboard. 77 | /// 78 | /// The unicode character to be simulated. 79 | IKeyboardSimulator TextEntry(char character); 80 | 81 | /// 82 | /// Sleeps the executing thread to create a pause between simulated inputs. 83 | /// 84 | /// The number of milliseconds to wait. 85 | IKeyboardSimulator Sleep(int millisecondsTimeout); 86 | 87 | /// 88 | /// Sleeps the executing thread to create a pause between simulated inputs. 89 | /// 90 | /// The time to wait. 91 | IKeyboardSimulator Sleep(TimeSpan timeout); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/IMouseSimulator.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard 2 | { 3 | using System; 4 | 5 | /// 6 | /// The service contract for a mouse simulator for the Windows platform. 7 | /// 8 | public interface IMouseSimulator 9 | { 10 | /// 11 | /// Gets or sets the amount of mouse wheel scrolling per click. The default value for this property is 120 and different values may cause some applications to interpret the scrolling differently than expected. 12 | /// 13 | int MouseWheelClickSize { get; set; } 14 | 15 | /// 16 | /// Retrieves the position of the mouse cursor, in screen coordinates. 17 | /// 18 | System.Drawing.Point Position { get; } 19 | 20 | /// 21 | /// Simulates mouse movement by the specified distance measured as a delta from the current mouse location in pixels. 22 | /// 23 | /// The distance in pixels to move the mouse horizontally. 24 | /// The distance in pixels to move the mouse vertically. 25 | IMouseSimulator MoveMouseBy(int pixelDeltaX, int pixelDeltaY); 26 | 27 | /// 28 | /// Simulates mouse movement to the specified location on the primary display device. 29 | /// 30 | /// The destination's absolute X-coordinate on the primary display device where 0 is the extreme left hand side of the display device and 65535 is the extreme right hand side of the display device. 31 | /// The destination's absolute Y-coordinate on the primary display device where 0 is the top of the display device and 65535 is the bottom of the display device. 32 | IMouseSimulator MoveMouseTo(double absoluteX, double absoluteY); 33 | 34 | /// 35 | /// Simulates mouse movement to the specified location on the Virtual Desktop which includes all active displays. 36 | /// 37 | /// The destination's absolute X-coordinate on the virtual desktop where 0 is the left hand side of the virtual desktop and 65535 is the extreme right hand side of the virtual desktop. 38 | /// The destination's absolute Y-coordinate on the virtual desktop where 0 is the top of the virtual desktop and 65535 is the bottom of the virtual desktop. 39 | IMouseSimulator MoveMouseToPositionOnVirtualDesktop(double absoluteX, double absoluteY); 40 | 41 | /// 42 | /// Simulates a mouse left button down gesture. 43 | /// 44 | IMouseSimulator LeftButtonDown(); 45 | 46 | /// 47 | /// Simulates a mouse left button up gesture. 48 | /// 49 | IMouseSimulator LeftButtonUp(); 50 | 51 | /// 52 | /// Simulates a mouse left button click gesture. 53 | /// 54 | IMouseSimulator LeftButtonClick(); 55 | 56 | /// 57 | /// Simulates a mouse left button double-click gesture. 58 | /// 59 | IMouseSimulator LeftButtonDoubleClick(); 60 | 61 | /// 62 | /// Simulates a mouse middle button down gesture. 63 | /// 64 | IMouseSimulator MiddleButtonDown(); 65 | 66 | /// 67 | /// Simulates a mouse middle button up gesture. 68 | /// 69 | IMouseSimulator MiddleButtonUp(); 70 | 71 | /// 72 | /// Simulates a mouse middle button click gesture. 73 | /// 74 | IMouseSimulator MiddleButtonClick(); 75 | 76 | /// 77 | /// Simulates a mouse middle button double-click gesture. 78 | /// 79 | IMouseSimulator MiddleButtonDoubleClick(); 80 | 81 | /// 82 | /// Simulates a mouse right button down gesture. 83 | /// 84 | IMouseSimulator RightButtonDown(); 85 | 86 | /// 87 | /// Simulates a mouse right button up gesture. 88 | /// 89 | IMouseSimulator RightButtonUp(); 90 | 91 | /// 92 | /// Simulates a mouse right button click gesture. 93 | /// 94 | IMouseSimulator RightButtonClick(); 95 | 96 | /// 97 | /// Simulates a mouse right button double-click gesture. 98 | /// 99 | IMouseSimulator RightButtonDoubleClick(); 100 | 101 | /// 102 | /// Simulates a mouse X button down gesture. 103 | /// 104 | /// The button id. 105 | IMouseSimulator XButtonDown(int buttonId); 106 | 107 | /// 108 | /// Simulates a mouse X button up gesture. 109 | /// 110 | /// The button id. 111 | IMouseSimulator XButtonUp(int buttonId); 112 | 113 | /// 114 | /// Simulates a mouse X button click gesture. 115 | /// 116 | /// The button id. 117 | IMouseSimulator XButtonClick(int buttonId); 118 | 119 | /// 120 | /// Simulates a mouse X button double-click gesture. 121 | /// 122 | /// The button id. 123 | IMouseSimulator XButtonDoubleClick(int buttonId); 124 | 125 | /// 126 | /// Simulates mouse vertical wheel scroll gesture. 127 | /// 128 | /// The amount to scroll in clicks. A positive value indicates that the wheel was rotated forward, away from the user; a negative value indicates that the wheel was rotated backward, toward the user. 129 | IMouseSimulator VerticalScroll(int scrollAmountInClicks); 130 | 131 | /// 132 | /// Simulates a mouse horizontal wheel scroll gesture. Supported by Windows Vista and later. 133 | /// 134 | /// The amount to scroll in clicks. A positive value indicates that the wheel was rotated to the right; a negative value indicates that the wheel was rotated to the left. 135 | IMouseSimulator HorizontalScroll(int scrollAmountInClicks); 136 | 137 | /// 138 | /// Sleeps the executing thread to create a pause between simulated inputs. 139 | /// 140 | /// The number of milliseconds to wait. 141 | IMouseSimulator Sleep(int millisecondsTimeout); 142 | 143 | /// 144 | /// Sleeps the executing thread to create a pause between simulated inputs. 145 | /// 146 | /// The time to wait. 147 | IMouseSimulator Sleep(TimeSpan timeout); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/InputBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard 2 | { 3 | using System; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | 7 | using Native; 8 | 9 | /// 10 | /// 11 | /// A helper class for building a list of messages ready to be sent to the native Windows API. 12 | /// 13 | internal class InputBuilder : IEnumerable 14 | { 15 | /// 16 | /// The public list of messages being built by this instance. 17 | /// 18 | private readonly List inputList; 19 | 20 | private static readonly List ExtendedKeys = new List 21 | { 22 | VirtualKeyCode.NUMPAD_RETURN, 23 | VirtualKeyCode.MENU, 24 | VirtualKeyCode.RMENU, 25 | VirtualKeyCode.CONTROL, 26 | VirtualKeyCode.RCONTROL, 27 | VirtualKeyCode.INSERT, 28 | VirtualKeyCode.DELETE, 29 | VirtualKeyCode.HOME, 30 | VirtualKeyCode.END, 31 | VirtualKeyCode.PRIOR, 32 | VirtualKeyCode.NEXT, 33 | VirtualKeyCode.RIGHT, 34 | VirtualKeyCode.UP, 35 | VirtualKeyCode.LEFT, 36 | VirtualKeyCode.DOWN, 37 | VirtualKeyCode.NUMLOCK, 38 | VirtualKeyCode.CANCEL, 39 | VirtualKeyCode.SNAPSHOT, 40 | VirtualKeyCode.DIVIDE 41 | }; 42 | 43 | /// 44 | /// Initializes a new instance of the class. 45 | /// 46 | public InputBuilder() 47 | { 48 | this.inputList = new List(); 49 | } 50 | 51 | /// 52 | /// Returns the list of messages as a of messages. 53 | /// 54 | /// The of messages. 55 | public Input[] ToArray() => this.inputList.ToArray(); 56 | 57 | /// 58 | /// 59 | /// Returns an enumerator that iterates through the list of messages. 60 | /// 61 | /// 62 | /// A that can be used to iterate through the list of messages. 63 | /// 64 | /// 1 65 | public IEnumerator GetEnumerator() => this.inputList.GetEnumerator(); 66 | 67 | /// 68 | /// 69 | /// Returns an enumerator that iterates through the list of messages. 70 | /// 71 | /// 72 | /// An object that can be used to iterate through the list of messages. 73 | /// 74 | /// 2 75 | IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); 76 | 77 | /// 78 | /// Gets the at the specified position. 79 | /// 80 | /// The message at the specified position. 81 | public Input this[int position] => this.inputList[position]; 82 | 83 | /// 84 | /// Determines if the is an ExtendedKey 85 | /// 86 | /// The key code. 87 | /// true if the key code is an extended key; otherwise, false. 88 | /// 89 | /// The extended keys consist of the ALT and CTRL keys on the right-hand side of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE DOWN, and arrow keys in the clusters to the left of the numeric keypad; the NUM LOCK key; the BREAK (CTRL+PAUSE) key; the PRINT SCRN key; and the divide (/) and ENTER keys in the numeric keypad. 90 | /// 91 | /// See http://msdn.microsoft.com/en-us/library/ms646267(v=vs.85).aspx Section "Extended-Key Flag" 92 | /// 93 | public static bool IsExtendedKey(VirtualKeyCode keyCode) => ExtendedKeys.Contains(keyCode); 94 | 95 | /// 96 | /// Adds a key down to the list of messages. 97 | /// 98 | /// The . 99 | /// This instance. 100 | public InputBuilder AddKeyDown(VirtualKeyCode keyCode) 101 | { 102 | var code = (ushort)((int)keyCode & 0xFFFF); 103 | var down = 104 | new Input 105 | { 106 | Type = (uint)InputType.Keyboard, 107 | Data = 108 | { 109 | Keyboard = 110 | new KeyboardInput 111 | { 112 | KeyCode = (ushort) code , 113 | Scan = (ushort)(NativeMethods.MapVirtualKey((uint)code, 0) & 0xFFU), 114 | Flags = IsExtendedKey(keyCode) ? (uint) KeyboardFlag.ExtendedKey : 0, 115 | Time = 0, 116 | ExtraInfo = IntPtr.Zero 117 | } 118 | } 119 | }; 120 | 121 | this.inputList.Add(down); 122 | return this; 123 | } 124 | 125 | /// 126 | /// Adds a key up to the list of messages. 127 | /// 128 | /// The . 129 | /// This instance. 130 | public InputBuilder AddKeyUp(VirtualKeyCode keyCode) 131 | { 132 | var code = (ushort)((int)keyCode & 0xFFFF); 133 | var up = 134 | new Input 135 | { 136 | Type = (uint)InputType.Keyboard, 137 | Data = 138 | { 139 | Keyboard = 140 | new KeyboardInput 141 | { 142 | KeyCode = (ushort) code, 143 | Scan = (ushort)(NativeMethods.MapVirtualKey((uint)code, 0) & 0xFFU), 144 | Flags = (uint) (IsExtendedKey(keyCode) 145 | ? KeyboardFlag.KeyUp | KeyboardFlag.ExtendedKey 146 | : KeyboardFlag.KeyUp), 147 | Time = 0, 148 | ExtraInfo = IntPtr.Zero 149 | } 150 | } 151 | }; 152 | 153 | this.inputList.Add(up); 154 | return this; 155 | } 156 | 157 | /// 158 | /// Adds a key press to the list of messages which is equivalent to a key down followed by a key up. 159 | /// 160 | /// The . 161 | /// This instance. 162 | public InputBuilder AddKeyPress(VirtualKeyCode keyCode) 163 | { 164 | this.AddKeyDown(keyCode); 165 | this.AddKeyUp(keyCode); 166 | return this; 167 | } 168 | 169 | /// 170 | /// Adds the character to the list of messages. 171 | /// 172 | /// The to be added to the list of messages. 173 | /// This instance. 174 | public InputBuilder AddCharacter(char character) 175 | { 176 | ushort scanCode = character; 177 | 178 | var down = new Input 179 | { 180 | Type = (uint)InputType.Keyboard, 181 | Data = 182 | { 183 | Keyboard = 184 | new KeyboardInput 185 | { 186 | KeyCode = 0, 187 | Scan = scanCode, 188 | Flags = (uint)KeyboardFlag.Unicode, 189 | Time = 0, 190 | ExtraInfo = IntPtr.Zero 191 | } 192 | } 193 | }; 194 | 195 | var up = new Input 196 | { 197 | Type = (uint)InputType.Keyboard, 198 | Data = 199 | { 200 | Keyboard = 201 | new KeyboardInput 202 | { 203 | KeyCode = 0, 204 | Scan = scanCode, 205 | Flags = 206 | (uint)(KeyboardFlag.KeyUp | KeyboardFlag.Unicode), 207 | Time = 0, 208 | ExtraInfo = IntPtr.Zero 209 | } 210 | } 211 | }; 212 | 213 | // Handle extended keys: 214 | // If the scan code is preceded by a prefix byte that has the value 0xE0 (224), 215 | // we need to include the KEYEVENTF_EXTENDEDKEY flag in the Flags property. 216 | if ((scanCode & 0xFF00) == 0xE000) 217 | { 218 | down.Data.Keyboard.Flags |= (uint)KeyboardFlag.ExtendedKey; 219 | up.Data.Keyboard.Flags |= (uint)KeyboardFlag.ExtendedKey; 220 | } 221 | 222 | this.inputList.Add(down); 223 | this.inputList.Add(up); 224 | return this; 225 | } 226 | 227 | /// 228 | /// Adds all of the characters in the specified of . 229 | /// 230 | /// The characters to add. 231 | /// This instance. 232 | public InputBuilder AddCharacters(IEnumerable characters) 233 | { 234 | foreach (var character in characters) 235 | { 236 | this.AddCharacter(character); 237 | } 238 | 239 | return this; 240 | } 241 | 242 | /// 243 | /// Adds the characters in the specified . 244 | /// 245 | /// The string of to add. 246 | /// This instance. 247 | public InputBuilder AddCharacters(string characters) => this.AddCharacters(characters.ToCharArray()); 248 | 249 | /// 250 | /// Moves the mouse relative to its current position. 251 | /// 252 | /// 253 | /// 254 | /// This instance. 255 | public InputBuilder AddRelativeMouseMovement(int x, int y) 256 | { 257 | var movement = new Input { Type = (uint)InputType.Mouse }; 258 | movement.Data.Mouse.Flags = (uint)MouseFlag.Move; 259 | movement.Data.Mouse.X = x; 260 | movement.Data.Mouse.Y = y; 261 | 262 | this.inputList.Add(movement); 263 | 264 | return this; 265 | } 266 | 267 | /// 268 | /// Move the mouse to an absolute position. 269 | /// 270 | /// 271 | /// 272 | /// This instance. 273 | public InputBuilder AddAbsoluteMouseMovement(int absoluteX, int absoluteY) 274 | { 275 | var movement = new Input { Type = (uint)InputType.Mouse }; 276 | movement.Data.Mouse.Flags = (uint)(MouseFlag.Move | MouseFlag.Absolute); 277 | movement.Data.Mouse.X = (int)((absoluteX * 65536) / NativeMethods.GetSystemMetrics((uint)SystemMetric.SM_CXSCREEN)); 278 | movement.Data.Mouse.Y = (int)((absoluteY * 65536) / NativeMethods.GetSystemMetrics((uint)SystemMetric.SM_CYSCREEN)); 279 | 280 | this.inputList.Add(movement); 281 | 282 | return this; 283 | } 284 | 285 | /// 286 | /// Move the mouse to the absolute position on the virtual desktop. 287 | /// 288 | /// 289 | /// 290 | /// This instance. 291 | public InputBuilder AddAbsoluteMouseMovementOnVirtualDesktop(int absoluteX, int absoluteY) 292 | { 293 | var movement = new Input { Type = (uint)InputType.Mouse }; 294 | movement.Data.Mouse.Flags = (uint)(MouseFlag.Move | MouseFlag.Absolute | MouseFlag.VirtualDesk); 295 | movement.Data.Mouse.X = absoluteX; 296 | movement.Data.Mouse.Y = absoluteY; 297 | 298 | this.inputList.Add(movement); 299 | 300 | return this; 301 | } 302 | 303 | /// 304 | /// Adds a mouse button down for the specified button. 305 | /// 306 | /// 307 | /// This instance. 308 | public InputBuilder AddMouseButtonDown(MouseButton button) 309 | { 310 | var buttonDown = new Input { Type = (uint)InputType.Mouse }; 311 | buttonDown.Data.Mouse.Flags = (uint)ToMouseButtonDownFlag(button); 312 | 313 | this.inputList.Add(buttonDown); 314 | 315 | return this; 316 | } 317 | 318 | /// 319 | /// Adds a mouse button down for the specified button. 320 | /// 321 | /// 322 | /// This instance. 323 | public InputBuilder AddMouseXButtonDown(int xButtonId) 324 | { 325 | var buttonDown = new Input { Type = (uint)InputType.Mouse }; 326 | buttonDown.Data.Mouse.Flags = (uint)MouseFlag.XDown; 327 | buttonDown.Data.Mouse.MouseData = (uint)xButtonId; 328 | 329 | this.inputList.Add(buttonDown); 330 | 331 | return this; 332 | } 333 | 334 | /// 335 | /// Adds a mouse button up for the specified button. 336 | /// 337 | /// 338 | /// This instance. 339 | public InputBuilder AddMouseButtonUp(MouseButton button) 340 | { 341 | var buttonUp = new Input { Type = (uint)InputType.Mouse }; 342 | buttonUp.Data.Mouse.Flags = (uint)ToMouseButtonUpFlag(button); 343 | 344 | this.inputList.Add(buttonUp); 345 | 346 | return this; 347 | } 348 | 349 | /// 350 | /// Adds a mouse button up for the specified button. 351 | /// 352 | /// 353 | /// This instance. 354 | public InputBuilder AddMouseXButtonUp(int xButtonId) 355 | { 356 | var buttonUp = new Input { Type = (uint)InputType.Mouse }; 357 | buttonUp.Data.Mouse.Flags = (uint)MouseFlag.XUp; 358 | buttonUp.Data.Mouse.MouseData = (uint)xButtonId; 359 | 360 | this.inputList.Add(buttonUp); 361 | 362 | return this; 363 | } 364 | 365 | /// 366 | /// Adds a single click of the specified button. 367 | /// 368 | /// 369 | /// This instance. 370 | public InputBuilder AddMouseButtonClick(MouseButton button) => this.AddMouseButtonDown(button).AddMouseButtonUp(button); 371 | 372 | /// 373 | /// Adds a single click of the specified button. 374 | /// 375 | /// 376 | /// This instance. 377 | public InputBuilder AddMouseXButtonClick(int xButtonId) => this.AddMouseXButtonDown(xButtonId).AddMouseXButtonUp(xButtonId); 378 | 379 | /// 380 | /// Adds a double click of the specified button. 381 | /// 382 | /// 383 | /// This instance. 384 | public InputBuilder AddMouseButtonDoubleClick(MouseButton button) => this.AddMouseButtonClick(button).AddMouseButtonClick(button); 385 | 386 | /// 387 | /// Adds a double click of the specified button. 388 | /// 389 | /// 390 | /// This instance. 391 | public InputBuilder AddMouseXButtonDoubleClick(int xButtonId) => this.AddMouseXButtonClick(xButtonId).AddMouseXButtonClick(xButtonId); 392 | 393 | /// 394 | /// Scroll the vertical mouse wheel by the specified amount. 395 | /// 396 | /// 397 | /// This instance. 398 | public InputBuilder AddMouseVerticalWheelScroll(int scrollAmount) 399 | { 400 | var scroll = new Input { Type = (uint)InputType.Mouse }; 401 | scroll.Data.Mouse.Flags = (uint)MouseFlag.VerticalWheel; 402 | scroll.Data.Mouse.MouseData = (uint)scrollAmount; 403 | 404 | this.inputList.Add(scroll); 405 | 406 | return this; 407 | } 408 | 409 | /// 410 | /// Scroll the horizontal mouse wheel by the specified amount. 411 | /// 412 | /// 413 | /// This instance. 414 | public InputBuilder AddMouseHorizontalWheelScroll(int scrollAmount) 415 | { 416 | var scroll = new Input { Type = (uint)InputType.Mouse }; 417 | scroll.Data.Mouse.Flags = (uint)MouseFlag.HorizontalWheel; 418 | scroll.Data.Mouse.MouseData = (uint)scrollAmount; 419 | 420 | this.inputList.Add(scroll); 421 | 422 | return this; 423 | } 424 | 425 | private static MouseFlag ToMouseButtonDownFlag(MouseButton button) 426 | { 427 | switch (button) 428 | { 429 | case MouseButton.LeftButton: 430 | return MouseFlag.LeftDown; 431 | 432 | case MouseButton.MiddleButton: 433 | return MouseFlag.MiddleDown; 434 | 435 | case MouseButton.RightButton: 436 | return MouseFlag.RightDown; 437 | 438 | default: 439 | return MouseFlag.LeftDown; 440 | } 441 | } 442 | 443 | private static MouseFlag ToMouseButtonUpFlag(MouseButton button) 444 | { 445 | switch (button) 446 | { 447 | case MouseButton.LeftButton: 448 | return MouseFlag.LeftUp; 449 | 450 | case MouseButton.MiddleButton: 451 | return MouseFlag.MiddleUp; 452 | 453 | case MouseButton.RightButton: 454 | return MouseFlag.RightUp; 455 | 456 | default: 457 | return MouseFlag.LeftUp; 458 | } 459 | } 460 | } 461 | } 462 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/InputSimulator.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard 2 | { 3 | using System; 4 | 5 | /// 6 | /// 7 | /// Implements the interface to simulate Keyboard and Mouse input and provide the state of those input devices. 8 | /// 9 | public class InputSimulator : IInputSimulator 10 | { 11 | /// 12 | /// Initializes a new instance of the class using the default , and instances. 13 | /// 14 | public InputSimulator() 15 | : this(new KeyboardSimulator(), new MouseSimulator(), new WindowsInputDeviceStateAdapter()) 16 | { 17 | } 18 | 19 | /// 20 | /// Initializes a new instance of the class using the specified , and instances. 21 | /// 22 | /// The instance to use for simulating keyboard input. 23 | /// The instance to use for simulating mouse input. 24 | /// The instance to use for interpreting the state of input devices. 25 | public InputSimulator(IKeyboardSimulator keyboardSimulator, IMouseSimulator mouseSimulator, IInputDeviceStateAdapter inputDeviceStateAdapter) 26 | { 27 | this.Keyboard = keyboardSimulator ?? throw new ArgumentNullException(nameof(keyboardSimulator)); 28 | this.Mouse = mouseSimulator ?? throw new ArgumentNullException(nameof(mouseSimulator)); 29 | this.InputDeviceState = inputDeviceStateAdapter ?? throw new ArgumentNullException(nameof(inputDeviceStateAdapter)); 30 | } 31 | 32 | /// 33 | /// 34 | /// Gets the instance for simulating Keyboard input. 35 | /// 36 | /// The instance. 37 | public IKeyboardSimulator Keyboard { get; } 38 | 39 | /// 40 | /// 41 | /// Gets the instance for simulating Mouse input. 42 | /// 43 | /// The instance. 44 | public IMouseSimulator Mouse { get; } 45 | 46 | /// 47 | /// 48 | /// Gets the instance for determining the state of the various input devices. 49 | /// 50 | /// The instance. 51 | public IInputDeviceStateAdapter InputDeviceState { get; } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/KeyboardSimulator.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading; 6 | 7 | using Native; 8 | 9 | /// 10 | /// 11 | /// Implements the interface by calling the an to simulate Keyboard gestures. 12 | /// 13 | public class KeyboardSimulator : IKeyboardSimulator 14 | { 15 | /// 16 | /// The instance of the to use for dispatching messages. 17 | /// 18 | private readonly IInputMessageDispatcher messageDispatcher; 19 | 20 | /// 21 | /// 22 | /// Initializes a new instance of the class using an instance of a for dispatching messages. 23 | /// 24 | public KeyboardSimulator() 25 | : this(new WindowsInputMessageDispatcher()) 26 | { 27 | } 28 | 29 | /// 30 | /// Initializes a new instance of the class using the specified for dispatching messages. 31 | /// 32 | /// The to use for dispatching messages. 33 | /// If null is passed as the . 34 | internal KeyboardSimulator(IInputMessageDispatcher messageDispatcher) 35 | { 36 | this.messageDispatcher = messageDispatcher ?? throw new InvalidOperationException( 37 | string.Format("The {0} cannot operate with a null {1}. Please provide a valid {1} instance to use for dispatching {2} messages.", 38 | typeof(KeyboardSimulator).Name, typeof(IInputMessageDispatcher).Name, typeof(Input).Name)); 39 | } 40 | 41 | /// 42 | /// 43 | /// Calls the Win32 SendInput method to simulate a KeyDown. 44 | /// 45 | /// The to press 46 | public IKeyboardSimulator KeyDown(VirtualKeyCode keyCode) 47 | { 48 | var inputList = new InputBuilder().AddKeyDown(keyCode).ToArray(); 49 | this.SendSimulatedInput(inputList); 50 | return this; 51 | } 52 | 53 | /// 54 | /// 55 | /// Calls the Win32 SendInput method to simulate a KeyUp. 56 | /// 57 | /// The to lift up 58 | public IKeyboardSimulator KeyUp(VirtualKeyCode keyCode) 59 | { 60 | var inputList = new InputBuilder().AddKeyUp(keyCode).ToArray(); 61 | this.SendSimulatedInput(inputList); 62 | return this; 63 | } 64 | 65 | /// 66 | /// 67 | /// Calls the Win32 SendInput method with a KeyDown and KeyUp message in the same input sequence in order to simulate a Key PRESS. 68 | /// 69 | /// The to press 70 | public IKeyboardSimulator KeyPress(VirtualKeyCode keyCode) 71 | { 72 | var inputList = new InputBuilder().AddKeyPress(keyCode).ToArray(); 73 | this.SendSimulatedInput(inputList); 74 | return this; 75 | } 76 | 77 | /// 78 | /// 79 | /// Simulates a key press for each of the specified key codes in the order they are specified. 80 | /// 81 | /// 82 | public IKeyboardSimulator KeyPress(params VirtualKeyCode[] keyCodes) 83 | { 84 | var builder = new InputBuilder(); 85 | this.KeysPress(builder, keyCodes); 86 | this.SendSimulatedInput(builder.ToArray()); 87 | return this; 88 | } 89 | 90 | /// 91 | /// 92 | /// Simulates a simple modified keystroke like CTRL-C where CTRL is the modifierKey and C is the key. 93 | /// The flow is Modifier KeyDown, Key Press, Modifier KeyUp. 94 | /// 95 | /// The modifier key 96 | /// The key to simulate 97 | public IKeyboardSimulator ModifiedKeyStroke(VirtualKeyCode modifierKeyCode, VirtualKeyCode keyCode) 98 | { 99 | this.ModifiedKeyStroke(new[] { modifierKeyCode }, new[] { keyCode }); 100 | return this; 101 | } 102 | 103 | /// 104 | /// 105 | /// Simulates a modified keystroke where there are multiple modifiers and one key like CTRL-ALT-C where CTRL and ALT are the modifierKeys and C is the key. 106 | /// The flow is Modifiers KeyDown in order, Key Press, Modifiers KeyUp in reverse order. 107 | /// 108 | /// The list of modifier keys 109 | /// The key to simulate 110 | public IKeyboardSimulator ModifiedKeyStroke(IEnumerable modifierKeyCodes, VirtualKeyCode keyCode) 111 | { 112 | this.ModifiedKeyStroke(modifierKeyCodes, new[] { keyCode }); 113 | return this; 114 | } 115 | 116 | /// 117 | /// 118 | /// Simulates a modified keystroke where there is one modifier and multiple keys like CTRL-K-C where CTRL is the modifierKey and K and C are the keys. 119 | /// The flow is Modifier KeyDown, Keys Press in order, Modifier KeyUp. 120 | /// 121 | /// The modifier key 122 | /// The list of keys to simulate 123 | public IKeyboardSimulator ModifiedKeyStroke(VirtualKeyCode modifierKey, IEnumerable keyCodes) 124 | { 125 | this.ModifiedKeyStroke(new[] { modifierKey }, keyCodes); 126 | return this; 127 | } 128 | 129 | /// 130 | /// 131 | /// Simulates a modified keystroke where there are multiple modifiers and multiple keys like CTRL-ALT-K-C where CTRL and ALT are the modifierKeys and K and C are the keys. 132 | /// The flow is Modifiers KeyDown in order, Keys Press in order, Modifiers KeyUp in reverse order. 133 | /// 134 | /// The list of modifier keys 135 | /// The list of keys to simulate 136 | public IKeyboardSimulator ModifiedKeyStroke(IEnumerable modifierKeyCodes, IEnumerable keyCodes) 137 | { 138 | var builder = new InputBuilder(); 139 | this.ModifiersDown(builder, modifierKeyCodes); 140 | this.KeysPress(builder, keyCodes); 141 | this.ModifiersUp(builder, modifierKeyCodes); 142 | 143 | this.SendSimulatedInput(builder.ToArray()); 144 | return this; 145 | } 146 | 147 | /// 148 | /// 149 | /// Calls the Win32 SendInput method with a stream of KeyDown and KeyUp messages in order to simulate uninterrupted text entry via the keyboard. 150 | /// 151 | /// The text to be simulated. 152 | public IKeyboardSimulator TextEntry(string text) 153 | { 154 | if (text.Length > uint.MaxValue / 2) 155 | { 156 | throw new ArgumentException($"The text parameter is too long. It must be less than {uint.MaxValue / 2} characters.", nameof(text)); 157 | } 158 | 159 | var inputList = new InputBuilder().AddCharacters(text).ToArray(); 160 | this.SendSimulatedInput(inputList); 161 | return this; 162 | } 163 | 164 | /// 165 | /// 166 | /// Simulates a single character text entry via the keyboard. 167 | /// 168 | /// The unicode character to be simulated. 169 | public IKeyboardSimulator TextEntry(char character) 170 | { 171 | var inputList = new InputBuilder().AddCharacter(character).ToArray(); 172 | this.SendSimulatedInput(inputList); 173 | return this; 174 | } 175 | 176 | /// 177 | /// 178 | /// Sleeps the executing thread to create a pause between simulated inputs. 179 | /// 180 | /// The number of milliseconds to wait. 181 | public IKeyboardSimulator Sleep(int millisecondsTimeout) 182 | { 183 | return this.Sleep(TimeSpan.FromMilliseconds(millisecondsTimeout)); 184 | } 185 | 186 | /// 187 | /// 188 | /// Sleeps the executing thread to create a pause between simulated inputs. 189 | /// 190 | /// The time to wait. 191 | public IKeyboardSimulator Sleep(TimeSpan timeout) 192 | { 193 | Thread.Sleep(timeout); 194 | return this; 195 | } 196 | 197 | private void ModifiersDown(InputBuilder builder, IEnumerable modifierKeyCodes) 198 | { 199 | if (modifierKeyCodes == null) 200 | { 201 | return; 202 | } 203 | 204 | foreach (var key in modifierKeyCodes) 205 | { 206 | builder.AddKeyDown(key); 207 | } 208 | } 209 | 210 | private void ModifiersUp(InputBuilder builder, IEnumerable modifierKeyCodes) 211 | { 212 | if (modifierKeyCodes == null) 213 | { 214 | return; 215 | } 216 | 217 | // Key up in reverse (I miss LINQ) 218 | var stack = new Stack(modifierKeyCodes); 219 | while (stack.Count > 0) 220 | { 221 | builder.AddKeyUp(stack.Pop()); 222 | } 223 | } 224 | 225 | private void KeysPress(InputBuilder builder, IEnumerable keyCodes) 226 | { 227 | if (keyCodes == null) 228 | { 229 | return; 230 | } 231 | 232 | foreach (var key in keyCodes) 233 | { 234 | builder.AddKeyPress(key); 235 | } 236 | } 237 | 238 | /// 239 | /// Sends the list of messages using the instance. 240 | /// 241 | /// The of messages to send. 242 | private void SendSimulatedInput(Input[] inputList) 243 | { 244 | this.messageDispatcher.DispatchInput(inputList); 245 | } 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/MouseButton.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard 2 | { 3 | /// 4 | /// The mouse button 5 | /// 6 | public enum MouseButton 7 | { 8 | /// 9 | /// Left mouse button 10 | /// 11 | LeftButton, 12 | 13 | /// 14 | /// Middle mouse button 15 | /// 16 | MiddleButton, 17 | 18 | /// 19 | /// Right mouse button 20 | /// 21 | RightButton, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/MouseSimulator.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard 2 | { 3 | using System; 4 | using System.Threading; 5 | 6 | using Native; 7 | 8 | /// 9 | /// 10 | /// Implements the interface by calling the an to simulate Mouse gestures. 11 | /// 12 | public class MouseSimulator : IMouseSimulator 13 | { 14 | /// 15 | /// The instance of the to use for dispatching messages. 16 | /// 17 | private readonly IInputMessageDispatcher messageDispatcher; 18 | 19 | /// 20 | /// 21 | /// Initializes a new instance of the class using an instance of a for dispatching messages. 22 | /// 23 | public MouseSimulator() 24 | : this(new WindowsInputMessageDispatcher()) 25 | { 26 | } 27 | 28 | /// 29 | /// Initializes a new instance of the class using the specified for dispatching messages. 30 | /// 31 | /// The to use for dispatching messages. 32 | /// If null is passed as the . 33 | internal MouseSimulator(IInputMessageDispatcher messageDispatcher) 34 | { 35 | this.messageDispatcher = messageDispatcher ?? throw new InvalidOperationException( 36 | string.Format("The {0} cannot operate with a null {1}. Please provide a valid {1} instance to use for dispatching {2} messages.", 37 | typeof(MouseSimulator).Name, typeof(IInputMessageDispatcher).Name, typeof(Input).Name)); 38 | } 39 | 40 | /// 41 | /// 42 | /// Gets or sets the amount of mouse wheel scrolling per click. The default value for this property is 120 and different values may cause some applications to interpret the scrolling differently than expected. 43 | /// 44 | public int MouseWheelClickSize { get; set; } = 120; 45 | 46 | /// 47 | /// 48 | /// Retrieves the position of the mouse cursor, in screen coordinates. 49 | /// 50 | public System.Drawing.Point Position 51 | { 52 | get 53 | { 54 | NativeMethods.GetCursorPos(out Point lpPoint); 55 | return lpPoint; 56 | } 57 | } 58 | 59 | /// 60 | /// 61 | /// Simulates mouse movement by the specified distance measured as a delta from the current mouse location in pixels. 62 | /// 63 | /// The distance in pixels to move the mouse horizontally. 64 | /// The distance in pixels to move the mouse vertically. 65 | public IMouseSimulator MoveMouseBy(int pixelDeltaX, int pixelDeltaY) 66 | { 67 | var inputList = new InputBuilder().AddRelativeMouseMovement(pixelDeltaX, pixelDeltaY).ToArray(); 68 | this.SendSimulatedInput(inputList); 69 | return this; 70 | } 71 | 72 | /// 73 | /// 74 | /// Simulates mouse movement to the specified location on the primary display device. 75 | /// 76 | /// The destination's absolute X-coordinate on the primary display device where 0 is the extreme left hand side of the display device and 65535 is the extreme right hand side of the display device. 77 | /// The destination's absolute Y-coordinate on the primary display device where 0 is the top of the display device and 65535 is the bottom of the display device. 78 | public IMouseSimulator MoveMouseTo(double absoluteX, double absoluteY) 79 | { 80 | var inputList = new InputBuilder().AddAbsoluteMouseMovement((int)Math.Truncate(absoluteX), (int)Math.Truncate(absoluteY)).ToArray(); 81 | this.SendSimulatedInput(inputList); 82 | return this; 83 | } 84 | 85 | /// 86 | /// 87 | /// Simulates mouse movement to the specified location on the Virtual Desktop which includes all active displays. 88 | /// 89 | /// The destination's absolute X-coordinate on the virtual desktop where 0 is the left hand side of the virtual desktop and 65535 is the extreme right hand side of the virtual desktop. 90 | /// The destination's absolute Y-coordinate on the virtual desktop where 0 is the top of the virtual desktop and 65535 is the bottom of the virtual desktop. 91 | public IMouseSimulator MoveMouseToPositionOnVirtualDesktop(double absoluteX, double absoluteY) 92 | { 93 | var inputList = new InputBuilder().AddAbsoluteMouseMovementOnVirtualDesktop((int)Math.Truncate(absoluteX), (int)Math.Truncate(absoluteY)).ToArray(); 94 | this.SendSimulatedInput(inputList); 95 | return this; 96 | } 97 | 98 | /// 99 | /// 100 | /// Simulates a mouse left button down gesture. 101 | /// 102 | public IMouseSimulator LeftButtonDown() => this.ButtonDown(MouseButton.LeftButton); 103 | 104 | /// 105 | /// 106 | /// Simulates a mouse left button up gesture. 107 | /// 108 | public IMouseSimulator LeftButtonUp() => this.ButtonUp(MouseButton.LeftButton); 109 | 110 | /// 111 | /// 112 | /// Simulates a mouse left-click gesture. 113 | /// 114 | public IMouseSimulator LeftButtonClick() => this.ButtonClick(MouseButton.LeftButton); 115 | 116 | /// 117 | /// 118 | /// Simulates a mouse left button double-click gesture. 119 | /// 120 | public IMouseSimulator LeftButtonDoubleClick() => this.ButtonDoubleClick(MouseButton.LeftButton); 121 | 122 | /// 123 | /// 124 | /// Simulates a mouse middle button down gesture. 125 | /// 126 | public IMouseSimulator MiddleButtonDown() => this.ButtonDown(MouseButton.MiddleButton); 127 | 128 | /// 129 | /// 130 | /// Simulates a mouse middle button up gesture. 131 | /// 132 | public IMouseSimulator MiddleButtonUp() => this.ButtonUp(MouseButton.MiddleButton); 133 | 134 | /// 135 | /// 136 | /// Simulates a mouse middle button click gesture. 137 | /// 138 | public IMouseSimulator MiddleButtonClick() => this.ButtonClick(MouseButton.MiddleButton); 139 | 140 | /// 141 | /// 142 | /// Simulates a mouse middle button double click gesture. 143 | /// 144 | public IMouseSimulator MiddleButtonDoubleClick() => this.ButtonDoubleClick(MouseButton.MiddleButton); 145 | 146 | /// 147 | /// 148 | /// Simulates a mouse right button down gesture. 149 | /// 150 | public IMouseSimulator RightButtonDown() => this.ButtonDown(MouseButton.RightButton); 151 | 152 | /// 153 | /// 154 | /// Simulates a mouse right button up gesture. 155 | /// 156 | public IMouseSimulator RightButtonUp() => this.ButtonUp(MouseButton.RightButton); 157 | 158 | /// 159 | /// 160 | /// Simulates a mouse right button click gesture. 161 | /// 162 | public IMouseSimulator RightButtonClick() => this.ButtonClick(MouseButton.RightButton); 163 | 164 | /// 165 | /// 166 | /// Simulates a mouse right button double-click gesture. 167 | /// 168 | public IMouseSimulator RightButtonDoubleClick() => this.ButtonDoubleClick(MouseButton.RightButton); 169 | 170 | /// 171 | /// 172 | /// Simulates a mouse X button down gesture. 173 | /// 174 | /// The button id. 175 | public IMouseSimulator XButtonDown(int buttonId) 176 | { 177 | var inputList = new InputBuilder().AddMouseXButtonDown(buttonId).ToArray(); 178 | this.SendSimulatedInput(inputList); 179 | return this; 180 | } 181 | 182 | /// 183 | /// 184 | /// Simulates a mouse X button up gesture. 185 | /// 186 | /// The button id. 187 | public IMouseSimulator XButtonUp(int buttonId) 188 | { 189 | var inputList = new InputBuilder().AddMouseXButtonUp(buttonId).ToArray(); 190 | this.SendSimulatedInput(inputList); 191 | return this; 192 | } 193 | 194 | /// 195 | /// 196 | /// Simulates a mouse X button click gesture. 197 | /// 198 | /// The button id. 199 | public IMouseSimulator XButtonClick(int buttonId) 200 | { 201 | var inputList = new InputBuilder().AddMouseXButtonClick(buttonId).ToArray(); 202 | this.SendSimulatedInput(inputList); 203 | return this; 204 | } 205 | 206 | /// 207 | /// 208 | /// Simulates a mouse X button double-click gesture. 209 | /// 210 | /// The button id. 211 | public IMouseSimulator XButtonDoubleClick(int buttonId) 212 | { 213 | var inputList = new InputBuilder().AddMouseXButtonDoubleClick(buttonId).ToArray(); 214 | this.SendSimulatedInput(inputList); 215 | return this; 216 | } 217 | 218 | /// 219 | /// 220 | /// Simulates mouse vertical wheel scroll gesture. 221 | /// 222 | /// The amount to scroll in clicks. A positive value indicates that the wheel was rotated forward, away from the user; a negative value indicates that the wheel was rotated backward, toward the user. 223 | public IMouseSimulator VerticalScroll(int scrollAmountInClicks) 224 | { 225 | var inputList = new InputBuilder().AddMouseVerticalWheelScroll(scrollAmountInClicks * this.MouseWheelClickSize).ToArray(); 226 | this.SendSimulatedInput(inputList); 227 | return this; 228 | } 229 | 230 | /// 231 | /// 232 | /// Simulates a mouse horizontal wheel scroll gesture. Supported by Windows Vista and later. 233 | /// 234 | /// The amount to scroll in clicks. A positive value indicates that the wheel was rotated to the right; a negative value indicates that the wheel was rotated to the left. 235 | public IMouseSimulator HorizontalScroll(int scrollAmountInClicks) 236 | { 237 | var inputList = new InputBuilder().AddMouseHorizontalWheelScroll(scrollAmountInClicks * this.MouseWheelClickSize).ToArray(); 238 | this.SendSimulatedInput(inputList); 239 | return this; 240 | } 241 | 242 | /// 243 | /// 244 | /// Sleeps the executing thread to create a pause between simulated inputs. 245 | /// 246 | /// The number of milliseconds to wait. 247 | public IMouseSimulator Sleep(int millisecondsTimeout) 248 | { 249 | return this.Sleep(TimeSpan.FromMilliseconds(millisecondsTimeout)); 250 | } 251 | 252 | /// 253 | /// 254 | /// Sleeps the executing thread to create a pause between simulated inputs. 255 | /// 256 | /// The time to wait. 257 | public IMouseSimulator Sleep(TimeSpan timeout) 258 | { 259 | Thread.Sleep(timeout); 260 | return this; 261 | } 262 | 263 | /// 264 | /// Sends the list of messages using the instance. 265 | /// 266 | /// The of messages to send. 267 | private void SendSimulatedInput(Input[] inputList) 268 | { 269 | this.messageDispatcher.DispatchInput(inputList); 270 | } 271 | 272 | private IMouseSimulator ButtonDown(MouseButton mouseButton) 273 | { 274 | var inputList = new InputBuilder().AddMouseButtonDown(mouseButton).ToArray(); 275 | this.SendSimulatedInput(inputList); 276 | return this; 277 | } 278 | 279 | private IMouseSimulator ButtonUp(MouseButton mouseButton) 280 | { 281 | var inputList = new InputBuilder().AddMouseButtonUp(mouseButton).ToArray(); 282 | this.SendSimulatedInput(inputList); 283 | return this; 284 | } 285 | 286 | private IMouseSimulator ButtonClick(MouseButton mouseButton) 287 | { 288 | var inputList = new InputBuilder().AddMouseButtonClick(mouseButton).ToArray(); 289 | this.SendSimulatedInput(inputList); 290 | return this; 291 | } 292 | 293 | private IMouseSimulator ButtonDoubleClick(MouseButton mouseButton) 294 | { 295 | var inputList = new InputBuilder().AddMouseButtonDoubleClick(mouseButton).ToArray(); 296 | this.SendSimulatedInput(inputList); 297 | return this; 298 | } 299 | } 300 | } 301 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/Native/HardwareInput.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Native 2 | { 3 | /// 4 | /// The structure contains information about a simulated message generated by an input device other than a keyboard or mouse. (see: http://msdn.microsoft.com/en-us/library/ms646269(VS.85).aspx) 5 | /// Declared in Winuser.h, include Windows.h 6 | /// 7 | internal struct HardwareInput 8 | { 9 | /// 10 | /// Value specifying the message generated by the input hardware. 11 | /// 12 | public uint Msg; 13 | 14 | /// 15 | /// Specifies the low-order word of the lParam parameter for uMsg. 16 | /// 17 | public ushort ParamL; 18 | 19 | /// 20 | /// Specifies the high-order word of the lParam parameter for uMsg. 21 | /// 22 | public ushort ParamH; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/Native/Input.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Native 2 | { 3 | /// 4 | /// The structure is used by SendInput to store information for synthesizing input events such as keystrokes, mouse movement, and mouse clicks. (see: http://msdn.microsoft.com/en-us/library/ms646270(VS.85).aspx) 5 | /// Declared in Winuser.h, include Windows.h 6 | /// 7 | /// 8 | /// This structure contains information identical to that used in the parameter list of the keybd_event or mouse_event function. 9 | /// Windows 2000/XP: INPUT_KEYBOARD supports nonkeyboard input methods, such as handwriting recognition or voice recognition, as if it were text input by using the KEYEVENTF_UNICODE flag. For more information, see the remarks section of KEYBDINPUT. 10 | /// 11 | internal struct Input 12 | { 13 | /// 14 | /// Specifies the type of the input event. This member can be one of the following values. 15 | /// - The event is a mouse event. Use the mi structure of the union. 16 | /// - The event is a keyboard event. Use the ki structure of the union. 17 | /// - Windows 95/98/Me: The event is from input hardware other than a keyboard or mouse. Use the hi structure of the union. 18 | /// 19 | public uint Type; 20 | 21 | /// 22 | /// The data structure that contains information about the simulated Mouse, Keyboard or Hardware event. 23 | /// 24 | public MouseKeyboardHardwareInput Data; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/Native/InputType.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Native 2 | { 3 | /// 4 | /// Specifies the type of the input event. This member can be one of the following values. 5 | /// 6 | internal enum InputType : uint 7 | { 8 | /// 9 | /// INPUT_MOUSE = 0x00 (The event is a mouse event. Use the mi structure of the union.) 10 | /// 11 | Mouse = 0, 12 | 13 | /// 14 | /// INPUT_KEYBOARD = 0x01 (The event is a keyboard event. Use the ki structure of the union.) 15 | /// 16 | Keyboard = 1, 17 | 18 | /// 19 | /// INPUT_HARDWARE = 0x02 (Windows 95/98/Me: The event is from input hardware other than a keyboard or mouse. Use the hi structure of the union.) 20 | /// 21 | Hardware = 2, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/Native/KeyboardFlag.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Native 2 | { 3 | using System; 4 | 5 | /// 6 | /// Specifies various aspects of a keystroke. This member can be certain combinations of the following values. 7 | /// 8 | [Flags] 9 | internal enum KeyboardFlag : uint 10 | { 11 | /// 12 | /// KEYEVENTF_EXTENDEDKEY = 0x0001 (If specified, the scan code was preceded by a prefix byte that has the value 0xE0 (224).) 13 | /// 14 | ExtendedKey = 0x0001, 15 | 16 | /// 17 | /// KEYEVENTF_KEYUP = 0x0002 (If specified, the key is being released. If not specified, the key is being pressed.) 18 | /// 19 | KeyUp = 0x0002, 20 | 21 | /// 22 | /// KEYEVENTF_UNICODE = 0x0004 (If specified, wScan identifies the key and wVk is ignored.) 23 | /// 24 | Unicode = 0x0004, 25 | 26 | /// 27 | /// KEYEVENTF_SCANCODE = 0x0008 (Windows 2000/XP: If specified, the system synthesizes a VK_PACKET keystroke. The wVk parameter must be zero. This flag can only be combined with the KEYEVENTF_KEYUP flag. For more information, see the Remarks section.) 28 | /// 29 | ScanCode = 0x0008, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/Native/KeyboardInput.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Native 2 | { 3 | using System; 4 | 5 | /// 6 | /// The structure contains information about a simulated keyboard event. (see: http://msdn.microsoft.com/en-us/library/ms646271(VS.85).aspx) 7 | /// Declared in Winuser.h, include Windows.h 8 | /// 9 | /// 10 | /// Windows 2000/XP: INPUT_KEYBOARD supports nonkeyboard-input methods—such as handwriting recognition or voice recognition—as if it were text input by using the KEYEVENTF_UNICODE flag. If KEYEVENTF_UNICODE is specified, SendInput sends a WM_KEYDOWN or WM_KEYUP message to the foreground thread's message queue with wParam equal to VK_PACKET. Once GetMessage or PeekMessage obtains this message, passing the message to TranslateMessage posts a WM_CHAR message with the Unicode character originally specified by wScan. This Unicode character will automatically be converted to the appropriate ANSI value if it is posted to an ANSI window. 11 | /// Windows 2000/XP: Set the KEYEVENTF_SCANCODE flag to define keyboard input in terms of the scan code. This is useful to simulate a physical keystroke regardless of which keyboard is currently being used. The virtual key value of a key may alter depending on the current keyboard layout or what other keys were pressed, but the scan code will always be the same. 12 | /// 13 | internal struct KeyboardInput 14 | { 15 | /// 16 | /// Specifies a virtual-key code. The code must be a value in the range 1 to 254. The Winuser.h header file provides macro definitions (VK_*) for each value. If the dwFlags member specifies KEYEVENTF_UNICODE, wVk must be 0. 17 | /// 18 | public ushort KeyCode; 19 | 20 | /// 21 | /// Specifies a hardware scan code for the key. If dwFlags specifies KEYEVENTF_UNICODE, wScan specifies a Unicode character which is to be sent to the foreground application. 22 | /// 23 | public ushort Scan; 24 | 25 | /// 26 | /// Specifies various aspects of a keystroke. This member can be certain combinations of the following values. 27 | /// KEYEVENTF_EXTENDEDKEY - If specified, the scan code was preceded by a prefix byte that has the value 0xE0 (224). 28 | /// KEYEVENTF_KEYUP - If specified, the key is being released. If not specified, the key is being pressed. 29 | /// KEYEVENTF_SCANCODE - If specified, wScan identifies the key and wVk is ignored. 30 | /// KEYEVENTF_UNICODE - Windows 2000/XP: If specified, the system synthesizes a VK_PACKET keystroke. The wVk parameter must be zero. This flag can only be combined with the KEYEVENTF_KEYUP flag. For more information, see the Remarks section. 31 | /// 32 | public uint Flags; 33 | 34 | /// 35 | /// Time stamp for the event, in milliseconds. If this parameter is zero, the system will provide its own time stamp. 36 | /// 37 | public uint Time; 38 | 39 | /// 40 | /// Specifies an additional value associated with the keystroke. Use the GetMessageExtraInfo function to obtain this information. 41 | /// 42 | public IntPtr ExtraInfo; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/Native/MouseFlag.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Native 2 | { 3 | using System; 4 | 5 | /// 6 | /// The set of mouse flags for use in the Flags property of the structure. (See: http://msdn.microsoft.com/en-us/library/ms646273(VS.85).aspx) 7 | /// 8 | [Flags] 9 | internal enum MouseFlag : uint 10 | { 11 | /// 12 | /// Specifies that movement occurred. 13 | /// 14 | Move = 0x0001, 15 | 16 | /// 17 | /// Specifies that the left button was pressed. 18 | /// 19 | LeftDown = 0x0002, 20 | 21 | /// 22 | /// Specifies that the left button was released. 23 | /// 24 | LeftUp = 0x0004, 25 | 26 | /// 27 | /// Specifies that the right button was pressed. 28 | /// 29 | RightDown = 0x0008, 30 | 31 | /// 32 | /// Specifies that the right button was released. 33 | /// 34 | RightUp = 0x0010, 35 | 36 | /// 37 | /// Specifies that the middle button was pressed. 38 | /// 39 | MiddleDown = 0x0020, 40 | 41 | /// 42 | /// Specifies that the middle button was released. 43 | /// 44 | MiddleUp = 0x0040, 45 | 46 | /// 47 | /// Windows 2000/XP: Specifies that an X button was pressed. 48 | /// 49 | XDown = 0x0080, 50 | 51 | /// 52 | /// Windows 2000/XP: Specifies that an X button was released. 53 | /// 54 | XUp = 0x0100, 55 | 56 | /// 57 | /// Windows NT/2000/XP: Specifies that the wheel was moved, if the mouse has a wheel. The amount of movement is specified in mouseData. 58 | /// 59 | VerticalWheel = 0x0800, 60 | 61 | /// 62 | /// Specifies that the wheel was moved horizontally, if the mouse has a wheel. The amount of movement is specified in mouseData. Windows 2000/XP: Not supported. 63 | /// 64 | HorizontalWheel = 0x1000, 65 | 66 | /// 67 | /// Windows 2000/XP: Maps coordinates to the entire desktop. Must be used with MOUSEEVENTF_ABSOLUTE. 68 | /// 69 | VirtualDesk = 0x4000, 70 | 71 | /// 72 | /// Specifies that the dx and dy members contain normalized absolute coordinates. If the flag is not set, dxand dy contain relative data (the change in position since the last reported position). This flag can be set, or not set, regardless of what kind of mouse or other pointing device, if any, is connected to the system. For further information about relative mouse motion, see the following Remarks section. 73 | /// 74 | Absolute = 0x8000, 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/Native/MouseInput.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Native 2 | { 3 | using System; 4 | 5 | /// 6 | /// The structure contains information about a simulated mouse event. (see: http://msdn.microsoft.com/en-us/library/ms646273(VS.85).aspx) 7 | /// Declared in Winuser.h, include Windows.h 8 | /// 9 | /// 10 | /// If the mouse has moved, indicated by MOUSEEVENTF_MOVE, dx and dy specify information about that movement. The information is specified as absolute or relative integer values. 11 | /// If MOUSEEVENTF_ABSOLUTE value is specified, dx and dy contain normalized absolute coordinates between 0 and 65,535. The event procedure maps these coordinates onto the display surface. Coordinate (0,0) maps onto the upper-left corner of the display surface; coordinate (65535,65535) maps onto the lower-right corner. In a multi-monitor system, the coordinates map to the primary monitor. 12 | /// Windows 2000/XP: If MOUSEEVENTF_VIRTUALDESK is specified, the coordinates map to the entire virtual desktop. 13 | /// If the MOUSEEVENTF_ABSOLUTE value is not specified, dx and dy specify movement relative to the previous mouse event (the last reported position). Positive values mean the mouse moved right (or down); negative values mean the mouse moved left (or up). 14 | /// Relative mouse motion is subject to the effects of the mouse speed and the two-mouse threshold values. A user sets these three values with the Pointer Speed slider of the Control Panel's Mouse Properties sheet. You can obtain and set these values using the SystemParametersInfo function. 15 | /// The system applies two tests to the specified relative mouse movement. If the specified distance along either the x or y axis is greater than the first mouse threshold value, and the mouse speed is not zero, the system doubles the distance. If the specified distance along either the x or y axis is greater than the second mouse threshold value, and the mouse speed is equal to two, the system doubles the distance that resulted from applying the first threshold test. It is thus possible for the system to multiply specified relative mouse movement along the x or y axis by up to four times. 16 | /// 17 | internal struct MouseInput 18 | { 19 | /// 20 | /// Specifies the absolute position of the mouse, or the amount of motion since the last mouse event was generated, depending on the value of the dwFlags member. Absolute data is specified as the x coordinate of the mouse; relative data is specified as the number of pixels moved. 21 | /// 22 | public int X; 23 | 24 | /// 25 | /// Specifies the absolute position of the mouse, or the amount of motion since the last mouse event was generated, depending on the value of the dwFlags member. Absolute data is specified as the y coordinate of the mouse; relative data is specified as the number of pixels moved. 26 | /// 27 | public int Y; 28 | 29 | /// 30 | /// If dwFlags contains MOUSEEVENTF_WHEEL, then mouseData specifies the amount of wheel movement. A positive value indicates that the wheel was rotated forward, away from the user; a negative value indicates that the wheel was rotated backward, toward the user. One wheel click is defined as WHEEL_DELTA, which is 120. 31 | /// Windows Vista: If dwFlags contains MOUSEEVENTF_HWHEEL, then dwData specifies the amount of wheel movement. A positive value indicates that the wheel was rotated to the right; a negative value indicates that the wheel was rotated to the left. One wheel click is defined as WHEEL_DELTA, which is 120. 32 | /// Windows 2000/XP: IfdwFlags does not contain MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, or MOUSEEVENTF_XUP, then mouseData should be zero. 33 | /// If dwFlags contains MOUSEEVENTF_XDOWN or MOUSEEVENTF_XUP, then mouseData specifies which X buttons were pressed or released. This value may be any combination of the following flags. 34 | /// 35 | public uint MouseData; 36 | 37 | /// 38 | /// A set of bit flags that specify various aspects of mouse motion and button clicks. The bits in this member can be any reasonable combination of the following values. 39 | /// The bit flags that specify mouse button status are set to indicate changes in status, not ongoing conditions. For example, if the left mouse button is pressed and held down, MOUSEEVENTF_LEFTDOWN is set when the left button is first pressed, but not for subsequent motions. Similarly, MOUSEEVENTF_LEFTUP is set only when the button is first released. 40 | /// You cannot specify both the MOUSEEVENTF_WHEEL flag and either MOUSEEVENTF_XDOWN or MOUSEEVENTF_XUP flags simultaneously in the dwFlags parameter, because they both require use of the mouseData field. 41 | /// 42 | public uint Flags; 43 | 44 | /// 45 | /// Time stamp for the event, in milliseconds. If this parameter is 0, the system will provide its own time stamp. 46 | /// 47 | public uint Time; 48 | 49 | /// 50 | /// Specifies an additional value associated with the mouse event. An application calls GetMessageExtraInfo to obtain this extra information. 51 | /// 52 | public IntPtr ExtraInfo; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/Native/MouseKeyboardHardwareInput.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Native 2 | { 3 | using System.Runtime.InteropServices; 4 | 5 | /// 6 | /// The combined structure that includes Mouse, Keyboard and Hardware Input message data (see: http://msdn.microsoft.com/en-us/library/ms646270(VS.85).aspx) 7 | /// 8 | [StructLayout(LayoutKind.Explicit)] 9 | internal struct MouseKeyboardHardwareInput 10 | { 11 | /// 12 | /// The definition. 13 | /// 14 | [FieldOffset(0)] 15 | public MouseInput Mouse; 16 | 17 | /// 18 | /// The definition. 19 | /// 20 | [FieldOffset(0)] 21 | public KeyboardInput Keyboard; 22 | 23 | /// 24 | /// The definition. 25 | /// 26 | [FieldOffset(0)] 27 | public HardwareInput Hardware; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/Native/NativeMethods.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Native 2 | { 3 | using System; 4 | using System.Runtime.InteropServices; 5 | 6 | /// 7 | /// References all of the Native Windows API methods for the WindowsInput functionality. 8 | /// 9 | internal static class NativeMethods 10 | { 11 | /// 12 | /// The function determines whether a key is up or down at the time the function is called, and whether the key was pressed after a previous call to GetAsyncKeyState. (See: http://msdn.microsoft.com/en-us/library/ms646293(VS.85).aspx) 13 | /// 14 | /// Specifies one of 256 possible virtual-key codes. For more information, see Virtual Key Codes. Windows NT/2000/XP: You can use left- and right-distinguishing constants to specify certain keys. See the Remarks section for further information. 15 | /// 16 | /// If the function succeeds, the return value specifies whether the key was pressed since the last call to GetAsyncKeyState, and whether the key is currently up or down. If the most significant bit is set, the key is down, and if the least significant bit is set, the key was pressed after the previous call to GetAsyncKeyState. However, you should not rely on this last behavior; for more information, see the Remarks. 17 | /// 18 | /// Windows NT/2000/XP: The return value is zero for the following cases: 19 | /// - The current desktop is not the active desktop 20 | /// - The foreground thread belongs to another process and the desktop does not allow the hook or the journal record. 21 | /// 22 | /// Windows 95/98/Me: The return value is the global asynchronous key state for each virtual key. The system does not check which thread has the keyboard focus. 23 | /// 24 | /// Windows 95/98/Me: Windows 95 does not support the left- and right-distinguishing constants. If you call GetAsyncKeyState with these constants, the return value is zero. 25 | /// 26 | /// 27 | /// The GetAsyncKeyState function works with mouse buttons. However, it checks on the state of the physical mouse buttons, not on the logical mouse buttons that the physical buttons are mapped to. For example, the call GetAsyncKeyState(VK_LBUTTON) always returns the state of the left physical mouse button, regardless of whether it is mapped to the left or right logical mouse button. You can determine the system's current mapping of physical mouse buttons to logical mouse buttons by calling 28 | /// Copy CodeGetSystemMetrics(SM_SWAPBUTTON) which returns TRUE if the mouse buttons have been swapped. 29 | /// 30 | /// Although the least significant bit of the return value indicates whether the key has been pressed since the last query, due to the pre-emptive multitasking nature of Windows, another application can call and receive the "recently pressed" bit instead of your application. The behavior of the least significant bit of the return value is retained strictly for compatibility with 16-bit Windows applications (which are non-preemptive) and should not be relied upon. 31 | /// 32 | /// You can use the virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU as values for the vKey parameter. This gives the state of the SHIFT, CTRL, or ALT keys without distinguishing between left and right. 33 | /// 34 | /// Windows NT/2000/XP: You can use the following virtual-key code constants as values for vKey to distinguish between the left and right instances of those keys. 35 | /// 36 | /// Code Meaning 37 | /// VK_LSHIFT Left-shift key. 38 | /// VK_RSHIFT Right-shift key. 39 | /// VK_LCONTROL Left-control key. 40 | /// VK_RCONTROL Right-control key. 41 | /// VK_LMENU Left-menu key. 42 | /// VK_RMENU Right-menu key. 43 | /// 44 | /// These left- and right-distinguishing constants are only available when you call the GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState, and MapVirtualKey functions. 45 | /// 46 | [DllImport("user32.dll", SetLastError = true)] 47 | public static extern short GetAsyncKeyState(ushort virtualKeyCode); 48 | 49 | /// 50 | /// The function retrieves the status of the specified virtual key. The status specifies whether the key is up, down, or toggled (on, off alternating each time the key is pressed). (See: http://msdn.microsoft.com/en-us/library/ms646301(VS.85).aspx) 51 | /// 52 | /// 53 | /// Specifies a virtual key. If the desired virtual key is a letter or digit (A through Z, a through z, or 0 through 9), nVirtKey must be set to the ASCII value of that character. For other keys, it must be a virtual-key code. 54 | /// If a non-English keyboard layout is used, virtual keys with values in the range ASCII A through Z and 0 through 9 are used to specify most of the character keys. For example, for the German keyboard layout, the virtual key of value ASCII O (0x4F) refers to the "o" key, whereas VK_OEM_1 refers to the "o with umlaut" key. 55 | /// 56 | /// 57 | /// The return value specifies the status of the specified virtual key, as follows: 58 | /// If the high-order bit is 1, the key is down; otherwise, it is up. 59 | /// If the low-order bit is 1, the key is toggled. A key, such as the CAPS LOCK key, is toggled if it is turned on. The key is off and untoggled if the low-order bit is 0. A toggle key's indicator light (if any) on the keyboard will be on when the key is toggled, and off when the key is untoggled. 60 | /// 61 | /// 62 | /// The key status returned from this function changes as a thread reads key messages from its message queue. The status does not reflect the interrupt-level state associated with the hardware. Use the GetAsyncKeyState function to retrieve that information. 63 | /// An application calls GetKeyState in response to a keyboard-input message. This function retrieves the state of the key when the input message was generated. 64 | /// To retrieve state information for all the virtual keys, use the GetKeyboardState function. 65 | /// An application can use the virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU as values for the nVirtKey parameter. This gives the status of the SHIFT, CTRL, or ALT keys without distinguishing between left and right. An application can also use the following virtual-key code constants as values for nVirtKey to distinguish between the left and right instances of those keys. 66 | /// VK_LSHIFT 67 | /// VK_RSHIFT 68 | /// VK_LCONTROL 69 | /// VK_RCONTROL 70 | /// VK_LMENU 71 | /// VK_RMENU 72 | /// 73 | /// These left- and right-distinguishing constants are available to an application only through the GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState, and MapVirtualKey functions. 74 | /// 75 | [DllImport("user32.dll", SetLastError = true)] 76 | public static extern short GetKeyState(ushort virtualKeyCode); 77 | 78 | /// 79 | /// The function synthesizes keystrokes, mouse motions, and button clicks. 80 | /// 81 | /// Number of structures in the Inputs array. 82 | /// Pointer to an array of INPUT structures. Each structure represents an event to be inserted into the keyboard or mouse input stream. 83 | /// Specifies the size, in bytes, of an INPUT structure. If cbSize is not the size of an INPUT structure, the function fails. 84 | /// The function returns the number of events that it successfully inserted into the keyboard or mouse input stream. If the function returns zero, the input was already blocked by another thread. To get extended error information, call GetLastError.Microsoft Windows Vista. This function fails when it is blocked by User Interface Privilege Isolation (UIPI). Note that neither GetLastError nor the return value will indicate the failure was caused by UIPI blocking. 85 | /// 86 | /// Microsoft Windows Vista. This function is subject to UIPI. Applications are permitted to inject input only into applications that are at an equal or lesser integrity level. 87 | /// The SendInput function inserts the events in the INPUT structures serially into the keyboard or mouse input stream. These events are not interspersed with other keyboard or mouse input events inserted either by the user (with the keyboard or mouse) or by calls to keybd_event, mouse_event, or other calls to SendInput. 88 | /// This function does not reset the keyboard's current state. Any keys that are already pressed when the function is called might interfere with the events that this function generates. To avoid this problem, check the keyboard's state with the GetAsyncKeyState function and correct as necessary. 89 | /// 90 | [DllImport("user32.dll", SetLastError = true)] 91 | public static extern uint SendInput(uint numberOfInputs, Input[] inputs, int sizeOfInputStructure); 92 | 93 | /// 94 | /// The function retrieves the extra message information for the current thread. Extra message information is an application- or driver-defined value associated with the current thread's message queue. 95 | /// 96 | /// 97 | /// To set a thread's extra message information, use the SetMessageExtraInfo function. 98 | [DllImport("user32.dll")] 99 | public static extern IntPtr GetMessageExtraInfo(); 100 | 101 | /// 102 | /// Used to find the keyboard input scan code for single key input. Some applications do not receive the input when scan is not set. 103 | /// 104 | /// 105 | /// 106 | /// 107 | [DllImport("user32.dll")] 108 | public static extern uint MapVirtualKey(uint uCode, uint uMapType); 109 | 110 | /// 111 | /// Retrieves the cursor's position, in screen coordinates. 112 | /// 113 | /// A pointer to a structure that receives the screen coordinates of the cursor. 114 | /// Returns true if successful or false otherwise. 115 | [DllImport("user32.dll", SetLastError = true)] 116 | public static extern bool GetCursorPos(out Point lpPoint); 117 | 118 | [DllImport("user32.dll")] 119 | public static extern uint GetSystemMetrics(uint smIndex); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/Native/Point.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Native 2 | { 3 | using System.Runtime.InteropServices; 4 | 5 | [StructLayout(LayoutKind.Sequential)] 6 | internal struct Point 7 | { 8 | /// 9 | /// Gets or sets the x-coordinate of this Point. 10 | /// 11 | public int X { get; set; } 12 | 13 | /// 14 | /// Gets or sets the y-coordinate of this Point. 15 | /// 16 | public int Y { get; set; } 17 | 18 | public static implicit operator System.Drawing.Point(Point point) 19 | { 20 | return new System.Drawing.Point(point.X, point.Y); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/Native/SystemMetric.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Native 2 | { 3 | /// 4 | /// Specifies the type of the system metric. This member can be one of the following values. 5 | /// 6 | internal enum SystemMetric : uint 7 | { 8 | SM_CXSCREEN = 0, 9 | SM_CYSCREEN = 1, 10 | SM_CXVSCROLL = 2, 11 | SM_CYHSCROLL = 3, 12 | SM_CYCAPTION = 4, 13 | SM_CXBORDER = 5, 14 | SM_CYBORDER = 6, 15 | SM_CXDLGFRAME = 7, 16 | //SM_CXFIXEDFRAME = 7, 17 | SM_CYDLGFRAME = 8, 18 | //SM_CYFIXEDFRAME = 8, 19 | SM_CYVTHUMB = 9, 20 | SM_CXHTHUMB = 10, 21 | SM_CXICON = 11, 22 | SM_CYICON = 12, 23 | SM_CXCURSOR = 13, 24 | SM_CYCURSOR = 14, 25 | SM_CYMENU = 15, 26 | SM_CXFULLSCREEN = 16, 27 | SM_CYFULLSCREEN = 17, 28 | SM_CYKANJIWINDOW = 18, 29 | SM_MOUSEPRESENT = 19, 30 | SM_CYVSCROLL = 20, 31 | SM_CXHSCROLL = 21, 32 | SM_DEBUG = 22, 33 | SM_SWAPBUTTON = 23, 34 | SM_CXMIN = 28, 35 | SM_CYMIN = 29, 36 | SM_CXSIZE = 30, 37 | SM_CYSIZE = 31, 38 | //SM_CXSIZEFRAME = 32, 39 | SM_CXFRAME = 32, 40 | //SM_CYSIZEFRAME = 33, 41 | SM_CYFRAME = 33, 42 | SM_CXMINTRACK = 34, 43 | SM_CYMINTRACK = 35, 44 | SM_CXDOUBLECLK = 36, 45 | SM_CYDOUBLECLK = 37, 46 | SM_CXICONSPACING = 38, 47 | SM_CYICONSPACING = 39, 48 | SM_MENUDROPALIGNMENT = 40, 49 | SM_PENWINDOWS = 41, 50 | SM_DBCSENABLED = 42, 51 | SM_CMOUSEBUTTONS = 43, 52 | SM_SECURE = 44, 53 | SM_CXEDGE = 45, 54 | SM_CYEDGE = 46, 55 | SM_CXMINSPACING = 47, 56 | SM_CYMINSPACING = 48, 57 | SM_CXSMICON = 49, 58 | SM_CYSMICON = 50, 59 | SM_CYSMCAPTION = 51, 60 | SM_CXSMSIZE = 52, 61 | SM_CYSMSIZE = 53, 62 | SM_CXMENUSIZE = 54, 63 | SM_CYMENUSIZE = 55, 64 | SM_ARRANGE = 56, 65 | SM_CXMINIMIZED = 57, 66 | SM_CYMINIMIZED = 58, 67 | SM_CXMAXTRACK = 59, 68 | SM_CYMAXTRACK = 60, 69 | SM_CXMAXIMIZED = 61, 70 | SM_CYMAXIMIZED = 62, 71 | SM_NETWORK = 63, 72 | SM_CLEANBOOT = 67, 73 | SM_CXDRAG = 68, 74 | SM_CYDRAG = 69, 75 | SM_SHOWSOUNDS = 70, 76 | SM_CXMENUCHECK = 71, 77 | SM_CYMENUCHECK = 72, 78 | SM_SLOWMACHINE = 73, 79 | SM_MIDEASTENABLED = 74, 80 | SM_MOUSEWHEELPRESENT = 75, 81 | SM_XVIRTUALSCREEN = 76, 82 | SM_YVIRTUALSCREEN = 77, 83 | SM_CXVIRTUALSCREEN = 78, 84 | SM_CYVIRTUALSCREEN = 79, 85 | SM_CMONITORS = 80, 86 | SM_SAMEDISPLAYFORMAT = 81, 87 | SM_IMMENABLED = 82, 88 | SM_CXFOCUSBORDER = 83, 89 | SM_CYFOCUSBORDER = 84, 90 | SM_TABLETPC = 86, 91 | SM_MEDIACENTER = 87, 92 | SM_STARTER = 88, 93 | SM_SERVERR2 = 89, 94 | SM_MOUSEHORIZONTALWHEELPRESENT = 91, 95 | SM_CXPADDEDBORDER = 92, 96 | SM_DIGITIZER = 94, 97 | SM_MAXIMUMTOUCHES = 95, 98 | SM_REMOTESESSION = 0x1000, 99 | SM_SHUTTINGDOWN = 0x2000, 100 | SM_REMOTECONTROL = 0x2001 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/Native/VirtualKeyCode.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Native 2 | { 3 | /// 4 | /// The list of virtual key codes (see: https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes) 5 | /// 6 | public enum VirtualKeyCode 7 | { 8 | /// 9 | /// Left mouse button 10 | /// 11 | LBUTTON = 0x01, 12 | 13 | /// 14 | /// Right mouse button 15 | /// 16 | RBUTTON = 0x02, 17 | 18 | /// 19 | /// Control-break processing 20 | /// 21 | CANCEL = 0x03, 22 | 23 | /// 24 | /// Middle mouse button (three-button mouse) - NOT contiguous with LBUTTON and RBUTTON 25 | /// 26 | MBUTTON = 0x04, 27 | 28 | /// 29 | /// Windows 2000/XP: X1 mouse button - NOT contiguous with LBUTTON and RBUTTON 30 | /// 31 | XBUTTON1 = 0x05, 32 | 33 | /// 34 | /// Windows 2000/XP: X2 mouse button - NOT contiguous with LBUTTON and RBUTTON 35 | /// 36 | XBUTTON2 = 0x06, 37 | 38 | // 0x07 : Undefined 39 | 40 | /// 41 | /// BACKSPACE key 42 | /// 43 | BACK = 0x08, 44 | 45 | /// 46 | /// TAB key 47 | /// 48 | TAB = 0x09, 49 | 50 | // 0x0A - 0x0B : Reserved 51 | 52 | /// 53 | /// CLEAR key 54 | /// 55 | CLEAR = 0x0C, 56 | 57 | /// 58 | /// ENTER key 59 | /// 60 | RETURN = 0x0D, 61 | 62 | /// 63 | /// Numeric keypad ENTER key 64 | /// 65 | NUMPAD_RETURN = 0x4000000D, 66 | 67 | // 0x0E - 0x0F : Undefined 68 | 69 | /// 70 | /// SHIFT key 71 | /// 72 | SHIFT = 0x10, 73 | 74 | /// 75 | /// CTRL key 76 | /// 77 | CONTROL = 0x11, 78 | 79 | /// 80 | /// ALT key 81 | /// 82 | MENU = 0x12, 83 | 84 | /// 85 | /// PAUSE key 86 | /// 87 | PAUSE = 0x13, 88 | 89 | /// 90 | /// CAPS LOCK key 91 | /// 92 | CAPITAL = 0x14, 93 | 94 | /// 95 | /// Input Method Editor (IME) Kana mode 96 | /// 97 | KANA = 0x15, 98 | 99 | /// 100 | /// IME Hanguel mode (maintained for compatibility; use HANGUL) 101 | /// 102 | HANGEUL = 0x15, 103 | 104 | /// 105 | /// IME Hangul mode 106 | /// 107 | HANGUL = 0x15, 108 | 109 | // 0x16 : Undefined 110 | 111 | /// 112 | /// IME Junja mode 113 | /// 114 | JUNJA = 0x17, 115 | 116 | /// 117 | /// IME final mode 118 | /// 119 | FINAL = 0x18, 120 | 121 | /// 122 | /// IME Hanja mode 123 | /// 124 | HANJA = 0x19, 125 | 126 | /// 127 | /// IME Kanji mode 128 | /// 129 | KANJI = 0x19, 130 | 131 | // 0x1A : Undefined 132 | 133 | /// 134 | /// ESC key 135 | /// 136 | ESCAPE = 0x1B, 137 | 138 | /// 139 | /// IME convert 140 | /// 141 | CONVERT = 0x1C, 142 | 143 | /// 144 | /// IME nonconvert 145 | /// 146 | NONCONVERT = 0x1D, 147 | 148 | /// 149 | /// IME accept 150 | /// 151 | ACCEPT = 0x1E, 152 | 153 | /// 154 | /// IME mode change request 155 | /// 156 | MODECHANGE = 0x1F, 157 | 158 | /// 159 | /// SPACEBAR 160 | /// 161 | SPACE = 0x20, 162 | 163 | /// 164 | /// PAGE UP key 165 | /// 166 | PRIOR = 0x21, 167 | 168 | /// 169 | /// PAGE DOWN key 170 | /// 171 | NEXT = 0x22, 172 | 173 | /// 174 | /// END key 175 | /// 176 | END = 0x23, 177 | 178 | /// 179 | /// HOME key 180 | /// 181 | HOME = 0x24, 182 | 183 | /// 184 | /// LEFT ARROW key 185 | /// 186 | LEFT = 0x25, 187 | 188 | /// 189 | /// UP ARROW key 190 | /// 191 | UP = 0x26, 192 | 193 | /// 194 | /// RIGHT ARROW key 195 | /// 196 | RIGHT = 0x27, 197 | 198 | /// 199 | /// DOWN ARROW key 200 | /// 201 | DOWN = 0x28, 202 | 203 | /// 204 | /// SELECT key 205 | /// 206 | SELECT = 0x29, 207 | 208 | /// 209 | /// PRINT key 210 | /// 211 | PRINT = 0x2A, 212 | 213 | /// 214 | /// EXECUTE key 215 | /// 216 | EXECUTE = 0x2B, 217 | 218 | /// 219 | /// PRINT SCREEN key 220 | /// 221 | SNAPSHOT = 0x2C, 222 | 223 | /// 224 | /// INS key 225 | /// 226 | INSERT = 0x2D, 227 | 228 | /// 229 | /// DEL key 230 | /// 231 | DELETE = 0x2E, 232 | 233 | /// 234 | /// HELP key 235 | /// 236 | HELP = 0x2F, 237 | 238 | /// 239 | /// 0 key 240 | /// 241 | VK_0 = 0x30, 242 | 243 | /// 244 | /// 1 key 245 | /// 246 | VK_1 = 0x31, 247 | 248 | /// 249 | /// 2 key 250 | /// 251 | VK_2 = 0x32, 252 | 253 | /// 254 | /// 3 key 255 | /// 256 | VK_3 = 0x33, 257 | 258 | /// 259 | /// 4 key 260 | /// 261 | VK_4 = 0x34, 262 | 263 | /// 264 | /// 5 key 265 | /// 266 | VK_5 = 0x35, 267 | 268 | /// 269 | /// 6 key 270 | /// 271 | VK_6 = 0x36, 272 | 273 | /// 274 | /// 7 key 275 | /// 276 | VK_7 = 0x37, 277 | 278 | /// 279 | /// 8 key 280 | /// 281 | VK_8 = 0x38, 282 | 283 | /// 284 | /// 9 key 285 | /// 286 | VK_9 = 0x39, 287 | 288 | // 289 | // 0x3A - 0x40 : Udefined 290 | // 291 | 292 | /// 293 | /// A key 294 | /// 295 | VK_A = 0x41, 296 | 297 | /// 298 | /// B key 299 | /// 300 | VK_B = 0x42, 301 | 302 | /// 303 | /// C key 304 | /// 305 | VK_C = 0x43, 306 | 307 | /// 308 | /// D key 309 | /// 310 | VK_D = 0x44, 311 | 312 | /// 313 | /// E key 314 | /// 315 | VK_E = 0x45, 316 | 317 | /// 318 | /// F key 319 | /// 320 | VK_F = 0x46, 321 | 322 | /// 323 | /// G key 324 | /// 325 | VK_G = 0x47, 326 | 327 | /// 328 | /// H key 329 | /// 330 | VK_H = 0x48, 331 | 332 | /// 333 | /// I key 334 | /// 335 | VK_I = 0x49, 336 | 337 | /// 338 | /// J key 339 | /// 340 | VK_J = 0x4A, 341 | 342 | /// 343 | /// K key 344 | /// 345 | VK_K = 0x4B, 346 | 347 | /// 348 | /// L key 349 | /// 350 | VK_L = 0x4C, 351 | 352 | /// 353 | /// M key 354 | /// 355 | VK_M = 0x4D, 356 | 357 | /// 358 | /// N key 359 | /// 360 | VK_N = 0x4E, 361 | 362 | /// 363 | /// O key 364 | /// 365 | VK_O = 0x4F, 366 | 367 | /// 368 | /// P key 369 | /// 370 | VK_P = 0x50, 371 | 372 | /// 373 | /// Q key 374 | /// 375 | VK_Q = 0x51, 376 | 377 | /// 378 | /// R key 379 | /// 380 | VK_R = 0x52, 381 | 382 | /// 383 | /// S key 384 | /// 385 | VK_S = 0x53, 386 | 387 | /// 388 | /// T key 389 | /// 390 | VK_T = 0x54, 391 | 392 | /// 393 | /// U key 394 | /// 395 | VK_U = 0x55, 396 | 397 | /// 398 | /// V key 399 | /// 400 | VK_V = 0x56, 401 | 402 | /// 403 | /// W key 404 | /// 405 | VK_W = 0x57, 406 | 407 | /// 408 | /// X key 409 | /// 410 | VK_X = 0x58, 411 | 412 | /// 413 | /// Y key 414 | /// 415 | VK_Y = 0x59, 416 | 417 | /// 418 | /// Z key 419 | /// 420 | VK_Z = 0x5A, 421 | 422 | /// 423 | /// Left Windows key (Microsoft Natural keyboard) 424 | /// 425 | LWIN = 0x5B, 426 | 427 | /// 428 | /// Right Windows key (Natural keyboard) 429 | /// 430 | RWIN = 0x5C, 431 | 432 | /// 433 | /// Applications key (Natural keyboard) 434 | /// 435 | APPS = 0x5D, 436 | 437 | // 0x5E : reserved 438 | 439 | /// 440 | /// Computer Sleep key 441 | /// 442 | SLEEP = 0x5F, 443 | 444 | /// 445 | /// Numeric keypad 0 key 446 | /// 447 | NUMPAD0 = 0x60, 448 | 449 | /// 450 | /// Numeric keypad 1 key 451 | /// 452 | NUMPAD1 = 0x61, 453 | 454 | /// 455 | /// Numeric keypad 2 key 456 | /// 457 | NUMPAD2 = 0x62, 458 | 459 | /// 460 | /// Numeric keypad 3 key 461 | /// 462 | NUMPAD3 = 0x63, 463 | 464 | /// 465 | /// Numeric keypad 4 key 466 | /// 467 | NUMPAD4 = 0x64, 468 | 469 | /// 470 | /// Numeric keypad 5 key 471 | /// 472 | NUMPAD5 = 0x65, 473 | 474 | /// 475 | /// Numeric keypad 6 key 476 | /// 477 | NUMPAD6 = 0x66, 478 | 479 | /// 480 | /// Numeric keypad 7 key 481 | /// 482 | NUMPAD7 = 0x67, 483 | 484 | /// 485 | /// Numeric keypad 8 key 486 | /// 487 | NUMPAD8 = 0x68, 488 | 489 | /// 490 | /// Numeric keypad 9 key 491 | /// 492 | NUMPAD9 = 0x69, 493 | 494 | /// 495 | /// Multiply key 496 | /// 497 | MULTIPLY = 0x6A, 498 | 499 | /// 500 | /// Add key 501 | /// 502 | ADD = 0x6B, 503 | 504 | /// 505 | /// Separator key 506 | /// 507 | SEPARATOR = 0x6C, 508 | 509 | /// 510 | /// Subtract key 511 | /// 512 | SUBTRACT = 0x6D, 513 | 514 | /// 515 | /// Decimal key 516 | /// 517 | DECIMAL = 0x6E, 518 | 519 | /// 520 | /// Divide key 521 | /// 522 | DIVIDE = 0x6F, 523 | 524 | /// 525 | /// F1 key 526 | /// 527 | F1 = 0x70, 528 | 529 | /// 530 | /// F2 key 531 | /// 532 | F2 = 0x71, 533 | 534 | /// 535 | /// F3 key 536 | /// 537 | F3 = 0x72, 538 | 539 | /// 540 | /// F4 key 541 | /// 542 | F4 = 0x73, 543 | 544 | /// 545 | /// F5 key 546 | /// 547 | F5 = 0x74, 548 | 549 | /// 550 | /// F6 key 551 | /// 552 | F6 = 0x75, 553 | 554 | /// 555 | /// F7 key 556 | /// 557 | F7 = 0x76, 558 | 559 | /// 560 | /// F8 key 561 | /// 562 | F8 = 0x77, 563 | 564 | /// 565 | /// F9 key 566 | /// 567 | F9 = 0x78, 568 | 569 | /// 570 | /// F10 key 571 | /// 572 | F10 = 0x79, 573 | 574 | /// 575 | /// F11 key 576 | /// 577 | F11 = 0x7A, 578 | 579 | /// 580 | /// F12 key 581 | /// 582 | F12 = 0x7B, 583 | 584 | /// 585 | /// F13 key 586 | /// 587 | F13 = 0x7C, 588 | 589 | /// 590 | /// F14 key 591 | /// 592 | F14 = 0x7D, 593 | 594 | /// 595 | /// F15 key 596 | /// 597 | F15 = 0x7E, 598 | 599 | /// 600 | /// F16 key 601 | /// 602 | F16 = 0x7F, 603 | 604 | /// 605 | /// F17 key 606 | /// 607 | F17 = 0x80, 608 | 609 | /// 610 | /// F18 key 611 | /// 612 | F18 = 0x81, 613 | 614 | /// 615 | /// F19 key 616 | /// 617 | F19 = 0x82, 618 | 619 | /// 620 | /// F20 key 621 | /// 622 | F20 = 0x83, 623 | 624 | /// 625 | /// F21 key 626 | /// 627 | F21 = 0x84, 628 | 629 | /// 630 | /// F22 key 631 | /// 632 | F22 = 0x85, 633 | 634 | /// 635 | /// F23 key 636 | /// 637 | F23 = 0x86, 638 | 639 | /// 640 | /// F24 key 641 | /// 642 | F24 = 0x87, 643 | 644 | // 645 | // 0x88 - 0x8F : Unassigned 646 | // 647 | 648 | /// 649 | /// NUM LOCK key 650 | /// 651 | NUMLOCK = 0x90, 652 | 653 | /// 654 | /// SCROLL LOCK key 655 | /// 656 | SCROLL = 0x91, 657 | 658 | // 0x92 - 0x96 : OEM Specific 659 | 660 | // 0x97 - 0x9F : Unassigned 661 | 662 | // 663 | // L* & R* - left and right Alt, Ctrl and Shift virtual keys. 664 | // Used only as parameters to GetAsyncKeyState() and GetKeyState(). 665 | // No other API or message will distinguish left and right keys in this way. 666 | // 667 | 668 | /// 669 | /// Left SHIFT key - Used only as parameters to GetAsyncKeyState() and GetKeyState() 670 | /// 671 | LSHIFT = 0xA0, 672 | 673 | /// 674 | /// Right SHIFT key - Used only as parameters to GetAsyncKeyState() and GetKeyState() 675 | /// 676 | RSHIFT = 0xA1, 677 | 678 | /// 679 | /// Left CONTROL key - Used only as parameters to GetAsyncKeyState() and GetKeyState() 680 | /// 681 | LCONTROL = 0xA2, 682 | 683 | /// 684 | /// Right CONTROL key - Used only as parameters to GetAsyncKeyState() and GetKeyState() 685 | /// 686 | RCONTROL = 0xA3, 687 | 688 | /// 689 | /// Left MENU key - Used only as parameters to GetAsyncKeyState() and GetKeyState() 690 | /// 691 | LMENU = 0xA4, 692 | 693 | /// 694 | /// Right MENU key - Used only as parameters to GetAsyncKeyState() and GetKeyState() 695 | /// 696 | RMENU = 0xA5, 697 | 698 | /// 699 | /// Windows 2000/XP: Browser Back key 700 | /// 701 | BROWSER_BACK = 0xA6, 702 | 703 | /// 704 | /// Windows 2000/XP: Browser Forward key 705 | /// 706 | BROWSER_FORWARD = 0xA7, 707 | 708 | /// 709 | /// Windows 2000/XP: Browser Refresh key 710 | /// 711 | BROWSER_REFRESH = 0xA8, 712 | 713 | /// 714 | /// Windows 2000/XP: Browser Stop key 715 | /// 716 | BROWSER_STOP = 0xA9, 717 | 718 | /// 719 | /// Windows 2000/XP: Browser Search key 720 | /// 721 | BROWSER_SEARCH = 0xAA, 722 | 723 | /// 724 | /// Windows 2000/XP: Browser Favorites key 725 | /// 726 | BROWSER_FAVORITES = 0xAB, 727 | 728 | /// 729 | /// Windows 2000/XP: Browser Start and Home key 730 | /// 731 | BROWSER_HOME = 0xAC, 732 | 733 | /// 734 | /// Windows 2000/XP: Volume Mute key 735 | /// 736 | VOLUME_MUTE = 0xAD, 737 | 738 | /// 739 | /// Windows 2000/XP: Volume Down key 740 | /// 741 | VOLUME_DOWN = 0xAE, 742 | 743 | /// 744 | /// Windows 2000/XP: Volume Up key 745 | /// 746 | VOLUME_UP = 0xAF, 747 | 748 | /// 749 | /// Windows 2000/XP: Next Track key 750 | /// 751 | MEDIA_NEXT_TRACK = 0xB0, 752 | 753 | /// 754 | /// Windows 2000/XP: Previous Track key 755 | /// 756 | MEDIA_PREV_TRACK = 0xB1, 757 | 758 | /// 759 | /// Windows 2000/XP: Stop Media key 760 | /// 761 | MEDIA_STOP = 0xB2, 762 | 763 | /// 764 | /// Windows 2000/XP: Play/Pause Media key 765 | /// 766 | MEDIA_PLAY_PAUSE = 0xB3, 767 | 768 | /// 769 | /// Windows 2000/XP: Start Mail key 770 | /// 771 | LAUNCH_MAIL = 0xB4, 772 | 773 | /// 774 | /// Windows 2000/XP: Select Media key 775 | /// 776 | LAUNCH_MEDIA_SELECT = 0xB5, 777 | 778 | /// 779 | /// Windows 2000/XP: Start Application 1 key 780 | /// 781 | LAUNCH_APP1 = 0xB6, 782 | 783 | /// 784 | /// Windows 2000/XP: Start Application 2 key 785 | /// 786 | LAUNCH_APP2 = 0xB7, 787 | 788 | // 789 | // 0xB8 - 0xB9 : Reserved 790 | // 791 | 792 | /// 793 | /// Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ';:' key 794 | /// 795 | OEM_1 = 0xBA, 796 | 797 | /// 798 | /// Windows 2000/XP: For any country/region, the '+' key 799 | /// 800 | OEM_PLUS = 0xBB, 801 | 802 | /// 803 | /// Windows 2000/XP: For any country/region, the ',' key 804 | /// 805 | OEM_COMMA = 0xBC, 806 | 807 | /// 808 | /// Windows 2000/XP: For any country/region, the '-' key 809 | /// 810 | OEM_MINUS = 0xBD, 811 | 812 | /// 813 | /// Windows 2000/XP: For any country/region, the '.' key 814 | /// 815 | OEM_PERIOD = 0xBE, 816 | 817 | /// 818 | /// Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '/?' key 819 | /// 820 | OEM_2 = 0xBF, 821 | 822 | /// 823 | /// Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '`~' key 824 | /// 825 | OEM_3 = 0xC0, 826 | 827 | // 828 | // 0xC1 - 0xD7 : Reserved 829 | // 830 | 831 | // 832 | // 0xD8 - 0xDA : Unassigned 833 | // 834 | 835 | /// 836 | /// Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '[{' key 837 | /// 838 | OEM_4 = 0xDB, 839 | 840 | /// 841 | /// Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '\|' key 842 | /// 843 | OEM_5 = 0xDC, 844 | 845 | /// 846 | /// Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ']}' key 847 | /// 848 | OEM_6 = 0xDD, 849 | 850 | /// 851 | /// Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key 852 | /// 853 | OEM_7 = 0xDE, 854 | 855 | /// 856 | /// Used for miscellaneous characters; it can vary by keyboard. 857 | /// 858 | OEM_8 = 0xDF, 859 | 860 | // 861 | // 0xE0 : Reserved 862 | // 863 | 864 | // 865 | // 0xE1 : OEM Specific 866 | // 867 | 868 | /// 869 | /// Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard 870 | /// 871 | OEM_102 = 0xE2, 872 | 873 | // 874 | // (0xE3-E4) : OEM specific 875 | // 876 | 877 | /// 878 | /// Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCESS key 879 | /// 880 | PROCESSKEY = 0xE5, 881 | 882 | // 883 | // 0xE6 : OEM specific 884 | // 885 | 886 | /// 887 | /// Windows 2000/XP: Used to pass Unicode characters as if they were keystrokes. The PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP 888 | /// 889 | PACKET = 0xE7, 890 | 891 | // 892 | // 0xE8 : Unassigned 893 | // 894 | 895 | // 896 | // 0xE9-F5 : OEM specific 897 | // 898 | 899 | /// 900 | /// Attn key 901 | /// 902 | ATTN = 0xF6, 903 | 904 | /// 905 | /// CrSel key 906 | /// 907 | CRSEL = 0xF7, 908 | 909 | /// 910 | /// ExSel key 911 | /// 912 | EXSEL = 0xF8, 913 | 914 | /// 915 | /// Erase EOF key 916 | /// 917 | EREOF = 0xF9, 918 | 919 | /// 920 | /// Play key 921 | /// 922 | PLAY = 0xFA, 923 | 924 | /// 925 | /// Zoom key 926 | /// 927 | ZOOM = 0xFB, 928 | 929 | /// 930 | /// Reserved 931 | /// 932 | NONAME = 0xFC, 933 | 934 | /// 935 | /// PA1 key 936 | /// 937 | PA1 = 0xFD, 938 | 939 | /// 940 | /// Clear key 941 | /// 942 | OEM_CLEAR = 0xFE, 943 | 944 | 945 | } 946 | } 947 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/Native/XButton.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Native 2 | { 3 | /// 4 | /// XButton definitions for use in the MouseData property of the structure. (See: http://msdn.microsoft.com/en-us/library/ms646273(VS.85).aspx) 5 | /// 6 | internal enum XButton : uint 7 | { 8 | /// 9 | /// Set if the first X button is pressed or released. 10 | /// 11 | XButton1 = 0x0001, 12 | 13 | /// 14 | /// Set if the second X button is pressed or released. 15 | /// 16 | XButton2 = 0x0002, 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/WindowsInputDeviceStateAdapter.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard 2 | { 3 | using Native; 4 | 5 | /// 6 | /// 7 | /// An implementation of for Windows by calling the native and methods. 8 | /// 9 | public class WindowsInputDeviceStateAdapter : IInputDeviceStateAdapter 10 | { 11 | /// 12 | /// 13 | /// Determines whether the specified key is up or down by calling the GetKeyState function. (See: http://msdn.microsoft.com/en-us/library/ms646301(VS.85).aspx) 14 | /// 15 | /// The for the key. 16 | /// true if the key is down; otherwise, false. 17 | /// 18 | /// The key status returned from this function changes as a thread reads key messages from its message queue. The status does not reflect the interrupt-level state associated with the hardware. Use the GetAsyncKeyState function to retrieve that information. 19 | /// An application calls GetKeyState in response to a keyboard-input message. This function retrieves the state of the key when the input message was generated. 20 | /// To retrieve state information for all the virtual keys, use the GetKeyboardState function. 21 | /// An application can use the virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU as values for Bthe nVirtKey parameter. This gives the status of the SHIFT, CTRL, or ALT keys without distinguishing between left and right. An application can also use the following virtual-key code constants as values for nVirtKey to distinguish between the left and right instances of those keys. 22 | /// VK_LSHIFT 23 | /// VK_RSHIFT 24 | /// VK_LCONTROL 25 | /// VK_RCONTROL 26 | /// VK_LMENU 27 | /// VK_RMENU 28 | /// These left- and right-distinguishing constants are available to an application only through the GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState, and MapVirtualKey functions. 29 | /// 30 | public bool IsKeyDown(VirtualKeyCode keyCode) 31 | { 32 | var result = NativeMethods.GetKeyState((ushort)keyCode); 33 | return (result < 0); 34 | } 35 | 36 | /// 37 | /// 38 | /// Determines whether the specified key is up or down by calling the function. (See: http://msdn.microsoft.com/en-us/library/ms646301(VS.85).aspx) 39 | /// 40 | /// The for the key. 41 | /// true if the key is up; otherwise, false. 42 | /// 43 | /// The key status returned from this function changes as a thread reads key messages from its message queue. The status does not reflect the interrupt-level state associated with the hardware. Use the GetAsyncKeyState function to retrieve that information. 44 | /// An application calls GetKeyState in response to a keyboard-input message. This function retrieves the state of the key when the input message was generated. 45 | /// To retrieve state information for all the virtual keys, use the GetKeyboardState function. 46 | /// An application can use the virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU as values for Bthe nVirtKey parameter. This gives the status of the SHIFT, CTRL, or ALT keys without distinguishing between left and right. An application can also use the following virtual-key code constants as values for nVirtKey to distinguish between the left and right instances of those keys. 47 | /// VK_LSHIFT 48 | /// VK_RSHIFT 49 | /// VK_LCONTROL 50 | /// VK_RCONTROL 51 | /// VK_LMENU 52 | /// VK_RMENU 53 | /// These left- and right-distinguishing constants are available to an application only through the GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState, and MapVirtualKey functions. 54 | /// 55 | public bool IsKeyUp(VirtualKeyCode keyCode) => !this.IsKeyDown(keyCode); 56 | 57 | /// 58 | /// 59 | /// Determines whether the physical key is up or down at the time the function is called regardless of whether the application thread has read the keyboard event from the message pump by calling the function. (See: http://msdn.microsoft.com/en-us/library/ms646293(VS.85).aspx) 60 | /// 61 | /// The for the key. 62 | /// true if the key is down; otherwise, false. 63 | /// 64 | /// The GetAsyncKeyState function works with mouse buttons. However, it checks on the state of the physical mouse buttons, not on the logical mouse buttons that the physical buttons are mapped to. For example, the call GetAsyncKeyState(VK_LBUTTON) always returns the state of the left physical mouse button, regardless of whether it is mapped to the left or right logical mouse button. You can determine the system's current mapping of physical mouse buttons to logical mouse buttons by calling 65 | /// Copy CodeGetSystemMetrics(SM_SWAPBUTTON) which returns TRUE if the mouse buttons have been swapped. 66 | /// Although the least significant bit of the return value indicates whether the key has been pressed since the last query, due to the preemptive multitasking nature of Windows, another application can call GetAsyncKeyState and receive the "recently pressed" bit instead of your application. The behavior of the least significant bit of the return value is retained strictly for compatibility with 16-bit Windows applications (which are non-preemptive) and should not be relied upon. 67 | /// You can use the virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU as values for the vKey parameter. This gives the state of the SHIFT, CTRL, or ALT keys without distinguishing between left and right. 68 | /// Windows NT/2000/XP: You can use the following virtual-key code constants as values for vKey to distinguish between the left and right instances of those keys. 69 | /// Code Meaning 70 | /// VK_LSHIFT Left-shift key. 71 | /// VK_RSHIFT Right-shift key. 72 | /// VK_LCONTROL Left-control key. 73 | /// VK_RCONTROL Right-control key. 74 | /// VK_LMENU Left-menu key. 75 | /// VK_RMENU Right-menu key. 76 | /// These left- and right-distinguishing constants are only available when you call the GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState, and MapVirtualKey functions. 77 | /// 78 | public bool IsHardwareKeyDown(VirtualKeyCode keyCode) 79 | { 80 | var result = NativeMethods.GetAsyncKeyState((ushort)keyCode); 81 | return result < 0; 82 | } 83 | 84 | /// 85 | /// 86 | /// Determines whether the physical key is up or down at the time the function is called regardless of whether the application thread has read the keyboard event from the message pump by calling the function. (See: http://msdn.microsoft.com/en-us/library/ms646293(VS.85).aspx) 87 | /// 88 | /// The for the key. 89 | /// true if the key is up; otherwise, false. 90 | /// 91 | /// The GetAsyncKeyState function works with mouse buttons. However, it checks on the state of the physical mouse buttons, not on the logical mouse buttons that the physical buttons are mapped to. For example, the call GetAsyncKeyState(VK_LBUTTON) always returns the state of the left physical mouse button, regardless of whether it is mapped to the left or right logical mouse button. You can determine the system's current mapping of physical mouse buttons to logical mouse buttons by calling 92 | /// Copy CodeGetSystemMetrics(SM_SWAPBUTTON) which returns TRUE if the mouse buttons have been swapped. 93 | /// Although the least significant bit of the return value indicates whether the key has been pressed since the last query, due to the preemptive multitasking nature of Windows, another application can call GetAsyncKeyState and receive the "recently pressed" bit instead of your application. The behavior of the least significant bit of the return value is retained strictly for compatibility with 16-bit Windows applications (which are non-preemptive) and should not be relied upon. 94 | /// You can use the virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU as values for the vKey parameter. This gives the state of the SHIFT, CTRL, or ALT keys without distinguishing between left and right. 95 | /// Windows NT/2000/XP: You can use the following virtual-key code constants as values for vKey to distinguish between the left and right instances of those keys. 96 | /// Code Meaning 97 | /// VK_LSHIFT Left-shift key. 98 | /// VK_RSHIFT Right-shift key. 99 | /// VK_LCONTROL Left-control key. 100 | /// VK_RCONTROL Right-control key. 101 | /// VK_LMENU Left-menu key. 102 | /// VK_RMENU Right-menu key. 103 | /// These left- and right-distinguishing constants are only available when you call the GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState, and MapVirtualKey functions. 104 | /// 105 | public bool IsHardwareKeyUp(VirtualKeyCode keyCode) => !this.IsHardwareKeyDown(keyCode); 106 | 107 | /// 108 | /// 109 | /// Determines whether the toggling key is toggled on (in-effect) or not by calling the function. (See: http://msdn.microsoft.com/en-us/library/ms646301(VS.85).aspx) 110 | /// 111 | /// The for the key. 112 | /// true if the toggling key is toggled on (in-effect); otherwise, false. 113 | /// 114 | /// The key status returned from this function changes as a thread reads key messages from its message queue. The status does not reflect the interrupt-level state associated with the hardware. Use the GetAsyncKeyState function to retrieve that information. 115 | /// An application calls GetKeyState in response to a keyboard-input message. This function retrieves the state of the key when the input message was generated. 116 | /// To retrieve state information for all the virtual keys, use the GetKeyboardState function. 117 | /// An application can use the virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU as values for the nVirtKey parameter. This gives the status of the SHIFT, CTRL, or ALT keys without distinguishing between left and right. An application can also use the following virtual-key code constants as values for nVirtKey to distinguish between the left and right instances of those keys. 118 | /// VK_LSHIFT 119 | /// VK_RSHIFT 120 | /// VK_LCONTROL 121 | /// VK_RCONTROL 122 | /// VK_LMENU 123 | /// VK_RMENU 124 | /// These left- and right-distinguishing constants are available to an application only through the GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState, and MapVirtualKey functions. 125 | /// 126 | public bool IsTogglingKeyInEffect(VirtualKeyCode keyCode) 127 | { 128 | var result = NativeMethods.GetKeyState((ushort)keyCode); 129 | return (result & 0x01) == 0x01; 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/GregsStack.InputSimulatorStandard/WindowsInputMessageDispatcher.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard 2 | { 3 | using System; 4 | using System.Runtime.InteropServices; 5 | 6 | using Native; 7 | 8 | /// 9 | /// 10 | /// Implements the by calling . 11 | /// 12 | internal class WindowsInputMessageDispatcher : IInputMessageDispatcher 13 | { 14 | /// 15 | /// 16 | /// Dispatches the specified list of messages in their specified order by issuing a single called to . 17 | /// 18 | /// The list of messages to be dispatched. 19 | /// If the array is empty. 20 | /// If the array is null. 21 | /// If the any of the commands in the array could not be sent successfully. 22 | public void DispatchInput(Input[] inputs) 23 | { 24 | if (inputs == null) 25 | { 26 | throw new ArgumentNullException(nameof(inputs)); 27 | } 28 | 29 | if (inputs.Length == 0) 30 | { 31 | throw new ArgumentException("The input array was empty", nameof(inputs)); 32 | } 33 | 34 | var successful = NativeMethods.SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(Input))); 35 | if (successful != inputs.Length) 36 | { 37 | throw new Exception("Some simulated input commands were not sent successfully. The most common reason for this happening are the security features of Windows including User Interface Privacy Isolation (UIPI). Your application can only send commands to applications of the same or lower elevation. Similarly certain commands are restricted to Accessibility/UIAutomation applications. Refer to the project home page and the code samples for more information."); 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/GregsStack.InputSimulatorStandard.Tests/GregsStack.InputSimulatorStandard.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net472 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /tests/GregsStack.InputSimulatorStandard.Tests/InputBuilderTests.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Tests 2 | { 3 | using System.Collections.Generic; 4 | 5 | using Native; 6 | 7 | using Xunit; 8 | 9 | public class InputBuilderTests 10 | { 11 | private readonly InputBuilder inputBuilder; 12 | 13 | public InputBuilderTests() 14 | { 15 | this.inputBuilder = new InputBuilder(); 16 | } 17 | 18 | public class GetEnumeratorMethod : InputBuilderTests 19 | { 20 | [Fact] 21 | public void ReturnsIEnumerator() 22 | { 23 | var result = this.inputBuilder.GetEnumerator(); 24 | Assert.IsAssignableFrom>(result); 25 | } 26 | } 27 | 28 | public class IsExtendedKeyMethod : InputBuilderTests 29 | { 30 | [Theory] 31 | [InlineData(VirtualKeyCode.NUMPAD_RETURN)] 32 | [InlineData(VirtualKeyCode.MENU)] 33 | [InlineData(VirtualKeyCode.RMENU)] 34 | [InlineData(VirtualKeyCode.CONTROL)] 35 | [InlineData(VirtualKeyCode.RCONTROL)] 36 | [InlineData(VirtualKeyCode.INSERT)] 37 | [InlineData(VirtualKeyCode.DELETE)] 38 | [InlineData(VirtualKeyCode.HOME)] 39 | [InlineData(VirtualKeyCode.END)] 40 | [InlineData(VirtualKeyCode.PRIOR)] 41 | [InlineData(VirtualKeyCode.NEXT)] 42 | [InlineData(VirtualKeyCode.RIGHT)] 43 | [InlineData(VirtualKeyCode.UP)] 44 | [InlineData(VirtualKeyCode.LEFT)] 45 | [InlineData(VirtualKeyCode.DOWN)] 46 | [InlineData(VirtualKeyCode.NUMLOCK)] 47 | [InlineData(VirtualKeyCode.CANCEL)] 48 | [InlineData(VirtualKeyCode.SNAPSHOT)] 49 | [InlineData(VirtualKeyCode.DIVIDE)] 50 | public void ReturnsTrue(VirtualKeyCode keyCode) 51 | { 52 | var result = InputBuilder.IsExtendedKey(keyCode); 53 | Assert.True(result); 54 | } 55 | } 56 | 57 | public class AddKeyDownMethod : InputBuilderTests 58 | { 59 | [Fact] 60 | public void AddKeyDown() 61 | { 62 | Assert.Empty(this.inputBuilder.ToArray()); 63 | this.inputBuilder.AddKeyDown(VirtualKeyCode.VK_A); 64 | Assert.Single(this.inputBuilder); 65 | Assert.Equal((uint)InputType.Keyboard, this.inputBuilder[0].Type); 66 | Assert.Equal((ushort)VirtualKeyCode.VK_A, this.inputBuilder[0].Data.Keyboard.KeyCode); 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /tests/GregsStack.InputSimulatorStandard.Tests/InputSimulatorExamples.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Tests 2 | { 3 | using Native; 4 | 5 | using Xunit; 6 | 7 | public class InputSimulatorExamples 8 | { 9 | [Fact] 10 | public void OpenWindowsExplorer() 11 | { 12 | var sim = new InputSimulator(); 13 | sim.Keyboard.ModifiedKeyStroke(VirtualKeyCode.LWIN, VirtualKeyCode.VK_E); 14 | } 15 | 16 | [Fact] 17 | public void SayHello() 18 | { 19 | var sim = new InputSimulator(); 20 | sim.Keyboard 21 | .ModifiedKeyStroke(VirtualKeyCode.LWIN, VirtualKeyCode.VK_R) 22 | .Sleep(1000) 23 | .TextEntry("notepad") 24 | .Sleep(1000) 25 | .KeyPress(VirtualKeyCode.NUMPAD_RETURN) 26 | .Sleep(1000) 27 | .TextEntry("These are your orders if you choose to accept them...") 28 | .TextEntry("This message will self destruct in 5 seconds.") 29 | .Sleep(5000) 30 | .ModifiedKeyStroke(VirtualKeyCode.MENU, VirtualKeyCode.SPACE) 31 | .KeyPress(VirtualKeyCode.DOWN) 32 | .KeyPress(VirtualKeyCode.RETURN); 33 | 34 | var i = 10; 35 | while (i-- > 0) 36 | { 37 | sim.Keyboard.KeyPress(VirtualKeyCode.DOWN).Sleep(100); 38 | } 39 | 40 | sim.Keyboard 41 | .KeyPress(VirtualKeyCode.RETURN) 42 | .Sleep(1000) 43 | .ModifiedKeyStroke(VirtualKeyCode.MENU, VirtualKeyCode.F4) 44 | .KeyPress(VirtualKeyCode.VK_N); 45 | } 46 | 47 | [Fact] 48 | public void AnotherTest() 49 | { 50 | var sim = new InputSimulator(); 51 | sim.Keyboard.KeyPress(VirtualKeyCode.SPACE); 52 | 53 | sim.Keyboard.ModifiedKeyStroke(VirtualKeyCode.LWIN, VirtualKeyCode.VK_R) 54 | .Sleep(1000) 55 | .TextEntry("mspaint") 56 | .Sleep(1000) 57 | .KeyPress(VirtualKeyCode.RETURN) 58 | .Sleep(1000); 59 | sim.Mouse 60 | .LeftButtonDown() 61 | .MoveMouseToPositionOnVirtualDesktop(65535 / 2, 65535 / 2) 62 | .LeftButtonUp(); 63 | } 64 | 65 | [Fact] 66 | public void TestMouseMoveTo() 67 | { 68 | var sim = new InputSimulator(); 69 | sim.Mouse 70 | .MoveMouseTo(0, 0) 71 | .Sleep(1000) 72 | .MoveMouseTo(65535, 65535) 73 | .Sleep(1000) 74 | .MoveMouseTo(65535 / 2, 65535 / 2); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tests/GregsStack.InputSimulatorStandard.Tests/InputSimulatorTests.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Tests 2 | { 3 | using System; 4 | 5 | using Moq; 6 | 7 | using Xunit; 8 | 9 | public class InputSimulatorTests 10 | { 11 | private IInputSimulator inputSimulator; 12 | 13 | public InputSimulatorTests() 14 | { 15 | this.inputSimulator = new InputSimulator(Mock.Of(), Mock.Of(), Mock.Of()); 16 | } 17 | 18 | public class Constructor : InputSimulatorTests 19 | { 20 | [Fact] 21 | public void NullKeyboardSimulatorThrowsArgumentNullException() 22 | { 23 | Assert.Throws("keyboardSimulator", () => 24 | { 25 | this.inputSimulator = new InputSimulator(null, Mock.Of(), Mock.Of()); 26 | }); 27 | } 28 | 29 | [Fact] 30 | public void NullMouseSimulatorThrowsArgumentNullException() 31 | { 32 | Assert.Throws("mouseSimulator", () => 33 | { 34 | this.inputSimulator = new InputSimulator(Mock.Of(), null, Mock.Of()); 35 | }); 36 | } 37 | 38 | [Fact] 39 | public void NullInputDeviceStateAdapterThrowsArgumentNullException() 40 | { 41 | Assert.Throws("inputDeviceStateAdapter", () => 42 | { 43 | this.inputSimulator = new InputSimulator(Mock.Of(), Mock.Of(), null); 44 | }); 45 | } 46 | } 47 | 48 | public class KeyboardProperty : InputSimulatorTests 49 | { 50 | [Fact] 51 | public void IsNotNull() 52 | { 53 | var result = this.inputSimulator.Keyboard; 54 | Assert.IsAssignableFrom(result); 55 | } 56 | } 57 | 58 | public class MouseProperty : InputSimulatorTests 59 | { 60 | [Fact] 61 | public void IsNotNull() 62 | { 63 | var result = this.inputSimulator.Mouse; 64 | Assert.IsAssignableFrom(result); 65 | } 66 | } 67 | 68 | public class InputDeviceStateProperty : InputSimulatorTests 69 | { 70 | [Fact] 71 | public void IsNotNull() 72 | { 73 | var result = this.inputSimulator.InputDeviceState; 74 | Assert.IsAssignableFrom(result); 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /tests/GregsStack.InputSimulatorStandard.Tests/MouseSimulatorTests.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Tests 2 | { 3 | using System; 4 | 5 | using Moq; 6 | 7 | using Xunit; 8 | 9 | public class MouseSimulatorTests 10 | { 11 | private IMouseSimulator mouseSimulator; 12 | 13 | public MouseSimulatorTests() 14 | { 15 | this.mouseSimulator = new MouseSimulator(Mock.Of()); 16 | } 17 | 18 | public class Constructor : MouseSimulatorTests 19 | { 20 | [Fact] 21 | public void NullMessageDispatcherThrowsInvalidOperationException() 22 | { 23 | Assert.Throws(() => this.mouseSimulator = new MouseSimulator(null)); 24 | } 25 | } 26 | 27 | public class PositionProperty : MouseSimulatorTests 28 | { 29 | [Fact] 30 | public void GetPosition() 31 | { 32 | var position = this.mouseSimulator.Position; 33 | Assert.False(position.IsEmpty); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/GregsStack.InputSimulatorStandard.Tests/UnicodeText/UnicodeRange.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Tests.UnicodeText 2 | { 3 | using System.Text; 4 | 5 | public class UnicodeRange 6 | { 7 | public string Name { get; set; } 8 | 9 | public int Low { get; set; } 10 | 11 | public int High { get; set; } 12 | 13 | public string Characters 14 | { 15 | get 16 | { 17 | var i = this.Low; 18 | var sb = new StringBuilder(this.High - this.Low + 10); 19 | while (i <= this.High) 20 | { 21 | sb.Append(char.ConvertFromUtf32(i)); 22 | i++; 23 | } 24 | 25 | return sb.ToString(); 26 | } 27 | } 28 | 29 | public UnicodeRange(string name, int low, int high) 30 | { 31 | this.Name = name; 32 | this.Low = low; 33 | this.High = high; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/GregsStack.InputSimulatorStandard.Tests/UnicodeText/UnicodeTestForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Tests.UnicodeText 2 | { 3 | partial class UnicodeTestForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | 21 | base.Dispose(disposing); 22 | } 23 | 24 | #region Windows Form Designer generated code 25 | 26 | /// 27 | /// Required method for Designer support - do not modify 28 | /// the contents of this method with the code editor. 29 | /// 30 | private void InitializeComponent() 31 | { 32 | this.RecievedTextBox = new System.Windows.Forms.TextBox(); 33 | this.ExpectedTextBox = new System.Windows.Forms.TextBox(); 34 | this.SuspendLayout(); 35 | // 36 | // RecievedTextBox 37 | // 38 | this.RecievedTextBox.Dock = System.Windows.Forms.DockStyle.Top; 39 | this.RecievedTextBox.Font = new System.Drawing.Font("Segoe UI", 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 40 | this.RecievedTextBox.Location = new System.Drawing.Point(0, 0); 41 | this.RecievedTextBox.Name = "RecievedTextBox"; 42 | this.RecievedTextBox.Size = new System.Drawing.Size(981, 39); 43 | this.RecievedTextBox.TabIndex = 0; 44 | // 45 | // ExpectedTextBox 46 | // 47 | this.ExpectedTextBox.Dock = System.Windows.Forms.DockStyle.Bottom; 48 | this.ExpectedTextBox.Font = new System.Drawing.Font("Segoe UI", 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 49 | this.ExpectedTextBox.Location = new System.Drawing.Point(0, 40); 50 | this.ExpectedTextBox.Name = "ExpectedTextBox"; 51 | this.ExpectedTextBox.ReadOnly = true; 52 | this.ExpectedTextBox.Size = new System.Drawing.Size(981, 39); 53 | this.ExpectedTextBox.TabIndex = 1; 54 | // 55 | // UnicodeTestForm 56 | // 57 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 58 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 59 | this.ClientSize = new System.Drawing.Size(981, 79); 60 | this.Controls.Add(this.ExpectedTextBox); 61 | this.Controls.Add(this.RecievedTextBox); 62 | this.Name = "UnicodeTestForm"; 63 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; 64 | this.Text = "UnicodeTestForm"; 65 | this.TopMost = true; 66 | this.WindowState = System.Windows.Forms.FormWindowState.Maximized; 67 | this.ResumeLayout(false); 68 | this.PerformLayout(); 69 | 70 | } 71 | 72 | #endregion 73 | 74 | private System.Windows.Forms.TextBox RecievedTextBox; 75 | private System.Windows.Forms.TextBox ExpectedTextBox; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tests/GregsStack.InputSimulatorStandard.Tests/UnicodeText/UnicodeTestForm.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Tests.UnicodeText 2 | { 3 | using System; 4 | using System.Windows.Forms; 5 | 6 | public partial class UnicodeTestForm : Form 7 | { 8 | public UnicodeTestForm() 9 | { 10 | this.InitializeComponent(); 11 | } 12 | 13 | public string Expected 14 | { 15 | get => this.ExpectedTextBox.Text; 16 | set => this.ExpectedTextBox.Text = value; 17 | } 18 | 19 | public string Received => this.RecievedTextBox.Text; 20 | 21 | protected override void OnLoad(EventArgs e) 22 | { 23 | base.OnLoad(e); 24 | this.RecievedTextBox.Focus(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/GregsStack.InputSimulatorStandard.Tests/UnicodeText/UnicodeTestForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /tests/GregsStack.InputSimulatorStandard.Tests/UnicodeText/UnicodeTextTests.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Tests.UnicodeText 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Net; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | using HtmlAgilityPack; 10 | 11 | using Xunit; 12 | using Xunit.Abstractions; 13 | 14 | public class UnicodeTextTests 15 | { 16 | private readonly ITestOutputHelper testOutputHelper; 17 | 18 | public UnicodeTextTests(ITestOutputHelper testOutputHelper) 19 | { 20 | this.testOutputHelper = testOutputHelper; 21 | } 22 | 23 | public static IEnumerable UnicodeTestCases = new[] 24 | { 25 | new []{new UnicodeRange("Basic Latin", 0x0020, 0x007F)}, 26 | new []{new UnicodeRange("Block Elements", 0x2580, 0x259F)}, 27 | new []{new UnicodeRange("Latin-1 Supplement", 0x00A0, 0x00FF)}, 28 | new []{new UnicodeRange("Geometric Shapes", 0x25A0, 0x25FF)}, 29 | new []{new UnicodeRange("Latin Extended-A", 0x0100, 0x017F)}, 30 | new []{new UnicodeRange("Miscellaneous Symbols", 0x2600, 0x26FF)}, 31 | new []{new UnicodeRange("Latin Extended-B", 0x0180, 0x024F)}, 32 | new []{new UnicodeRange("Dingbats", 0x2700, 0x27BF)}, 33 | new []{new UnicodeRange("IPA Extensions", 0x0250, 0x02AF)}, 34 | new []{new UnicodeRange("Miscellaneous Mathematical Symbols-A", 0x27C0, 0x27EF)}, 35 | new []{new UnicodeRange("Spacing Modifier Letters", 0x02B0, 0x02FF)}, 36 | new []{new UnicodeRange("Supplemental Arrows-A", 0x27F0, 0x27FF)}, 37 | new []{new UnicodeRange("Combining Diacritical Marks", 0x0300, 0x036F)}, 38 | new []{new UnicodeRange("Braille Patterns", 0x2800, 0x28FF)}, 39 | new []{new UnicodeRange("Greek and Coptic", 0x0370, 0x03FF)}, 40 | new []{new UnicodeRange("Supplemental Arrows-B", 0x2900, 0x297F)}, 41 | new []{new UnicodeRange("Cyrillic", 0x0400, 0x04FF)}, 42 | new []{new UnicodeRange("Miscellaneous Mathematical Symbols-B", 0x2980, 0x29FF)}, 43 | new []{new UnicodeRange("Cyrillic Supplementary", 0x0500, 0x052F)}, 44 | new []{new UnicodeRange("Supplemental Mathematical Operators", 0x2A00, 0x2AFF)}, 45 | new []{new UnicodeRange("Armenian", 0x0530, 0x058F)}, 46 | new []{new UnicodeRange("Miscellaneous Symbols and Arrows", 0x2B00, 0x2BFF)}, 47 | new []{new UnicodeRange("Hebrew", 0x0590, 0x05FF)}, 48 | new []{new UnicodeRange("CJK Radicals Supplement", 0x2E80, 0x2EFF)}, 49 | new []{new UnicodeRange("Arabic", 0x0600, 0x06FF)}, 50 | new []{new UnicodeRange("Kangxi Radicals", 0x2F00, 0x2FDF)}, 51 | new []{new UnicodeRange("Syriac", 0x0700, 0x074F)}, 52 | new []{new UnicodeRange("Ideographic Description Characters", 0x2FF0, 0x2FFF)}, 53 | new []{new UnicodeRange("Thaana", 0x0780, 0x07BF)}, 54 | new []{new UnicodeRange("CJK Symbols and Punctuation", 0x3000, 0x303F)}, 55 | new []{new UnicodeRange("Devanagari", 0x0900, 0x097F)}, 56 | new []{new UnicodeRange("Hiragana", 0x3040, 0x309F)}, 57 | new []{new UnicodeRange("Bengali", 0x0980, 0x09FF)}, 58 | new []{new UnicodeRange("Katakana", 0x30A0, 0x30FF)}, 59 | new []{new UnicodeRange("Gurmukhi", 0x0A00, 0x0A7F)}, 60 | new []{new UnicodeRange("Bopomofo", 0x3100, 0x312F)}, 61 | new []{new UnicodeRange("Gujarati", 0x0A80, 0x0AFF)}, 62 | new []{new UnicodeRange("Hangul Compatibility Jamo", 0x3130, 0x318F)}, 63 | new []{new UnicodeRange("Oriya", 0x0B00, 0x0B7F)}, 64 | new []{new UnicodeRange("Kanbun", 0x3190, 0x319F)}, 65 | new []{new UnicodeRange("Tamil", 0x0B80, 0x0BFF)}, 66 | new []{new UnicodeRange("Bopomofo Extended", 0x31A0, 0x31BF)}, 67 | new []{new UnicodeRange("Telugu", 0x0C00, 0x0C7F)}, 68 | new []{new UnicodeRange("Katakana Phonetic Extensions", 0x31F0, 0x31FF)}, 69 | new []{new UnicodeRange("Kannada", 0x0C80, 0x0CFF)}, 70 | new []{new UnicodeRange("Enclosed CJK Letters and Months", 0x3200, 0x32FF)}, 71 | new []{new UnicodeRange("Malayalam", 0x0D00, 0x0D7F)}, 72 | new []{new UnicodeRange("CJK Compatibility", 0x3300, 0x33FF)}, 73 | new []{new UnicodeRange("Sinhala", 0x0D80, 0x0DFF)}, 74 | new []{new UnicodeRange("CJK Unified Ideographs Extension A", 0x3400, 0x4DBF)}, 75 | new []{new UnicodeRange("Thai", 0x0E00, 0x0E7F)}, 76 | new []{new UnicodeRange("Yijing Hexagram Symbols", 0x4DC0, 0x4DFF)}, 77 | new []{new UnicodeRange("Lao", 0x0E80, 0x0EFF)}, 78 | new []{new UnicodeRange("CJK Unified Ideographs", 0x4E00, 0x9FFF)}, 79 | new []{new UnicodeRange("Tibetan", 0x0F00, 0x0FFF)}, 80 | new []{new UnicodeRange("Yi Syllables", 0xA000, 0xA48F)}, 81 | new []{new UnicodeRange("Myanmar", 0x1000, 0x109F)}, 82 | new []{new UnicodeRange("Yi Radicals", 0xA490, 0xA4CF)}, 83 | new []{new UnicodeRange("Georgian", 0x10A0, 0x10FF)}, 84 | new []{new UnicodeRange("Hangul Syllables", 0xAC00, 0xD7AF)}, 85 | new []{new UnicodeRange("Hangul Jamo", 0x1100, 0x11FF)}, 86 | new []{new UnicodeRange("High Surrogates", 0xD800, 0xDB7F)}, 87 | new []{new UnicodeRange("Ethiopic", 0x1200, 0x137F)}, 88 | new []{new UnicodeRange("High Private Use Surrogates", 0xDB80, 0xDBFF)}, 89 | new []{new UnicodeRange("Cherokee", 0x13A0, 0x13FF)}, 90 | new []{new UnicodeRange("Low Surrogates", 0xDC00, 0xDFFF)}, 91 | new []{new UnicodeRange("Unified Canadian Aboriginal Syllabics", 0x1400, 0x167F)}, 92 | new []{new UnicodeRange("Private Use Area", 0xE000, 0xF8FF)}, 93 | new []{new UnicodeRange("Ogham", 0x1680, 0x169F)}, 94 | new []{new UnicodeRange("CJK Compatibility Ideographs", 0xF900, 0xFAFF)}, 95 | new []{new UnicodeRange("Runic", 0x16A0, 0x16FF)}, 96 | new []{new UnicodeRange("Alphabetic Presentation Forms", 0xFB00, 0xFB4F)}, 97 | new []{new UnicodeRange("Tagalog", 0x1700, 0x171F)}, 98 | new []{new UnicodeRange("Arabic Presentation Forms-A", 0xFB50, 0xFDFF)}, 99 | new []{new UnicodeRange("Hanunoo", 0x1720, 0x173F)}, 100 | new []{new UnicodeRange("Variation Selectors", 0xFE00, 0xFE0F)}, 101 | new []{new UnicodeRange("Buhid", 0x1740, 0x175F)}, 102 | new []{new UnicodeRange("Combining Half Marks", 0xFE20, 0xFE2F)}, 103 | new []{new UnicodeRange("Tagbanwa", 0x1760, 0x177F)}, 104 | new []{new UnicodeRange("CJK Compatibility Forms", 0xFE30, 0xFE4F)}, 105 | new []{new UnicodeRange("Khmer", 0x1780, 0x17FF)}, 106 | new []{new UnicodeRange("Small Form Variants", 0xFE50, 0xFE6F)}, 107 | new []{new UnicodeRange("Mongolian", 0x1800, 0x18AF)}, 108 | new []{new UnicodeRange("Arabic Presentation Forms-B", 0xFE70, 0xFEFF)}, 109 | new []{new UnicodeRange("Limbu", 0x1900, 0x194F)}, 110 | new []{new UnicodeRange("Halfwidth and Fullwidth Forms", 0xFF00, 0xFFEF)}, 111 | new []{new UnicodeRange("Tai Le", 0x1950, 0x197F)}, 112 | new []{new UnicodeRange("Specials", 0xFFF0, 0xFFFF)}, 113 | new []{new UnicodeRange("Khmer Symbols", 0x19E0, 0x19FF)}, 114 | new []{new UnicodeRange("Linear B Syllabary", 0x10000, 0x1007F)}, 115 | new []{new UnicodeRange("Phonetic Extensions", 0x1D00, 0x1D7F)}, 116 | new []{new UnicodeRange("Linear B Ideograms", 0x10080, 0x100FF)}, 117 | new []{new UnicodeRange("Latin Extended Additional", 0x1E00, 0x1EFF)}, 118 | new []{new UnicodeRange("Aegean Numbers", 0x10100, 0x1013F)}, 119 | new []{new UnicodeRange("Greek Extended", 0x1F00, 0x1FFF)}, 120 | new []{new UnicodeRange("Old Italic", 0x10300, 0x1032F)}, 121 | new []{new UnicodeRange("General Punctuation", 0x2000, 0x206F)}, 122 | new []{new UnicodeRange("Gothic", 0x10330, 0x1034F)}, 123 | new []{new UnicodeRange("Superscripts and Subscripts", 0x2070, 0x209F)}, 124 | new []{new UnicodeRange("Ugaritic", 0x10380, 0x1039F)} 125 | }; 126 | 127 | [Theory(Skip = "Run only interactive")] 128 | [MemberData(nameof(UnicodeTestCases))] 129 | public void TestUnicodeRanges(UnicodeRange range) 130 | { 131 | // ReSharper disable AccessToDisposedClosure 132 | using (var form = new UnicodeTestForm 133 | { 134 | Expected = range.Characters 135 | }) 136 | { 137 | var ready = false; 138 | var formTask = Task.Factory.StartNew( 139 | () => 140 | { 141 | form.Shown += (x, y) => ready = true; 142 | form.ShowDialog(); 143 | }, TaskCreationOptions.LongRunning); 144 | 145 | var simTask = Task.Factory.StartNew( 146 | () => 147 | { 148 | while (!ready) 149 | { 150 | Thread.Sleep(250); 151 | } 152 | 153 | var sim = new InputSimulator(); 154 | sim.Keyboard.TextEntry(range.Characters); 155 | while (form.Received != form.Expected) 156 | { 157 | Thread.Sleep(500); 158 | } 159 | 160 | form.Close(); 161 | }, TaskCreationOptions.LongRunning); 162 | 163 | Task.WaitAll(new[] { formTask, simTask }, TimeSpan.FromSeconds(60)); 164 | Assert.Equal(form.Expected, form.Received); 165 | } 166 | // ReSharper restore AccessToDisposedClosure 167 | } 168 | 169 | [Fact(Skip = "Generate Unicode test data manually")] 170 | public void GetCharacterRanges() 171 | { 172 | using (var client = new WebClient()) 173 | { 174 | var html = client.DownloadString("http://jrgraphix.net/r/Unicode/"); 175 | var htmlDoc = new HtmlDocument(); 176 | htmlDoc.LoadHtml(html); 177 | foreach (var link in htmlDoc.DocumentNode.SelectNodes("//a[@href]")) 178 | { 179 | var a = link.GetAttributeValue("href", "unknown"); 180 | if (!a.Contains("Unicode")) 181 | { 182 | continue; 183 | } 184 | 185 | a = "0x" + a.Replace("/r/Unicode/", "").Replace("-", ", 0x"); 186 | this.testOutputHelper.WriteLine($"new []{{new UnicodeRange(\"{link.InnerText}\", {a})}},"); 187 | } 188 | } 189 | } 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /tests/GregsStack.InputSimulatorStandard.Tests/WindowsInputMessageDispatcherTests.cs: -------------------------------------------------------------------------------- 1 | namespace GregsStack.InputSimulatorStandard.Tests 2 | { 3 | using System; 4 | 5 | using Native; 6 | 7 | using Xunit; 8 | 9 | public class WindowsInputMessageDispatcherTests 10 | { 11 | private readonly IInputMessageDispatcher inputMessageDispatcher; 12 | 13 | public WindowsInputMessageDispatcherTests() 14 | { 15 | this.inputMessageDispatcher = new WindowsInputMessageDispatcher(); 16 | } 17 | 18 | public class DispatchInputMethod : WindowsInputMessageDispatcherTests 19 | { 20 | [Fact] 21 | public void NullInputsThrowsArgumentNullException() 22 | { 23 | Assert.Throws("inputs", () => this.inputMessageDispatcher.DispatchInput(null)); 24 | } 25 | 26 | [Fact] 27 | public void EmptyInputsThrowsArgumentException() 28 | { 29 | Assert.Throws("inputs", () => this.inputMessageDispatcher.DispatchInput(new Input[0])); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tools/NuGet.Tools/NuGet.Tools.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | --------------------------------------------------------------------------------