├── .gitattributes ├── .gitignore ├── LICENSE ├── MaiSense.Launcher.vcxproj ├── MaiSense.Launcher.vcxproj.filters ├── MaiSense.sln ├── MaiSense.vcxproj ├── MaiSense.vcxproj.filters ├── README.md ├── build └── .gitignore ├── extlibs ├── include │ ├── detours.h │ ├── detver.h │ └── syelog.h └── lib │ └── detours.lib ├── include └── MaiSense │ ├── InputController.hpp │ ├── InputManager.hpp │ ├── KeyEvent.hpp │ ├── KeyboardController.hpp │ ├── Launcher │ ├── Injector.hpp │ └── Process.hpp │ ├── MouseController.hpp │ ├── MouseEvent.hpp │ ├── Point.hpp │ ├── Sensor.hpp │ ├── SensorChecker.hpp │ ├── SensorProcessor.hpp │ ├── SensorRegion.hpp │ ├── TouchController.hpp │ └── TouchEvent.hpp ├── src ├── InputManager.cpp ├── KeyboardController.cpp ├── Launcher │ ├── Injector.cpp │ ├── Process.cpp │ └── main.cpp ├── MouseController.cpp ├── Sensor.cpp ├── SensorChecker.cpp ├── SensorProcessor.cpp ├── SensorRegion.cpp ├── TouchController.cpp └── dllmain.cpp └── temp └── .gitignore /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | .idea/ 13 | 14 | # Build results 15 | [Dd]ebug/ 16 | [Dd]ebugPublic/ 17 | [Rr]elease/ 18 | [Rr]eleases/ 19 | [Xx]64/ 20 | [Xx]86/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Microsoft Azure ApplicationInsights config file 170 | ApplicationInsights.config 171 | 172 | # Windows Store app package directory 173 | AppPackages/ 174 | BundleArtifacts/ 175 | 176 | # Visual Studio cache files 177 | # files ending in .cache can be ignored 178 | *.[Cc]ache 179 | # but keep track of directories ending in .cache 180 | !*.[Cc]ache/ 181 | 182 | # Others 183 | ClientBin/ 184 | [Ss]tyle[Cc]op.* 185 | ~$* 186 | *~ 187 | *.dbmdl 188 | *.dbproj.schemaview 189 | *.pfx 190 | *.publishsettings 191 | node_modules/ 192 | orleans.codegen.cs 193 | 194 | # RIA/Silverlight projects 195 | Generated_Code/ 196 | 197 | # Backup & report files from converting an old project file 198 | # to a newer Visual Studio version. Backup files are not needed, 199 | # because we have git ;-) 200 | _UpgradeReport_Files/ 201 | Backup*/ 202 | UpgradeLog*.XML 203 | UpgradeLog*.htm 204 | 205 | # SQL Server files 206 | *.mdf 207 | *.ldf 208 | 209 | # Business Intelligence projects 210 | *.rdl.data 211 | *.bim.layout 212 | *.bim_*.settings 213 | 214 | # Microsoft Fakes 215 | FakesAssemblies/ 216 | 217 | # GhostDoc plugin setting file 218 | *.GhostDoc.xml 219 | 220 | # Node.js Tools for Visual Studio 221 | .ntvs_analysis.dat 222 | 223 | # Visual Studio 6 build log 224 | *.plg 225 | 226 | # Visual Studio 6 workspace options file 227 | *.opt 228 | 229 | # Visual Studio LightSwitch build output 230 | **/*.HTMLClient/GeneratedArtifacts 231 | **/*.DesktopClient/GeneratedArtifacts 232 | **/*.DesktopClient/ModelManifest.xml 233 | **/*.Server/GeneratedArtifacts 234 | **/*.Server/ModelManifest.xml 235 | _Pvt_Extensions 236 | 237 | # LightSwitch generated files 238 | GeneratedArtifacts/ 239 | ModelManifest.xml 240 | 241 | # Paket dependency manager 242 | .paket/paket.exe 243 | 244 | # FAKE - F# Make 245 | .fake/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 SirusDoma 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 | -------------------------------------------------------------------------------- /MaiSense.Launcher.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {60C5B665-943F-476F-8EDB-C57DDFE74560} 24 | InputKeyboard 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v142 32 | MultiByte 33 | 34 | 35 | Application 36 | false 37 | v142 38 | true 39 | MultiByte 40 | 41 | 42 | Application 43 | true 44 | v142 45 | MultiByte 46 | 47 | 48 | Application 49 | false 50 | v142 51 | true 52 | MultiByte 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | MaiSense.Launcher 74 | build\$(Configuration)\ 75 | temp\$(Configuration)\launcher\ 76 | 77 | 78 | MaiSense.Launcher 79 | build\$(Configuration)\ 80 | temp\$(Configuration)\launcher\ 81 | 82 | 83 | MaiSense.Launcher 84 | build\$(Configuration)\ 85 | temp\$(Configuration)\launcher\ 86 | 87 | 88 | MaiSense.Launcher 89 | build\$(Configuration)\ 90 | temp\$(Configuration)\launcher\ 91 | 92 | 93 | 94 | Level3 95 | Disabled 96 | true 97 | true 98 | ./include/%(AdditionalIncludeDirectories) 99 | stdcpp17 100 | MultiThreadedDebug 101 | 102 | 103 | Console 104 | 105 | 106 | 107 | 108 | Level3 109 | Disabled 110 | true 111 | true 112 | ./include/%(AdditionalIncludeDirectories) 113 | stdcpp17 114 | MultiThreadedDebug 115 | 116 | 117 | Console 118 | 119 | 120 | 121 | 122 | Level3 123 | MaxSpeed 124 | true 125 | true 126 | true 127 | true 128 | ./include/%(AdditionalIncludeDirectories) 129 | stdcpp17 130 | MultiThreaded 131 | 132 | 133 | Console 134 | true 135 | true 136 | 137 | 138 | 139 | 140 | Level3 141 | MaxSpeed 142 | true 143 | true 144 | true 145 | true 146 | ./include/%(AdditionalIncludeDirectories) 147 | stdcpp17 148 | MultiThreaded 149 | 150 | 151 | Console 152 | true 153 | true 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /MaiSense.Launcher.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 6 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 7 | 8 | 9 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 10 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 11 | 12 | 13 | 14 | 15 | Sources 16 | 17 | 18 | Sources 19 | 20 | 21 | Sources 22 | 23 | 24 | 25 | 26 | Headers 27 | 28 | 29 | Headers 30 | 31 | 32 | -------------------------------------------------------------------------------- /MaiSense.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29009.5 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MaiSense", "MaiSense.vcxproj", "{E69E1597-4570-4115-BAE6-EC49177F62E8}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MaiSense.Launcher", "MaiSense.Launcher.vcxproj", "{60C5B665-943F-476F-8EDB-C57DDFE74560}" 9 | ProjectSection(ProjectDependencies) = postProject 10 | {E69E1597-4570-4115-BAE6-EC49177F62E8} = {E69E1597-4570-4115-BAE6-EC49177F62E8} 11 | EndProjectSection 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|x64 = Debug|x64 16 | Debug|x86 = Debug|x86 17 | Release|x64 = Release|x64 18 | Release|x86 = Release|x86 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {E69E1597-4570-4115-BAE6-EC49177F62E8}.Debug|x64.ActiveCfg = Debug|x64 22 | {E69E1597-4570-4115-BAE6-EC49177F62E8}.Debug|x64.Build.0 = Debug|x64 23 | {E69E1597-4570-4115-BAE6-EC49177F62E8}.Debug|x86.ActiveCfg = Debug|Win32 24 | {E69E1597-4570-4115-BAE6-EC49177F62E8}.Debug|x86.Build.0 = Debug|Win32 25 | {E69E1597-4570-4115-BAE6-EC49177F62E8}.Release|x64.ActiveCfg = Release|x64 26 | {E69E1597-4570-4115-BAE6-EC49177F62E8}.Release|x64.Build.0 = Release|x64 27 | {E69E1597-4570-4115-BAE6-EC49177F62E8}.Release|x86.ActiveCfg = Release|Win32 28 | {E69E1597-4570-4115-BAE6-EC49177F62E8}.Release|x86.Build.0 = Release|Win32 29 | {60C5B665-943F-476F-8EDB-C57DDFE74560}.Debug|x64.ActiveCfg = Debug|x64 30 | {60C5B665-943F-476F-8EDB-C57DDFE74560}.Debug|x64.Build.0 = Debug|x64 31 | {60C5B665-943F-476F-8EDB-C57DDFE74560}.Debug|x86.ActiveCfg = Debug|Win32 32 | {60C5B665-943F-476F-8EDB-C57DDFE74560}.Debug|x86.Build.0 = Debug|Win32 33 | {60C5B665-943F-476F-8EDB-C57DDFE74560}.Release|x64.ActiveCfg = Release|x64 34 | {60C5B665-943F-476F-8EDB-C57DDFE74560}.Release|x64.Build.0 = Release|x64 35 | {60C5B665-943F-476F-8EDB-C57DDFE74560}.Release|x86.ActiveCfg = Release|Win32 36 | {60C5B665-943F-476F-8EDB-C57DDFE74560}.Release|x86.Build.0 = Release|Win32 37 | EndGlobalSection 38 | GlobalSection(SolutionProperties) = preSolution 39 | HideSolutionNode = FALSE 40 | EndGlobalSection 41 | GlobalSection(ExtensibilityGlobals) = postSolution 42 | SolutionGuid = {B2140A4E-FC02-4FB8-9F06-D551A5F2B6BE} 43 | SolutionGuid = {670D5EC6-74C3-48BC-9971-84B8BF6D4511} 44 | EndGlobalSection 45 | EndGlobal 46 | -------------------------------------------------------------------------------- /MaiSense.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {E69E1597-4570-4115-BAE6-EC49177F62E8} 24 | Win32Proj 25 | MaiSense 26 | 10.0 27 | 28 | 29 | 30 | DynamicLibrary 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | DynamicLibrary 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | DynamicLibrary 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | DynamicLibrary 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | build\$(Configuration)\ 76 | temp\$(Configuration)\ 77 | MaiSense 78 | $(IncludePath) 79 | 80 | 81 | true 82 | build\$(Configuration)\ 83 | temp\$(Configuration)\ 84 | MaiSense 85 | $(IncludePath) 86 | 87 | 88 | false 89 | build\$(Configuration)\ 90 | temp\$(Configuration)\ 91 | MaiSense 92 | $(IncludePath) 93 | 94 | 95 | false 96 | build\$(Configuration)\ 97 | temp\$(Configuration)\ 98 | MaiSense 99 | $(IncludePath) 100 | 101 | 102 | 103 | NotUsing 104 | Level3 105 | Disabled 106 | true 107 | WIN32;_DEBUG;MAISENSE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 108 | true 109 | 110 | 111 | stdcpp17 112 | ./include/;./extlibs/include/ 113 | MultiThreadedDebug 114 | 115 | 116 | Windows 117 | true 118 | false 119 | ./extlibs/lib/;%(AdditionalLibraryDirectories) 120 | detours.lib;%(AdditionalDependencies) 121 | 122 | 123 | 124 | 125 | NotUsing 126 | Level3 127 | Disabled 128 | true 129 | _DEBUG;MAISENSE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 130 | true 131 | 132 | 133 | stdcpp17 134 | ./include/;./extlibs/include/ 135 | MultiThreadedDebug 136 | 137 | 138 | Windows 139 | true 140 | false 141 | ./extlibs/lib/;%(AdditionalLibraryDirectories) 142 | detours.lib;%(AdditionalDependencies) 143 | 144 | 145 | 146 | 147 | NotUsing 148 | Level3 149 | MaxSpeed 150 | true 151 | true 152 | true 153 | WIN32;NDEBUG;MAISENSE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 154 | true 155 | stdcpp17 156 | ./include/;./extlibs/include/ 157 | 158 | 159 | 160 | Windows 161 | true 162 | true 163 | true 164 | false 165 | detours.lib;%(AdditionalDependencies) 166 | ./extlibs/lib/;%(AdditionalLibraryDirectories) 167 | 168 | 169 | 170 | 171 | NotUsing 172 | Level3 173 | MaxSpeed 174 | true 175 | true 176 | true 177 | NDEBUG;MAISENSE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 178 | true 179 | stdcpp17 180 | ./include/;./extlibs/include/ 181 | 182 | 183 | 184 | Windows 185 | true 186 | true 187 | true 188 | false 189 | ./extlibs/lib/;%(AdditionalLibraryDirectories) 190 | detours.lib;%(AdditionalDependencies) 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | -------------------------------------------------------------------------------- /MaiSense.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {21603add-e118-448d-91f9-110ed6508917} 10 | 11 | 12 | 13 | 14 | Headers 15 | 16 | 17 | Headers 18 | 19 | 20 | Headers 21 | 22 | 23 | Headers 24 | 25 | 26 | Headers 27 | 28 | 29 | Headers 30 | 31 | 32 | Headers 33 | 34 | 35 | Headers 36 | 37 | 38 | Headers 39 | 40 | 41 | Headers 42 | 43 | 44 | Headers 45 | 46 | 47 | Headers 48 | 49 | 50 | Headers 51 | 52 | 53 | 54 | 55 | Sources 56 | 57 | 58 | Sources 59 | 60 | 61 | Sources 62 | 63 | 64 | Sources 65 | 66 | 67 | Sources 68 | 69 | 70 | Sources 71 | 72 | 73 | Sources 74 | 75 | 76 | Sources 77 | 78 | 79 | Sources 80 | 81 | 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MaiSense # 2 | 3 | - **Author**: SirusDoma (a.k.a CXO2) 4 | - **Email**: com@cxo2.me 5 | - **Version**: 1.0.0 6 | 7 | Touch Sensor Input for SDEY, touchlaundry disco 💦. 8 | 9 | ## How it works ## 10 | 11 | It make a use of `SetWindowsHookEx` to listen `WH_GETMESSAGE` and hook any input events. 12 | In order to register touch input, `CreateWindowExA` is detoured to perform `RegisterTouchWindow` after the actual `CreateWindowExA` is called. 13 | 14 | The game did **not** emulate any hardware input such as JVS and touch sensors instead, it write input flag directly to the game memory. 15 | 16 | ## Usage ## 17 | 18 | 1. [Download](https://github.com/SirusDoma/MaiSense/releases/latest) or Build the project 19 | 2. Copy `MaiSense.Launcher.exe` and `MaiSense.dll` into game directory 20 | 3. Run `MaiSense.Launcher.exe` 21 | 22 | ### Touch Hook ### 23 | 24 | Multi touch input is supported. Make sure that touch input emulation from Mouse middle button is not activated, otherwise restart the game. 25 | 26 | Only support 1P with DEV mode only, has no plan to support 2P or any other mode. If you're interested in this feature, consider make a contribution by creating a PR. 27 | 28 | ### Mouse Hook ### 29 | 30 | - Pressing middle button click will emulate mouse into touch input natively. 31 | - Produced touch tap by the emulation only last for few millisecond or even nanosecond, so it doesn't not registered as proper touch input at most of the time. 32 | - Native mouse event is not supported. 33 | 34 | ### Keyboard Hook ### 35 | 36 | - Key 1\~8 as for A1\~A8 Sensors respectively, 0 for C Sensor 37 | - Numpad 1\~8 as for B1\~B8 Sensors respectively 38 | 39 | ## License ## 40 | 41 | This is an open-sourced library licensed under the [MIT License](http://github.com/SirusDoma/MaiSense/blob/master/LICENSE) 42 | -------------------------------------------------------------------------------- /build/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | 3 | !.gitignore -------------------------------------------------------------------------------- /extlibs/include/detours.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Core Detours Functionality (detours.h of detours.lib) 4 | // 5 | // Microsoft Research Detours Package, Version 4.0.1 6 | // 7 | // Copyright (c) Microsoft Corporation. All rights reserved. 8 | // 9 | 10 | #pragma once 11 | #ifndef _DETOURS_H_ 12 | #define _DETOURS_H_ 13 | 14 | #define DETOURS_VERSION 0x4c0c1 // 0xMAJORcMINORcPATCH 15 | 16 | ////////////////////////////////////////////////////////////////////////////// 17 | // 18 | 19 | #undef DETOURS_X64 20 | #undef DETOURS_X86 21 | #undef DETOURS_IA64 22 | #undef DETOURS_ARM 23 | #undef DETOURS_ARM64 24 | #undef DETOURS_BITS 25 | #undef DETOURS_32BIT 26 | #undef DETOURS_64BIT 27 | 28 | #if defined(_X86_) 29 | #define DETOURS_X86 30 | #define DETOURS_OPTION_BITS 64 31 | 32 | #elif defined(_AMD64_) 33 | #define DETOURS_X64 34 | #define DETOURS_OPTION_BITS 32 35 | 36 | #elif defined(_IA64_) 37 | #define DETOURS_IA64 38 | #define DETOURS_OPTION_BITS 32 39 | 40 | #elif defined(_ARM_) 41 | #define DETOURS_ARM 42 | 43 | #elif defined(_ARM64_) 44 | #define DETOURS_ARM64 45 | 46 | #else 47 | #error Unknown architecture (x86, amd64, ia64, arm, arm64) 48 | #endif 49 | 50 | #ifdef _WIN64 51 | #undef DETOURS_32BIT 52 | #define DETOURS_64BIT 1 53 | #define DETOURS_BITS 64 54 | // If all 64bit kernels can run one and only one 32bit architecture. 55 | //#define DETOURS_OPTION_BITS 32 56 | #else 57 | #define DETOURS_32BIT 1 58 | #undef DETOURS_64BIT 59 | #define DETOURS_BITS 32 60 | // If all 64bit kernels can run one and only one 32bit architecture. 61 | //#define DETOURS_OPTION_BITS 32 62 | #endif 63 | 64 | #define VER_DETOURS_BITS DETOUR_STRINGIFY(DETOURS_BITS) 65 | 66 | ////////////////////////////////////////////////////////////////////////////// 67 | // 68 | 69 | #if (_MSC_VER < 1299) 70 | typedef LONG LONG_PTR; 71 | typedef ULONG ULONG_PTR; 72 | #endif 73 | 74 | ///////////////////////////////////////////////// SAL 2.0 Annotations w/o SAL. 75 | // 76 | // These definitions are include so that Detours will build even if the 77 | // compiler doesn't have full SAL 2.0 support. 78 | // 79 | #ifndef DETOURS_DONT_REMOVE_SAL_20 80 | 81 | #ifdef DETOURS_TEST_REMOVE_SAL_20 82 | #undef _Analysis_assume_ 83 | #undef _Benign_race_begin_ 84 | #undef _Benign_race_end_ 85 | #undef _Field_range_ 86 | #undef _Field_size_ 87 | #undef _In_ 88 | #undef _In_bytecount_ 89 | #undef _In_count_ 90 | #undef _In_opt_ 91 | #undef _In_opt_bytecount_ 92 | #undef _In_opt_count_ 93 | #undef _In_opt_z_ 94 | #undef _In_range_ 95 | #undef _In_reads_ 96 | #undef _In_reads_bytes_ 97 | #undef _In_reads_opt_ 98 | #undef _In_reads_opt_bytes_ 99 | #undef _In_reads_or_z_ 100 | #undef _In_z_ 101 | #undef _Inout_ 102 | #undef _Inout_opt_ 103 | #undef _Inout_z_count_ 104 | #undef _Out_ 105 | #undef _Out_opt_ 106 | #undef _Out_writes_ 107 | #undef _Outptr_result_maybenull_ 108 | #undef _Readable_bytes_ 109 | #undef _Success_ 110 | #undef _Writable_bytes_ 111 | #undef _Pre_notnull_ 112 | #endif 113 | 114 | #if defined(_Deref_out_opt_z_) && !defined(_Outptr_result_maybenull_) 115 | #define _Outptr_result_maybenull_ _Deref_out_opt_z_ 116 | #endif 117 | 118 | #if defined(_In_count_) && !defined(_In_reads_) 119 | #define _In_reads_(x) _In_count_(x) 120 | #endif 121 | 122 | #if defined(_In_opt_count_) && !defined(_In_reads_opt_) 123 | #define _In_reads_opt_(x) _In_opt_count_(x) 124 | #endif 125 | 126 | #if defined(_In_opt_bytecount_) && !defined(_In_reads_opt_bytes_) 127 | #define _In_reads_opt_bytes_(x) _In_opt_bytecount_(x) 128 | #endif 129 | 130 | #if defined(_In_bytecount_) && !defined(_In_reads_bytes_) 131 | #define _In_reads_bytes_(x) _In_bytecount_(x) 132 | #endif 133 | 134 | #ifndef _In_ 135 | #define _In_ 136 | #endif 137 | 138 | #ifndef _In_bytecount_ 139 | #define _In_bytecount_(x) 140 | #endif 141 | 142 | #ifndef _In_count_ 143 | #define _In_count_(x) 144 | #endif 145 | 146 | #ifndef _In_opt_ 147 | #define _In_opt_ 148 | #endif 149 | 150 | #ifndef _In_opt_bytecount_ 151 | #define _In_opt_bytecount_(x) 152 | #endif 153 | 154 | #ifndef _In_opt_count_ 155 | #define _In_opt_count_(x) 156 | #endif 157 | 158 | #ifndef _In_opt_z_ 159 | #define _In_opt_z_ 160 | #endif 161 | 162 | #ifndef _In_range_ 163 | #define _In_range_(x,y) 164 | #endif 165 | 166 | #ifndef _In_reads_ 167 | #define _In_reads_(x) 168 | #endif 169 | 170 | #ifndef _In_reads_bytes_ 171 | #define _In_reads_bytes_(x) 172 | #endif 173 | 174 | #ifndef _In_reads_opt_ 175 | #define _In_reads_opt_(x) 176 | #endif 177 | 178 | #ifndef _In_reads_opt_bytes_ 179 | #define _In_reads_opt_bytes_(x) 180 | #endif 181 | 182 | #ifndef _In_reads_or_z_ 183 | #define _In_reads_or_z_ 184 | #endif 185 | 186 | #ifndef _In_z_ 187 | #define _In_z_ 188 | #endif 189 | 190 | #ifndef _Inout_ 191 | #define _Inout_ 192 | #endif 193 | 194 | #ifndef _Inout_opt_ 195 | #define _Inout_opt_ 196 | #endif 197 | 198 | #ifndef _Inout_z_count_ 199 | #define _Inout_z_count_(x) 200 | #endif 201 | 202 | #ifndef _Out_ 203 | #define _Out_ 204 | #endif 205 | 206 | #ifndef _Out_opt_ 207 | #define _Out_opt_ 208 | #endif 209 | 210 | #ifndef _Out_writes_ 211 | #define _Out_writes_(x) 212 | #endif 213 | 214 | #ifndef _Outptr_result_maybenull_ 215 | #define _Outptr_result_maybenull_ 216 | #endif 217 | 218 | #ifndef _Writable_bytes_ 219 | #define _Writable_bytes_(x) 220 | #endif 221 | 222 | #ifndef _Readable_bytes_ 223 | #define _Readable_bytes_(x) 224 | #endif 225 | 226 | #ifndef _Success_ 227 | #define _Success_(x) 228 | #endif 229 | 230 | #ifndef _Pre_notnull_ 231 | #define _Pre_notnull_ 232 | #endif 233 | 234 | #ifdef DETOURS_INTERNAL 235 | 236 | #pragma warning(disable:4615) // unknown warning type (suppress with older compilers) 237 | 238 | #ifndef _Benign_race_begin_ 239 | #define _Benign_race_begin_ 240 | #endif 241 | 242 | #ifndef _Benign_race_end_ 243 | #define _Benign_race_end_ 244 | #endif 245 | 246 | #ifndef _Field_size_ 247 | #define _Field_size_(x) 248 | #endif 249 | 250 | #ifndef _Field_range_ 251 | #define _Field_range_(x,y) 252 | #endif 253 | 254 | #ifndef _Analysis_assume_ 255 | #define _Analysis_assume_(x) 256 | #endif 257 | 258 | #endif // DETOURS_INTERNAL 259 | #endif // DETOURS_DONT_REMOVE_SAL_20 260 | 261 | ////////////////////////////////////////////////////////////////////////////// 262 | // 263 | #ifndef GUID_DEFINED 264 | #define GUID_DEFINED 265 | typedef struct _GUID 266 | { 267 | DWORD Data1; 268 | WORD Data2; 269 | WORD Data3; 270 | BYTE Data4[ 8 ]; 271 | } GUID; 272 | 273 | #ifdef INITGUID 274 | #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 275 | const GUID name \ 276 | = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } 277 | #else 278 | #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 279 | const GUID name 280 | #endif // INITGUID 281 | #endif // !GUID_DEFINED 282 | 283 | #if defined(__cplusplus) 284 | #ifndef _REFGUID_DEFINED 285 | #define _REFGUID_DEFINED 286 | #define REFGUID const GUID & 287 | #endif // !_REFGUID_DEFINED 288 | #else // !__cplusplus 289 | #ifndef _REFGUID_DEFINED 290 | #define _REFGUID_DEFINED 291 | #define REFGUID const GUID * const 292 | #endif // !_REFGUID_DEFINED 293 | #endif // !__cplusplus 294 | 295 | #ifndef ARRAYSIZE 296 | #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) 297 | #endif 298 | 299 | // 300 | ////////////////////////////////////////////////////////////////////////////// 301 | 302 | #ifdef __cplusplus 303 | extern "C" { 304 | #endif // __cplusplus 305 | 306 | /////////////////////////////////////////////////// Instruction Target Macros. 307 | // 308 | #define DETOUR_INSTRUCTION_TARGET_NONE ((PVOID)0) 309 | #define DETOUR_INSTRUCTION_TARGET_DYNAMIC ((PVOID)(LONG_PTR)-1) 310 | #define DETOUR_SECTION_HEADER_SIGNATURE 0x00727444 // "Dtr\0" 311 | 312 | extern const GUID DETOUR_EXE_RESTORE_GUID; 313 | extern const GUID DETOUR_EXE_HELPER_GUID; 314 | 315 | #define DETOUR_TRAMPOLINE_SIGNATURE 0x21727444 // Dtr! 316 | typedef struct _DETOUR_TRAMPOLINE DETOUR_TRAMPOLINE, *PDETOUR_TRAMPOLINE; 317 | 318 | /////////////////////////////////////////////////////////// Binary Structures. 319 | // 320 | #pragma pack(push, 8) 321 | typedef struct _DETOUR_SECTION_HEADER 322 | { 323 | DWORD cbHeaderSize; 324 | DWORD nSignature; 325 | DWORD nDataOffset; 326 | DWORD cbDataSize; 327 | 328 | DWORD nOriginalImportVirtualAddress; 329 | DWORD nOriginalImportSize; 330 | DWORD nOriginalBoundImportVirtualAddress; 331 | DWORD nOriginalBoundImportSize; 332 | 333 | DWORD nOriginalIatVirtualAddress; 334 | DWORD nOriginalIatSize; 335 | DWORD nOriginalSizeOfImage; 336 | DWORD cbPrePE; 337 | 338 | DWORD nOriginalClrFlags; 339 | DWORD reserved1; 340 | DWORD reserved2; 341 | DWORD reserved3; 342 | 343 | // Followed by cbPrePE bytes of data. 344 | } DETOUR_SECTION_HEADER, *PDETOUR_SECTION_HEADER; 345 | 346 | typedef struct _DETOUR_SECTION_RECORD 347 | { 348 | DWORD cbBytes; 349 | DWORD nReserved; 350 | GUID guid; 351 | } DETOUR_SECTION_RECORD, *PDETOUR_SECTION_RECORD; 352 | 353 | typedef struct _DETOUR_CLR_HEADER 354 | { 355 | // Header versioning 356 | ULONG cb; 357 | USHORT MajorRuntimeVersion; 358 | USHORT MinorRuntimeVersion; 359 | 360 | // Symbol table and startup information 361 | IMAGE_DATA_DIRECTORY MetaData; 362 | ULONG Flags; 363 | 364 | // Followed by the rest of the IMAGE_COR20_HEADER 365 | } DETOUR_CLR_HEADER, *PDETOUR_CLR_HEADER; 366 | 367 | typedef struct _DETOUR_EXE_RESTORE 368 | { 369 | DWORD cb; 370 | DWORD cbidh; 371 | DWORD cbinh; 372 | DWORD cbclr; 373 | 374 | PBYTE pidh; 375 | PBYTE pinh; 376 | PBYTE pclr; 377 | 378 | IMAGE_DOS_HEADER idh; 379 | union { 380 | IMAGE_NT_HEADERS inh; 381 | IMAGE_NT_HEADERS32 inh32; 382 | IMAGE_NT_HEADERS64 inh64; 383 | BYTE raw[sizeof(IMAGE_NT_HEADERS64) + 384 | sizeof(IMAGE_SECTION_HEADER) * 32]; 385 | }; 386 | DETOUR_CLR_HEADER clr; 387 | 388 | } DETOUR_EXE_RESTORE, *PDETOUR_EXE_RESTORE; 389 | 390 | typedef struct _DETOUR_EXE_HELPER 391 | { 392 | DWORD cb; 393 | DWORD pid; 394 | DWORD nDlls; 395 | CHAR rDlls[4]; 396 | } DETOUR_EXE_HELPER, *PDETOUR_EXE_HELPER; 397 | 398 | #pragma pack(pop) 399 | 400 | #define DETOUR_SECTION_HEADER_DECLARE(cbSectionSize) \ 401 | { \ 402 | sizeof(DETOUR_SECTION_HEADER),\ 403 | DETOUR_SECTION_HEADER_SIGNATURE,\ 404 | sizeof(DETOUR_SECTION_HEADER),\ 405 | (cbSectionSize),\ 406 | \ 407 | 0,\ 408 | 0,\ 409 | 0,\ 410 | 0,\ 411 | \ 412 | 0,\ 413 | 0,\ 414 | 0,\ 415 | 0,\ 416 | } 417 | 418 | /////////////////////////////////////////////////////////////// Helper Macros. 419 | // 420 | #define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x) 421 | #define DETOURS_STRINGIFY_(x) #x 422 | 423 | ///////////////////////////////////////////////////////////// Binary Typedefs. 424 | // 425 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_BYWAY_CALLBACK)( 426 | _In_opt_ PVOID pContext, 427 | _In_opt_ LPCSTR pszFile, 428 | _Outptr_result_maybenull_ LPCSTR *ppszOutFile); 429 | 430 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_FILE_CALLBACK)( 431 | _In_opt_ PVOID pContext, 432 | _In_ LPCSTR pszOrigFile, 433 | _In_ LPCSTR pszFile, 434 | _Outptr_result_maybenull_ LPCSTR *ppszOutFile); 435 | 436 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_SYMBOL_CALLBACK)( 437 | _In_opt_ PVOID pContext, 438 | _In_ ULONG nOrigOrdinal, 439 | _In_ ULONG nOrdinal, 440 | _Out_ ULONG *pnOutOrdinal, 441 | _In_opt_ LPCSTR pszOrigSymbol, 442 | _In_opt_ LPCSTR pszSymbol, 443 | _Outptr_result_maybenull_ LPCSTR *ppszOutSymbol); 444 | 445 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_COMMIT_CALLBACK)( 446 | _In_opt_ PVOID pContext); 447 | 448 | typedef BOOL (CALLBACK *PF_DETOUR_ENUMERATE_EXPORT_CALLBACK)(_In_opt_ PVOID pContext, 449 | _In_ ULONG nOrdinal, 450 | _In_opt_ LPCSTR pszName, 451 | _In_opt_ PVOID pCode); 452 | 453 | typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FILE_CALLBACK)(_In_opt_ PVOID pContext, 454 | _In_opt_ HMODULE hModule, 455 | _In_opt_ LPCSTR pszFile); 456 | 457 | typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK)(_In_opt_ PVOID pContext, 458 | _In_ DWORD nOrdinal, 459 | _In_opt_ LPCSTR pszFunc, 460 | _In_opt_ PVOID pvFunc); 461 | 462 | // Same as PF_DETOUR_IMPORT_FUNC_CALLBACK but extra indirection on last parameter. 463 | typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK_EX)(_In_opt_ PVOID pContext, 464 | _In_ DWORD nOrdinal, 465 | _In_opt_ LPCSTR pszFunc, 466 | _In_opt_ PVOID* ppvFunc); 467 | 468 | typedef VOID * PDETOUR_BINARY; 469 | typedef VOID * PDETOUR_LOADED_BINARY; 470 | 471 | //////////////////////////////////////////////////////////// Transaction APIs. 472 | // 473 | LONG WINAPI DetourTransactionBegin(VOID); 474 | LONG WINAPI DetourTransactionAbort(VOID); 475 | LONG WINAPI DetourTransactionCommit(VOID); 476 | LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer); 477 | 478 | LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread); 479 | 480 | LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer, 481 | _In_ PVOID pDetour); 482 | 483 | LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer, 484 | _In_ PVOID pDetour, 485 | _Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline, 486 | _Out_opt_ PVOID *ppRealTarget, 487 | _Out_opt_ PVOID *ppRealDetour); 488 | 489 | LONG WINAPI DetourDetach(_Inout_ PVOID *ppPointer, 490 | _In_ PVOID pDetour); 491 | 492 | BOOL WINAPI DetourSetIgnoreTooSmall(_In_ BOOL fIgnore); 493 | BOOL WINAPI DetourSetRetainRegions(_In_ BOOL fRetain); 494 | PVOID WINAPI DetourSetSystemRegionLowerBound(_In_ PVOID pSystemRegionLowerBound); 495 | PVOID WINAPI DetourSetSystemRegionUpperBound(_In_ PVOID pSystemRegionUpperBound); 496 | 497 | ////////////////////////////////////////////////////////////// Code Functions. 498 | // 499 | PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule, 500 | _In_ LPCSTR pszFunction); 501 | PVOID WINAPI DetourCodeFromPointer(_In_ PVOID pPointer, 502 | _Out_opt_ PVOID *ppGlobals); 503 | PVOID WINAPI DetourCopyInstruction(_In_opt_ PVOID pDst, 504 | _Inout_opt_ PVOID *ppDstPool, 505 | _In_ PVOID pSrc, 506 | _Out_opt_ PVOID *ppTarget, 507 | _Out_opt_ LONG *plExtra); 508 | BOOL WINAPI DetourSetCodeModule(_In_ HMODULE hModule, 509 | _In_ BOOL fLimitReferencesToModule); 510 | 511 | ///////////////////////////////////////////////////// Loaded Binary Functions. 512 | // 513 | HMODULE WINAPI DetourGetContainingModule(_In_ PVOID pvAddr); 514 | HMODULE WINAPI DetourEnumerateModules(_In_opt_ HMODULE hModuleLast); 515 | PVOID WINAPI DetourGetEntryPoint(_In_opt_ HMODULE hModule); 516 | ULONG WINAPI DetourGetModuleSize(_In_opt_ HMODULE hModule); 517 | BOOL WINAPI DetourEnumerateExports(_In_ HMODULE hModule, 518 | _In_opt_ PVOID pContext, 519 | _In_ PF_DETOUR_ENUMERATE_EXPORT_CALLBACK pfExport); 520 | BOOL WINAPI DetourEnumerateImports(_In_opt_ HMODULE hModule, 521 | _In_opt_ PVOID pContext, 522 | _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, 523 | _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK pfImportFunc); 524 | 525 | BOOL WINAPI DetourEnumerateImportsEx(_In_opt_ HMODULE hModule, 526 | _In_opt_ PVOID pContext, 527 | _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, 528 | _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK_EX pfImportFuncEx); 529 | 530 | _Writable_bytes_(*pcbData) 531 | _Readable_bytes_(*pcbData) 532 | _Success_(return != NULL) 533 | PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule, 534 | _In_ REFGUID rguid, 535 | _Out_ DWORD *pcbData); 536 | 537 | _Writable_bytes_(*pcbData) 538 | _Readable_bytes_(*pcbData) 539 | _Success_(return != NULL) 540 | PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid, 541 | _Out_ DWORD * pcbData); 542 | 543 | DWORD WINAPI DetourGetSizeOfPayloads(_In_opt_ HMODULE hModule); 544 | 545 | ///////////////////////////////////////////////// Persistent Binary Functions. 546 | // 547 | 548 | PDETOUR_BINARY WINAPI DetourBinaryOpen(_In_ HANDLE hFile); 549 | 550 | _Writable_bytes_(*pcbData) 551 | _Readable_bytes_(*pcbData) 552 | _Success_(return != NULL) 553 | PVOID WINAPI DetourBinaryEnumeratePayloads(_In_ PDETOUR_BINARY pBinary, 554 | _Out_opt_ GUID *pGuid, 555 | _Out_ DWORD *pcbData, 556 | _Inout_ DWORD *pnIterator); 557 | 558 | _Writable_bytes_(*pcbData) 559 | _Readable_bytes_(*pcbData) 560 | _Success_(return != NULL) 561 | PVOID WINAPI DetourBinaryFindPayload(_In_ PDETOUR_BINARY pBinary, 562 | _In_ REFGUID rguid, 563 | _Out_ DWORD *pcbData); 564 | 565 | PVOID WINAPI DetourBinarySetPayload(_In_ PDETOUR_BINARY pBinary, 566 | _In_ REFGUID rguid, 567 | _In_reads_opt_(cbData) PVOID pData, 568 | _In_ DWORD cbData); 569 | BOOL WINAPI DetourBinaryDeletePayload(_In_ PDETOUR_BINARY pBinary, _In_ REFGUID rguid); 570 | BOOL WINAPI DetourBinaryPurgePayloads(_In_ PDETOUR_BINARY pBinary); 571 | BOOL WINAPI DetourBinaryResetImports(_In_ PDETOUR_BINARY pBinary); 572 | BOOL WINAPI DetourBinaryEditImports(_In_ PDETOUR_BINARY pBinary, 573 | _In_opt_ PVOID pContext, 574 | _In_opt_ PF_DETOUR_BINARY_BYWAY_CALLBACK pfByway, 575 | _In_opt_ PF_DETOUR_BINARY_FILE_CALLBACK pfFile, 576 | _In_opt_ PF_DETOUR_BINARY_SYMBOL_CALLBACK pfSymbol, 577 | _In_opt_ PF_DETOUR_BINARY_COMMIT_CALLBACK pfCommit); 578 | BOOL WINAPI DetourBinaryWrite(_In_ PDETOUR_BINARY pBinary, _In_ HANDLE hFile); 579 | BOOL WINAPI DetourBinaryClose(_In_ PDETOUR_BINARY pBinary); 580 | 581 | /////////////////////////////////////////////////// Create Process & Load Dll. 582 | // 583 | typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEA)( 584 | _In_opt_ LPCSTR lpApplicationName, 585 | _Inout_opt_ LPSTR lpCommandLine, 586 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 587 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 588 | _In_ BOOL bInheritHandles, 589 | _In_ DWORD dwCreationFlags, 590 | _In_opt_ LPVOID lpEnvironment, 591 | _In_opt_ LPCSTR lpCurrentDirectory, 592 | _In_ LPSTARTUPINFOA lpStartupInfo, 593 | _Out_ LPPROCESS_INFORMATION lpProcessInformation); 594 | 595 | typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEW)( 596 | _In_opt_ LPCWSTR lpApplicationName, 597 | _Inout_opt_ LPWSTR lpCommandLine, 598 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 599 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 600 | _In_ BOOL bInheritHandles, 601 | _In_ DWORD dwCreationFlags, 602 | _In_opt_ LPVOID lpEnvironment, 603 | _In_opt_ LPCWSTR lpCurrentDirectory, 604 | _In_ LPSTARTUPINFOW lpStartupInfo, 605 | _Out_ LPPROCESS_INFORMATION lpProcessInformation); 606 | 607 | BOOL WINAPI DetourCreateProcessWithDllA(_In_opt_ LPCSTR lpApplicationName, 608 | _Inout_opt_ LPSTR lpCommandLine, 609 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 610 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 611 | _In_ BOOL bInheritHandles, 612 | _In_ DWORD dwCreationFlags, 613 | _In_opt_ LPVOID lpEnvironment, 614 | _In_opt_ LPCSTR lpCurrentDirectory, 615 | _In_ LPSTARTUPINFOA lpStartupInfo, 616 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 617 | _In_ LPCSTR lpDllName, 618 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 619 | 620 | BOOL WINAPI DetourCreateProcessWithDllW(_In_opt_ LPCWSTR lpApplicationName, 621 | _Inout_opt_ LPWSTR lpCommandLine, 622 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 623 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 624 | _In_ BOOL bInheritHandles, 625 | _In_ DWORD dwCreationFlags, 626 | _In_opt_ LPVOID lpEnvironment, 627 | _In_opt_ LPCWSTR lpCurrentDirectory, 628 | _In_ LPSTARTUPINFOW lpStartupInfo, 629 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 630 | _In_ LPCSTR lpDllName, 631 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 632 | 633 | #ifdef UNICODE 634 | #define DetourCreateProcessWithDll DetourCreateProcessWithDllW 635 | #define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEW 636 | #else 637 | #define DetourCreateProcessWithDll DetourCreateProcessWithDllA 638 | #define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEA 639 | #endif // !UNICODE 640 | 641 | BOOL WINAPI DetourCreateProcessWithDllExA(_In_opt_ LPCSTR lpApplicationName, 642 | _Inout_opt_ LPSTR lpCommandLine, 643 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 644 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 645 | _In_ BOOL bInheritHandles, 646 | _In_ DWORD dwCreationFlags, 647 | _In_opt_ LPVOID lpEnvironment, 648 | _In_opt_ LPCSTR lpCurrentDirectory, 649 | _In_ LPSTARTUPINFOA lpStartupInfo, 650 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 651 | _In_ LPCSTR lpDllName, 652 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 653 | 654 | BOOL WINAPI DetourCreateProcessWithDllExW(_In_opt_ LPCWSTR lpApplicationName, 655 | _Inout_opt_ LPWSTR lpCommandLine, 656 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 657 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 658 | _In_ BOOL bInheritHandles, 659 | _In_ DWORD dwCreationFlags, 660 | _In_opt_ LPVOID lpEnvironment, 661 | _In_opt_ LPCWSTR lpCurrentDirectory, 662 | _In_ LPSTARTUPINFOW lpStartupInfo, 663 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 664 | _In_ LPCSTR lpDllName, 665 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 666 | 667 | #ifdef UNICODE 668 | #define DetourCreateProcessWithDllEx DetourCreateProcessWithDllExW 669 | #else 670 | #define DetourCreateProcessWithDllEx DetourCreateProcessWithDllExA 671 | #endif // !UNICODE 672 | 673 | BOOL WINAPI DetourCreateProcessWithDllsA(_In_opt_ LPCSTR lpApplicationName, 674 | _Inout_opt_ LPSTR lpCommandLine, 675 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 676 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 677 | _In_ BOOL bInheritHandles, 678 | _In_ DWORD dwCreationFlags, 679 | _In_opt_ LPVOID lpEnvironment, 680 | _In_opt_ LPCSTR lpCurrentDirectory, 681 | _In_ LPSTARTUPINFOA lpStartupInfo, 682 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 683 | _In_ DWORD nDlls, 684 | _In_reads_(nDlls) LPCSTR *rlpDlls, 685 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 686 | 687 | BOOL WINAPI DetourCreateProcessWithDllsW(_In_opt_ LPCWSTR lpApplicationName, 688 | _Inout_opt_ LPWSTR lpCommandLine, 689 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 690 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 691 | _In_ BOOL bInheritHandles, 692 | _In_ DWORD dwCreationFlags, 693 | _In_opt_ LPVOID lpEnvironment, 694 | _In_opt_ LPCWSTR lpCurrentDirectory, 695 | _In_ LPSTARTUPINFOW lpStartupInfo, 696 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 697 | _In_ DWORD nDlls, 698 | _In_reads_(nDlls) LPCSTR *rlpDlls, 699 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 700 | 701 | #ifdef UNICODE 702 | #define DetourCreateProcessWithDlls DetourCreateProcessWithDllsW 703 | #else 704 | #define DetourCreateProcessWithDlls DetourCreateProcessWithDllsA 705 | #endif // !UNICODE 706 | 707 | BOOL WINAPI DetourProcessViaHelperA(_In_ DWORD dwTargetPid, 708 | _In_ LPCSTR lpDllName, 709 | _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 710 | 711 | BOOL WINAPI DetourProcessViaHelperW(_In_ DWORD dwTargetPid, 712 | _In_ LPCSTR lpDllName, 713 | _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 714 | 715 | #ifdef UNICODE 716 | #define DetourProcessViaHelper DetourProcessViaHelperW 717 | #else 718 | #define DetourProcessViaHelper DetourProcessViaHelperA 719 | #endif // !UNICODE 720 | 721 | BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid, 722 | _In_ DWORD nDlls, 723 | _In_reads_(nDlls) LPCSTR *rlpDlls, 724 | _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 725 | 726 | BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid, 727 | _In_ DWORD nDlls, 728 | _In_reads_(nDlls) LPCSTR *rlpDlls, 729 | _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 730 | 731 | #ifdef UNICODE 732 | #define DetourProcessViaHelperDlls DetourProcessViaHelperDllsW 733 | #else 734 | #define DetourProcessViaHelperDlls DetourProcessViaHelperDllsA 735 | #endif // !UNICODE 736 | 737 | BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess, 738 | _In_reads_(nDlls) LPCSTR *rlpDlls, 739 | _In_ DWORD nDlls); 740 | 741 | BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess, 742 | _In_ HMODULE hImage, 743 | _In_ BOOL bIs32Bit, 744 | _In_reads_(nDlls) LPCSTR *rlpDlls, 745 | _In_ DWORD nDlls); 746 | 747 | BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess, 748 | _In_ REFGUID rguid, 749 | _In_reads_bytes_(cbData) PVOID pvData, 750 | _In_ DWORD cbData); 751 | BOOL WINAPI DetourRestoreAfterWith(VOID); 752 | BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData, 753 | _In_ DWORD cbData); 754 | BOOL WINAPI DetourIsHelperProcess(VOID); 755 | VOID CALLBACK DetourFinishHelperProcess(_In_ HWND, 756 | _In_ HINSTANCE, 757 | _In_ LPSTR, 758 | _In_ INT); 759 | 760 | // 761 | ////////////////////////////////////////////////////////////////////////////// 762 | #ifdef __cplusplus 763 | } 764 | #endif // __cplusplus 765 | 766 | //////////////////////////////////////////////// Detours Internal Definitions. 767 | // 768 | #ifdef __cplusplus 769 | #ifdef DETOURS_INTERNAL 770 | 771 | #define NOTHROW 772 | // #define NOTHROW (nothrow) 773 | 774 | ////////////////////////////////////////////////////////////////////////////// 775 | // 776 | #if (_MSC_VER < 1299) 777 | #include 778 | typedef IMAGEHLP_MODULE IMAGEHLP_MODULE64; 779 | typedef PIMAGEHLP_MODULE PIMAGEHLP_MODULE64; 780 | typedef IMAGEHLP_SYMBOL SYMBOL_INFO; 781 | typedef PIMAGEHLP_SYMBOL PSYMBOL_INFO; 782 | 783 | static inline 784 | LONG InterlockedCompareExchange(_Inout_ LONG *ptr, _In_ LONG nval, _In_ LONG oval) 785 | { 786 | return (LONG)::InterlockedCompareExchange((PVOID*)ptr, (PVOID)nval, (PVOID)oval); 787 | } 788 | #else 789 | #pragma warning(push) 790 | #pragma warning(disable:4091) // empty typedef 791 | #include 792 | #pragma warning(pop) 793 | #endif 794 | 795 | #ifdef IMAGEAPI // defined by DBGHELP.H 796 | typedef LPAPI_VERSION (NTAPI *PF_ImagehlpApiVersionEx)(_In_ LPAPI_VERSION AppVersion); 797 | 798 | typedef BOOL (NTAPI *PF_SymInitialize)(_In_ HANDLE hProcess, 799 | _In_opt_ LPCSTR UserSearchPath, 800 | _In_ BOOL fInvadeProcess); 801 | typedef DWORD (NTAPI *PF_SymSetOptions)(_In_ DWORD SymOptions); 802 | typedef DWORD (NTAPI *PF_SymGetOptions)(VOID); 803 | typedef DWORD64 (NTAPI *PF_SymLoadModule64)(_In_ HANDLE hProcess, 804 | _In_opt_ HANDLE hFile, 805 | _In_ LPSTR ImageName, 806 | _In_opt_ LPSTR ModuleName, 807 | _In_ DWORD64 BaseOfDll, 808 | _In_opt_ DWORD SizeOfDll); 809 | typedef BOOL (NTAPI *PF_SymGetModuleInfo64)(_In_ HANDLE hProcess, 810 | _In_ DWORD64 qwAddr, 811 | _Out_ PIMAGEHLP_MODULE64 ModuleInfo); 812 | typedef BOOL (NTAPI *PF_SymFromName)(_In_ HANDLE hProcess, 813 | _In_ LPSTR Name, 814 | _Out_ PSYMBOL_INFO Symbol); 815 | 816 | typedef struct _DETOUR_SYM_INFO 817 | { 818 | HANDLE hProcess; 819 | HMODULE hDbgHelp; 820 | PF_ImagehlpApiVersionEx pfImagehlpApiVersionEx; 821 | PF_SymInitialize pfSymInitialize; 822 | PF_SymSetOptions pfSymSetOptions; 823 | PF_SymGetOptions pfSymGetOptions; 824 | PF_SymLoadModule64 pfSymLoadModule64; 825 | PF_SymGetModuleInfo64 pfSymGetModuleInfo64; 826 | PF_SymFromName pfSymFromName; 827 | } DETOUR_SYM_INFO, *PDETOUR_SYM_INFO; 828 | 829 | PDETOUR_SYM_INFO DetourLoadImageHlp(VOID); 830 | 831 | #endif // IMAGEAPI 832 | 833 | #if defined(_INC_STDIO) && !defined(_CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS) 834 | #error detours.h must be included before stdio.h (or at least define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS earlier) 835 | #endif 836 | #define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1 837 | 838 | #ifndef DETOUR_TRACE 839 | #if DETOUR_DEBUG 840 | #define DETOUR_TRACE(x) printf x 841 | #define DETOUR_BREAK() __debugbreak() 842 | #include 843 | #include 844 | #else 845 | #define DETOUR_TRACE(x) 846 | #define DETOUR_BREAK() 847 | #endif 848 | #endif 849 | 850 | #if 1 || defined(DETOURS_IA64) 851 | 852 | // 853 | // IA64 instructions are 41 bits, 3 per bundle, plus 5 bit bundle template => 128 bits per bundle. 854 | // 855 | 856 | #define DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE (3) 857 | 858 | #define DETOUR_IA64_TEMPLATE_OFFSET (0) 859 | #define DETOUR_IA64_TEMPLATE_SIZE (5) 860 | 861 | #define DETOUR_IA64_INSTRUCTION_SIZE (41) 862 | #define DETOUR_IA64_INSTRUCTION0_OFFSET (DETOUR_IA64_TEMPLATE_SIZE) 863 | #define DETOUR_IA64_INSTRUCTION1_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE) 864 | #define DETOUR_IA64_INSTRUCTION2_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE + DETOUR_IA64_INSTRUCTION_SIZE) 865 | 866 | C_ASSERT(DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE * DETOUR_IA64_INSTRUCTION_SIZE == 128); 867 | 868 | __declspec(align(16)) struct DETOUR_IA64_BUNDLE 869 | { 870 | public: 871 | union 872 | { 873 | BYTE data[16]; 874 | UINT64 wide[2]; 875 | }; 876 | 877 | enum { 878 | A_UNIT = 1u, 879 | I_UNIT = 2u, 880 | M_UNIT = 3u, 881 | B_UNIT = 4u, 882 | F_UNIT = 5u, 883 | L_UNIT = 6u, 884 | X_UNIT = 7u, 885 | }; 886 | struct DETOUR_IA64_METADATA 887 | { 888 | ULONG nTemplate : 8; // Instruction template. 889 | ULONG nUnit0 : 4; // Unit for slot 0 890 | ULONG nUnit1 : 4; // Unit for slot 1 891 | ULONG nUnit2 : 4; // Unit for slot 2 892 | }; 893 | 894 | protected: 895 | static const DETOUR_IA64_METADATA s_rceCopyTable[33]; 896 | 897 | UINT RelocateBundle(_Inout_ DETOUR_IA64_BUNDLE* pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const; 898 | 899 | bool RelocateInstruction(_Inout_ DETOUR_IA64_BUNDLE* pDst, 900 | _In_ BYTE slot, 901 | _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const; 902 | 903 | // 120 112 104 96 88 80 72 64 56 48 40 32 24 16 8 0 904 | // f. e. d. c. b. a. 9. 8. 7. 6. 5. 4. 3. 2. 1. 0. 905 | 906 | // 00 907 | // f.e. d.c. b.a. 9.8. 7.6. 5.4. 3.2. 1.0. 908 | // 0000 0000 0000 0000 0000 0000 0000 001f : Template [4..0] 909 | // 0000 0000 0000 0000 0000 03ff ffff ffe0 : Zero [ 41.. 5] 910 | // 0000 0000 0000 0000 0000 3c00 0000 0000 : Zero [ 45.. 42] 911 | // 0000 0000 0007 ffff ffff c000 0000 0000 : One [ 82.. 46] 912 | // 0000 0000 0078 0000 0000 0000 0000 0000 : One [ 86.. 83] 913 | // 0fff ffff ff80 0000 0000 0000 0000 0000 : Two [123.. 87] 914 | // f000 0000 0000 0000 0000 0000 0000 0000 : Two [127..124] 915 | BYTE GetTemplate() const; 916 | // Get 4 bit opcodes. 917 | BYTE GetInst0() const; 918 | BYTE GetInst1() const; 919 | BYTE GetInst2() const; 920 | BYTE GetUnit(BYTE slot) const; 921 | BYTE GetUnit0() const; 922 | BYTE GetUnit1() const; 923 | BYTE GetUnit2() const; 924 | // Get 37 bit data. 925 | UINT64 GetData0() const; 926 | UINT64 GetData1() const; 927 | UINT64 GetData2() const; 928 | 929 | // Get/set the full 41 bit instructions. 930 | UINT64 GetInstruction(BYTE slot) const; 931 | UINT64 GetInstruction0() const; 932 | UINT64 GetInstruction1() const; 933 | UINT64 GetInstruction2() const; 934 | void SetInstruction(BYTE slot, UINT64 instruction); 935 | void SetInstruction0(UINT64 instruction); 936 | void SetInstruction1(UINT64 instruction); 937 | void SetInstruction2(UINT64 instruction); 938 | 939 | // Get/set bitfields. 940 | static UINT64 GetBits(UINT64 Value, UINT64 Offset, UINT64 Count); 941 | static UINT64 SetBits(UINT64 Value, UINT64 Offset, UINT64 Count, UINT64 Field); 942 | 943 | // Get specific read-only fields. 944 | static UINT64 GetOpcode(UINT64 instruction); // 4bit opcode 945 | static UINT64 GetX(UINT64 instruction); // 1bit opcode extension 946 | static UINT64 GetX3(UINT64 instruction); // 3bit opcode extension 947 | static UINT64 GetX6(UINT64 instruction); // 6bit opcode extension 948 | 949 | // Get/set specific fields. 950 | static UINT64 GetImm7a(UINT64 instruction); 951 | static UINT64 SetImm7a(UINT64 instruction, UINT64 imm7a); 952 | static UINT64 GetImm13c(UINT64 instruction); 953 | static UINT64 SetImm13c(UINT64 instruction, UINT64 imm13c); 954 | static UINT64 GetSignBit(UINT64 instruction); 955 | static UINT64 SetSignBit(UINT64 instruction, UINT64 signBit); 956 | static UINT64 GetImm20a(UINT64 instruction); 957 | static UINT64 SetImm20a(UINT64 instruction, UINT64 imm20a); 958 | static UINT64 GetImm20b(UINT64 instruction); 959 | static UINT64 SetImm20b(UINT64 instruction, UINT64 imm20b); 960 | 961 | static UINT64 SignExtend(UINT64 Value, UINT64 Offset); 962 | 963 | BOOL IsMovlGp() const; 964 | 965 | VOID SetInst(BYTE Slot, BYTE nInst); 966 | VOID SetInst0(BYTE nInst); 967 | VOID SetInst1(BYTE nInst); 968 | VOID SetInst2(BYTE nInst); 969 | VOID SetData(BYTE Slot, UINT64 nData); 970 | VOID SetData0(UINT64 nData); 971 | VOID SetData1(UINT64 nData); 972 | VOID SetData2(UINT64 nData); 973 | BOOL SetNop(BYTE Slot); 974 | BOOL SetNop0(); 975 | BOOL SetNop1(); 976 | BOOL SetNop2(); 977 | 978 | public: 979 | BOOL IsBrl() const; 980 | VOID SetBrl(); 981 | VOID SetBrl(UINT64 target); 982 | UINT64 GetBrlTarget() const; 983 | VOID SetBrlTarget(UINT64 target); 984 | VOID SetBrlImm(UINT64 imm); 985 | UINT64 GetBrlImm() const; 986 | 987 | UINT64 GetMovlGp() const; 988 | VOID SetMovlGp(UINT64 gp); 989 | 990 | VOID SetStop(); 991 | 992 | UINT Copy(_Out_ DETOUR_IA64_BUNDLE *pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra = NULL) const; 993 | }; 994 | #endif // DETOURS_IA64 995 | 996 | #ifdef DETOURS_ARM 997 | 998 | #define DETOURS_PFUNC_TO_PBYTE(p) ((PBYTE)(((ULONG_PTR)(p)) & ~(ULONG_PTR)1)) 999 | #define DETOURS_PBYTE_TO_PFUNC(p) ((PBYTE)(((ULONG_PTR)(p)) | (ULONG_PTR)1)) 1000 | 1001 | #endif // DETOURS_ARM 1002 | 1003 | ////////////////////////////////////////////////////////////////////////////// 1004 | 1005 | #ifdef __cplusplus 1006 | extern "C" { 1007 | #endif // __cplusplus 1008 | 1009 | #define DETOUR_OFFLINE_LIBRARY(x) \ 1010 | PVOID WINAPI DetourCopyInstruction##x(_In_opt_ PVOID pDst, \ 1011 | _Inout_opt_ PVOID *ppDstPool, \ 1012 | _In_ PVOID pSrc, \ 1013 | _Out_opt_ PVOID *ppTarget, \ 1014 | _Out_opt_ LONG *plExtra); \ 1015 | \ 1016 | BOOL WINAPI DetourSetCodeModule##x(_In_ HMODULE hModule, \ 1017 | _In_ BOOL fLimitReferencesToModule); \ 1018 | 1019 | DETOUR_OFFLINE_LIBRARY(X86) 1020 | DETOUR_OFFLINE_LIBRARY(X64) 1021 | DETOUR_OFFLINE_LIBRARY(ARM) 1022 | DETOUR_OFFLINE_LIBRARY(ARM64) 1023 | DETOUR_OFFLINE_LIBRARY(IA64) 1024 | 1025 | #undef DETOUR_OFFLINE_LIBRARY 1026 | 1027 | ////////////////////////////////////////////////////////////////////////////// 1028 | // 1029 | // Helpers for manipulating page protection. 1030 | // 1031 | 1032 | _Success_(return != FALSE) 1033 | BOOL WINAPI DetourVirtualProtectSameExecuteEx(_In_ HANDLE hProcess, 1034 | _In_ PVOID pAddress, 1035 | _In_ SIZE_T nSize, 1036 | _In_ DWORD dwNewProtect, 1037 | _Out_ PDWORD pdwOldProtect); 1038 | 1039 | _Success_(return != FALSE) 1040 | BOOL WINAPI DetourVirtualProtectSameExecute(_In_ PVOID pAddress, 1041 | _In_ SIZE_T nSize, 1042 | _In_ DWORD dwNewProtect, 1043 | _Out_ PDWORD pdwOldProtect); 1044 | #ifdef __cplusplus 1045 | } 1046 | #endif // __cplusplus 1047 | 1048 | ////////////////////////////////////////////////////////////////////////////// 1049 | 1050 | #define MM_ALLOCATION_GRANULARITY 0x10000 1051 | 1052 | ////////////////////////////////////////////////////////////////////////////// 1053 | 1054 | #endif // DETOURS_INTERNAL 1055 | #endif // __cplusplus 1056 | 1057 | #endif // _DETOURS_H_ 1058 | // 1059 | //////////////////////////////////////////////////////////////// End of File. 1060 | -------------------------------------------------------------------------------- /extlibs/include/detver.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Common version parameters. 4 | // 5 | // Microsoft Research Detours Package, Version 4.0.1 6 | // 7 | // Copyright (c) Microsoft Corporation. All rights reserved. 8 | // 9 | 10 | #define _USING_V110_SDK71_ 1 11 | #include "winver.h" 12 | #if 0 13 | #include 14 | #include 15 | #else 16 | #ifndef DETOURS_STRINGIFY 17 | #define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x) 18 | #define DETOURS_STRINGIFY_(x) #x 19 | #endif 20 | 21 | #define VER_FILEFLAGSMASK 0x3fL 22 | #define VER_FILEFLAGS 0x0L 23 | #define VER_FILEOS 0x00040004L 24 | #define VER_FILETYPE 0x00000002L 25 | #define VER_FILESUBTYPE 0x00000000L 26 | #endif 27 | #define VER_DETOURS_BITS DETOUR_STRINGIFY(DETOURS_BITS) 28 | -------------------------------------------------------------------------------- /extlibs/include/syelog.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Detours Test Program (syelog.h of syelog.lib) 4 | // 5 | // Microsoft Research Detours Package 6 | // 7 | // Copyright (c) Microsoft Corporation. All rights reserved. 8 | // 9 | #pragma once 10 | #ifndef _SYELOGD_H_ 11 | #define _SYELOGD_H_ 12 | #include 13 | 14 | #pragma pack(push, 1) 15 | #pragma warning(push) 16 | #pragma warning(disable: 4200) 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | // 20 | // 21 | #define SYELOG_PIPE_NAMEA "\\\\.\\pipe\\syelog" 22 | #define SYELOG_PIPE_NAMEW L"\\\\.\\pipe\\syelog" 23 | #ifdef UNICODE 24 | #define SYELOG_PIPE_NAME SYELOG_PIPE_NAMEW 25 | #else 26 | #define SYELOG_PIPE_NAME SYELOG_PIPE_NAMEA 27 | #endif 28 | 29 | ////////////////////////////////////////////////////////////////////////////// 30 | // 31 | #define SYELOG_MAXIMUM_MESSAGE 4086 // 4096 - sizeof(header stuff) 32 | 33 | typedef struct _SYELOG_MESSAGE 34 | { 35 | USHORT nBytes; 36 | BYTE nFacility; 37 | BYTE nSeverity; 38 | DWORD nProcessId; 39 | FILETIME ftOccurance; 40 | BOOL fTerminate; 41 | CHAR szMessage[SYELOG_MAXIMUM_MESSAGE]; 42 | } SYELOG_MESSAGE, *PSYELOG_MESSAGE; 43 | 44 | 45 | // Facility Codes. 46 | // 47 | #define SYELOG_FACILITY_KERNEL 0x10 // OS Kernel 48 | #define SYELOG_FACILITY_SECURITY 0x20 // OS Security 49 | #define SYELOG_FACILITY_LOGGING 0x30 // OS Logging-internal 50 | #define SYELOG_FACILITY_SERVICE 0x40 // User-mode system daemon 51 | #define SYELOG_FACILITY_APPLICATION 0x50 // User-mode application 52 | #define SYELOG_FACILITY_USER 0x60 // User self-generated. 53 | #define SYELOG_FACILITY_LOCAL0 0x70 // Locally defined. 54 | #define SYELOG_FACILITY_LOCAL1 0x71 // Locally defined. 55 | #define SYELOG_FACILITY_LOCAL2 0x72 // Locally defined. 56 | #define SYELOG_FACILITY_LOCAL3 0x73 // Locally defined. 57 | #define SYELOG_FACILITY_LOCAL4 0x74 // Locally defined. 58 | #define SYELOG_FACILITY_LOCAL5 0x75 // Locally defined. 59 | #define SYELOG_FACILITY_LOCAL6 0x76 // Locally defined. 60 | #define SYELOG_FACILITY_LOCAL7 0x77 // Locally defined. 61 | #define SYELOG_FACILITY_LOCAL8 0x78 // Locally defined. 62 | #define SYELOG_FACILITY_LOCAL9 0x79 // Locally defined. 63 | 64 | // Severity Codes. 65 | // 66 | #define SYELOG_SEVERITY_FATAL 0x00 // System is dead. 67 | #define SYELOG_SEVERITY_ALERT 0x10 // Take action immediately. 68 | #define SYELOG_SEVERITY_CRITICAL 0x20 // Critical condition. 69 | #define SYELOG_SEVERITY_ERROR 0x30 // Error 70 | #define SYELOG_SEVERITY_WARNING 0x40 // Warning 71 | #define SYELOG_SEVERITY_NOTICE 0x50 // Significant condition. 72 | #define SYELOG_SEVERITY_INFORMATION 0x60 // Informational 73 | #define SYELOG_SEVERITY_AUDIT_FAIL 0x66 // Audit Failed 74 | #define SYELOG_SEVERITY_AUDIT_PASS 0x67 // Audit Succeeeded 75 | #define SYELOG_SEVERITY_DEBUG 0x70 // Debugging 76 | 77 | // Logging Functions. 78 | // 79 | VOID SyelogOpen(PCSTR pszIdentifier, BYTE nFacility); 80 | VOID Syelog(BYTE nSeverity, PCSTR pszMsgf, ...); 81 | VOID SyelogV(BYTE nSeverity, PCSTR pszMsgf, va_list args); 82 | VOID SyelogClose(BOOL fTerminate); 83 | 84 | #pragma warning(pop) 85 | #pragma pack(pop) 86 | 87 | #endif // _SYELOGD_H_ 88 | // 89 | ///////////////////////////////////////////////////////////////// End of File. 90 | -------------------------------------------------------------------------------- /extlibs/lib/detours.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SirusDoma/MaiSense/dabd99af9c5439be1db9e47955cf3c5acad8f91d/extlibs/lib/detours.lib -------------------------------------------------------------------------------- /include/MaiSense/InputController.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAISENSE_INPUT_CONTROLLER_HPP 2 | #define MAISENSE_INPUT_CONTROLLER_HPP 3 | 4 | #include 5 | 6 | namespace MaiSense 7 | { 8 | class InputController 9 | { 10 | public: 11 | InputController() {} 12 | virtual ~InputController() {} 13 | 14 | virtual bool Check(int evCode) = 0; 15 | virtual void OnInput(int nCode, WPARAM wParam, LPARAM lParam) = 0; 16 | }; 17 | } 18 | 19 | #endif -------------------------------------------------------------------------------- /include/MaiSense/InputManager.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAISENSE_INPUT_MANAGER_HPP 2 | #define MAISENSE_INPUT_MANAGER_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | namespace MaiSense 11 | { 12 | class InputController; 13 | class InputManager 14 | { 15 | private: 16 | static HHOOK hHook; 17 | static HWND hWnd; 18 | static Sensor *sensor; 19 | static std::vector controllers; 20 | 21 | static LRESULT WINAPI GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam); 22 | static DWORD WINAPI HookGameInput(); 23 | static HWND WINAPI HookCreateWindowExA( 24 | DWORD dwExStyle, 25 | LPCSTR lpClassName, 26 | LPCSTR lpWindowName, 27 | DWORD dwStyle, 28 | int X, 29 | int Y, 30 | int nWidth, 31 | int nHeight, 32 | HWND hWndParent, 33 | HMENU hMenu, 34 | HINSTANCE hInstance, 35 | LPVOID lpParam 36 | ); 37 | 38 | public: 39 | static bool Ready(); 40 | static void Hook(); 41 | static void Unhook(); 42 | 43 | static bool Install(InputController *controller); 44 | 45 | static Sensor *GetSensor(); 46 | static HHOOK GetHookHandle(); 47 | static HWND GetGameWindow(); 48 | }; 49 | } 50 | 51 | #endif -------------------------------------------------------------------------------- /include/MaiSense/KeyEvent.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAISENSE_KEY_EVENT_HPP 2 | #define MAISENSE_KEY_EVENT_HPP 3 | 4 | namespace MaiSense 5 | { 6 | struct KeyEvent 7 | { 8 | int KeyCode; 9 | bool Active; 10 | }; 11 | } 12 | 13 | #endif -------------------------------------------------------------------------------- /include/MaiSense/KeyboardController.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAISENSE_KEYBOARD_CONTROLLER_HPP 2 | #define MAISENSE_KEYBOARD_CONTROLLER_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | namespace MaiSense 12 | { 13 | class KeyboardController : public InputController 14 | { 15 | private: 16 | std::function callback; 17 | virtual void OnInput(int nCode, WPARAM wParam, LPARAM lParam); 18 | 19 | public: 20 | KeyboardController(); 21 | virtual ~KeyboardController(); 22 | 23 | virtual bool Check(int evCode); 24 | void SetCallback(std::function cb); 25 | }; 26 | } 27 | 28 | #endif -------------------------------------------------------------------------------- /include/MaiSense/Launcher/Injector.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAISENSE_INJECTOR_HPP 2 | #define MAISENSE_INJECTOR_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace MaiSense::Launcher 8 | { 9 | class Injector 10 | { 11 | private: 12 | Process *process; 13 | void *remoteAddr; 14 | HANDLE remoteThread; 15 | 16 | bool Close(); 17 | 18 | public: 19 | Injector(Process *process); 20 | HANDLE Inject(std::string dll_name); 21 | }; 22 | } 23 | 24 | #endif -------------------------------------------------------------------------------- /include/MaiSense/Launcher/Process.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAISENSE_LAUNCHER_PROCESS_HPP 2 | #define MAISENSE_LAUNCHER_PROCESS_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace MaiSense 13 | { 14 | class Process 15 | { 16 | private: 17 | std::string moduleName; 18 | 19 | int processId, threadId; 20 | HANDLE hProcess, hThread; 21 | LPCVOID hModule; 22 | 23 | DWORD GetTargetAddress(DWORD address, bool relative); 24 | 25 | public: 26 | Process(std::string moduleName); 27 | Process(HANDLE hProcess, HANDLE hThread, int processId, int threadId); 28 | 29 | virtual ~Process(); 30 | 31 | static Process Create(std::string path, bool suspended = false); 32 | static Process Create(std::string path, std::string args = "", bool suspended = false); 33 | 34 | int GetProcessId(); 35 | int GetThreadId(); 36 | 37 | HANDLE GetProcessHandle(); 38 | HANDLE GetThreadHandle(); 39 | LPCVOID GetBaseAddress(); 40 | 41 | bool Resume(); 42 | bool Suspend(); 43 | 44 | void Wait(); 45 | 46 | unsigned int Read(DWORD address, bool relative = true); 47 | unsigned int Write(DWORD address, LPCVOID buffer, SIZE_T size, bool relative = true); 48 | }; 49 | } 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /include/MaiSense/MouseController.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAISENSE_MOUSE_CONTROLLER_HPP 2 | #define MAISENSE_MOUSE_CONTROLLER_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | namespace MaiSense 12 | { 13 | class MouseController : public InputController 14 | { 15 | private: 16 | const int MAX_CONTACT_SIMULATION = 32; 17 | 18 | POINTER_TOUCH_INFO contact; 19 | bool touchEmulationActive; 20 | 21 | MouseEvent prevEvent; 22 | std::function callback; 23 | 24 | virtual void OnInput(int nCode, WPARAM wParam, LPARAM lParam); 25 | 26 | public: 27 | MouseController(); 28 | virtual ~MouseController(); 29 | 30 | void EmulateTouch(); 31 | virtual bool Check(int evCode); 32 | void SetCallback(std::function cb); 33 | }; 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /include/MaiSense/MouseEvent.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAISENSE_MOUSE_EVENT_HPP 2 | #define MAISENSE_MOUSE_EVENT_HPP 3 | 4 | namespace MaiSense 5 | { 6 | struct MouseEvent 7 | { 8 | int X; 9 | int Y; 10 | bool LButton; 11 | bool MButton; 12 | bool RButton; 13 | }; 14 | } 15 | 16 | #endif -------------------------------------------------------------------------------- /include/MaiSense/Point.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAISENSE_POINT_HPP 2 | #define MAISENSE_POINT_HPP 3 | 4 | namespace MaiSense 5 | { 6 | struct Point 7 | { 8 | int X; 9 | int Y; 10 | }; 11 | } 12 | 13 | #endif -------------------------------------------------------------------------------- /include/MaiSense/Sensor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAISENSE_MAIN_HPP 2 | #define MAISENSE_MAIN_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | typedef int SensorId; 11 | 12 | namespace MaiSense 13 | { 14 | class Process; 15 | class Sensor 16 | { 17 | private: 18 | const int TOUCH_POINTER_ADDRESS = 0xF40D28; 19 | const int P1_OFFSET_ACTIVE_ADDRESS = 52; 20 | const int P2_OFFSET_ACTIVE_ADDRESS = 56; 21 | const int P1_OFFSET_INACTIVE_ADDRESS = 60; 22 | const int P2_OFFSET_INACTIVE_ADDRESS = 64; 23 | 24 | struct Message 25 | { 26 | SensorId SensorId; 27 | bool Value; 28 | }; 29 | 30 | int* activeFlags; 31 | int* inactiveFlags; 32 | std::unordered_map states; 33 | std::vector queue; 34 | 35 | public: 36 | static const SensorId 37 | A1 = 1 << 0, 38 | B1 = 1 << 1, 39 | A2 = 1 << 2, 40 | B2 = 1 << 3, 41 | A3 = 1 << 5, 42 | B3 = 1 << 6, 43 | A4 = 1 << 7, 44 | B4 = 1 << 8, 45 | A5 = 1 << 10, 46 | B5 = 1 << 11, 47 | A6 = 1 << 12, 48 | B6 = 1 << 13, 49 | A7 = 1 << 15, 50 | B7 = 1 << 16, 51 | A8 = 1 << 17, 52 | B8 = 1 << 18, 53 | C = 1 << 19; 54 | 55 | Sensor(); 56 | 57 | ~Sensor(); 58 | 59 | bool Connect(); 60 | bool SetSensorState(SensorId sensorId, bool value); 61 | void Queue(SensorId sensorId, bool value); 62 | 63 | bool Activate(SensorId sensorId); 64 | bool Deactivate(SensorId sensorId); 65 | bool Remove(SensorId sensorId, bool value); 66 | 67 | bool ProcessQueue(); 68 | void Reset(); 69 | }; 70 | } 71 | 72 | #endif -------------------------------------------------------------------------------- /include/MaiSense/SensorChecker.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAISENSE_SENSOR_CHECKER_HPP 2 | #define MAISENSE_SENSOR_CHECKER_HPP 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace MaiSense 11 | { 12 | class SensorChecker 13 | { 14 | private: 15 | const SensorRegion C_REGION = SensorRegion({ { 500, 380 }, { 585, 415 }, { 615, 500 }, { 585, 585 }, { 500, 620 }, { 415, 585 }, { 380, 500 }, { 415, 415 } }); 16 | const SensorRegion A1_REGION = SensorRegion({ { 500, 0 }, { 999, 0 }, { 710, 290 }, { 500, 200 } }); 17 | const SensorRegion A2_REGION = SensorRegion({ { 999, 0 }, { 999, 500 }, { 800, 500 }, { 710, 290 } }); 18 | const SensorRegion A3_REGION = SensorRegion({ { 800, 500 }, { 999, 500 }, { 999, 999 }, { 710, 710 } }); 19 | const SensorRegion A4_REGION = SensorRegion({ { 710, 710 }, { 999, 999 }, { 500, 999 }, { 500, 800 } }); 20 | const SensorRegion A5_REGION = SensorRegion({ { 500, 800 }, { 500, 999 }, { 0, 999 }, { 290, 710 } }); 21 | const SensorRegion A6_REGION = SensorRegion({ { 290, 710 }, { 0, 999 }, { 0, 500 }, { 200, 500 } }); 22 | const SensorRegion A7_REGION = SensorRegion({ { 200, 500 }, { 0, 500 }, { 0, 0 }, { 290, 290 } }); 23 | const SensorRegion A8_REGION = SensorRegion({ { 0, 0 }, { 500, 0 }, { 500, 200 }, { 290, 290 } }); 24 | const SensorRegion B1_REGION = SensorRegion({ { 500, 200 }, { 790, 290 }, { 585, 415 }, { 500, 380 } }); 25 | const SensorRegion B2_REGION = SensorRegion({ { 710, 290 }, { 800, 500 }, { 620, 500 }, { 585, 415 } }); 26 | const SensorRegion B3_REGION = SensorRegion({ { 620, 500 }, { 800, 500 }, { 710, 710 }, { 585, 585 } }); 27 | const SensorRegion B4_REGION = SensorRegion({ { 585, 585 }, { 710, 710 }, { 500, 800 }, { 500, 620 } }); 28 | const SensorRegion B5_REGION = SensorRegion({ { 500, 620 }, { 500, 800 }, { 290, 710 }, { 415, 585 } }); 29 | const SensorRegion B6_REGION = SensorRegion({ { 415, 585 }, { 380, 500 }, { 200, 500 }, { 290, 710 } }); 30 | const SensorRegion B7_REGION = SensorRegion({ { 200, 500 }, { 380, 500 }, { 415, 415 }, { 290, 290 } }); 31 | const SensorRegion B8_REGION = SensorRegion({ { 290, 290 }, { 500, 200 }, { 500, 380 }, { 415, 415 } }); 32 | const int REF_SCREEN_WIDTH = 1000; 33 | const int REF_SCREEN_HEIGHT = 1000; 34 | 35 | std::map regionMap; 36 | int screenWidth; 37 | int screenHeight; 38 | 39 | void InitRegions(); 40 | public: 41 | SensorChecker(); 42 | SensorChecker(int screenWidth, int screenHeight); 43 | SensorChecker(int screenWidth, int screenHeight, const std::map& regionMap); 44 | ~SensorChecker(); 45 | 46 | void AddRegion(SensorId sensorId, const SensorRegion& region); 47 | void RemoveRegion(SensorId sensorId); 48 | bool Check(Point position, SensorId sensorId); 49 | 50 | int GetScreenWidth(); 51 | int GetScreenHeight(); 52 | void SetScreenSize(int width, int height); 53 | }; 54 | } 55 | 56 | #endif -------------------------------------------------------------------------------- /include/MaiSense/SensorProcessor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAISENSE_SENSOR_PROCESSOR_HPP 2 | #define MAISENSE_SENSOR_PROCESSOR_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace MaiSense 14 | { 15 | class SensorProcessor 16 | { 17 | private: 18 | SensorChecker *checker; 19 | Sensor *sensor; 20 | 21 | public: 22 | SensorProcessor(); 23 | virtual ~SensorProcessor(); 24 | 25 | SensorChecker *GetChecker(); 26 | Sensor *GetSensor(); 27 | 28 | void SetChecker(SensorChecker *checker); 29 | void SetSensor(Sensor *sensor); 30 | 31 | bool Handle(TouchEvent ev); 32 | bool Handle(MouseEvent ev); 33 | bool Handle(const Point& pointer, bool active); 34 | }; 35 | } 36 | 37 | #endif -------------------------------------------------------------------------------- /include/MaiSense/SensorRegion.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAISENSE_SENSOR_REGION_HPP 2 | #define MAISENSE_SENSOR_REGION_HPP 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | namespace MaiSense 10 | { 11 | class SensorRegion 12 | { 13 | private: 14 | const int COLINEAR = 0; 15 | const int CLOCKWISE = 1; 16 | const int COUNTER_CLOCKWISE = 2; 17 | 18 | std::vector points; 19 | 20 | bool IsOnSegment(const Point& p, const Point& q, const Point& r); 21 | int FindOrientation(const Point& p, const Point& q, const Point& r); 22 | bool DoesSegmentIntersect(const Point& p1, const Point& q1, const Point& p2, const Point& q2); 23 | 24 | public: 25 | SensorRegion(); 26 | SensorRegion(const std::vector& points); 27 | ~SensorRegion(); 28 | 29 | void AddPoint(const Point& point); 30 | bool Test(const Point& testPoint, float scaleX = 1.0, float scaleY = 1.0f); 31 | }; 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /include/MaiSense/TouchController.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAISENSE_TOUCH_CONTROLLER_HPP 2 | #define MAISENSE_TOUCH_CONTROLLER_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | namespace MaiSense 12 | { 13 | class TouchController : public InputController 14 | { 15 | private: 16 | std::function callback; 17 | 18 | virtual void OnInput(int nCode, WPARAM wParam, LPARAM lParam); 19 | 20 | public: 21 | TouchController(); 22 | virtual ~TouchController(); 23 | 24 | virtual bool Check(int evCode); 25 | void SetCallback(std::function cb); 26 | }; 27 | } 28 | 29 | #endif -------------------------------------------------------------------------------- /include/MaiSense/TouchEvent.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MAISENSE_TOUCH_EVENT_HPP 2 | #define MAISENSE_TOUCH_EVENT_HPP 3 | 4 | namespace MaiSense 5 | { 6 | struct TouchEvent 7 | { 8 | unsigned int Id; 9 | int X; 10 | int Y; 11 | unsigned int Flag; 12 | }; 13 | } 14 | 15 | #endif -------------------------------------------------------------------------------- /src/InputManager.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | namespace MaiSense 8 | { 9 | HWND(WINAPI* TrueCreateWindowExA)( 10 | DWORD dwExStyle, 11 | LPCSTR lpClassName, 12 | LPCSTR lpWindowName, 13 | DWORD dwStyle, 14 | int X, 15 | int Y, 16 | int nWidth, 17 | int nHeight, 18 | HWND hWndParent, 19 | HMENU hMenu, 20 | HINSTANCE hInstance, 21 | LPVOID lpParam 22 | ) = CreateWindowExA; 23 | 24 | /* 25 | BOOL(__thiscall* TrueGetTouchState)(void*, int, char, int) = (BOOL(__thiscall*)(void*, int, char, int))0x00582860; 26 | BOOL(__cdecl* TrueGetInputState)(char, char, int) = (BOOL(__cdecl*)(char, char, int))0x005725B0; 27 | BOOL(__cdecl* TrueGetButtonState)(char, char, int) = (BOOL(__cdecl*)(char, char, int))0x00572430; 28 | BOOL(WINAPI* TrueGetButtonFlag)(int) = (int(WINAPI*)(int))0x00582830; 29 | char(WINAPI* TrueGetCharacterState)(int*) = (char(WINAPI*)(int*))0x0060A580; 30 | */ 31 | 32 | DWORD(WINAPI* TrueGameInput)() = (DWORD(WINAPI*)())0x00571610; 33 | 34 | HHOOK InputManager::hHook; 35 | HWND InputManager::hWnd; 36 | Sensor *InputManager::sensor; 37 | std::vector InputManager::controllers; 38 | 39 | void InputManager::Hook() 40 | { 41 | DetourRestoreAfterWith(); 42 | DetourTransactionBegin(); 43 | DetourUpdateThread(GetCurrentThread()); 44 | DetourAttach(&(PVOID&)TrueCreateWindowExA, HookCreateWindowExA); 45 | DetourAttach(&(PVOID&)TrueGameInput, HookGameInput); 46 | DetourTransactionCommit(); 47 | } 48 | 49 | void InputManager::Unhook() 50 | { 51 | DetourTransactionBegin(); 52 | DetourUpdateThread(GetCurrentThread()); 53 | DetourDetach(&(PVOID&)TrueCreateWindowExA, HookCreateWindowExA); 54 | DetourDetach(&(PVOID&)TrueGameInput, HookGameInput); 55 | DetourTransactionCommit(); 56 | } 57 | 58 | bool InputManager::Install(InputController *controller) 59 | { 60 | if (controller) 61 | { 62 | controllers.push_back(controller); 63 | return true; 64 | } 65 | 66 | return false; 67 | } 68 | 69 | Sensor *InputManager::GetSensor() 70 | { 71 | if (!sensor) 72 | sensor = new Sensor(); 73 | 74 | return sensor; 75 | } 76 | 77 | HHOOK InputManager::GetHookHandle() 78 | { 79 | return hHook; 80 | } 81 | 82 | HWND InputManager::GetGameWindow() 83 | { 84 | return hWnd; 85 | } 86 | 87 | bool InputManager::Ready() 88 | { 89 | return !DetourIsHelperProcess(); 90 | } 91 | 92 | HWND WINAPI InputManager::HookCreateWindowExA( 93 | DWORD dwExStyle, 94 | LPCSTR lpClassName, 95 | LPCSTR lpWindowName, 96 | DWORD dwStyle, 97 | int X, 98 | int Y, 99 | int nWidth, 100 | int nHeight, 101 | HWND hWndParent, 102 | HMENU hMenu, 103 | HINSTANCE hInstance, 104 | LPVOID lpParam 105 | ) 106 | { 107 | hWnd = TrueCreateWindowExA( 108 | dwExStyle, 109 | lpClassName, 110 | lpWindowName, 111 | dwStyle, 112 | X, 113 | Y, 114 | nWidth, 115 | nHeight, 116 | hWndParent, 117 | hMenu, 118 | hInstance, 119 | lpParam 120 | ); 121 | 122 | if (!RegisterTouchWindow(hWnd, TWF_WANTPALM)) 123 | { 124 | MessageBoxA(NULL, ("MAISENSE: Failed to register touch: " + std::to_string(GetLastError())).c_str(), "Hook", MB_ICONEXCLAMATION); 125 | CloseWindow(hWnd); 126 | 127 | return NULL; 128 | } 129 | 130 | hHook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, hInstance, GetCurrentThreadId()); 131 | if (hHook == NULL) 132 | { 133 | MessageBoxA(NULL, ("MAISENSE: Failed to install hook: " + std::to_string(GetLastError())).c_str(), "Hook", MB_ICONEXCLAMATION); 134 | CloseWindow(hWnd); 135 | 136 | return NULL; 137 | } 138 | 139 | return hWnd; 140 | } 141 | 142 | LRESULT WINAPI InputManager::GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam) 143 | { 144 | auto msg = (LPMSG)lParam; 145 | if (nCode >= 0 && msg != NULL) 146 | { 147 | for (auto controller : controllers) 148 | { 149 | if (controller->Check(msg->message)) 150 | controller->OnInput(nCode, wParam, lParam); 151 | } 152 | } 153 | 154 | return CallNextHookEx(hHook, nCode, wParam, lParam); 155 | } 156 | 157 | DWORD __stdcall InputManager::HookGameInput() 158 | { 159 | GetSensor()->Reset(); 160 | auto result = TrueGameInput(); 161 | GetSensor()->ProcessQueue(); 162 | 163 | return result; 164 | } 165 | } -------------------------------------------------------------------------------- /src/KeyboardController.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace MaiSense 4 | { 5 | KeyboardController::KeyboardController() : 6 | callback() 7 | { 8 | } 9 | 10 | KeyboardController::~KeyboardController() 11 | { 12 | } 13 | 14 | void KeyboardController::SetCallback(std::function cb) 15 | { 16 | callback = cb; 17 | } 18 | 19 | bool KeyboardController::Check(int evCode) 20 | { 21 | switch (evCode) 22 | { 23 | case WM_KEYDOWN: 24 | case WM_KEYUP: 25 | return true; 26 | default: 27 | return false; 28 | } 29 | } 30 | 31 | void KeyboardController::OnInput(int nCode, WPARAM wParam, LPARAM lParam) 32 | { 33 | // Parse keyboard hook event 34 | auto ev = KeyEvent(); 35 | auto msg = (LPMSG)lParam; 36 | 37 | // Initialize key event 38 | ev.KeyCode = msg->wParam; 39 | ev.Active = msg->message == WM_KEYDOWN; 40 | 41 | // Pass event into callback 42 | if (callback) 43 | callback(ev); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Launcher/Injector.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace MaiSense::Launcher 5 | { 6 | Injector::Injector(MaiSense::Process *process) : 7 | process(process), 8 | remoteAddr(0), 9 | remoteThread(0) 10 | { 11 | } 12 | 13 | HANDLE Injector::Inject(std::string dll_name) 14 | { 15 | // Lookup DLL to inject 16 | if (!SearchPath(NULL, dll_name.c_str(), NULL, 0, NULL, NULL)) 17 | { 18 | std::fprintf(stderr, "MAISENSE: DLL to inject not found (%s).\n", dll_name.c_str()); 19 | return 0; 20 | } 21 | 22 | // Allocate memory to inject the DLL 23 | remoteAddr = VirtualAllocEx( 24 | process->GetProcessHandle(), 25 | NULL, 26 | dll_name.length() + 1, 27 | MEM_RESERVE | MEM_COMMIT, 28 | PAGE_READWRITE 29 | ); 30 | 31 | // Check allocation operation 32 | if (!remoteAddr) 33 | { 34 | std::fprintf(stderr, "MAISENSE: Failed to allocate DLL memory (%d).\n", GetLastError()); 35 | return 0; 36 | } 37 | 38 | // Write dll name into allocated memory 39 | bool success = WriteProcessMemory( 40 | process->GetProcessHandle(), 41 | remoteAddr, 42 | dll_name.c_str(), 43 | dll_name.length() + 1, 44 | NULL 45 | ); 46 | 47 | // Check write DLL operation 48 | if (!success) 49 | { 50 | std::fprintf(stderr, "MAISENSE: Failed to write DLL into memory (%d).\n", GetLastError()); 51 | Close(); 52 | 53 | return 0; 54 | } 55 | 56 | // Create remote thread to load dll that written into memory 57 | remoteThread = CreateRemoteThread( 58 | process->GetProcessHandle(), 59 | NULL, 60 | 0, 61 | (LPTHREAD_START_ROUTINE)LoadLibraryA, 62 | remoteAddr, 63 | 0, 64 | NULL 65 | ); 66 | 67 | // Validate remote thread 68 | if (!remoteThread) 69 | { 70 | std::fprintf(stderr, "MAISENSE: Failed to CreateRemoteThread (%d).\n", GetLastError()); 71 | Close(); 72 | 73 | return remoteThread; 74 | } 75 | 76 | if (WaitForSingleObject(remoteThread, INFINITE) != WAIT_OBJECT_0) 77 | std::fprintf(stderr, "MAISENSE: Failed to wait object (%d).\n", GetLastError()); 78 | 79 | DWORD result; 80 | if (!GetExitCodeThread(remoteThread, &result)) 81 | std::fprintf(stderr, "MAISENSE: Failed to wait exit thread (%d).\n", GetLastError()); 82 | 83 | if (result == 0) 84 | std::fprintf(stderr, "MAISENSE: Failed to load inside target process (%d).\n", GetLastError()); 85 | 86 | // return created remote thread 87 | return remoteThread; 88 | } 89 | 90 | bool Injector::Close() 91 | { 92 | // Dispose remote thread 93 | if (remoteThread != NULL) 94 | CloseHandle(remoteThread); 95 | 96 | // Free allocated memory for DLL 97 | if (remoteAddr) 98 | { 99 | bool success = VirtualFreeEx(process->GetProcessHandle(), remoteAddr, 0, MEM_RELEASE); 100 | if (!success) 101 | { 102 | std::fprintf(stderr, "MAISENSE: Failed to clear allocated dll memory (%d).\n", GetLastError()); 103 | return false; 104 | } 105 | } 106 | 107 | return true; 108 | } 109 | } -------------------------------------------------------------------------------- /src/Launcher/Process.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace MaiSense 4 | { 5 | 6 | Process::Process(std::string moduleName) : 7 | moduleName(moduleName), 8 | processId(0), 9 | threadId(0), 10 | hProcess(0), 11 | hThread(0), 12 | hModule(0) 13 | { 14 | if (!moduleName.empty()) 15 | GetProcessHandle(); 16 | } 17 | 18 | Process::Process(HANDLE hProcess, HANDLE hThread, int processId, int threadId) : 19 | moduleName(), 20 | processId(processId), 21 | threadId(threadId), 22 | hProcess(hProcess), 23 | hThread(hThread), 24 | hModule(0) 25 | { 26 | } 27 | 28 | Process::~Process() 29 | { 30 | if (hProcess) 31 | CloseHandle(hProcess); 32 | 33 | if (hThread) 34 | CloseHandle(hThread); 35 | } 36 | 37 | Process Process::Create(std::string path, bool suspended) 38 | { 39 | return Create(path, "", suspended); 40 | } 41 | 42 | Process Process::Create(std::string path, std::string args, bool suspended) 43 | { 44 | STARTUPINFO si = { sizeof(si) }; 45 | PROCESS_INFORMATION pi; 46 | bool success = CreateProcess( 47 | path.c_str(), 48 | const_cast(args.c_str()), 49 | NULL, 50 | NULL, 51 | TRUE, 52 | suspended ? CREATE_SUSPENDED : 0, 53 | NULL, 54 | NULL, 55 | &si, 56 | &pi 57 | ); 58 | 59 | if (!success) 60 | { 61 | std::fprintf(stderr, "MAISENSE: Failed to create process\n"); 62 | return Process(""); 63 | } 64 | 65 | return Process(pi.hProcess, pi.hThread, pi.dwProcessId, pi.dwThreadId); 66 | } 67 | 68 | DWORD Process::GetTargetAddress(DWORD address, bool relative) 69 | { 70 | DWORD target = address; 71 | if (relative) 72 | target = (DWORD)GetBaseAddress() + address; 73 | 74 | return target; 75 | } 76 | 77 | HANDLE Process::GetProcessHandle() 78 | { 79 | // Check for existing process 80 | if (hProcess) 81 | return hProcess; 82 | 83 | // Create snapshots of processes 84 | PROCESSENTRY32 entry; 85 | entry.dwSize = sizeof(PROCESSENTRY32); 86 | 87 | // Get Process from processes snapshot 88 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); 89 | if (Process32First(snapshot, &entry) == TRUE) 90 | { 91 | while (Process32Next(snapshot, &entry) == TRUE) 92 | { 93 | // Check for target process that match with moduleName 94 | std::string exeFile = entry.szExeFile; 95 | if (exeFile.find(moduleName) != std::string::npos) 96 | { 97 | // Process found, attempt to open process 98 | processId = entry.th32ProcessID; 99 | hProcess = OpenProcess( 100 | PROCESS_ALL_ACCESS, 101 | FALSE, 102 | entry.th32ProcessID 103 | ); 104 | 105 | break; 106 | } 107 | } 108 | } 109 | 110 | // Check process handle 111 | if (!hProcess) 112 | std::fprintf(stderr, "MAISENSE: Failed to open process\n"); 113 | 114 | return hProcess; 115 | } 116 | 117 | HANDLE Process::GetThreadHandle() 118 | { 119 | // Check for existing thread 120 | if (hThread) 121 | return hThread; 122 | 123 | // Check for existing process 124 | if (!processId) 125 | GetProcessHandle(); 126 | 127 | // Look after thread handle 128 | THREADENTRY32 tEntry; 129 | tEntry.dwSize = sizeof(THREADENTRY32); 130 | auto hThreadSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 131 | 132 | // Validate snapshot 133 | if (hThreadSnapshot == INVALID_HANDLE_VALUE) 134 | { 135 | std::fprintf(stderr, "MAISENSE: Failed to open find thread\n"); 136 | return hProcess; 137 | } 138 | 139 | // Get Thread from threads snapshot 140 | if (Thread32First(hThreadSnapshot, &tEntry) == TRUE) 141 | { 142 | while (Thread32Next(hThreadSnapshot, &tEntry) == TRUE) 143 | { 144 | // Check for thread process id that match with handle process 145 | if (tEntry.th32OwnerProcessID == processId) 146 | { 147 | threadId = tEntry.th32ThreadID; 148 | hThread = OpenThread( 149 | THREAD_ALL_ACCESS, 150 | FALSE, 151 | tEntry.th32ThreadID 152 | ); 153 | 154 | break; 155 | } 156 | } 157 | } 158 | 159 | // Check process handle 160 | if (!hThread) 161 | std::fprintf(stderr, "MAISENSE: Failed to locate thread handle\n"); 162 | 163 | return hThread; 164 | } 165 | 166 | int Process::GetProcessId() 167 | { 168 | if (!processId) 169 | GetProcessHandle(); 170 | 171 | return processId; 172 | } 173 | 174 | int Process::GetThreadId() 175 | { 176 | if (!threadId) 177 | GetThreadHandle(); 178 | 179 | return threadId; 180 | } 181 | 182 | LPCVOID Process::GetBaseAddress() 183 | { 184 | // Retrieve process handle if not yet fetched 185 | if (!hProcess) 186 | GetProcessHandle(); 187 | 188 | // Return existing address if previous query handle still valid 189 | if (hModule) 190 | return hModule; 191 | 192 | // Define variables to query modules 193 | HMODULE hMods[1024]; 194 | DWORD cbNeeded; 195 | LPCVOID address = 0; 196 | 197 | // Enumerate the list of loaded module in the process handle 198 | if (hProcess && EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) 199 | { 200 | for (unsigned int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) 201 | { 202 | // Resolve module filename 203 | TCHAR szModName[MAX_PATH]; 204 | if (GetModuleFileNameEx(hProcess, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR))) 205 | { 206 | // Check if module matched with target module name 207 | std::string name = szModName; 208 | if (name.find(moduleName) != std::string::npos) 209 | { 210 | // Module found, get the address 211 | address = hMods[i]; 212 | break; 213 | } 214 | } 215 | } 216 | } 217 | 218 | // No main module found 219 | if (!address) 220 | std::fprintf(stderr, "MAISENSE: Failed to find module.\n"); 221 | 222 | hModule = address; 223 | return address; 224 | } 225 | 226 | 227 | bool Process::Resume() 228 | { 229 | if (!hThread) 230 | { 231 | std::fprintf(stderr, "MAISENSE: No valid thread handle found\n"); 232 | return false; 233 | } 234 | 235 | if (!ResumeThread(hThread)) 236 | { 237 | std::fprintf(stderr, "MAISENSE: Failed to resume thread\n"); 238 | return false; 239 | } 240 | 241 | return true; 242 | } 243 | 244 | bool Process::Suspend() 245 | { 246 | if (!hThread) 247 | { 248 | std::fprintf(stderr, "MAISENSE: No valid thread handle found\n"); 249 | return false; 250 | } 251 | 252 | if (!SuspendThread(hThread)) 253 | { 254 | std::fprintf(stderr, "MAISENSE: Failed to suspend thread\n"); 255 | return false; 256 | } 257 | 258 | return true; 259 | } 260 | 261 | void Process::Wait() 262 | { 263 | WaitForSingleObject(hProcess, INFINITE); 264 | } 265 | 266 | unsigned int Process::Read(DWORD address, bool relative) 267 | { 268 | // Validate process handle 269 | if (!hProcess) 270 | { 271 | std::fprintf(stderr, "MAISENSE: Invalid process handle.\n"); 272 | return 0; 273 | } 274 | 275 | // Calculate address 276 | LPCVOID target = (LPCVOID)GetTargetAddress(address, relative); 277 | 278 | // Read data from target address process memory 279 | unsigned int result = 0; 280 | if (!ReadProcessMemory(hProcess, target, &result, sizeof(result), NULL)) 281 | std::fprintf(stderr, "MAISENSE: Failed to read process memory.\n"); 282 | 283 | return result; 284 | } 285 | 286 | unsigned int Process::Write(DWORD address, LPCVOID buffer, SIZE_T size, bool relative) 287 | { 288 | // Validate process handle 289 | if (!hProcess) 290 | { 291 | std::fprintf(stderr, "MAISENSE: Invalid process handle.\n"); 292 | return 0; 293 | } 294 | 295 | // Calculate address 296 | LPVOID target = (LPVOID)GetTargetAddress(address, relative); 297 | 298 | // Write data to target address process memory 299 | SIZE_T bytesWritten = 0; 300 | if (!WriteProcessMemory(hProcess, target, buffer, size, &bytesWritten)) 301 | std::fprintf(stderr, "MAISENSE: Failed to write process memory %d.\n", GetLastError()); 302 | 303 | return bytesWritten; 304 | } 305 | } -------------------------------------------------------------------------------- /src/Launcher/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | int main() 8 | { 9 | const std::string client = "maimai_dump_.exe"; 10 | auto process = MaiSense::Process::Create(client, true); 11 | auto injector = MaiSense::Launcher::Injector(&process); 12 | auto remote = injector.Inject("MaiSense.dll"); 13 | 14 | process.Resume(); 15 | return 0; 16 | } -------------------------------------------------------------------------------- /src/MouseController.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace MaiSense 6 | { 7 | MouseController::MouseController() : 8 | callback(), 9 | contact(), 10 | touchEmulationActive(false), 11 | prevEvent() 12 | { 13 | } 14 | 15 | MouseController::~MouseController() 16 | { 17 | } 18 | 19 | void MouseController::EmulateTouch() 20 | { 21 | if (touchEmulationActive) 22 | return; 23 | 24 | touchEmulationActive = true; 25 | 26 | // Setup touch contact (only use single contact, there's only single mouse after all) 27 | contact = { sizeof(POINTER_TOUCH_INFO) }; 28 | contact.pointerInfo.pointerType = PT_TOUCH; 29 | contact.pointerInfo.pointerId = 0; 30 | 31 | // Set touch contact flags 32 | contact.touchFlags = TOUCH_FLAG_NONE; 33 | contact.touchMask = TOUCH_MASK_CONTACTAREA | TOUCH_MASK_ORIENTATION | TOUCH_MASK_PRESSURE; 34 | contact.orientation = 90; // Orientation of 90 means touching perpendicular to screen. 35 | contact.pressure = 32000; 36 | 37 | // Initialize touch injection 38 | if (!InitializeTouchInjection(MAX_CONTACT_SIMULATION, TOUCH_FEEDBACK_DEFAULT)) 39 | MessageBoxA(NULL, ("MAISENSE: Failed to register touch injection: " + std::to_string(GetLastError())).c_str(), "MaiSense", MB_ICONEXCLAMATION); 40 | } 41 | 42 | void MouseController::SetCallback(std::function cb) 43 | { 44 | callback = cb; 45 | } 46 | 47 | bool MouseController::Check(int evCode) 48 | { 49 | switch (evCode) 50 | { 51 | case WM_MOUSEACTIVATE: 52 | case WM_MOUSEMOVE: 53 | case WM_MOUSEWHEEL: 54 | case WM_MOUSEHOVER: 55 | case WM_MOUSELEAVE: 56 | case WM_NCMOUSEHOVER: 57 | case WM_NCMOUSEMOVE: 58 | case WM_NCMOUSELEAVE: 59 | case WM_MOUSELAST: 60 | case WM_LBUTTONDOWN: 61 | case WM_LBUTTONUP: 62 | case WM_LBUTTONDBLCLK: 63 | case WM_NCLBUTTONDOWN: 64 | case WM_NCLBUTTONUP: 65 | case WM_NCLBUTTONDBLCLK: 66 | case WM_RBUTTONDOWN: 67 | case WM_RBUTTONUP: 68 | case WM_RBUTTONDBLCLK: 69 | case WM_NCRBUTTONDOWN: 70 | case WM_NCRBUTTONUP: 71 | case WM_NCRBUTTONDBLCLK: 72 | case WM_MBUTTONDOWN: 73 | case WM_MBUTTONUP: 74 | case WM_MBUTTONDBLCLK: 75 | case WM_NCMBUTTONDOWN: 76 | case WM_NCMBUTTONUP: 77 | case WM_NCMBUTTONDBLCLK: 78 | case WM_XBUTTONDOWN: 79 | case WM_XBUTTONUP: 80 | case WM_XBUTTONDBLCLK: 81 | case WM_NCXBUTTONDOWN: 82 | case WM_NCXBUTTONUP: 83 | case WM_NCXBUTTONDBLCLK: 84 | return true; 85 | default: 86 | return false; 87 | } 88 | } 89 | 90 | void MouseController::OnInput(int nCode, WPARAM wParam, LPARAM lParam) 91 | { 92 | // Parse message 93 | auto msg = (LPMSG)lParam; 94 | 95 | // Map coordinate into client coordinate 96 | POINT point = msg->pt; 97 | if (ScreenToClient(msg->hwnd, &point)) 98 | { 99 | // Initialize touch event 100 | auto ev = MouseEvent(); 101 | ev.X = point.x; 102 | ev.Y = point.y; 103 | 104 | if (msg->message != WM_MOUSEMOVE && msg->message != WM_NCMOUSEMOVE) 105 | { 106 | ev.LButton = msg->message == WM_LBUTTONDOWN; 107 | ev.MButton = msg->message == WM_MBUTTONDOWN; 108 | ev.RButton = msg->message == WM_RBUTTONDOWN; 109 | } 110 | else 111 | { 112 | ev.LButton = prevEvent.LButton; 113 | ev.MButton = prevEvent.MButton; 114 | ev.RButton = prevEvent.RButton; 115 | } 116 | 117 | 118 | // Check whether touch simulation is active 119 | if (touchEmulationActive) 120 | { 121 | // Set touch contact coordinate and area 122 | contact.pointerInfo.ptPixelLocation = msg->pt; 123 | contact.rcContact.top = contact.pointerInfo.ptPixelLocation.y - 2; 124 | contact.rcContact.bottom = contact.pointerInfo.ptPixelLocation.y + 2; 125 | contact.rcContact.left = contact.pointerInfo.ptPixelLocation.x - 2; 126 | contact.rcContact.right = contact.pointerInfo.ptPixelLocation.x + 2; 127 | 128 | // Set touch contact state 129 | if (msg->message == WM_LBUTTONDOWN) 130 | contact.pointerInfo.pointerFlags = POINTER_FLAG_DOWN | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT; 131 | else if (msg->message == WM_LBUTTONUP) 132 | contact.pointerInfo.pointerFlags = POINTER_FLAG_UP | POINTER_FLAG_CANCELED; 133 | else // Mouse move or other possible events 134 | contact.pointerInfo.pointerFlags = POINTER_FLAG_UPDATE; 135 | 136 | // Inject touch contact into screen 137 | contact.pointerInfo.pointerId = 0; 138 | InjectTouchInput(1, &contact); 139 | } 140 | 141 | // Pass event into callback 142 | prevEvent = ev; 143 | if (callback) 144 | callback(ev); 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/Sensor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace MaiSense 4 | { 5 | 6 | Sensor::Sensor() : 7 | activeFlags(0), 8 | inactiveFlags(0) 9 | { 10 | } 11 | 12 | Sensor::~Sensor() 13 | { 14 | } 15 | 16 | bool Sensor::Connect() 17 | { 18 | // Process hook is created, no need to recreate 19 | if (activeFlags && inactiveFlags) 20 | return true; 21 | 22 | // Lookup for sensor addresses 23 | int input = *(int*)(TOUCH_POINTER_ADDRESS); 24 | if (input) 25 | { 26 | // Read sensor flag from given address 27 | // TODO: Add P2 Support(?) 28 | activeFlags = (int*)(input + P1_OFFSET_ACTIVE_ADDRESS); 29 | inactiveFlags = (int*)(input + P1_OFFSET_INACTIVE_ADDRESS); 30 | 31 | return true; 32 | } 33 | 34 | return false; 35 | } 36 | 37 | bool Sensor::SetSensorState(SensorId sensorId, bool value) 38 | { 39 | // Attempt to read sensor state in case not initialized yet 40 | if (!Connect()) 41 | return false; 42 | 43 | // Validate Sensor Id (there's still so much gap tho) 44 | if (sensorId < Sensor::A1 || sensorId > Sensor::C) 45 | return false; 46 | 47 | // No need to trigger the sensor if sensor already in desired state 48 | if (states.count(sensorId) > 0 && states[sensorId] == value) 49 | return true; 50 | 51 | // Update sensor states 52 | states[sensorId] = value; 53 | 54 | // Write sensor bits into memory 55 | if (value) 56 | { 57 | *activeFlags |= sensorId; 58 | *inactiveFlags &= ~sensorId; 59 | } 60 | else 61 | { 62 | *activeFlags &= ~sensorId; 63 | *inactiveFlags |= sensorId; 64 | } 65 | 66 | return true; 67 | } 68 | 69 | bool Sensor::Remove(SensorId sensorId, bool value) 70 | { 71 | // Attempt to read sensor state in case not initialized yet 72 | if (!Connect()) 73 | return false; 74 | 75 | // Validate Sensor Id (there's still so much gap tho) 76 | if (sensorId < Sensor::A1 || sensorId > Sensor::C) 77 | return false; 78 | 79 | // Remove the flag 80 | states.erase(sensorId); 81 | *activeFlags &= ~sensorId; 82 | *inactiveFlags &= ~sensorId; 83 | 84 | return true; 85 | } 86 | 87 | void Sensor::Queue(SensorId sensorId, bool value) 88 | { 89 | auto message = Message(); 90 | message.SensorId = sensorId; 91 | message.Value = value; 92 | 93 | queue.push_back(message); 94 | } 95 | 96 | bool Sensor::Activate(SensorId sensorId) 97 | { 98 | return SetSensorState(sensorId, true); 99 | } 100 | 101 | bool Sensor::Deactivate(SensorId sensorId) 102 | { 103 | return SetSensorState(sensorId, false); 104 | } 105 | 106 | bool Sensor::ProcessQueue() 107 | { 108 | int evCount = 0; 109 | auto it = queue.begin(); 110 | 111 | std::unordered_map processed; 112 | while (it != queue.end()) 113 | { 114 | auto message = *it; 115 | SetSensorState(message.SensorId, message.Value); 116 | 117 | it = queue.erase(it); 118 | processed[message.SensorId] = message.Value; 119 | 120 | evCount++; 121 | } 122 | 123 | // Set the leftover states due touch move. 124 | // When the touch is moved and out of sensor region bound it give no signal to former sensor that it no longer active 125 | // Therefore we need to clear those sensor flag manually 126 | for (auto state : states) 127 | { 128 | if (state.second && (processed.count(state.first) == 0 || !processed[state.first])) 129 | SetSensorState(state.first, false); 130 | } 131 | 132 | return evCount > 0; 133 | } 134 | 135 | void Sensor::Reset() 136 | { 137 | // Attempt to read sensor state in case not initialized yet 138 | if (!Connect()) 139 | return; 140 | 141 | // Reset sensor bitflag each game frame 142 | *activeFlags = 0; 143 | *inactiveFlags = 0; 144 | } 145 | } -------------------------------------------------------------------------------- /src/SensorChecker.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace MaiSense 6 | { 7 | SensorChecker::SensorChecker() 8 | { 9 | this->screenWidth = 0; 10 | this->screenHeight = 0; 11 | this->InitRegions(); 12 | } 13 | 14 | SensorChecker::SensorChecker(int screenWidth, int screenHeight) 15 | { 16 | this->screenWidth = screenWidth; 17 | this->screenHeight = screenHeight; 18 | this->InitRegions(); 19 | } 20 | 21 | SensorChecker::SensorChecker(int screenWidth, int screenHeight, const std::map& regionMap) 22 | { 23 | this->screenWidth = screenWidth; 24 | this->screenHeight = screenHeight; 25 | this->InitRegions(); 26 | this->regionMap.insert(regionMap.begin(), regionMap.end()); 27 | } 28 | 29 | SensorChecker::~SensorChecker() 30 | { 31 | } 32 | 33 | void SensorChecker::InitRegions() 34 | { 35 | this->AddRegion(Sensor::C, C_REGION); 36 | this->AddRegion(Sensor::A1, A1_REGION); 37 | this->AddRegion(Sensor::A2, A2_REGION); 38 | this->AddRegion(Sensor::A3, A3_REGION); 39 | this->AddRegion(Sensor::A4, A4_REGION); 40 | this->AddRegion(Sensor::A5, A5_REGION); 41 | this->AddRegion(Sensor::A6, A6_REGION); 42 | this->AddRegion(Sensor::A7, A7_REGION); 43 | this->AddRegion(Sensor::A8, A8_REGION); 44 | this->AddRegion(Sensor::B1, B1_REGION); 45 | this->AddRegion(Sensor::B2, B2_REGION); 46 | this->AddRegion(Sensor::B3, B3_REGION); 47 | this->AddRegion(Sensor::B4, B4_REGION); 48 | this->AddRegion(Sensor::B5, B5_REGION); 49 | this->AddRegion(Sensor::B6, B6_REGION); 50 | this->AddRegion(Sensor::B7, B7_REGION); 51 | this->AddRegion(Sensor::B8, B8_REGION); 52 | } 53 | 54 | void SensorChecker::AddRegion(SensorId sensorId, const SensorRegion& region) 55 | { 56 | this->regionMap.insert(std::pair(sensorId, region)); 57 | } 58 | 59 | void SensorChecker::RemoveRegion(SensorId sensorId) 60 | { 61 | this->regionMap.erase(sensorId); 62 | } 63 | 64 | bool SensorChecker::Check(Point position, SensorId sensorId) 65 | { 66 | auto sensor = InputManager::GetSensor(); 67 | float scaleX = this->screenWidth / (float)REF_SCREEN_WIDTH; 68 | float scaleY = this->screenHeight / (float)REF_SCREEN_HEIGHT; 69 | 70 | if (this->regionMap.count(sensorId) <= 0) 71 | return false; 72 | 73 | return this->regionMap[sensorId].Test(position, scaleX, scaleY); 74 | } 75 | 76 | int SensorChecker::GetScreenWidth() 77 | { 78 | return this->screenWidth; 79 | } 80 | 81 | int SensorChecker::GetScreenHeight() 82 | { 83 | return this->screenHeight; 84 | } 85 | 86 | void SensorChecker::SetScreenSize(int width, int height) 87 | { 88 | this->screenWidth = width; 89 | this->screenHeight = height; 90 | } 91 | } -------------------------------------------------------------------------------- /src/SensorProcessor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace MaiSense 4 | { 5 | SensorProcessor::SensorProcessor() : 6 | checker(0), 7 | sensor(0) 8 | { 9 | } 10 | 11 | SensorProcessor::~SensorProcessor() 12 | { 13 | } 14 | 15 | SensorChecker* SensorProcessor::GetChecker() 16 | { 17 | return this->checker; 18 | } 19 | 20 | Sensor* SensorProcessor::GetSensor() 21 | { 22 | return this->sensor; 23 | } 24 | 25 | void SensorProcessor::SetChecker(SensorChecker* checker) 26 | { 27 | this->checker = checker; 28 | } 29 | 30 | void SensorProcessor::SetSensor(Sensor* sensor) 31 | { 32 | this->sensor = sensor; 33 | } 34 | 35 | bool SensorProcessor::Handle(TouchEvent ev) 36 | { 37 | bool active = !(ev.Flag & POINTER_FLAG_UP || ev.Flag & POINTER_FLAG_CANCELED); 38 | return Handle({ev.X, ev.Y}, ev.Flag); 39 | } 40 | 41 | bool SensorProcessor::Handle(MouseEvent ev) 42 | { 43 | return Handle({ ev.X, ev.Y }, ev.LButton); 44 | } 45 | 46 | bool SensorProcessor::Handle(const Point& pointer, bool active) 47 | { 48 | if (this->checker == NULL) 49 | return false; 50 | 51 | if (this->sensor == NULL) 52 | return false; 53 | 54 | const auto sensors = { 55 | Sensor::A1, 56 | Sensor::A2, 57 | Sensor::A3, 58 | Sensor::A4, 59 | Sensor::A5, 60 | Sensor::A6, 61 | Sensor::A7, 62 | Sensor::A8, 63 | Sensor::B1, 64 | Sensor::B2, 65 | Sensor::B3, 66 | Sensor::B4, 67 | Sensor::B5, 68 | Sensor::B6, 69 | Sensor::B7, 70 | Sensor::B8, 71 | Sensor::C 72 | }; 73 | 74 | for (auto sensorId : sensors) 75 | { 76 | if (checker->Check(pointer, sensorId)) 77 | { 78 | sensor->Queue(sensorId, active); 79 | return true; 80 | } 81 | } 82 | 83 | return false; 84 | } 85 | } -------------------------------------------------------------------------------- /src/SensorRegion.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace MaiSense 5 | { 6 | SensorRegion::SensorRegion() 7 | { 8 | } 9 | 10 | SensorRegion::SensorRegion(const std::vector& points) 11 | { 12 | this->points.reserve(points.size()); 13 | this->points.insert(this->points.end(), points.begin(), points.end()); 14 | } 15 | 16 | SensorRegion::~SensorRegion() 17 | { 18 | } 19 | 20 | void SensorRegion::AddPoint(const Point& point) 21 | { 22 | this->points.push_back(point); 23 | } 24 | 25 | bool SensorRegion::Test(const Point& testPoint, float scaleX, float scaleY) 26 | { 27 | if (this->points.size() < 3) 28 | return false; 29 | 30 | std::vector scaledPoints; 31 | 32 | for (unsigned int i = 0; i < this->points.size(); i++) 33 | { 34 | int scaledX = (int)ceil(this->points[i].X * scaleX); 35 | int scaledY = (int)ceil(this->points[i].Y * scaleY); 36 | scaledPoints.push_back({ scaledX, scaledY }); 37 | } 38 | 39 | Point extreme = { 9999, testPoint.Y }; 40 | 41 | int count = 0, i = 0, n = scaledPoints.size(); 42 | do 43 | { 44 | int next = (i + 1) % n; 45 | 46 | if (DoesSegmentIntersect(scaledPoints[i], scaledPoints[next], testPoint, extreme)) 47 | { 48 | if (FindOrientation(scaledPoints[i], testPoint, scaledPoints[next]) == COLINEAR) 49 | return IsOnSegment(scaledPoints[i], testPoint, scaledPoints[next]); 50 | 51 | count++; 52 | } 53 | 54 | i = next; 55 | } while (i != 0); 56 | 57 | return count & 1; 58 | } 59 | 60 | bool SensorRegion::IsOnSegment(const Point& p, const Point& q, const Point& r) 61 | { 62 | if (q.X <= max(p.X, r.X) && q.X >= min(p.X, r.X) && 63 | q.Y <= max(p.Y, r.Y) && q.Y >= min(p.Y, r.Y)) 64 | return true; 65 | return false; 66 | } 67 | 68 | int SensorRegion::FindOrientation(const Point& p, const Point& q, const Point& r) 69 | { 70 | int val = (q.Y - p.Y) * (r.X - q.X) - 71 | (q.X - p.X) * (r.Y - q.Y); 72 | 73 | if (val == 0) 74 | return COLINEAR; 75 | 76 | return (val > 0) ? CLOCKWISE : COUNTER_CLOCKWISE; 77 | } 78 | 79 | bool SensorRegion::DoesSegmentIntersect(const Point& p1, const Point& q1, const Point& p2, const Point& q2) 80 | { 81 | int o1 = FindOrientation(p1, q1, p2); 82 | int o2 = FindOrientation(p1, q1, q2); 83 | int o3 = FindOrientation(p2, q2, p1); 84 | int o4 = FindOrientation(p2, q2, q1); 85 | 86 | if (o1 != o2 && o3 != o4) 87 | return true; 88 | 89 | if (o1 == COLINEAR && IsOnSegment(p1, p2, q1)) 90 | return true; 91 | 92 | if (o2 == COLINEAR && IsOnSegment(p1, q2, q1)) 93 | return true; 94 | 95 | if (o3 == COLINEAR && IsOnSegment(p2, p1, q2)) 96 | return true; 97 | 98 | if (o4 == COLINEAR && IsOnSegment(p2, q1, q2)) 99 | return true; 100 | 101 | return false; 102 | } 103 | } -------------------------------------------------------------------------------- /src/TouchController.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace MaiSense 4 | { 5 | TouchController::TouchController() : 6 | callback() 7 | { 8 | } 9 | 10 | TouchController::~TouchController() 11 | { 12 | } 13 | 14 | void TouchController::SetCallback(std::function cb) 15 | { 16 | callback = cb; 17 | } 18 | 19 | bool TouchController::Check(int evCode) 20 | { 21 | switch (evCode) 22 | { 23 | case WM_POINTERENTER: 24 | case WM_NCPOINTERDOWN: 25 | case WM_NCPOINTERUP: 26 | case WM_NCPOINTERUPDATE: 27 | case WM_POINTERACTIVATE: 28 | case WM_POINTERCAPTURECHANGED: 29 | case WM_POINTERDOWN: 30 | case WM_POINTERLEAVE: 31 | case WM_POINTERUP: 32 | case WM_POINTERUPDATE: 33 | return true; 34 | default: 35 | return false; 36 | } 37 | } 38 | 39 | void TouchController::OnInput(int nCode, WPARAM wParam, LPARAM lParam) 40 | { 41 | // Parse message 42 | auto msg = (LPMSG)lParam; 43 | 44 | // Declare pointer info 45 | UINT32 pointerId = GET_POINTERID_WPARAM(msg->wParam); 46 | POINTER_INFO pointerInfo = { sizeof(POINTER_INFO) }; 47 | POINTER_INPUT_TYPE pointerType = 0; 48 | 49 | // Parse pointer info 50 | if (GetPointerType(pointerId, &pointerType) && GetPointerInfo(pointerId, &pointerInfo)) 51 | { 52 | // Only retrieve touch event and map coordinate into client coordinate 53 | POINT point = pointerInfo.ptPixelLocation; 54 | if (pointerType == PT_TOUCH && ScreenToClient(msg->hwnd, &point)) 55 | { 56 | // Initialize touch event 57 | auto ev = TouchEvent(); 58 | ev.Id = pointerInfo.pointerId; 59 | ev.X = point.x; 60 | ev.Y = point.y; 61 | ev.Flag = pointerInfo.pointerFlags; 62 | 63 | // Pass event into callback 64 | if (callback) 65 | callback(ev); 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #pragma warning (disable : 4996) 12 | 13 | using namespace MaiSense; 14 | 15 | TouchController touchController; 16 | KeyboardController keyboardController; 17 | MouseController mouseController; 18 | SensorChecker sensorChecker; 19 | SensorProcessor processor; 20 | 21 | BOOL APIENTRY DllMain(HMODULE hMod, DWORD cause, LPVOID lpReserved) 22 | { 23 | if (!InputManager::Ready()) 24 | return TRUE; 25 | 26 | if (cause == DLL_PROCESS_ATTACH) 27 | { 28 | AllocConsole(); 29 | freopen("CONIN$", "r", stdin); 30 | freopen("CONOUT$", "w", stdout); 31 | 32 | touchController.SetCallback([&](TouchEvent ev) 33 | { 34 | processor.Handle(ev); 35 | if (sensorChecker.GetScreenWidth() == 0 || sensorChecker.GetScreenHeight() == 0) 36 | { 37 | RECT clientRect; 38 | GetClientRect(InputManager::GetGameWindow(), &clientRect); 39 | sensorChecker.SetScreenSize 40 | ( 41 | clientRect.left + clientRect.right, 42 | clientRect.top + clientRect.bottom 43 | ); 44 | } 45 | 46 | if (processor.GetChecker() == NULL) 47 | processor.SetChecker(&sensorChecker); 48 | 49 | if (processor.GetSensor() == NULL) 50 | processor.SetSensor(InputManager::GetSensor()); 51 | }); 52 | 53 | keyboardController.SetCallback([&](KeyEvent ev) 54 | { 55 | auto sensor = InputManager::GetSensor(); 56 | switch (ev.KeyCode) 57 | { 58 | case 0x30: // 0 59 | sensor->Queue(Sensor::C, ev.Active); 60 | break; 61 | case 0x31: // 1 62 | sensor->Queue(Sensor::A1, ev.Active); 63 | break; 64 | case 0x32: // 2 65 | sensor->Queue(Sensor::A2, ev.Active); 66 | break; 67 | case 0x33: // 3 68 | sensor->Queue(Sensor::A3, ev.Active); 69 | break; 70 | case 0x34: // 4 71 | sensor->Queue(Sensor::A4, ev.Active); 72 | break; 73 | case 0x35: // 5 74 | sensor->Queue(Sensor::A5, ev.Active); 75 | break; 76 | case 0x36: // 6 77 | sensor->Queue(Sensor::A6, ev.Active); 78 | break; 79 | case 0x37: // 7 80 | sensor->Queue(Sensor::A7, ev.Active); 81 | break; 82 | case 0x38: // 8 83 | sensor->Queue(Sensor::A8, ev.Active); 84 | break; 85 | case VK_NUMPAD1: // NUMPAD 1 86 | sensor->Queue(Sensor::B1, ev.Active); 87 | break; 88 | case VK_NUMPAD2: // NUMPAD 2 89 | sensor->Queue(Sensor::B2, ev.Active); 90 | break; 91 | case VK_NUMPAD3: // NUMPAD 3 92 | sensor->Queue(Sensor::B3, ev.Active); 93 | break; 94 | case VK_NUMPAD4: // NUMPAD 4 95 | sensor->Queue(Sensor::B4, ev.Active); 96 | break; 97 | case VK_NUMPAD5: // NUMPAD 5 98 | sensor->Queue(Sensor::B5, ev.Active); 99 | break; 100 | case VK_NUMPAD6: // NUMPAD 6 101 | sensor->Queue(Sensor::B6, ev.Active); 102 | break; 103 | case VK_NUMPAD7: // NUMPAD 7 104 | sensor->Queue(Sensor::B7, ev.Active); 105 | break; 106 | case VK_NUMPAD8: // NUMPAD 8 107 | sensor->Queue(Sensor::B8, ev.Active); 108 | break; 109 | } 110 | }); 111 | mouseController.SetCallback([&](MouseEvent ev) 112 | { 113 | if (ev.MButton) 114 | mouseController.EmulateTouch(); 115 | }); 116 | 117 | InputManager::Hook(); 118 | InputManager::Install(&touchController); 119 | InputManager::Install(&keyboardController); 120 | InputManager::Install(&mouseController); 121 | } 122 | else if (cause == DLL_PROCESS_DETACH) 123 | { 124 | InputManager::Unhook(); 125 | } 126 | 127 | return TRUE; 128 | } 129 | -------------------------------------------------------------------------------- /temp/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | 3 | !.gitignore --------------------------------------------------------------------------------