├── .gitattributes ├── .github └── workflows │ └── codeql-analysis.yml ├── .gitignore ├── LICENSE.md ├── MouseToVJoy.sln ├── MouseToVJoy ├── MouseToVJoy.cpp ├── MouseToVJoy.filters ├── MouseToVJoy.user ├── MouseToVJoy.vcxproj ├── MouseToVJoy.vcxproj.filters ├── MouseToVJoy.vcxproj.user ├── Stopwatch.h ├── cInputDevices.cpp ├── config.txt ├── ffbsize.h ├── fileRead.cpp ├── fileRead.h ├── forceFeedBack.cpp ├── forceFeedBack.h ├── input.h ├── main.cpp ├── mousetovjoy.h ├── public.h ├── vJoy.cpp ├── vjoy.h └── vjoyinterface.h ├── MouseToVjoy.ini ├── README.md ├── contentmanager.PNG ├── header.PNG └── lib ├── x64 ├── vJoyInterface.dll └── vJoyInterface.lib └── x86 ├── vJoyInterface.dll ├── vJoyInterface.lib └── vJoyInterface218.dll /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '34 22 * * 5' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: windows-2019 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'cpp' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 37 | # Learn more: 38 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 39 | 40 | steps: 41 | - name: Checkout repository 42 | uses: actions/checkout@v2 43 | 44 | # Initializes the CodeQL tools for scanning. 45 | - name: Initialize CodeQL 46 | uses: github/codeql-action/init@v2 47 | with: 48 | languages: ${{ matrix.language }} 49 | # If you wish to specify custom queries, you can do so here or in a config file. 50 | # By default, queries listed here will override any specified in a config file. 51 | # Prefix the list here with "+" to use these queries and those in the config file. 52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 53 | 54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 55 | # If this step fails, then you should remove it and run the build manually (see below) 56 | - name: Autobuild 57 | uses: github/codeql-action/autobuild@v2 58 | 59 | # ℹ️ Command-line programs to run using the OS shell. 60 | # 📚 https://git.io/JvXDl 61 | 62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 63 | # and modify them (or add more) to build your code if your project 64 | # uses a compiled language 65 | 66 | #- run: | 67 | # make bootstrap 68 | # make release 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v2 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | [Aa][Rr][Mm]/ 25 | [Aa][Rr][Mm]64/ 26 | bld/ 27 | [Bb]in/ 28 | [Oo]bj/ 29 | [Ll]og/ 30 | [Ll]ogs/ 31 | 32 | # Visual Studio 2015/2017 cache/options directory 33 | .vs/ 34 | # Uncomment if you have tasks that create the project's static files in wwwroot 35 | #wwwroot/ 36 | 37 | # Visual Studio 2017 auto generated files 38 | Generated\ Files/ 39 | 40 | # MSTest test Results 41 | [Tt]est[Rr]esult*/ 42 | [Bb]uild[Ll]og.* 43 | 44 | # NUnit 45 | *.VisualState.xml 46 | TestResult.xml 47 | nunit-*.xml 48 | 49 | # Build Results of an ATL Project 50 | [Dd]ebugPS/ 51 | [Rr]eleasePS/ 52 | dlldata.c 53 | 54 | # Benchmark Results 55 | BenchmarkDotNet.Artifacts/ 56 | 57 | # .NET Core 58 | project.lock.json 59 | project.fragment.lock.json 60 | artifacts/ 61 | 62 | # StyleCop 63 | StyleCopReport.xml 64 | 65 | # Files built by Visual Studio 66 | *_i.c 67 | *_p.c 68 | *_h.h 69 | *.ilk 70 | *.meta 71 | *.obj 72 | *.iobj 73 | *.pch 74 | *.pdb 75 | *.ipdb 76 | *.pgc 77 | *.pgd 78 | *.rsp 79 | *.sbr 80 | *.tlb 81 | *.tli 82 | *.tlh 83 | *.tmp 84 | *.tmp_proj 85 | *_wpftmp.csproj 86 | *.log 87 | *.vspscc 88 | *.vssscc 89 | .builds 90 | *.pidb 91 | *.svclog 92 | *.scc 93 | 94 | # Chutzpah Test files 95 | _Chutzpah* 96 | 97 | # Visual C++ cache files 98 | ipch/ 99 | *.aps 100 | *.ncb 101 | *.opendb 102 | *.opensdf 103 | *.sdf 104 | *.cachefile 105 | *.VC.db 106 | *.VC.VC.opendb 107 | 108 | # Visual Studio profiler 109 | *.psess 110 | *.vsp 111 | *.vspx 112 | *.sap 113 | 114 | # Visual Studio Trace Files 115 | *.e2e 116 | 117 | # TFS 2012 Local Workspace 118 | $tf/ 119 | 120 | # Guidance Automation Toolkit 121 | *.gpState 122 | 123 | # ReSharper is a .NET coding add-in 124 | _ReSharper*/ 125 | *.[Rr]e[Ss]harper 126 | *.DotSettings.user 127 | 128 | # TeamCity is a build add-in 129 | _TeamCity* 130 | 131 | # DotCover is a Code Coverage Tool 132 | *.dotCover 133 | 134 | # AxoCover is a Code Coverage Tool 135 | .axoCover/* 136 | !.axoCover/settings.json 137 | 138 | # Coverlet is a free, cross platform Code Coverage Tool 139 | coverage*[.json, .xml, .info] 140 | 141 | # Visual Studio code coverage results 142 | *.coverage 143 | *.coveragexml 144 | 145 | # NCrunch 146 | _NCrunch_* 147 | .*crunch*.local.xml 148 | nCrunchTemp_* 149 | 150 | # MightyMoose 151 | *.mm.* 152 | AutoTest.Net/ 153 | 154 | # Web workbench (sass) 155 | .sass-cache/ 156 | 157 | # Installshield output folder 158 | [Ee]xpress/ 159 | 160 | # DocProject is a documentation generator add-in 161 | DocProject/buildhelp/ 162 | DocProject/Help/*.HxT 163 | DocProject/Help/*.HxC 164 | DocProject/Help/*.hhc 165 | DocProject/Help/*.hhk 166 | DocProject/Help/*.hhp 167 | DocProject/Help/Html2 168 | DocProject/Help/html 169 | 170 | # Click-Once directory 171 | publish/ 172 | 173 | # Publish Web Output 174 | *.[Pp]ublish.xml 175 | *.azurePubxml 176 | # Note: Comment the next line if you want to checkin your web deploy settings, 177 | # but database connection strings (with potential passwords) will be unencrypted 178 | *.pubxml 179 | *.publishproj 180 | 181 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 182 | # checkin your Azure Web App publish settings, but sensitive information contained 183 | # in these scripts will be unencrypted 184 | PublishScripts/ 185 | 186 | # NuGet Packages 187 | *.nupkg 188 | # NuGet Symbol Packages 189 | *.snupkg 190 | # The packages folder can be ignored because of Package Restore 191 | **/[Pp]ackages/* 192 | # except build/, which is used as an MSBuild target. 193 | !**/[Pp]ackages/build/ 194 | # Uncomment if necessary however generally it will be regenerated when needed 195 | #!**/[Pp]ackages/repositories.config 196 | # NuGet v3's project.json files produces more ignorable files 197 | *.nuget.props 198 | *.nuget.targets 199 | 200 | # Microsoft Azure Build Output 201 | csx/ 202 | *.build.csdef 203 | 204 | # Microsoft Azure Emulator 205 | ecf/ 206 | rcf/ 207 | 208 | # Windows Store app package directories and files 209 | AppPackages/ 210 | BundleArtifacts/ 211 | Package.StoreAssociation.xml 212 | _pkginfo.txt 213 | *.appx 214 | *.appxbundle 215 | *.appxupload 216 | 217 | # Visual Studio cache files 218 | # files ending in .cache can be ignored 219 | *.[Cc]ache 220 | # but keep track of directories ending in .cache 221 | !?*.[Cc]ache/ 222 | 223 | # Others 224 | ClientBin/ 225 | ~$* 226 | *~ 227 | *.dbmdl 228 | *.dbproj.schemaview 229 | *.jfm 230 | *.pfx 231 | *.publishsettings 232 | orleans.codegen.cs 233 | 234 | # Including strong name files can present a security risk 235 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 236 | #*.snk 237 | 238 | # Since there are multiple workflows, uncomment next line to ignore bower_components 239 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 240 | #bower_components/ 241 | 242 | # RIA/Silverlight projects 243 | Generated_Code/ 244 | 245 | # Backup & report files from converting an old project file 246 | # to a newer Visual Studio version. Backup files are not needed, 247 | # because we have git ;-) 248 | _UpgradeReport_Files/ 249 | Backup*/ 250 | UpgradeLog*.XML 251 | UpgradeLog*.htm 252 | ServiceFabricBackup/ 253 | *.rptproj.bak 254 | 255 | # SQL Server files 256 | *.mdf 257 | *.ldf 258 | *.ndf 259 | 260 | # Business Intelligence projects 261 | *.rdl.data 262 | *.bim.layout 263 | *.bim_*.settings 264 | *.rptproj.rsuser 265 | *- [Bb]ackup.rdl 266 | *- [Bb]ackup ([0-9]).rdl 267 | *- [Bb]ackup ([0-9][0-9]).rdl 268 | 269 | # Microsoft Fakes 270 | FakesAssemblies/ 271 | 272 | # GhostDoc plugin setting file 273 | *.GhostDoc.xml 274 | 275 | # Node.js Tools for Visual Studio 276 | .ntvs_analysis.dat 277 | node_modules/ 278 | 279 | # Visual Studio 6 build log 280 | *.plg 281 | 282 | # Visual Studio 6 workspace options file 283 | *.opt 284 | 285 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 286 | *.vbw 287 | 288 | # Visual Studio LightSwitch build output 289 | **/*.HTMLClient/GeneratedArtifacts 290 | **/*.DesktopClient/GeneratedArtifacts 291 | **/*.DesktopClient/ModelManifest.xml 292 | **/*.Server/GeneratedArtifacts 293 | **/*.Server/ModelManifest.xml 294 | _Pvt_Extensions 295 | 296 | # Paket dependency manager 297 | .paket/paket.exe 298 | paket-files/ 299 | 300 | # FAKE - F# Make 301 | .fake/ 302 | 303 | # CodeRush personal settings 304 | .cr/personal 305 | 306 | # Python Tools for Visual Studio (PTVS) 307 | __pycache__/ 308 | *.pyc 309 | 310 | # Cake - Uncomment if you are using it 311 | # tools/** 312 | # !tools/packages.config 313 | 314 | # Tabs Studio 315 | *.tss 316 | 317 | # Telerik's JustMock configuration file 318 | *.jmconfig 319 | 320 | # BizTalk build output 321 | *.btp.cs 322 | *.btm.cs 323 | *.odx.cs 324 | *.xsd.cs 325 | 326 | # OpenCover UI analysis results 327 | OpenCover/ 328 | 329 | # Azure Stream Analytics local run output 330 | ASALocalRun/ 331 | 332 | # MSBuild Binary and Structured Log 333 | *.binlog 334 | 335 | # NVidia Nsight GPU debugger configuration file 336 | *.nvuser 337 | 338 | # MFractors (Xamarin productivity tool) working folder 339 | .mfractor/ 340 | 341 | # Local History for Visual Studio 342 | .localhistory/ 343 | 344 | # BeatPulse healthcheck temp database 345 | healthchecksdb 346 | 347 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 348 | MigrationBackup/ 349 | 350 | # Ionide (cross platform F# VS Code tools) working folder 351 | .ionide/ -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Sebastian Waluś 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 | -------------------------------------------------------------------------------- /MouseToVJoy.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26430.14 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MouseToVJoy", "MouseToVJoy\MouseToVJoy.vcxproj", "{4F43963C-7AAA-442D-A71C-AFDA187DEB01}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {4F43963C-7AAA-442D-A71C-AFDA187DEB01}.Debug|x64.ActiveCfg = Debug|x64 17 | {4F43963C-7AAA-442D-A71C-AFDA187DEB01}.Debug|x64.Build.0 = Debug|x64 18 | {4F43963C-7AAA-442D-A71C-AFDA187DEB01}.Debug|x86.ActiveCfg = Debug|Win32 19 | {4F43963C-7AAA-442D-A71C-AFDA187DEB01}.Debug|x86.Build.0 = Debug|Win32 20 | {4F43963C-7AAA-442D-A71C-AFDA187DEB01}.Release|x64.ActiveCfg = Release|x64 21 | {4F43963C-7AAA-442D-A71C-AFDA187DEB01}.Release|x64.Build.0 = Release|x64 22 | {4F43963C-7AAA-442D-A71C-AFDA187DEB01}.Release|x86.ActiveCfg = Release|Win32 23 | {4F43963C-7AAA-442D-A71C-AFDA187DEB01}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /MouseToVJoy/MouseToVJoy.cpp: -------------------------------------------------------------------------------- 1 | #include "mousetovjoy.h" 2 | #include 3 | #include 4 | #define STEERING_MAX 16384 5 | #define STEERING_MIN -16384 6 | //Function responsible for getting and modifying vars for throttle, brake, clutch. 7 | void MouseToVjoy::inputLogic(CInputDevices input, INT &axisX, INT &axisY, INT &axisZ, INT &axisRX, BOOL &isButton1Clicked, BOOL &isButton2Clicked, BOOL &isButton3Clicked, DOUBLE attackTimeThrottle, DOUBLE releaseTimeThrottle, DOUBLE attackTimeBrake, DOUBLE releaseTimeBrake, DOUBLE attackTimeClutch, DOUBLE releaseTimeClutch, INT throttleKey, INT brakeKey, INT clutchKey, INT gearShiftUpKey, INT gearShiftDownKey, INT handBrakeKey, INT mouseCenterKey, INT useMouse, DOUBLE accelerationThrottle, DOUBLE accelerationBrake, DOUBLE accelerationClutch, BOOL useWheelAsShifter, BOOL touchpad, INT disableAxis, BOOL disableKeys, DOUBLE deltaTime) noexcept { 8 | if (input.isAlphabeticKeyDown(mouseCenterKey)) { 9 | SleepEx(250, !(input.isAlphabeticKeyDown(mouseCenterKey))); 10 | axisX = (32768 / 2); 11 | } 12 | 13 | if (useMouse == 1) { 14 | if (input.isLeftMouseButtonDown() && axisY < 32767 && useWheelAsShifter) 15 | axisY = (int)(attackTimeThrottle == 0 ? 32767 : (axisY + (attackTimeThrottle * deltaTime) * accelerationThrottle)); 16 | if (!input.isLeftMouseButtonDown() && axisY > 1 && useWheelAsShifter) 17 | axisY = (int)(releaseTimeThrottle == 0 ? 0 : (axisY - (releaseTimeThrottle * deltaTime) / accelerationThrottle)); 18 | if (!touchpad) { 19 | if (input.isRightMouseButtonDown() && axisZ < 32767) 20 | axisZ = (int)(attackTimeBrake == 0 ? 32767 : (axisZ + (attackTimeBrake * deltaTime) * accelerationBrake)); 21 | if (!input.isRightMouseButtonDown() && axisZ > 1) 22 | axisZ = (int)(releaseTimeBrake == 0 ? 0 : (axisZ - (releaseTimeBrake * deltaTime) / accelerationBrake)); 23 | } 24 | } 25 | else { 26 | if (input.isAlphabeticKeyDown(throttleKey) && axisY < 32767 && useWheelAsShifter) 27 | axisY = (int)(attackTimeThrottle == 0 ? 32767 : (axisY + (attackTimeThrottle * deltaTime) * accelerationThrottle)); 28 | if (!input.isAlphabeticKeyDown(throttleKey) && axisY > 1 && useWheelAsShifter) 29 | axisY = (int)(releaseTimeThrottle == 0 ? 0 : (axisY - (releaseTimeThrottle * deltaTime) / accelerationThrottle)); 30 | if (!(touchpad && disableKeys) || (touchpad && disableAxis == 2)) { 31 | if (input.isAlphabeticKeyDown(brakeKey) && axisZ < 32767) 32 | axisZ = (int)(attackTimeBrake == 0 ? 32767 : (axisZ + (attackTimeBrake * deltaTime) * accelerationBrake)); 33 | if (!input.isAlphabeticKeyDown(brakeKey) && axisZ > 1) 34 | axisZ = (int)(releaseTimeBrake == 0 ? 0 : (axisZ - (releaseTimeBrake * deltaTime) / accelerationBrake)); 35 | } 36 | } 37 | if (!(touchpad && disableKeys) || (touchpad && disableAxis == 1)) { 38 | if (input.isAlphabeticKeyDown(clutchKey) && axisRX < 32767) 39 | axisRX = (int)(attackTimeClutch == 0 ? 32767 : (axisRX + (attackTimeClutch * deltaTime) * accelerationClutch)); 40 | if (!input.isAlphabeticKeyDown(clutchKey) && axisRX > 1) 41 | axisRX = (int)(releaseTimeClutch == 0 ? 0 : (axisRX - (releaseTimeClutch * deltaTime) / accelerationClutch)); 42 | } 43 | 44 | isButton1Clicked = input.isAlphabeticKeyDown(gearShiftUpKey); 45 | isButton2Clicked = input.isAlphabeticKeyDown(gearShiftDownKey); 46 | isButton3Clicked = input.isAlphabeticKeyDown(handBrakeKey); 47 | } 48 | //Function responsible for getting and modifying vars for steering wheel. 49 | void MouseToVjoy::mouseLogic(INT change, INT &X, DOUBLE sensitivity, DOUBLE sensitivityCenterReduction, INT useCenterReduction) noexcept { 50 | //vjoy max value is 0-32767 to make it easier to scale linear reduction/acceleration I subtract half of it so 16384 to make it -16384 to 16384. 51 | X = X - 16384; 52 | if (X > 0) 53 | _centerMultiplier = pow(sensitivityCenterReduction, (1 - (double)((double)X / (double)STEERING_MAX))); 54 | else if(X < 0) 55 | _centerMultiplier = pow(sensitivityCenterReduction, (1 - (double)((double)X / (double)STEERING_MIN))); 56 | if (useCenterReduction == 1) 57 | X = (int)(X + ((change * sensitivity) / _centerMultiplier)); 58 | else 59 | X = (int)(X + (change * sensitivity)); 60 | 61 | X = std::clamp(X, -16384, 16384) + 16384; 62 | }; -------------------------------------------------------------------------------- /MouseToVJoy/MouseToVJoy.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 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Pliki nagłówkowe 20 | 21 | 22 | Pliki nagłówkowe 23 | 24 | 25 | Pliki nagłówkowe 26 | 27 | 28 | Pliki nagłówkowe 29 | 30 | 31 | 32 | 33 | Pliki źródłowe 34 | 35 | 36 | -------------------------------------------------------------------------------- /MouseToVJoy/MouseToVJoy.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | true 5 | 6 | -------------------------------------------------------------------------------- /MouseToVJoy/MouseToVJoy.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 | 15.0 23 | {4F43963C-7AAA-442D-A71C-AFDA187DEB01} 24 | Win32Proj 25 | MouseToVjoy 26 | 10.0 27 | MouseToVJoy 28 | 29 | 30 | 31 | Application 32 | true 33 | v143 34 | MultiByte 35 | 36 | 37 | Application 38 | false 39 | v143 40 | true 41 | MultiByte 42 | 43 | 44 | Application 45 | true 46 | v143 47 | MultiByte 48 | 49 | 50 | Application 51 | false 52 | v143 53 | true 54 | MultiByte 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | true 76 | 77 | 78 | true 79 | 80 | 81 | false 82 | 83 | 84 | false 85 | 86 | 87 | 88 | 89 | 90 | Level3 91 | Disabled 92 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 93 | stdcpp17 94 | 95 | 96 | Windows 97 | $(SolutionDir)\lib\$(PlatformShortName);%(AdditionalLibraryDirectories) 98 | vJoyInterface.lib;hid.lib;ws2_32.lib;IPHLPAPI.lib;%(AdditionalDependencies) 99 | 100 | 101 | xcopy /y /d "$(SolutionDir)lib\$(PlatformShortName)\*.dll" "$(OutDir)" 102 | xcopy /y /d "$(ProjectDir)config.txt" "$(OutDir)" 103 | 104 | 105 | 106 | 107 | 108 | 109 | Level3 110 | Disabled 111 | _DEBUG;_WINDOWS;%(PreprocessorDefinitions) 112 | stdcpp17 113 | 114 | 115 | Windows 116 | $(SolutionDir)\lib\$(PlatformShortName);%(AdditionalLibraryDirectories) 117 | vJoyInterface.lib;hid.lib;ws2_32.lib;IPHLPAPI.lib;%(AdditionalDependencies) 118 | 119 | 120 | xcopy /y /d "$(SolutionDir)lib\$(PlatformShortName)\*.dll" "$(OutDir)" 121 | xcopy /y /d "$(ProjectDir)config.txt" "$(OutDir)" 122 | 123 | 124 | 125 | 126 | Level3 127 | 128 | 129 | MaxSpeed 130 | true 131 | true 132 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 133 | stdcpp17 134 | 135 | 136 | Windows 137 | true 138 | true 139 | $(SolutionDir)\lib\$(PlatformShortName);%(AdditionalLibraryDirectories) 140 | vJoyInterface.lib;hid.lib;ws2_32.lib;IPHLPAPI.lib;%(AdditionalDependencies) 141 | 142 | 143 | xcopy /y /d "$(SolutionDir)lib\$(PlatformShortName)\*.dll" "$(OutDir)" 144 | xcopy /y /d "$(ProjectDir)config.txt" "$(OutDir)" 145 | 146 | 147 | 148 | 149 | Level3 150 | 151 | 152 | MaxSpeed 153 | true 154 | true 155 | NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 156 | stdcpp17 157 | 158 | 159 | Windows 160 | true 161 | true 162 | $(SolutionDir)\lib\$(PlatformShortName);%(AdditionalLibraryDirectories) 163 | vJoyInterface.lib;hid.lib;ws2_32.lib;IPHLPAPI.lib;%(AdditionalDependencies) 164 | 165 | 166 | xcopy /y /d "$(SolutionDir)lib\$(PlatformShortName)\*.dll" "$(OutDir)" 167 | xcopy /y /d "$(ProjectDir)config.txt" "$(OutDir)" 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | NotUsing 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /MouseToVJoy/MouseToVJoy.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Headers 6 | 7 | 8 | Headers 9 | 10 | 11 | Headers 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 | 33 | 34 | {8fe8e660-a3fd-4309-94f0-dc0d2ad981d5} 35 | 36 | 37 | {d2b96050-2abd-48e0-a05c-ebaada19a565} 38 | 39 | 40 | 41 | 42 | Source 43 | 44 | 45 | Source 46 | 47 | 48 | Source 49 | 50 | 51 | Source 52 | 53 | 54 | Source 55 | 56 | 57 | Source 58 | 59 | 60 | -------------------------------------------------------------------------------- /MouseToVJoy/MouseToVJoy.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /MouseToVJoy/Stopwatch.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Stopwatch.h -- A simple stopwatch implementation, based on Windows 4 | // high-performance timers. 5 | // Can come in handy when measuring elapsed times of 6 | // portions of C++ code. 7 | // 8 | // Copyright (C) 2016 by Giovanni Dicanio 9 | // 10 | //////////////////////////////////////////////////////////////////////////////// 11 | 12 | 13 | #pragma once 14 | 15 | #include // For _ASSERTE 16 | #include // For high-performance timers 17 | 18 | 19 | namespace win32 20 | { 21 | 22 | 23 | //------------------------------------------------------------------------------ 24 | // Class to measure time intervals, for benchmarking portions of code. 25 | // It's a convenient wrapper around the Win32 high-resolution timer APIs 26 | // QueryPerformanceCounter() and QueryPerformanceFrequency(). 27 | //------------------------------------------------------------------------------ 28 | class Stopwatch 29 | { 30 | public: 31 | // Initialize the stopwatch to a safe initial state 32 | Stopwatch() noexcept; 33 | 34 | // Clear the stopwatch state 35 | void reset() noexcept; 36 | 37 | // Start measuring time. 38 | // When finished, call Stop(). 39 | // Can call ElapsedTime() also before calling Stop(): in this case, 40 | // the elapsed time is measured since the Start() call. 41 | void start() noexcept; 42 | 43 | // Stop measuring time. 44 | // Call ElapsedMilliseconds() to get the elapsed time from the Start() call. 45 | void stop() noexcept; 46 | 47 | // Return elapsed time interval duration, in milliseconds. 48 | // Can be called both after Stop() and before it. 49 | // (Start() must have been called to initiate time interval measurements). 50 | double elapsedMilliseconds() const noexcept; 51 | 52 | 53 | // 54 | // Ban copy 55 | // 56 | private: 57 | Stopwatch(const Stopwatch&) = delete; 58 | Stopwatch& operator=(const Stopwatch&) = delete; 59 | 60 | 61 | // 62 | // *** IMPLEMENTATION *** 63 | // 64 | private: 65 | bool _running; // is the timer running? 66 | long long _start; // start tick count 67 | long long _finish; // end tick count 68 | const long long _frequency; // cached frequency value 69 | 70 | // 71 | // According to MSDN documentation: 72 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms644905(v=vs.85).aspx 73 | // 74 | // The frequency of the performance counter is fixed at system boot and 75 | // is consistent across all processors. 76 | // Therefore, the frequency need only be queried upon application 77 | // initialization, and the result can be cached. 78 | // 79 | 80 | // Wrapper to Win32 API QueryPerformanceCounter() 81 | static long long counter() noexcept; 82 | 83 | // Wrapper to Win32 API QueryPerformanceFrequency() 84 | static long long frequency() noexcept; 85 | 86 | // Calculate elapsed time in milliseconds, 87 | // given a start tick and end tick counts. 88 | double elapsedMilliseconds(long long start, long long finish) const noexcept; 89 | }; 90 | 91 | 92 | 93 | // 94 | // Inline implementations 95 | // 96 | 97 | 98 | inline Stopwatch::Stopwatch() noexcept 99 | : _running{ false } 100 | , _start{ 0 } 101 | , _finish{ 0 } 102 | , _frequency{ frequency() } 103 | {} 104 | 105 | 106 | inline void Stopwatch::reset() noexcept 107 | { 108 | _finish = _start = 0; 109 | _running = false; 110 | } 111 | 112 | 113 | inline void Stopwatch::start() noexcept 114 | { 115 | _running = true; 116 | _finish = 0; 117 | 118 | _start = counter(); 119 | } 120 | 121 | 122 | inline void Stopwatch::stop() noexcept 123 | { 124 | _finish = counter(); 125 | _running = false; 126 | } 127 | 128 | 129 | inline double Stopwatch::elapsedMilliseconds() const noexcept 130 | { 131 | if (_running) 132 | { 133 | const long long current{ counter() }; 134 | return elapsedMilliseconds(_start, current); 135 | } 136 | 137 | return elapsedMilliseconds(_start, _finish); 138 | } 139 | 140 | 141 | inline long long Stopwatch::counter() noexcept 142 | { 143 | LARGE_INTEGER li; 144 | ::QueryPerformanceCounter(&li); 145 | return li.QuadPart; 146 | } 147 | 148 | 149 | inline long long Stopwatch::frequency() noexcept 150 | { 151 | LARGE_INTEGER li; 152 | ::QueryPerformanceFrequency(&li); 153 | return li.QuadPart; 154 | } 155 | 156 | 157 | inline double Stopwatch::elapsedMilliseconds(long long start, long long finish) const noexcept 158 | { 159 | _ASSERTE(start >= 0); 160 | _ASSERTE(finish >= 0); 161 | _ASSERTE(start <= finish); 162 | 163 | return ((finish - start) * 1000.0) / _frequency; 164 | } 165 | 166 | 167 | } // namespace win32 168 | -------------------------------------------------------------------------------- /MouseToVJoy/cInputDevices.cpp: -------------------------------------------------------------------------------- 1 | #include "input.h" 2 | #include 3 | void CInputDevices::getData(LPARAM lParam, bool ptouchpad, bool ttouchpad, int kInfo) noexcept 4 | { 5 | // Determine how big the buffer should be 6 | UINT bufferSize = 0; 7 | GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &bufferSize, sizeof(RAWINPUTHEADER)); 8 | 9 | // Create a buffer of the correct size - but see note below 10 | 11 | // Call the function again, this time with the buffer to get the data 12 | if (bufferSize <= 40) 13 | GetRawInputData((HRAWINPUT)lParam, RID_INPUT, (LPVOID)_buffer, &bufferSize, sizeof(RAWINPUTHEADER)); 14 | 15 | RAWINPUT *raw = (RAWINPUT*)_buffer; 16 | 17 | // get tablet input 18 | if (raw->header.dwType == RIM_TYPEMOUSE && raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) { 19 | if (_tabletPressed) { 20 | _absX = raw->data.mouse.lLastX; 21 | _absY = 65535 - raw->data.mouse.lLastY; 22 | } 23 | else { 24 | _absX = 0; 25 | _absY = 0; 26 | } 27 | return; 28 | } 29 | // Prevent touchpad interfere 30 | else if ((ptouchpad || ttouchpad) && !raw->header.hDevice) { 31 | if (ttouchpad) { 32 | bool bStateDown = raw->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN; 33 | bool bStateUp = raw->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP; 34 | if (bStateDown == true && bStateUp == false) { 35 | _tabletPressed = true; 36 | } 37 | else if (bStateUp) 38 | _tabletPressed = false; 39 | } 40 | _mouseXChange = 0; 41 | _mouseYChange = 0; 42 | _mouseZChange = 0; 43 | _isMouseWheelUp = false; 44 | _isMouseWheelDown = false; 45 | return; 46 | } 47 | 48 | // The mouse has not been tested extensively, 49 | // but I believe it works. 50 | _mouseXChange = raw->data.mouse.lLastX; 51 | _mouseYChange = raw->data.mouse.lLastY; 52 | _mouseZChange = (short)raw->data.mouse.usButtonData; 53 | 54 | if (kInfo) { 55 | // Filter jumps that are caused by le funni number. why does this even happen ? 56 | if (_mouseXChange == kInfo) 57 | _mouseXChange = 0; 58 | if (_mouseYChange == kInfo) 59 | _mouseYChange = 0; 60 | } 61 | 62 | if (_mouseZChange == 120) 63 | _isMouseWheelUp = true; 64 | else 65 | _isMouseWheelUp = false; 66 | 67 | if (_mouseZChange == -120) 68 | _isMouseWheelDown = true; 69 | else 70 | _isMouseWheelDown = false; 71 | 72 | if (raw->header.dwType == RIM_TYPEMOUSE) 73 | { 74 | // Get values from the mouse member (of type RAWMOUSE) 75 | bool bStateDown = raw->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN; 76 | bool bStateUp = raw->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP; 77 | if (bStateDown == true && bStateUp == false) 78 | { 79 | _isLeftMouseButtonPressed = true; 80 | _isKeyboardButtonPressed[0x01] = true; 81 | } 82 | else if (bStateUp) 83 | { 84 | _isLeftMouseButtonPressed = false; 85 | _isKeyboardButtonPressed[0x01] = false; 86 | } 87 | 88 | 89 | bool bStateDownTwo = raw->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN; 90 | bool bStateUpTwo = raw->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP; 91 | 92 | if (bStateDownTwo == true && bStateUpTwo == false) 93 | { 94 | _isRightMouseButtonPressed = true; 95 | _isKeyboardButtonPressed[0x02] = true; 96 | } 97 | else if (bStateUpTwo) 98 | { 99 | _isRightMouseButtonPressed = false; 100 | _isKeyboardButtonPressed[0x02] = false; 101 | } 102 | 103 | 104 | bool bStateDownThree = raw->data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN; 105 | bool bStateUpThree = raw->data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP; 106 | 107 | if (bStateDownThree == true && bStateUpThree == false) 108 | { 109 | _isMiddleMouseButtonPressed = true; 110 | _isKeyboardButtonPressed[0x04] = true; 111 | } 112 | else if (bStateUpThree) 113 | { 114 | _isMiddleMouseButtonPressed = false; 115 | _isKeyboardButtonPressed[0x04] = false; 116 | } 117 | 118 | } 119 | if (raw->header.dwType == RIM_TYPEKEYBOARD) 120 | { 121 | // Get key value from the keyboard member (of type RAWKEYBOARD) 122 | USHORT keyCode = raw->data.keyboard.VKey; 123 | bool keyUp = raw->data.keyboard.Flags & RI_KEY_BREAK; 124 | 125 | // Ok because I put the most effort into this section of my code, 126 | // I will briefly explain. 127 | 128 | // We need a boolean pointer to start. 129 | bool* pbToKey = NULL; 130 | 131 | // The keycode can be one of many possibilities, 132 | // which is why a switch case is to exhaustive to 133 | // use and I believe for the most part switch case 134 | // would not be efficient. 135 | 136 | // So instead of manually typing every possible 137 | // case value, we can just start by looping through 138 | // an expected range of keys the keycode might be. 139 | 140 | for (int i = 0; i < 165; ++i) 141 | { 142 | // We add the hex-code 0x41 because that is the 143 | // value MSDN lists for virtual keycode 'A'. 144 | if (keyCode == i + 0x01) 145 | { 146 | // However our alphabet or array of booleans that 147 | // represent it, begins at 0 and is only 25 in length. 148 | // So i itself is the appropritate index. 149 | pbToKey = &_isKeyboardButtonPressed[i + 0x01]; 150 | 151 | // At this point we have assigned our boolean pointer variable 152 | // a new address which is whatever index i would be accessing. 153 | // We break because there is no need to go further since we found the 154 | // matching keycode! 155 | break; 156 | } 157 | } 158 | 159 | if (pbToKey != NULL && (!kInfo || raw->data.keyboard.ExtraInformation != (u_long)kInfo)) // Check if ExtraInformation matches le funni number and ignore if it does 160 | { 161 | *pbToKey = !keyUp; 162 | // Be sure to return ASAP! 163 | return; 164 | } 165 | 166 | // TODO: Add more key ranges to check for! Just follow 167 | // how I have set things up so far. 168 | 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /MouseToVJoy/config.txt: -------------------------------------------------------------------------------- 1 | Sensitivity = 5 2 | AttackTimeThrottle = 100 3 | ReleaseTimeThrottle = 200 4 | AttackTimeBreak = 100 5 | ReleaseTimeBreak = 200 6 | AttackTimeClutch = 100 7 | ReleaseTimeClutch = 200 8 | ThrottleKey = 87 9 | BrakeKey = 83 10 | ClutchKey = 69 11 | GearShiftUpKey = 1 12 | GearShiftDownKey = 2 13 | HandBrakeKey = 32 14 | MouseLockKey = 85 15 | MouseCenterKey = 0 16 | UseMouse = 0 17 | UseCenterReduction = 1 18 | UseForceFeedback = 0 19 | UseWheelAsShifter = 0 20 | UseWheelAsThrottle = 0 21 | WheelThrottleMiddle = 0 22 | AccelerationThrottle = 1 23 | AccelerationBreak = 1 24 | AccelerationClutch = 1 25 | CenterMultiplier = 1.5 26 | Touchpad = 0 27 | TouchpadApp = 0 28 | TouchpadXInvert = 1 29 | TouchpadYInvert = 0 30 | TouchpadXPercent = 65 31 | TouchpadYPercent = 70 32 | TouchpadXStartPercent = 0 33 | TouchpadYStartPercent = 0 34 | RequireLocked = 1 35 | RequireClutch = 0 36 | ForceFeedbackKey = 78 37 | TouchpadButtonsH = 0 38 | TouchpadButtonsV = 0 39 | TouchpadButtons = 0 40 | MouseHook = 0 41 | VJoyID = 1 42 | TouchpadTablet = 0 43 | TouchpadAxisDisable = 0 44 | DisableKeys = 1 45 | Use keycodes from 0 TO 165 46 | 47 | 48 | http://keycode.info 49 | -------------------------------------------------------------------------------- /MouseToVJoy/ffbsize.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef FFBSIZE_H 3 | #define FFBSIZE_H 4 | #include 5 | using namespace std; 6 | struct FFBSIZE { 7 | private: 8 | //Forcefeedback data 9 | string _effectTypeStr = ""; 10 | int _magnitudeVar = 0; 11 | int _directionVar = 0; 12 | int _offsetVar = 0; 13 | int _periodVar = 0; 14 | int _durationVar = 0; 15 | public: 16 | //fuctions that returns forcefeedback data 17 | string getEffectType() { return _effectTypeStr; } 18 | int getMagnitude() noexcept { return _magnitudeVar; } 19 | int getDirection() noexcept { return _directionVar; } 20 | int getOffset() noexcept { return _offsetVar; } 21 | int getPeriod() noexcept { return _periodVar; } 22 | int getDuration() noexcept { return _durationVar; } 23 | void setEffectType(string type) { if (type != "NULL") { _effectTypeStr = type; } } 24 | void setMagnitude(int size) noexcept { if (size != NULL) { _magnitudeVar = size; } } 25 | void setDirection(int size) noexcept { if (size != NULL) { _directionVar = size; } } 26 | void setOffset(int size) noexcept { if (size != NULL) { _offsetVar = size; } } 27 | void setPeriod(int size) noexcept { if (size != NULL) { _periodVar = size; } } 28 | void setDuration(int size) noexcept { if (size != NULL) { _durationVar = size; } } 29 | }; 30 | #endif -------------------------------------------------------------------------------- /MouseToVJoy/fileRead.cpp: -------------------------------------------------------------------------------- 1 | #include "fileRead.h" 2 | void FileRead::newFile(string fileName, string checkArray[]) { 3 | string line; 4 | ifstream file(fileName); 5 | if (file.is_open()) { 6 | while (getline(file, line)) { 7 | stringstream ss(line); 8 | string tmp; 9 | string value; 10 | char c; 11 | int b; 12 | ss >> tmp >> c >> value; 13 | 14 | if (tmp.empty()) 15 | continue; 16 | for(int i = 0; i < CHECK_LENGTH; i++){ 17 | b = tmp.find("Break"); 18 | if (b != string::npos) 19 | tmp.replace(b, 5, "Brake"); 20 | 21 | if (tmp == checkArray[i]) { 22 | _resultArray[i] = atof(value.c_str()); 23 | _resultArrayStr[i] = value; 24 | } 25 | } 26 | } 27 | file.close(); 28 | } 29 | else{ 30 | printf("Config file not found\n"); 31 | } 32 | } -------------------------------------------------------------------------------- /MouseToVJoy/fileRead.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef FILEREAD_H 3 | #define FILEREAD_H 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define CHECK_LENGTH 44 13 | 14 | using namespace std; 15 | /*Funtion takes two strings and returns array of numbers from that file. 16 | "fileName" is name of the file that will be opened, 17 | "checkArray" is array of strings that will be read(max 32 strings), 18 | function works like this: opens fileName then goes by every line in the file in this way: 19 | "/string name/ = /value/" eg. "Sensitivity = 2", 20 | then it checks if /string name/ is equal to any string from checkArray, then parses it into resultArray. 21 | Result order is the same as checkArray order. 22 | Eg. checkArray = "Sensitivity, Multiplier, Divider" then no matter the order in file, 23 | output will be restultArray[sensitivity, multiplier, divider etc.]. 24 | To access result just use funtion result[number] eg. result[0] for sensitivity. 25 | */ 26 | class FileRead{ 27 | public: 28 | void newFile(string fileName, string checkArray[]); 29 | 30 | inline double result(int number) noexcept { return _resultArray[number]; }; 31 | 32 | double _resultArray[CHECK_LENGTH] = { 0 }; 33 | string _resultArrayStr[CHECK_LENGTH]; 34 | }; 35 | #endif -------------------------------------------------------------------------------- /MouseToVJoy/forceFeedBack.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "forceFeedBack.h" 4 | 5 | using namespace std; 6 | // Convert Packet type to String 7 | BOOL ForceFeedBack::packetType2Str(FFBPType type, LPTSTR outStr) noexcept 8 | { 9 | BOOL stat = TRUE; 10 | LPTSTR Str = ""; 11 | 12 | switch (type) 13 | { 14 | case PT_EFFREP: 15 | Str = "Effect Report"; 16 | break; 17 | case PT_ENVREP: 18 | Str = "Envelope Report"; 19 | break; 20 | case PT_CONDREP: 21 | Str = "Condition Report"; 22 | break; 23 | case PT_PRIDREP: 24 | Str = "Periodic Report"; 25 | break; 26 | case PT_CONSTREP: 27 | Str = "Constant Force Report"; 28 | break; 29 | case PT_RAMPREP: 30 | Str = "Ramp Force Report"; 31 | break; 32 | case PT_CSTMREP: 33 | Str = "Custom Force Data Report"; 34 | break; 35 | case PT_SMPLREP: 36 | Str = "Download Force Sample"; 37 | break; 38 | case PT_EFOPREP: 39 | Str = "Effect Operation Report"; 40 | break; 41 | case PT_BLKFRREP: 42 | Str = "PID Block Free Report"; 43 | break; 44 | case PT_CTRLREP: 45 | Str = "PID Device Control"; 46 | break; 47 | case PT_GAINREP: 48 | Str = "Device Gain Report"; 49 | break; 50 | case PT_SETCREP: 51 | Str = "Set Custom Force Report"; 52 | break; 53 | case PT_NEWEFREP: 54 | Str = "Create New Effect Report"; 55 | break; 56 | case PT_BLKLDREP: 57 | Str = "Block Load Report"; 58 | break; 59 | case PT_POOLREP: 60 | Str = "PID Pool Report"; 61 | break; 62 | default: 63 | stat = FALSE; 64 | break; 65 | } 66 | 67 | if (stat) 68 | _tcscpy_s(outStr, 100, Str); 69 | 70 | return stat; 71 | } 72 | 73 | // Convert Effect type to String 74 | BOOL ForceFeedBack::effectType2Str(FFBEType type, LPTSTR outStr) noexcept 75 | { 76 | BOOL stat = TRUE; 77 | LPTSTR Str = ""; 78 | 79 | switch (type) 80 | { 81 | case ET_NONE: 82 | stat = FALSE; 83 | break; 84 | case ET_CONST: 85 | Str = "Constant Force"; 86 | break; 87 | case ET_RAMP: 88 | Str = "Ramp"; 89 | break; 90 | case ET_SQR: 91 | Str = "Square"; 92 | break; 93 | case ET_SINE: 94 | Str = "Sine"; 95 | break; 96 | case ET_TRNGL: 97 | Str = "Triangle"; 98 | break; 99 | case ET_STUP: 100 | Str = "Sawtooth Up"; 101 | break; 102 | case ET_STDN: 103 | Str = "Sawtooth Down"; 104 | break; 105 | case ET_SPRNG: 106 | Str = "Spring"; 107 | break; 108 | case ET_DMPR: 109 | Str = "Damper"; 110 | break; 111 | case ET_INRT: 112 | Str = "Inertia"; 113 | break; 114 | case ET_FRCTN: 115 | Str = "Friction"; 116 | break; 117 | case ET_CSTM: 118 | Str = "Custom Force"; 119 | break; 120 | default: 121 | stat = FALSE; 122 | break; 123 | }; 124 | 125 | if (stat) 126 | _tcscpy_s(outStr, 100, Str); 127 | 128 | return stat; 129 | } 130 | 131 | // Convert PID Device Control to String 132 | BOOL ForceFeedBack::devCtrl2Str(FFB_CTRL ctrl, LPTSTR outStr) noexcept 133 | { 134 | BOOL stat = TRUE; 135 | LPTSTR Str = ""; 136 | 137 | switch (ctrl) 138 | { 139 | case CTRL_ENACT: 140 | Str = "Enable Actuators"; 141 | break; 142 | case CTRL_DISACT: 143 | Str = "Disable Actuators"; 144 | break; 145 | case CTRL_STOPALL: 146 | Str = "Stop All Effects"; 147 | break; 148 | case CTRL_DEVRST: 149 | Str = "Device Reset"; 150 | break; 151 | case CTRL_DEVPAUSE: 152 | Str = "Device Pause"; 153 | break; 154 | case CTRL_DEVCONT: 155 | Str = "Device Continue"; 156 | break; 157 | default: 158 | stat = FALSE; 159 | break; 160 | } 161 | if (stat) 162 | _tcscpy_s(outStr, 100, Str); 163 | 164 | return stat; 165 | } 166 | 167 | // Convert Effect operation to string 168 | BOOL ForceFeedBack::effectOpStr(FFBOP op, LPTSTR outStr) noexcept 169 | { 170 | BOOL stat = TRUE; 171 | LPTSTR Str = ""; 172 | 173 | switch (op) 174 | { 175 | case EFF_START: 176 | Str = "Effect Start"; 177 | break; 178 | case EFF_SOLO: 179 | Str = "Effect Solo Start"; 180 | break; 181 | case EFF_STOP: 182 | Str = "Effect Stop"; 183 | break; 184 | default: 185 | stat = FALSE; 186 | break; 187 | } 188 | 189 | if (stat) 190 | _tcscpy_s(outStr, 100, Str); 191 | 192 | return stat; 193 | } 194 | 195 | // Polar values (0x00-0xFF) to Degrees (0-360) 196 | int ForceFeedBack::polar2Deg(BYTE polar) noexcept 197 | { 198 | return ((UINT)polar * 360) / 255; 199 | } 200 | 201 | // Convert range 0x00-0xFF to 0%-100% 202 | int ForceFeedBack::byte2Percent(BYTE inByte) noexcept 203 | { 204 | return ((UINT)inByte * 100) / 255; 205 | } 206 | 207 | // Convert One-Byte 2's complement input to integer 208 | int ForceFeedBack::twosCompByte2Int(BYTE in) noexcept 209 | { 210 | int tmp; 211 | BYTE inv = ~in; 212 | BOOL isNeg = in >> 7; 213 | if (isNeg) 214 | { 215 | tmp = (int)(inv); 216 | tmp = -1 * tmp; 217 | return tmp; 218 | } 219 | else 220 | return (int)in; 221 | } 222 | 223 | // Convert One-Byte 2's complement input to integer 224 | int ForceFeedBack::twosCompWord2Int(WORD in) noexcept 225 | { 226 | int tmp; 227 | WORD inv = ~in; 228 | BOOL isNeg = in >> 15; 229 | if (isNeg) 230 | { 231 | tmp = (int)(inv); 232 | tmp = -1 * tmp; 233 | return tmp - 1; 234 | } 235 | else 236 | return (int)in; 237 | } 238 | // Convert Ffb Calls into FFBSIZE struct 239 | void CALLBACK ForceFeedBack::ffbToVJoy(PVOID data, PVOID userData) noexcept 240 | { 241 | /////// Effect Report 242 | #pragma region Effect Report 243 | #pragma warning( push ) 244 | #pragma warning( disable : 4996 ) 245 | FFB_EFF_CONST Effect; 246 | if (ERROR_SUCCESS == Ffb_h_Eff_Const((FFB_DATA *)data, &Effect)) 247 | { 248 | 249 | }; 250 | #pragma endregion 251 | #pragma region PID Device Control 252 | FFB_CTRL Control; 253 | TCHAR CtrlStr[100]; 254 | if (ERROR_SUCCESS == Ffb_h_DevCtrl((FFB_DATA *)data, &Control) && devCtrl2Str(Control, CtrlStr)) 255 | { 256 | 257 | } 258 | #pragma endregion 259 | #pragma region Effect Operation 260 | FFB_EFF_OP Operation; 261 | TCHAR EffOpStr[100]; 262 | if (ERROR_SUCCESS == Ffb_h_EffOp((FFB_DATA *)data, &Operation) && effectOpStr(Operation.EffectOp, EffOpStr)) 263 | { 264 | 265 | }; 266 | #pragma endregion 267 | #pragma region Global Device Gain 268 | BYTE Gain; 269 | if (ERROR_SUCCESS == Ffb_h_DevGain((FFB_DATA *)data, &Gain)) { 270 | 271 | } 272 | 273 | #pragma endregion 274 | #pragma region Condition 275 | FFB_EFF_COND Condition; 276 | if (ERROR_SUCCESS == Ffb_h_Eff_Cond((FFB_DATA *)data, &Condition)) 277 | { 278 | 279 | } 280 | #pragma endregion 281 | #pragma region Envelope 282 | FFB_EFF_ENVLP Envelope; 283 | if (ERROR_SUCCESS == Ffb_h_Eff_Envlp((FFB_DATA *)data, &Envelope)) 284 | { 285 | 286 | }; 287 | 288 | #pragma endregion 289 | #pragma region Periodic 290 | FFB_EFF_PERIOD EffPrd; 291 | if (ERROR_SUCCESS == Ffb_h_Eff_Period((FFB_DATA *)data, &EffPrd)) 292 | { 293 | _ffbSize.setEffectType("Period"); 294 | _ffbSize.setMagnitude(EffPrd.Magnitude); 295 | _ffbSize.setDirection(Effect.DirX); 296 | _ffbSize.setOffset(twosCompWord2Int(static_cast(EffPrd.Offset))); 297 | _ffbSize.setPeriod(EffPrd.Period); 298 | _ffbSize.setDuration(Effect.Duration); 299 | }; 300 | #pragma endregion 301 | 302 | #pragma region Effect Type 303 | FFBEType EffectType; 304 | if (ERROR_SUCCESS == Ffb_h_EffNew((FFB_DATA *)data, &EffectType)) 305 | { 306 | 307 | }; 308 | 309 | #pragma endregion 310 | 311 | #pragma region Ramp Effect 312 | FFB_EFF_RAMP RampEffect; 313 | if (ERROR_SUCCESS == Ffb_h_Eff_Ramp((FFB_DATA *)data, &RampEffect)) 314 | { 315 | 316 | }; 317 | 318 | #pragma endregion 319 | 320 | #pragma region Constant Effect 321 | FFB_EFF_CONSTANT ConstantEffect; 322 | if (ERROR_SUCCESS == Ffb_h_Eff_Constant((FFB_DATA *)data, &ConstantEffect)) 323 | { 324 | 325 | _ffbSize.setEffectType("Constant"); 326 | _ffbSize.setMagnitude((INT16)ConstantEffect.Magnitude); 327 | _ffbSize.setDirection(polar2Deg(Effect.Direction)); 328 | _ffbSize.setOffset(0); 329 | _ffbSize.setPeriod(0); 330 | _ffbSize.setDuration(Effect.Duration); 331 | }; 332 | #pragma endregion 333 | } -------------------------------------------------------------------------------- /MouseToVJoy/forceFeedBack.h: -------------------------------------------------------------------------------- 1 | #ifndef FORCEFEEDBACK_H 2 | #define FORCEFEEDBACK_H 3 | #include "vjoy.h" 4 | #include "vjoyinterface.h" 5 | #include "input.h" 6 | #include "ffbsize.h" 7 | #include 8 | 9 | /* Basic funtion that gets data, then processes it and modifies inputs.*/ 10 | 11 | class ForceFeedBack{ 12 | public: 13 | // Convert Packet type to String 14 | BOOL packetType2Str(FFBPType Type, LPTSTR OutStr) noexcept; 15 | // Convert Effect type to String 16 | BOOL effectType2Str(FFBEType Type, LPTSTR OutStr) noexcept; 17 | // Convert PID Device Control to String 18 | BOOL devCtrl2Str(FFB_CTRL Ctrl, LPTSTR OutStr) noexcept; 19 | // Convert Effect operation to string 20 | BOOL effectOpStr(FFBOP Op, LPTSTR OutStr) noexcept; 21 | // Polar values (0x00-0xFF) to Degrees (0-360) 22 | int polar2Deg(BYTE Polar) noexcept; 23 | // Convert range 0x00-0xFF to 0%-100% 24 | int byte2Percent(BYTE InByte) noexcept; 25 | // Convert One-Byte 2's complement input to integer 26 | int twosCompByte2Int(BYTE in) noexcept; 27 | // Convert One-Byte 2's complement input to integer 28 | int twosCompWord2Int(WORD in) noexcept; 29 | // Returns private _ffbSize struct 30 | FFBSIZE getFfbSize() { return _ffbSize; }; 31 | // Callback used to get ffb data 32 | void CALLBACK ffbToVJoy(PVOID data, PVOID userData) noexcept; 33 | private: 34 | // Names of effects 35 | LPCTSTR _ffbEffectName[13] = { "NONE", "Constant Force", "Ramp", "Square", "Sine", "Triangle", "Sawtooth Up", 36 | "Sawtooth Down", "Spring", "Damper", "Inertia", "Friction", "Custom Force" }; 37 | // Struct to store ffb data 38 | FFBSIZE _ffbSize; 39 | }; 40 | #endif -------------------------------------------------------------------------------- /MouseToVJoy/input.h: -------------------------------------------------------------------------------- 1 | #ifndef _INPUT_H 2 | #define _INPUT_H 3 | 4 | // This code was built based upon what I learned from an internet site called ToyMaker. 5 | // In my opinion, their site is a great source for most of the basics one needs to know 6 | // to get started in game programming. Mainpage: http://www.toymaker.info/ 7 | 8 | // Yes this is for WINDOWS only. 9 | #include 10 | 11 | // The follwoing enumerations are set to cover related key-ranges from 12 | // A-Z and left, up, right, down. 13 | // Source page: 14 | // http://msdn.microsoft.com/en-us/library/ms645540%28VS.85%29.aspx 15 | 16 | class CInputDevices 17 | { 18 | public: 19 | // The constructor is important. I suppose I could of made a separate function for initalization 20 | // but I am trying to keep a consistent attitude with things. 21 | 22 | 23 | // Only call this once when your Application begins. 24 | // I may be wrong, but I saw nothing from what I read that indicated 25 | // devices need to be unregistered. 26 | 27 | 28 | // Everytime your MsgProc's uMsg is WM_INPUT, you will want to call the GetData function. 29 | // I believe this is smarter than calling it every frame in a game loop. 30 | 31 | void getData(LPARAM lParam, bool touchpad, bool ttouchpad, int kInfo) noexcept; 32 | // This should be self-explanatory. Depending on which function 33 | // you call, you will get true or false about the state of the mouse button. 34 | // The code in the source file may be a bit difficult to follow, 35 | // but I tried my best to make it match what was described as the best way 36 | // to be sure the 37 | 38 | bool isLeftMouseButtonDown() noexcept { return _isLeftMouseButtonPressed; } 39 | bool isMiddleMouseButtonDown() noexcept { return _isMiddleMouseButtonPressed; } 40 | bool isRightMouseButtonDown() noexcept { return _isRightMouseButtonPressed; } 41 | bool isMouseWheelUp() noexcept { return _isMouseWheelUp; } 42 | bool isMouseWheelDown() noexcept { return _isMouseWheelDown; } 43 | 44 | // These functions return values that are relative to the change in position 45 | // of your mouse. 46 | 47 | int getMouseChangeX() noexcept { return _mouseXChange; } 48 | int getMouseChangeY() noexcept { return _mouseYChange; } 49 | int getMouseChangeZ() noexcept { return _mouseZChange; } 50 | int getAbsX() noexcept { return _absX; } 51 | int getAbsY() noexcept { return _absY; } 52 | // OPTIONALLY: 53 | // To obtain exact mouse coords check the uMsg in your Application's MsgProc 54 | // for WM_MOUSEMOVE, and use HIWORD() LOWORD() functions to extract the mouse X,Y 55 | // from lParam. Store them in the below variables. 56 | 57 | int mouseX; 58 | int mouseY; 59 | 60 | // Notice how I use an array of bools rather than having a separate bool for each. 61 | // In the source file you will see how my enumerations come into play for knowing what index 62 | // to access. 63 | bool _isKeyboardButtonPressed[166]; 64 | 65 | // Alphabetic as in any letter from the Alphabet. So IsAlphabeticKeyDown returns 66 | // a value of true or false from an array of 25 booleans. Each index is associated 67 | // with a position in the english alphabet. Use one of the enumerated values 68 | // such as VKey_A and subtract 0x41 or make a different enumeration list 69 | // for all 25 letters and set the first value to 0. 70 | 71 | bool isAlphabeticKeyDown(int letter) noexcept { return _isKeyboardButtonPressed[letter]; } 72 | 73 | private: 74 | // As said on www.toymaker.info the mouse size is 40 and the keyboard 32. 75 | // So it appears as if the buffer will be filled with either or, not both. 76 | // Thus, just 40 bytes. 77 | BYTE _buffer[40] = {0}; 78 | 79 | // Should be obvious what functions return these two values. 80 | int _mouseXChange = 0; 81 | int _mouseYChange = 0; 82 | int _mouseZChange = 0; 83 | int _absX = 0; 84 | int _absY = 0; 85 | 86 | // Again, should be obvious what functions use these. 87 | // LMB = Left Mouse Button. RMB = Right Mouse Button 88 | bool _isLeftMouseButtonPressed = false; 89 | bool _isMiddleMouseButtonPressed = false; 90 | bool _isRightMouseButtonPressed = false; 91 | bool _isMouseWheelUp = false; 92 | bool _isMouseWheelDown = false; 93 | bool _tabletPressed = false; 94 | }; 95 | 96 | #endif -------------------------------------------------------------------------------- /MouseToVJoy/main.cpp: -------------------------------------------------------------------------------- 1 | #define _WINSOCKAPI_ 2 | #define _WINSOCK_DEPRECATED_NO_WARNINGS 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "fileRead.h" 8 | #include "vjoy.h" 9 | #include "mousetovjoy.h" 10 | #include "public.h" 11 | #include "vjoyinterface.h" 12 | #include "input.h" 13 | #include "Stopwatch.h" 14 | #include "forceFeedBack.h" 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | using win32::Stopwatch; 24 | 25 | #define APP_VERSION 3 26 | #define HID_USAGE_DIGITIZER_CONTACT_ID 0x51 27 | #define HID_USAGE_DIGITIZER_CONTACT_COUNT 0x54 28 | 29 | UINT DEV_ID; 30 | HWND hwnd; 31 | WNDCLASSEX wc; 32 | MSG msgWindow; // Intantiating a MSG class, which recives messages from "dummy" window 33 | VJoy vJ; 34 | MouseToVjoy mTV; // Class that gets data, then processes it and modifies axises. 35 | CInputDevices rInput; // Class that helps with determining what key was pressed. 36 | FileRead fR; // Class used for reading and writing to config.txt file. 37 | ForceFeedBack fFB; // Used to recive and interpret ForceFeedback calls from game window. 38 | Stopwatch sw; // Measuring time in nanoseconds 39 | Stopwatch timeout; // Timeout used for connecting and detecting disconnect 40 | Stopwatch setCursor; // Timer used to set the cursor every second 41 | INT axisX, axisY, kaxisZ, kaxisRX, taxisZ, taxisRX, gear, pgear, msg, ffbStrength; 42 | BOOL isButton1Clicked, isButton2Clicked, isButton3Clicked, lisButton1Clicked, lisButton2Clicked, console, ctrlDown, atouchpad, ptouchpad, ttouchpad, lastDown, disconnected, connecting; 43 | std::vector buttons; 44 | BOOL isCursorLocked; 45 | HCURSOR origCursor; // For restore after cursor blank 46 | HCURSOR blankCursor; 47 | POINT cursorPos; 48 | u_long kInfo; 49 | HHOOK hMouseHook; 50 | std::vector tpbtns; 51 | double xpmul, ypmul, btnxsize, btnysize, xstart, ystart; 52 | RECT bounds = { -1, -1, -1, -1 }; // Set from calibration(touchpad) or recieved data(android) 53 | 54 | // Android USB UDP connection 55 | SOCKET udpsocket; 56 | struct sockaddr_in udpaddr; 57 | 58 | // Contact information parsed from the HID report descriptor. 59 | struct contact_info 60 | { 61 | USHORT link; 62 | }; 63 | 64 | // The data for a touch event. 65 | struct contact 66 | { 67 | contact_info info; 68 | ULONG id; 69 | POINT point; 70 | }; 71 | 72 | #pragma pack(1) 73 | struct udptouch { 74 | float x; 75 | float y; 76 | }; 77 | 78 | #pragma pack(1) 79 | struct udptouchpad 80 | { 81 | char count; 82 | udptouch touch[10]; 83 | }; 84 | 85 | #pragma pack(1) 86 | struct udptouchpadinfo 87 | { 88 | uint32_t right; 89 | uint32_t top; 90 | char version; 91 | char device[128]; 92 | } touchinfo; 93 | 94 | // Wrapper for malloc with unique_ptr semantics, to allow 95 | // for variable-sized structures. 96 | struct free_deleter { void operator()(void* ptr) noexcept { free(ptr); } }; 97 | template using malloc_ptr = std::unique_ptr; 98 | 99 | // Device information, such as touch area bounds and HID offsets. 100 | // This can be reused across HID events, so we only have to parse 101 | // this info once. 102 | struct device_info 103 | { 104 | malloc_ptr<_HIDP_PREPARSED_DATA> preparsedData; // HID internal data 105 | USHORT linkContactCount = 0; // Link collection for number of contacts present 106 | std::vector contactInfo; // Link collection and touch area for each contact 107 | }; 108 | 109 | // Caches per-device info for better performance 110 | static std::unordered_map g_devices; 111 | 112 | // Allocates a malloc_ptr with the given size. The size must be 113 | // greater than or equal to sizeof(T). 114 | template 115 | static malloc_ptr 116 | make_malloc(size_t size) noexcept 117 | { 118 | T* ptr = (T*)malloc(size); 119 | if (ptr == nullptr) { 120 | std::terminate(); 121 | } 122 | return malloc_ptr(ptr); 123 | } 124 | //Creating local callback which just executes callback from ForceFeedBack class. 125 | void CALLBACK FFBCALLBACK(PVOID data, PVOID userData) noexcept { 126 | fFB.ffbToVJoy(data, userData); 127 | SendMessage(hwnd, 727, 0, 0); 128 | } 129 | // Mouse disable hook 130 | LRESULT CALLBACK mouseHook(int nCode, WPARAM wParam, LPARAM lParam) noexcept 131 | { 132 | return 1; 133 | } 134 | 135 | LRESULT CALLBACK keyboardHook(int nCode, WPARAM wParam, LPARAM lParam) noexcept { 136 | switch (wParam) 137 | { 138 | case WM_KEYDOWN: 139 | case WM_SYSKEYDOWN: 140 | case WM_KEYUP: 141 | case WM_SYSKEYUP: 142 | if (((int)fR.result(31) != 0 && isCursorLocked) || (int)fR.result(31) == 0) { 143 | PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)(lParam); 144 | USHORT vkCode = MapVirtualKey(p->scanCode, MAPVK_VSC_TO_VK); 145 | if (vkCode == 17 && p->dwExtraInfo != kInfo) { 146 | ctrlDown = (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN); 147 | for (int i = 7; i <= 14; i++) { 148 | if ((rInput.isAlphabeticKeyDown((int)fR.result(i)) && (int)fR.result(i) != 17)) { 149 | if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) { 150 | rInput._isKeyboardButtonPressed[17] = true; 151 | return 1; 152 | } 153 | else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP) { 154 | rInput._isKeyboardButtonPressed[17] = false; 155 | return 1; 156 | } 157 | break; 158 | } 159 | } 160 | } 161 | for (int i = 7; i <= 14; i++) 162 | if ((int)fR.result(i) == vkCode && (int)fR.result(i) != 17 && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && ctrlDown) { 163 | // Set the CTRL key to up and set dwExtraInfo to le funni number so we can ignore it 164 | keybd_event(17, 0, KEYEVENTF_KEYUP, kInfo); 165 | break; 166 | } 167 | break; 168 | } 169 | } 170 | return CallNextHookEx(NULL, nCode, wParam, lParam); 171 | } 172 | BOOL WINAPI exitHandler(DWORD event) noexcept { 173 | if (event == CTRL_CLOSE_EVENT) { 174 | if (isCursorLocked) { 175 | SetSystemCursor(origCursor, 32512); 176 | SetCursorPos(cursorPos.x, cursorPos.y); 177 | isCursorLocked = false; 178 | } 179 | return true; 180 | } 181 | return false; 182 | } 183 | // Reads the raw input header for the given raw input handle. 184 | static RAWINPUTHEADER GetRawInputHeader(HRAWINPUT hInput) noexcept 185 | { 186 | RAWINPUTHEADER hdr; 187 | UINT size = sizeof(hdr); 188 | if (GetRawInputData(hInput, RID_HEADER, &hdr, &size, sizeof(RAWINPUTHEADER)) == (UINT)-1) { 189 | std::terminate(); 190 | } 191 | return hdr; 192 | } 193 | 194 | // Reads the raw input data for the given raw input handle. 195 | static malloc_ptr GetRawInput(HRAWINPUT hInput, RAWINPUTHEADER hdr) noexcept 196 | { 197 | malloc_ptr input = make_malloc(hdr.dwSize); 198 | UINT size = hdr.dwSize; 199 | if (GetRawInputData(hInput, RID_INPUT, input.get(), &size, sizeof(RAWINPUTHEADER)) == (UINT)-1) { 200 | std::terminate(); 201 | } 202 | return input; 203 | } 204 | 205 | // Reads the preparsed HID report descriptor for the device 206 | // that generated the given raw input. 207 | static malloc_ptr<_HIDP_PREPARSED_DATA> GetHidPreparsedData(HANDLE hDevice) noexcept 208 | { 209 | UINT size = 0; 210 | if (GetRawInputDeviceInfoW(hDevice, RIDI_PREPARSEDDATA, nullptr, &size) == (UINT)-1) { 211 | std::terminate(); 212 | } 213 | malloc_ptr<_HIDP_PREPARSED_DATA> preparsedData = make_malloc<_HIDP_PREPARSED_DATA>(size); 214 | if (GetRawInputDeviceInfoW(hDevice, RIDI_PREPARSEDDATA, preparsedData.get(), &size) == (UINT)-1) { 215 | std::terminate(); 216 | } 217 | return preparsedData; 218 | } 219 | 220 | // Returns all input button caps for the given preparsed 221 | // HID report descriptor. 222 | static std::vector GetHidInputButtonCaps(PHIDP_PREPARSED_DATA preparsedData) noexcept 223 | { 224 | NTSTATUS status; 225 | HIDP_CAPS caps; 226 | status = HidP_GetCaps(preparsedData, &caps); 227 | if (status != HIDP_STATUS_SUCCESS) { 228 | std::terminate(); 229 | } 230 | USHORT numCaps = caps.NumberInputButtonCaps; 231 | std::vector buttonCaps(numCaps); 232 | status = HidP_GetButtonCaps(HidP_Input, &buttonCaps[0], &numCaps, preparsedData); 233 | if (status != HIDP_STATUS_SUCCESS) { 234 | std::terminate(); 235 | } 236 | buttonCaps.resize(numCaps); 237 | return buttonCaps; 238 | } 239 | 240 | // Returns all input value caps for the given preparsed 241 | // HID report descriptor. 242 | static std::vector GetHidInputValueCaps(PHIDP_PREPARSED_DATA preparsedData) noexcept 243 | { 244 | NTSTATUS status; 245 | HIDP_CAPS caps; 246 | status = HidP_GetCaps(preparsedData, &caps); 247 | if (status != HIDP_STATUS_SUCCESS) { 248 | std::terminate(); 249 | } 250 | USHORT numCaps = caps.NumberInputValueCaps; 251 | std::vector valueCaps(numCaps); 252 | status = HidP_GetValueCaps(HidP_Input, &valueCaps[0], &numCaps, preparsedData); 253 | if (status != HIDP_STATUS_SUCCESS) { 254 | std::terminate(); 255 | } 256 | valueCaps.resize(numCaps); 257 | return valueCaps; 258 | } 259 | 260 | // Reads the pressed status of a single HID report button. 261 | static bool GetHidUsageButton( 262 | HIDP_REPORT_TYPE reportType, 263 | USAGE usagePage, 264 | USHORT linkCollection, 265 | USAGE usage, 266 | PHIDP_PREPARSED_DATA preparsedData, 267 | PBYTE report, 268 | ULONG reportLen) noexcept 269 | { 270 | ULONG numUsages = HidP_MaxUsageListLength( 271 | reportType, 272 | usagePage, 273 | preparsedData); 274 | std::vector usages(numUsages); 275 | NTSTATUS status = HidP_GetUsages( 276 | reportType, 277 | usagePage, 278 | linkCollection, 279 | &usages[0], 280 | &numUsages, 281 | preparsedData, 282 | (PCHAR)report, 283 | reportLen); 284 | if (status != HIDP_STATUS_SUCCESS) { 285 | std::terminate(); 286 | } 287 | usages.resize(numUsages); 288 | return std::find(usages.begin(), usages.end(), usage) != usages.end(); 289 | } 290 | 291 | // Reads a single HID report value in logical units. 292 | static ULONG GetHidUsageLogicalValue( 293 | HIDP_REPORT_TYPE reportType, 294 | USAGE usagePage, 295 | USHORT linkCollection, 296 | USAGE usage, 297 | PHIDP_PREPARSED_DATA preparsedData, 298 | PBYTE report, 299 | ULONG reportLen) noexcept 300 | { 301 | ULONG value; 302 | NTSTATUS status = HidP_GetUsageValue( 303 | reportType, 304 | usagePage, 305 | linkCollection, 306 | usage, 307 | &value, 308 | preparsedData, 309 | (PCHAR)report, 310 | reportLen); 311 | if (status != HIDP_STATUS_SUCCESS) { 312 | std::terminate(); 313 | } 314 | return value; 315 | } 316 | 317 | // Reads a single HID report value in physical units. 318 | static LONG GetHidUsagePhysicalValue( 319 | HIDP_REPORT_TYPE reportType, 320 | USAGE usagePage, 321 | USHORT linkCollection, 322 | USAGE usage, 323 | PHIDP_PREPARSED_DATA preparsedData, 324 | PBYTE report, 325 | ULONG reportLen) noexcept 326 | { 327 | LONG value; 328 | NTSTATUS status = HidP_GetScaledUsageValue( 329 | reportType, 330 | usagePage, 331 | linkCollection, 332 | usage, 333 | &value, 334 | preparsedData, 335 | (PCHAR)report, 336 | reportLen); 337 | if (status != HIDP_STATUS_SUCCESS) { 338 | return -1; 339 | } 340 | return value; 341 | } 342 | 343 | // Gets the device info associated with the given raw input. Uses the 344 | // cached info if available; otherwise parses the HID report descriptor 345 | // and stores it into the cache. 346 | static device_info& GetDeviceInfo(HANDLE hDevice) noexcept 347 | { 348 | if (g_devices.count(hDevice)) { 349 | return g_devices.at(hDevice); 350 | } 351 | 352 | device_info dev; 353 | std::optional linkContactCount; 354 | dev.preparsedData = GetHidPreparsedData(hDevice); 355 | 356 | // Struct to hold our parser state 357 | struct contact_info_tmp 358 | { 359 | bool hasContactID = false; 360 | bool hasTip = false; 361 | bool hasX = false; 362 | bool hasY = false; 363 | }; 364 | std::unordered_map contacts; 365 | 366 | // Get the touch area for all the contacts. Also make sure that each one 367 | // is actually a contact, as specified by: 368 | // https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-precision-touchpad-required-hid-top-level-collections 369 | for (const HIDP_VALUE_CAPS& cap : GetHidInputValueCaps(dev.preparsedData.get())) { 370 | if (cap.IsRange || !cap.IsAbsolute) { 371 | continue; 372 | } 373 | 374 | if (cap.UsagePage == HID_USAGE_PAGE_GENERIC) { 375 | if (cap.NotRange.Usage == HID_USAGE_GENERIC_X) { 376 | contacts[cap.LinkCollection].hasX = true; 377 | } 378 | else if (cap.NotRange.Usage == HID_USAGE_GENERIC_Y) { 379 | contacts[cap.LinkCollection].hasY = true; 380 | } 381 | } 382 | else if (cap.UsagePage == HID_USAGE_PAGE_DIGITIZER) { 383 | if (cap.NotRange.Usage == HID_USAGE_DIGITIZER_CONTACT_COUNT) { 384 | linkContactCount = cap.LinkCollection; 385 | } 386 | else if (cap.NotRange.Usage == HID_USAGE_DIGITIZER_CONTACT_ID) { 387 | contacts[cap.LinkCollection].hasContactID = true; 388 | } 389 | } 390 | } 391 | 392 | for (const HIDP_BUTTON_CAPS& cap : GetHidInputButtonCaps(dev.preparsedData.get())) { 393 | if (cap.UsagePage == HID_USAGE_PAGE_DIGITIZER) { 394 | if (cap.NotRange.Usage == HID_USAGE_DIGITIZER_TIP_SWITCH) { 395 | contacts[cap.LinkCollection].hasTip = true; 396 | } 397 | } 398 | } 399 | 400 | if (!linkContactCount.has_value()) { 401 | std::terminate(); 402 | } 403 | dev.linkContactCount = linkContactCount.value(); 404 | 405 | for (const auto& kvp : contacts) { 406 | USHORT link = kvp.first; 407 | const contact_info_tmp& info = kvp.second; 408 | if (info.hasContactID && info.hasTip && info.hasX && info.hasY) { 409 | dev.contactInfo.push_back({ link }); 410 | } 411 | } 412 | 413 | return g_devices[hDevice] = std::move(dev); 414 | } 415 | 416 | // Reads all touch contact points from a raw input event. 417 | static std::vector GetContacts(device_info& dev, RAWINPUT* input) noexcept 418 | { 419 | std::vector contacts; 420 | 421 | DWORD sizeHid = input->data.hid.dwSizeHid; 422 | DWORD count = input->data.hid.dwCount; 423 | BYTE* rawData = input->data.hid.bRawData; 424 | if (count == 0) { 425 | return contacts; 426 | } 427 | 428 | ULONG numContacts = GetHidUsageLogicalValue( 429 | HidP_Input, 430 | HID_USAGE_PAGE_DIGITIZER, 431 | dev.linkContactCount, 432 | HID_USAGE_DIGITIZER_CONTACT_COUNT, 433 | dev.preparsedData.get(), 434 | rawData, 435 | sizeHid); 436 | 437 | if (numContacts > dev.contactInfo.size()) { 438 | numContacts = (ULONG)dev.contactInfo.size(); 439 | } 440 | 441 | // It's a little ambiguous as to whether contact count includes 442 | // released contacts. I interpreted the specs as a yes, but this 443 | // may require additional testing. 444 | for (ULONG i = 0; i < numContacts; ++i) { 445 | contact_info& info = dev.contactInfo[i]; 446 | bool tip = GetHidUsageButton( 447 | HidP_Input, 448 | HID_USAGE_PAGE_DIGITIZER, 449 | info.link, 450 | HID_USAGE_DIGITIZER_TIP_SWITCH, 451 | dev.preparsedData.get(), 452 | rawData, 453 | sizeHid); 454 | 455 | if (!tip) { 456 | continue; 457 | } 458 | 459 | ULONG id = GetHidUsageLogicalValue( 460 | HidP_Input, 461 | HID_USAGE_PAGE_DIGITIZER, 462 | info.link, 463 | HID_USAGE_DIGITIZER_CONTACT_ID, 464 | dev.preparsedData.get(), 465 | rawData, 466 | sizeHid); 467 | 468 | LONG x = GetHidUsagePhysicalValue( 469 | HidP_Input, 470 | HID_USAGE_PAGE_GENERIC, 471 | info.link, 472 | HID_USAGE_GENERIC_X, 473 | dev.preparsedData.get(), 474 | rawData, 475 | sizeHid); 476 | 477 | LONG y = GetHidUsagePhysicalValue( 478 | HidP_Input, 479 | HID_USAGE_PAGE_GENERIC, 480 | info.link, 481 | HID_USAGE_GENERIC_Y, 482 | dev.preparsedData.get(), 483 | rawData, 484 | sizeHid); 485 | 486 | if (x != -1 && y != -1) 487 | contacts.push_back({ info, id, { x, y } }); 488 | } 489 | 490 | return contacts; 491 | } 492 | 493 | BOOL HasPrecisionTouchpad() noexcept { 494 | std::vector devices(64); 495 | 496 | while (true) { 497 | UINT numDevices = (UINT)devices.size(); 498 | UINT ret = GetRawInputDeviceList(&devices[0], &numDevices, sizeof(RAWINPUTDEVICELIST)); 499 | if (ret != (UINT)-1) { 500 | devices.resize(ret); 501 | break; 502 | } 503 | else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { 504 | devices.resize(numDevices); 505 | } 506 | else { 507 | return false; 508 | } 509 | } 510 | 511 | for (RAWINPUTDEVICELIST dev : devices) { 512 | RID_DEVICE_INFO info; 513 | info.cbSize = sizeof(RID_DEVICE_INFO); 514 | UINT size = sizeof(RID_DEVICE_INFO); 515 | if (GetRawInputDeviceInfoW(dev.hDevice, RIDI_DEVICEINFO, &info, &size) == (UINT)-1) { 516 | continue; 517 | } 518 | if (info.dwType == RIM_TYPEHID && 519 | info.hid.usUsagePage == HID_USAGE_PAGE_DIGITIZER && 520 | info.hid.usUsage == HID_USAGE_DIGITIZER_TOUCH_PAD) { 521 | device_info& iinfo = GetDeviceInfo(dev.hDevice); 522 | if (!iinfo.contactInfo.empty()) { 523 | return true; 524 | } 525 | else 526 | break; 527 | } 528 | } 529 | return false; 530 | } 531 | 532 | void HandleTouchpad(std::vector contacts) noexcept { 533 | int b; 534 | double _axisZ, _axisRX, x, y; 535 | 536 | taxisRX = 0; 537 | taxisZ = 0; 538 | 539 | buttons.clear(); 540 | 541 | for (const contact& contact : contacts) { 542 | x = ((double)contact.point.x - bounds.left) / ((double)bounds.right - bounds.left); 543 | y = ((double)contact.point.y - bounds.top) / ((double)bounds.bottom - bounds.top); 544 | 545 | b = 14 + ((1 + (int)floor(contact.point.x / btnxsize)) * (1 + (int)floor(contact.point.y / btnysize))); 546 | 547 | if (!tpbtns.empty()) { 548 | if ((std::find(tpbtns.begin(), tpbtns.end(), (double)b) != tpbtns.end() || tpbtns.at(0) == (double)1) && tpbtns.at(0) != (double)0) { 549 | buttons.push_back(b - 1); 550 | continue; 551 | } 552 | } 553 | 554 | _axisZ = ((INT)round((((int)fR.result(25) ? 1 - x : x) * xpmul) * 32767) - (32767 * xstart)) / (1 - xstart); 555 | _axisRX = ((INT)round((((int)fR.result(26) ? 1 - y : y) * ypmul) * 32767) - (32767 * ystart)) / (1 - ystart); 556 | 557 | if ((_axisRX > _axisZ && _axisRX > taxisRX && (int)fR.result(41) != 1) || (int)fR.result(41) == 2) 558 | taxisRX = (int)_axisRX; 559 | 560 | if ((_axisRX < _axisZ && _axisZ > taxisZ && (int)fR.result(41) != 2) || (int)fR.result(41) == 1) 561 | taxisZ = (int)_axisZ; 562 | } 563 | } 564 | 565 | void WriteCalibration() { 566 | std::ofstream calib; 567 | calib.open("tpcalib.dat"); 568 | calib << bounds.left << std::endl; 569 | calib << bounds.right << std::endl; 570 | calib << bounds.top << std::endl; 571 | calib << bounds.bottom << std::endl; 572 | calib.close(); 573 | } 574 | 575 | void ReadCalibration() noexcept { 576 | try { 577 | int i = 0; 578 | std::ifstream input("tpcalib.dat"); 579 | if (input.good()) { 580 | for (std::string line; std::getline(input, line); ) 581 | { 582 | switch (i) { 583 | case 0: 584 | bounds.left = std::stol(line.c_str()); 585 | break; 586 | case 1: 587 | bounds.right = std::stol(line.c_str()); 588 | break; 589 | case 2: 590 | bounds.top = std::stol(line.c_str()); 591 | break; 592 | case 3: 593 | bounds.bottom = std::stol(line.c_str()); 594 | break; 595 | } 596 | i++; 597 | } 598 | printf("Loaded calibration %ld %ld %ld %ld\n", bounds.left, bounds.right, bounds.top, bounds.bottom); 599 | } 600 | else { 601 | printf("Calibrate touchpad by touching each corner\n"); 602 | } 603 | } catch (...) { 604 | printf("Failed to read calibration\n"); 605 | } 606 | } 607 | 608 | void HandleCalibration(LONG x, LONG y) noexcept { 609 | try { 610 | if (x < bounds.left || bounds.left == -1) { 611 | bounds.left = x; 612 | WriteCalibration(); 613 | } 614 | if (x > bounds.right || bounds.right == -1) { 615 | bounds.right = x; 616 | WriteCalibration(); 617 | } 618 | if (y < bounds.top || bounds.top == -1) { 619 | bounds.top = y; 620 | WriteCalibration(); 621 | } 622 | if (y > bounds.bottom || bounds.bottom == -1) { 623 | bounds.bottom = y; 624 | WriteCalibration(); 625 | } 626 | } 627 | catch (...) { 628 | printf("Failed to write calibration\n"); 629 | } 630 | } 631 | 632 | // Locate USB tethering touchpad and connect to it 633 | void TouchpadConnect() noexcept { 634 | /* Declare and initialize variables */ 635 | DWORD dwRetVal = 0; 636 | 637 | // Set the flags to pass to GetAdaptersAddresses 638 | ULONG flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS; 639 | 640 | // default to unspecified address family (both) 641 | ULONG family = AF_UNSPEC; 642 | 643 | PIP_ADAPTER_ADDRESSES pAddresses = NULL; 644 | ULONG outBufLen = 0; 645 | ULONG Iterations = 0; 646 | 647 | PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; 648 | bool found = false; 649 | WSADATA wsaData; 650 | 651 | // Allocate a 15 KB buffer to start with. 652 | outBufLen = 15000; 653 | 654 | if (udpsocket) 655 | closesocket(udpsocket); 656 | 657 | // init sockets 658 | if (WSAStartup(MAKEWORD(2, 2), &wsaData) < 0) 659 | printf("WsaStartup error"); 660 | if ((udpsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) 661 | printf("Creating socket failed"); 662 | 663 | memset(&udpaddr, 0, sizeof(udpaddr)); 664 | udpaddr.sin_family = AF_INET; 665 | udpaddr.sin_port = htons(7270); // touchpad app socket 666 | 667 | // latency fix 668 | u_long a = 0; 669 | setsockopt(udpsocket, SOL_SOCKET, SO_RCVBUF, (const char*)&a, sizeof(int)); 670 | 671 | // 100ms timeout 672 | a = 100; 673 | setsockopt(udpsocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&a, sizeof(int)); 674 | 675 | // enable non blocking 676 | a = 1; 677 | ioctlsocket(udpsocket, FIONBIO, &a); 678 | 679 | do { 680 | pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen); 681 | if (pAddresses == NULL) { 682 | printf("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n"); 683 | exit(1); 684 | } 685 | 686 | dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen); 687 | 688 | if (dwRetVal == ERROR_BUFFER_OVERFLOW) { 689 | free(pAddresses); 690 | pAddresses = NULL; 691 | } 692 | else 693 | break; 694 | 695 | Iterations++; 696 | } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < 3)); 697 | 698 | 699 | // If successful, output some information from the data we received 700 | pCurrAddresses = pAddresses; 701 | while (pCurrAddresses) { 702 | PIP_ADAPTER_GATEWAY_ADDRESS pGatewayAddress = pCurrAddresses->FirstGatewayAddress; 703 | if (pGatewayAddress && wcsstr(pCurrAddresses->Description, L"Remote NDIS based Internet Sharing Device")) { 704 | udpaddr.sin_addr = ((sockaddr_in*)pGatewayAddress->Address.lpSockaddr)->sin_addr; 705 | 706 | found = true; 707 | } 708 | pCurrAddresses = pCurrAddresses->Next; 709 | } 710 | 711 | if (!found) { 712 | if (msg != 1) { 713 | printf("Failed to detect device. Is it plugged in with USB Tethering enabled?\n"); 714 | msg = 1; 715 | } 716 | timeout.stop(); 717 | timeout.start(); 718 | goto free; 719 | } 720 | 721 | WSAAsyncSelect(udpsocket, hwnd, 7272, FD_READ); 722 | timeout.stop(); 723 | timeout.start(); 724 | connecting = true; 725 | 726 | const char b = (int)fR.result(33); 727 | sendto(udpsocket, &b, 1, 0, (const struct sockaddr*)&udpaddr, sizeof(struct sockaddr_in)); 728 | // the response is recieved in updateNetwork() 729 | 730 | free: 731 | if (pAddresses) { 732 | free(pAddresses); 733 | } 734 | } 735 | //Code that is run once application is initialized, test virtual joystick and accuires it, also it reads config.txt file and prints out menu and variables. 736 | void initializationCode() noexcept { 737 | string configFileName = "config.txt"; 738 | //what strings to look for in config file. 739 | string checkArray[CHECK_LENGTH] = { "Sensitivity", "AttackTimeThrottle", "ReleaseTimeThrottle", "AttackTimeBrake", "ReleaseTimeBrake", "AttackTimeClutch", "ReleaseTimeClutch", "ThrottleKey", "BrakeKey", "ClutchKey", "GearShiftUpKey", "GearShiftDownKey", "HandBrakeKey", "MouseLockKey", "MouseCenterKey", "UseMouse","UseCenterReduction" , "AccelerationThrottle", "AccelerationBrake", "AccelerationClutch", "CenterMultiplier", "UseForceFeedback", "UseWheelAsShifter", "UseWheelAsThrottle", "Touchpad", "TouchpadXInvert", "TouchpadYInvert", "TouchpadXPercent", "TouchpadYPercent", "TouchpadXStartPercent", "TouchpadYStartPercent", "RequireLocked", "ForceFeedbackKey", "TouchpadApp", "TouchpadButtonsH", "TouchpadButtonsV", "TouchpadButtons", "WheelThrottleMiddle", "MouseHook", "VJoyID", "TouchpadTablet", "TouchpadAxisDisable", "DisableKeys", "RequireClutch"}; 740 | try { 741 | fR.newFile(configFileName, checkArray);//read configFileName and look for checkArray 742 | } 743 | catch (...) { 744 | printf("Failed to open config.txt\n"); 745 | } 746 | SetConsoleCtrlHandler((PHANDLER_ROUTINE)(exitHandler), TRUE);//Set the exit handler 747 | 748 | //Code that is run only once, tests vjoy device, reads config file and prints basic out accuired vars. 749 | DEV_ID = (UINT)(fR.result(39) >= 1 ? fR.result(39) : 1); 750 | vJ.testDriver();//Test if driver is installed and compatible. 751 | //Test if virtually created joystick is up and running. 752 | if (vJ.testVirtualDevices(DEV_ID)) { 753 | if (console) 754 | system("pause"); 755 | exit(EXIT_FAILURE); 756 | } 757 | vJ.accuireDevice(DEV_ID);//Accuire virtual joystick of index number DEV_ID 758 | 759 | int maxbtn = 14; 760 | std::string split; 761 | std::istringstream ss(fR._resultArrayStr[36]); 762 | while (std::getline(ss, split, ',')) 763 | tpbtns.push_back(atof(split.c_str())); 764 | if (!tpbtns.empty()) 765 | maxbtn = max((int)*max_element(tpbtns.begin(), tpbtns.end()), 12); 766 | 767 | if (GetVJDButtonNumber(DEV_ID) < maxbtn) { 768 | printf("Not enough vJoy buttons. Increase Number of Buttons to %d in Configure vJoy\n", maxbtn); 769 | if (console) 770 | system("pause"); 771 | exit(EXIT_FAILURE); 772 | } 773 | 774 | if ((int)fR.result(21)) { 775 | vJ.enableFFB(DEV_ID);//Enable virtual joystick of index number DEV_ID to accept forcefeedback calls 776 | FfbRegisterGenCB(FFBCALLBACK, &DEV_ID);//Registed what function to run on forcefeedback call. 777 | } 778 | for (int i = 7; i <= 14; i++) 779 | if ((int)fR.result(i) == 17) { 780 | printf("Using global keyboard hook to disable Assetto Corsa keyboard shortcuts\n"); 781 | kInfo = rand(); 782 | SetWindowsHookEx(WH_KEYBOARD_LL, keyboardHook, wc.hInstance, 0); 783 | break; 784 | } 785 | if (HasPrecisionTouchpad() && (int)fR.result(24)) { 786 | printf("Found precision touchpad, using it for axis Z and RX\n"); 787 | ReadCalibration(); 788 | ptouchpad = true; 789 | printf("Make sure your touchpad is set to disabled while mouse connected so it doesn't interfere with mouse input\n"); 790 | } 791 | else if ((int)fR.result(24)) { 792 | printf("Could not find precision touchpad\n"); 793 | } 794 | else { 795 | printf("Precision touchpad disabled\n"); 796 | } 797 | if ((int)fR.result(40) && !ptouchpad) { 798 | bounds.top = 0; 799 | bounds.bottom = 65535; 800 | bounds.right = 0; 801 | bounds.left = 65535; 802 | ttouchpad = true; 803 | } 804 | 805 | xstart = (double)fR.result(29) / 100; 806 | ystart = (double)fR.result(30) / 100; 807 | xpmul = 1 / ((INT)fR.result(27) == 0 ? 1 : fR.result(27) / 100); 808 | ypmul = 1 / ((INT)fR.result(28) == 0 ? 1 : fR.result(28) / 100); 809 | setCursor.start(); 810 | 811 | //Printing basic menu with assigned values 812 | printf("==================================\n"); 813 | printf("Sensitivity = %.2f \n", fR.result(0)); 814 | printf("Throttle Attack Time = %.0f \n", fR.result(1)); 815 | printf("Throttle Release Time = %.0f \n", fR.result(2)); 816 | printf("Brake Attack Time = %.0f \n", fR.result(3)); 817 | printf("Brake Release Time = %.0f \n", fR.result(4)); 818 | printf("Clutch Attack Time = %.0f \n", fR.result(5)); 819 | printf("Clutch Release Time = %.0f \n", fR.result(6)); 820 | printf("Throttle key = %d \n", (int)fR.result(7)); 821 | printf("Brake key = %d \n", (int)fR.result(8)); 822 | printf("Clutch key = %d \n", (int)fR.result(9)); 823 | printf("Gear Shift Up key = %d \n", (int)fR.result(10)); 824 | printf("Gear Shift Down key = %d \n", (int)fR.result(11)); 825 | printf("Hand Brake Key = %d \n", (int)fR.result(12)); 826 | printf("Mouse Lock key = %d \n", (int)fR.result(13)); 827 | printf("Mouse Center key = %d \n", (int)fR.result(14)); 828 | printf("Required Locked = %d \n", (int)fR.result(31)); 829 | printf("Use Mouse = %d \n", (int)fR.result(15)); 830 | printf("Use Center Reduction = %d \n", (int)fR.result(16)); 831 | printf("Use Force Feedback = %d \n", (int)fR.result(21)); 832 | printf("Force Feedback Key = %d \n", (int)fR.result(32)); 833 | printf("Use Mouse Wheel As Shifter = %d \n", (int)fR.result(22)); 834 | printf("Use Mouse Wheel As Throttle = %d \n", (int)fR.result(23)); 835 | printf("Wheel Throttle Middle = %d \n", (int)fR.result(37)); 836 | printf("Acceleration Throttle = %.2f \n", fR.result(17)); 837 | printf("Acceleration Brake = %.2f \n", fR.result(18)); 838 | printf("Acceleration Clutch = %.2f \n", fR.result(19)); 839 | printf("Center Multiplier = %.2f \n", fR.result(20)); 840 | printf("Disable Keys = %d \n", (int)fR.result(42)); 841 | printf("Require clutch = %d \n", (int)fR.result(43)); 842 | printf("Touchpad X Invert = %d \n", (INT)fR.result(25)); 843 | printf("Touchpad Y Invert = %d \n", (INT)fR.result(26)); 844 | printf("Touchpad X Start = %d \n", (INT)fR.result(29)); 845 | printf("Touchpad Y Start = %d \n", (INT)fR.result(30)); 846 | printf("Touchpad X Percent = %.0f \n", (1 / xpmul) * 100); 847 | printf("Touchpad Y Percent = %.0f \n", (1 / ypmul) * 100); 848 | printf("Touchpad H Buttons = %d \n", (INT)fR.result(34)); 849 | printf("Touchpad V Buttons = %d \n", (INT)fR.result(35)); 850 | printf("Touchpad Buttons = %s \n", fR._resultArrayStr[36].c_str()); 851 | printf("Touchpad Axis Disable = %d \n", (int)fR.result(41)); 852 | printf("Touchpad App = %d \n", (int)fR.result(33)); 853 | printf("Touchpad Tablet = %d \n", (int)fR.result(40)); 854 | printf("==================================\n"); 855 | SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); 856 | 857 | SetTimer(hwnd, 727, USER_TIMER_MINIMUM, (TIMERPROC)NULL); 858 | 859 | if (fR.result(33) && !ptouchpad && !ttouchpad) { 860 | disconnected = true; 861 | timeout.start(); 862 | TouchpadConnect(); 863 | } 864 | } 865 | 866 | void updateNetwork(bool enabled) noexcept { 867 | udptouchpad udptouches; 868 | std::vector contacts; 869 | if (atouchpad) { 870 | // validate size to avoid broken data 871 | int recvs = recv(udpsocket, (char*)&udptouches, sizeof(udptouchpad), 0); 872 | if (recvs == sizeof(udptouchpad) || recvs == 1) { 873 | timeout.stop(); 874 | timeout.start(); 875 | 876 | if (udptouches.count >= 0) { 877 | for (int i = 0; i < udptouches.count; i++) 878 | { 879 | contact tcontact = { }; 880 | 881 | tcontact.point.x = (long)udptouches.touch[i].y; 882 | tcontact.point.y = (long)udptouches.touch[i].x; 883 | contacts.push_back(tcontact); 884 | } 885 | HandleTouchpad(contacts); 886 | } 887 | else if (udptouches.count == -2) { 888 | if (udptouches.touch[0].x == 1) 889 | buttons.push_back(12); 890 | else if (udptouches.touch[0].x == 2) 891 | buttons.push_back(13); 892 | else if (udptouches.touch[0].x >= 3) 893 | buttons.erase(std::remove(buttons.begin(), buttons.end(), 9 + udptouches.touch[0].x), buttons.end()); 894 | } else 895 | return; // ping packet so do nothing 896 | } 897 | } 898 | else if (!atouchpad && disconnected) { 899 | touchinfo = {}; 900 | if (recv(udpsocket, (char*)&touchinfo, sizeof(udptouchpadinfo), 0) == 136) { 901 | printf("Connected to %s\n", touchinfo.device); 902 | if (touchinfo.version == APP_VERSION) { 903 | bounds.top = touchinfo.top; 904 | bounds.bottom = 0; 905 | bounds.right = touchinfo.right; 906 | bounds.left = 0; 907 | 908 | timeout.stop(); 909 | timeout.start(); 910 | 911 | btnxsize = ((double)bounds.right - bounds.left) / max((INT)fR.result(34), 1); 912 | btnysize = ((double)bounds.top - bounds.bottom) / max((INT)fR.result(35), 1); 913 | taxisZ = 0; 914 | taxisRX = 0; 915 | kaxisZ = 0; 916 | kaxisRX = 0; 917 | atouchpad = true; 918 | msg = 0; 919 | disconnected = false; 920 | connecting = false; 921 | } 922 | else { 923 | if (msg != 3) { 924 | printf("App protocol version %d mismatch client %d\n", touchinfo.version, APP_VERSION); 925 | msg = 3; 926 | } 927 | } 928 | } 929 | } 930 | if (enabled) 931 | vJ.feedDevice(DEV_ID, axisX, axisY, max(kaxisZ, taxisZ), max(kaxisRX, taxisRX), gear, isButton1Clicked, isButton2Clicked, isButton3Clicked, buttons); 932 | } 933 | 934 | void updateCode(bool enabled) noexcept { 935 | if (fR.result(33) && !ptouchpad && !ttouchpad && (timeout.elapsedMilliseconds() > 6000 || disconnected && !connecting && timeout.elapsedMilliseconds() > 500 || connecting && timeout.elapsedMilliseconds() > 100)) { 936 | if (connecting && timeout.elapsedMilliseconds() > 100) { 937 | if (msg != 2) { 938 | printf("Failed to connect to app. Is the touchpad app running?\n"); 939 | msg = 2; 940 | } 941 | connecting = false; 942 | timeout.stop(); 943 | timeout.start(); 944 | } 945 | if (!disconnected) { 946 | disconnected = true; 947 | taxisZ = 0; 948 | taxisRX = 0; 949 | atouchpad = false; 950 | } 951 | TouchpadConnect(); 952 | } 953 | 954 | if (enabled) { 955 | if ((((int)fR.result(32) != 0 && rInput.isAlphabeticKeyDown((int)fR.result(32))) || (int)fR.result(32) == 0) && fR.result(21) == 1) { 956 | if (fFB.getFfbSize().getEffectType() == "Constant") { 957 | if (fFB.getFfbSize().getDirection() > 100) 958 | ffbStrength = (int)((fFB.getFfbSize().getMagnitude()) * (sw.elapsedMilliseconds() * 0.001)); 959 | else 960 | ffbStrength = (int)(-(fFB.getFfbSize().getMagnitude()) * (sw.elapsedMilliseconds() * 0.001)); 961 | } 962 | if (fFB.getFfbSize().getEffectType() == "Period") 963 | ffbStrength = (int)((fFB.getFfbSize().getOffset() * 0.5) * (sw.elapsedMilliseconds() * 0.001)); 964 | 965 | axisX += ffbStrength; 966 | ffbStrength = 0; 967 | } 968 | 969 | bool clutchin = min((double)fR.result(43) / 100, 100) * 32767 <= max(kaxisRX, taxisRX); 970 | if (rInput.isAlphabeticKeyDown((int)fR.result(10)) && !lisButton1Clicked && gear < 7) { 971 | lisButton1Clicked = true; 972 | if (clutchin) 973 | gear++; 974 | } 975 | else 976 | lisButton1Clicked = rInput.isAlphabeticKeyDown((int)fR.result(10)); 977 | if (rInput.isAlphabeticKeyDown((int)fR.result(11)) && !lisButton2Clicked && gear > -1) { 978 | lisButton2Clicked = true; 979 | if (clutchin) 980 | gear--; 981 | } 982 | else 983 | lisButton2Clicked = rInput.isAlphabeticKeyDown((int)fR.result(11)); 984 | mTV.inputLogic(rInput, axisX, axisY, kaxisZ, kaxisRX, isButton1Clicked, isButton2Clicked, isButton3Clicked, fR.result(1), fR.result(2), fR.result(3), fR.result(4), fR.result(5), fR.result(6), (int)fR.result(7), (int)fR.result(8), (int)fR.result(9), (int)fR.result(10), (int)fR.result(11), (int)fR.result(12), (int)fR.result(14), (int)fR.result(15), fR.result(17), fR.result(18), fR.result(19), ((int)fR.result(22) && !(int)fR.result(23)) || (!(int)fR.result(22) && !(int)fR.result(23)), atouchpad || ptouchpad || ttouchpad, (int)fR.result(41), (int)fR.result(42), sw.elapsedMilliseconds()); 985 | vJ.feedDevice(DEV_ID, axisX, axisY, max(kaxisZ, taxisZ), max(kaxisRX, taxisRX), gear, isButton1Clicked, isButton2Clicked, isButton3Clicked, buttons); 986 | } 987 | sw.stop(); 988 | sw.start(); 989 | } 990 | 991 | BOOL HandlePrecisionTouchpad(LPARAM* lParam, bool enabled) noexcept { 992 | HRAWINPUT hInput = (HRAWINPUT)*lParam; 993 | RAWINPUTHEADER hdr = GetRawInputHeader(hInput); 994 | if (hdr.dwType != RIM_TYPEHID) 995 | return false; 996 | device_info& dev = GetDeviceInfo(hdr.hDevice); 997 | malloc_ptr input = GetRawInput(hInput, hdr); 998 | std::vector contacts = GetContacts(dev, input.get()); 999 | 1000 | for (const contact& contact : contacts) { 1001 | HandleCalibration(contact.point.x, contact.point.y); 1002 | } 1003 | 1004 | HandleTouchpad(contacts); 1005 | 1006 | if (enabled) 1007 | vJ.feedDevice(DEV_ID, axisX, axisY, max(kaxisZ, taxisZ), max(kaxisRX, taxisRX), gear, isButton1Clicked, isButton2Clicked, isButton3Clicked, buttons); 1008 | 1009 | return true; 1010 | } 1011 | 1012 | BOOL HandleTabletTouchpad(bool enabled) noexcept { 1013 | std::vector contacts; 1014 | contact tcontact = { }; 1015 | 1016 | tcontact.point.x = (long)rInput.getAbsX(); 1017 | tcontact.point.y = (long)rInput.getAbsY(); 1018 | contacts.push_back(tcontact); 1019 | 1020 | HandleTouchpad(contacts); 1021 | if (enabled) 1022 | vJ.feedDevice(DEV_ID, axisX, axisY, max(kaxisZ, taxisZ), max(kaxisRX, taxisRX), gear, isButton1Clicked, isButton2Clicked, isButton3Clicked, buttons); 1023 | 1024 | return true; 1025 | } 1026 | //Creates callback on window, registers raw input devices and processes mouse and keyboard input 1027 | LRESULT CALLBACK WndProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam) noexcept 1028 | { 1029 | bool enabled = ((int)fR.result(31) != 0 && isCursorLocked) || (int)fR.result(31) == 0; 1030 | 1031 | switch (Msg) 1032 | { 1033 | case WM_CREATE: 1034 | //Creating new raw input devices 1035 | RAWINPUTDEVICE m_Rid[3]; 1036 | //Keyboard 1037 | m_Rid[0].usUsagePage = 1; 1038 | m_Rid[0].usUsage = 6; 1039 | m_Rid[0].dwFlags = RIDEV_INPUTSINK; 1040 | m_Rid[0].hwndTarget = hwnd; 1041 | //Mouse 1042 | m_Rid[1].usUsagePage = 1; 1043 | m_Rid[1].usUsage = 2; 1044 | m_Rid[1].dwFlags = RIDEV_INPUTSINK; 1045 | m_Rid[1].hwndTarget = hwnd; 1046 | //Touchpad 1047 | m_Rid[2].usUsagePage = HID_USAGE_PAGE_DIGITIZER; 1048 | m_Rid[2].usUsage = HID_USAGE_DIGITIZER_TOUCH_PAD; 1049 | m_Rid[2].dwFlags = RIDEV_INPUTSINK; 1050 | m_Rid[2].hwndTarget = hwnd; 1051 | RegisterRawInputDevices(m_Rid, 3, sizeof(RAWINPUTDEVICE)); 1052 | break; 1053 | case WM_INPUT: 1054 | //When window recives input message get data for rinput device and run mouse logic function. 1055 | if (ptouchpad) 1056 | if (HandlePrecisionTouchpad(&lParam, enabled)) 1057 | break; 1058 | rInput.getData(lParam, ptouchpad, ttouchpad, kInfo); 1059 | if (ttouchpad) 1060 | HandleTabletTouchpad(enabled); 1061 | 1062 | enabled = ((int)fR.result(31) != 0 && isCursorLocked) || (int)fR.result(31) == 0; 1063 | if (rInput.isAlphabeticKeyDown((int)fR.result(13)) && rInput.isAlphabeticKeyDown(18)) { 1064 | if (!isCursorLocked && !lastDown) { 1065 | // Set cursor to blank but first save the current one so we can restore it. 1066 | BYTE cura[] = { 0xFF }; 1067 | BYTE curx[] = { 0x00 }; 1068 | if (!blankCursor) 1069 | blankCursor = CreateCursor(wc.hInstance, 0, 0, 1, 1, cura, curx); 1070 | origCursor = CopyCursor(LoadCursor(0, IDC_ARROW)); 1071 | GetCursorPos(&cursorPos); 1072 | SetSystemCursor(CopyCursor(blankCursor), 32512); 1073 | isCursorLocked = true; 1074 | if ((int)fR.result(38)) 1075 | hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, mouseHook, wc.hInstance, 0); 1076 | } 1077 | else if (!lastDown && isCursorLocked) { 1078 | SetSystemCursor(origCursor, 32512); 1079 | SetCursorPos(cursorPos.x, cursorPos.y); 1080 | isCursorLocked = false; 1081 | if ((int)fR.result(38)) 1082 | UnhookWindowsHookEx(hMouseHook); 1083 | } 1084 | lastDown = true; 1085 | } 1086 | else 1087 | lastDown = false; 1088 | if (isCursorLocked) { 1089 | // only set cursor every second as it is expensive 1090 | if (setCursor.elapsedMilliseconds() > 1000) { 1091 | SetSystemCursor(CopyCursor(blankCursor), 32512); 1092 | setCursor.stop(); 1093 | setCursor.start(); 1094 | } 1095 | SetCursorPos(0, 0); 1096 | } 1097 | if ((int)fR.result(31) != 0 && !isCursorLocked) 1098 | break; 1099 | 1100 | if ((int)fR.result(22) && !(int)fR.result(23)) { 1101 | isButton1Clicked = rInput.isMouseWheelUp(); 1102 | isButton2Clicked = rInput.isMouseWheelDown(); 1103 | if (min((double)fR.result(43) / 100, 100) * 32767 <= max(kaxisRX, taxisRX)) { 1104 | if (rInput.isMiddleMouseButtonDown() && !pgear) { 1105 | pgear = gear; 1106 | gear = 0; 1107 | } 1108 | else if (!rInput.isMiddleMouseButtonDown() && pgear) { 1109 | gear = pgear; 1110 | pgear = 0; 1111 | } 1112 | if (rInput.isMiddleMouseButtonDown()) { 1113 | if (rInput.isMouseWheelUp() && pgear < 7) pgear++; 1114 | if (rInput.isMouseWheelDown() && pgear > -1) pgear--; 1115 | } 1116 | else { 1117 | if (rInput.isMouseWheelUp() && gear < 7) gear++; 1118 | if (rInput.isMouseWheelDown() && gear > -1) gear--; 1119 | } 1120 | } 1121 | } 1122 | else if ((int)fR.result(23)) { 1123 | if (rInput.isMiddleMouseButtonDown() && (int)fR.result(37) >= 1) { 1124 | if (rInput.isMouseWheelUp() && axisY <= 32767) axisY += 32767 / (int)fR.result(37); 1125 | if (rInput.isMouseWheelDown() && axisY > 0) axisY -= 32767 / (int)fR.result(37); 1126 | } 1127 | else { 1128 | if (rInput.isMouseWheelUp() && axisY <= 32767) axisY += 32767 / (int)fR.result(23); 1129 | if (rInput.isMouseWheelDown() && axisY > 0) axisY -= 32767 / (int)fR.result(23); 1130 | } 1131 | if (axisY == ((INT)(32767 / (int)fR.result(23))) * (int)fR.result(23)) 1132 | axisY = 32767; 1133 | } 1134 | axisY = std::clamp(axisY, 0, 32767); 1135 | mTV.mouseLogic(rInput.getMouseChangeX(), axisX, fR.result(0), fR.result(20), (int)fR.result(16)); 1136 | [[fallthrough]]; 1137 | case WM_TIMER: 1138 | case 727: 1139 | updateCode(enabled); 1140 | break; 1141 | case 7272: 1142 | updateNetwork(enabled); 1143 | break; 1144 | case WM_CLOSE: 1145 | exitHandler(CTRL_CLOSE_EVENT); 1146 | PostQuitMessage(0); 1147 | break; 1148 | case WM_DESTROY: 1149 | DestroyWindow(hwnd); 1150 | break; 1151 | default: 1152 | return DefWindowProc(hwnd, Msg, wParam, lParam); 1153 | } 1154 | return 0; 1155 | } 1156 | 1157 | int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow) 1158 | { 1159 | string cmdLine = lpCmdLine; 1160 | static const char* class_name = "MouseToVjoy"; 1161 | 1162 | if (cmdLine == "-kill") { 1163 | PostMessage(FindWindow(nullptr, class_name), WM_CLOSE, 0, 0); 1164 | return 0; 1165 | } else if (cmdLine != "-noconsole") { 1166 | //Allocating console to process and redirect every stdout, stdin to it. 1167 | AllocConsole(); 1168 | FILE* file = nullptr; 1169 | freopen_s(&file, "CONIN$", "r", stdin); 1170 | freopen_s(&file, "CONOUT$", "w", stdout); 1171 | ios::sync_with_stdio(); 1172 | console = true; 1173 | } 1174 | 1175 | //invisible window initialization to be able to recive raw input even if the window is not focused. 1176 | wc.cbSize = sizeof(WNDCLASSEX); 1177 | wc.lpfnWndProc = WndProc; // function which will handle messages 1178 | wc.hInstance = hInstance; 1179 | wc.lpszClassName = class_name; 1180 | if (RegisterClassEx(&wc)) 1181 | hwnd = CreateWindowEx(0, class_name, class_name, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); 1182 | 1183 | //Show invisible window, update it, then do initialization code. 1184 | ShowWindow(hwnd, nCmdShow); 1185 | UpdateWindow(hwnd); 1186 | initializationCode(); 1187 | 1188 | while(GetMessage(&msgWindow, NULL, 0, 0)) 1189 | { 1190 | TranslateMessage(&msgWindow); 1191 | DispatchMessage(&msgWindow); 1192 | 1193 | //If Message is equal to quit or destroy, break loop and end program. 1194 | if (msgWindow.message == WM_QUIT || msgWindow.message == WM_DESTROY) 1195 | break; 1196 | } 1197 | return 0; 1198 | } 1199 | 1200 | 1201 | -------------------------------------------------------------------------------- /MouseToVJoy/mousetovjoy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MOUSETOVJOY_H 3 | #define MOUSETOVJOY_H 4 | #include "input.h" 5 | #include "vjoy.h" 6 | #include "stopwatch.h" 7 | #include 8 | /* Basic funtion that gets data, then processes it and modifies inputs.*/ 9 | 10 | class MouseToVjoy { 11 | public: 12 | //Function responsible for getting and modifying vars for throttle, break, clutch. 13 | void MouseToVjoy::inputLogic(CInputDevices input, INT &axisX, INT &axisY, INT &axisZ, INT &axisRX, BOOL &isButton1Clicked, BOOL &isButton2Clicked, BOOL &isButton3Clicked, DOUBLE attackTimeThrottle, DOUBLE releaseTimeThrottle, DOUBLE attackTimeBrake, DOUBLE releaseTimeBrake, DOUBLE attackTimeClutch, DOUBLE releaseTimeClutch, INT throttleKey, INT brakeKey, INT clutchKey, INT gearShiftUpKey, INT gearShiftDownKey, INT handBrakeKey, INT mouseCenterKey, INT useMouse, DOUBLE accelerationThrottle, DOUBLE accelerationBrake, DOUBLE accelerationClutch, BOOL useWheelAsShifter, BOOL touchpad, INT disableAxis, BOOL disableKeys, DOUBLE deltaTime) noexcept; 14 | //Function responsible for getting and modifying vars for steering wheel. 15 | void MouseToVjoy::mouseLogic(INT change, INT &axisX, DOUBLE sensitivity, DOUBLE sensitivityCenterReduction, INT useCenterReduction) noexcept; 16 | private: 17 | //**Gets if the Center Reduction is used, when used function mouselogic() uses linear algorithm to calculate sensitivity, the more the joystick is centered the sloweer the sensitivity(max 1.0 of the sensitivity.), the further the faster the sensitivity(max = CenterReduction value * Sensitivity ) 18 | //bool _useCenterReduction; 19 | //define center multiplier to be able to modify it during function. 20 | DOUBLE _centerMultiplier; 21 | }; 22 | #endif -------------------------------------------------------------------------------- /MouseToVJoy/public.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | 3 | Copyright (c) Shaul Eizikovich. All rights reserved. 4 | 5 | THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 6 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 7 | IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR 8 | PURPOSE. 9 | 10 | Module Name: 11 | 12 | public.h 13 | 14 | Abstract: 15 | 16 | Public header file for the vJoy project 17 | Developpers that need to interface with vJoy need to include this file 18 | 19 | Author: 20 | 21 | 22 | Environment: 23 | 24 | kernel mode and User mode 25 | 26 | Notes: 27 | 28 | 29 | Revision History: 30 | 31 | 32 | --*/ 33 | #ifndef _PUBLIC_H 34 | #define _PUBLIC_H 35 | 36 | // Compilation directives 37 | #define PPJOY_MODE 38 | #undef PPJOY_MODE // Comment-out for compatibility mode 39 | 40 | #ifdef PPJOY_MODE 41 | #include "PPJIoctl.h" 42 | #endif 43 | 44 | #include // Definitions for controlling GUID initialization 45 | 46 | // Sideband comunication with vJoy Device 47 | //{781EF630-72B2-11d2-B852-00C04FAD5101} 48 | DEFINE_GUID(GUID_DEVINTERFACE_VJOY, 0x781EF630, 0x72B2, 0x11d2, 0xB8, 0x52, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x01); 49 | 50 | // 51 | // Usage example: 52 | // CreateFile(TEXT("\\\\.\\vJoy"), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); 53 | #ifdef PPJOY_MODE 54 | #define DEVICENAME_STRING "PPJoyIOCTL1" 55 | #else 56 | #define DEVICENAME_STRING "vJoy" 57 | #endif 58 | #define NTDEVICE_NAME_STRING "\\Device\\"DEVICENAME_STRING 59 | #define SYMBOLIC_NAME_STRING "\\DosDevices\\"DEVICENAME_STRING 60 | #define DOS_FILE_NAME "\\\\.\\"DEVICENAME_STRING 61 | #define VJOY_INTERFACE L"Device_" 62 | 63 | // Version parts 64 | #define VER_X_ 0 65 | #define VER_H_ 2 66 | #define VER_M_ 1 67 | #define VER_L_ 8 68 | 69 | #define STRINGIFY_1(x) #x 70 | #define STRINGIFY(x) STRINGIFY_1(x) 71 | #define PASTE(x, y) x##y 72 | #define MAKEWIDE(x) PASTE(L,x) 73 | 74 | // Device Attributes 75 | // 76 | #define VENDOR_N_ID 0x1234 77 | #define PRODUCT_N_ID 0xBEAD 78 | #define VERSION_N (VER_L_ + 0x10*VER_M_ + 0x100*VER_H_ + 0x1000*VER_X_) 79 | 80 | // Device Strings 81 | // 82 | #define VENDOR_STR_ID L"Shaul Eizikovich" 83 | #define PRODUCT_STR_ID L"vJoy - Virtual Joystick" 84 | #define SERIALNUMBER_STR MAKEWIDE(STRINGIFY(VER_H_)) L"." MAKEWIDE(STRINGIFY(VER_M_)) L"." MAKEWIDE(STRINGIFY(VER_L_)) 85 | 86 | // Function codes; 87 | //#define LOAD_POSITIONS 0x910 88 | //#define GETATTRIB 0x911 89 | // #define GET_FFB_DATA 0x00222912 // METHOD_OUT_DIRECT + FILE_DEVICE_UNKNOWN + FILE_ANY_ACCESS 90 | //#define SET_FFB_STAT 0x913 // METHOD_NEITHER 91 | //#define GET_FFB_STAT 0x916 92 | 93 | #define F_LOAD_POSITIONS 0x910 94 | #define F_GETATTRIB 0x911 95 | #define F_GET_FFB_DATA 0x912 96 | #define F_SET_FFB_STAT 0x913 97 | #define F_GET_FFB_STAT 0x916 98 | #define F_GET_DEV_INFO 0x917 99 | #define F_IS_DRV_FFB_CAP 0x918 100 | #define F_IS_DRV_FFB_EN 0x919 101 | #define F_GET_DRV_DEV_MAX 0x91A 102 | #define F_GET_DRV_DEV_EN 0x91B 103 | #define F_IS_DEV_FFB_START 0x91C 104 | #define F_GET_DEV_STAT 0x91D 105 | #define F_GET_DRV_INFO 0x91E 106 | #define F_RESET_DEV 0x91F 107 | #define F_GET_POSITIONS 0x920 108 | 109 | // IO Device Control codes; 110 | #define IOCTL_VJOY_GET_ATTRIB CTL_CODE (FILE_DEVICE_UNKNOWN, GETATTRIB, METHOD_BUFFERED, FILE_WRITE_ACCESS) 111 | #define LOAD_POSITIONS CTL_CODE (FILE_DEVICE_UNKNOWN, F_LOAD_POSITIONS, METHOD_BUFFERED, FILE_WRITE_ACCESS) 112 | #define GET_POSITIONS CTL_CODE (FILE_DEVICE_UNKNOWN, F_GET_POSITIONS, METHOD_BUFFERED, FILE_READ_ACCESS) 113 | #define GET_FFB_DATA CTL_CODE (FILE_DEVICE_UNKNOWN, F_GET_FFB_DATA, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) 114 | #define SET_FFB_STAT CTL_CODE (FILE_DEVICE_UNKNOWN, F_SET_FFB_STAT, METHOD_NEITHER, FILE_ANY_ACCESS) 115 | #define GET_FFB_STAT CTL_CODE (FILE_DEVICE_UNKNOWN, F_GET_FFB_STAT, METHOD_BUFFERED, FILE_ANY_ACCESS) 116 | #define GET_DEV_INFO CTL_CODE (FILE_DEVICE_UNKNOWN, F_GET_DEV_INFO, METHOD_BUFFERED, FILE_ANY_ACCESS) 117 | #define IS_DRV_FFB_CAP CTL_CODE (FILE_DEVICE_UNKNOWN, F_IS_DRV_FFB_CAP, METHOD_BUFFERED, FILE_ANY_ACCESS) 118 | #define IS_DRV_FFB_EN CTL_CODE (FILE_DEVICE_UNKNOWN, F_IS_DRV_FFB_EN, METHOD_BUFFERED, FILE_ANY_ACCESS) 119 | #define GET_DRV_DEV_MAX CTL_CODE (FILE_DEVICE_UNKNOWN, F_GET_DRV_DEV_MAX, METHOD_BUFFERED, FILE_ANY_ACCESS) 120 | #define GET_DRV_DEV_EN CTL_CODE (FILE_DEVICE_UNKNOWN, F_GET_DRV_DEV_EN, METHOD_BUFFERED, FILE_ANY_ACCESS) 121 | #define IS_DEV_FFB_START CTL_CODE (FILE_DEVICE_UNKNOWN, F_IS_DEV_FFB_START, METHOD_BUFFERED, FILE_ANY_ACCESS) 122 | #define GET_DEV_STAT CTL_CODE (FILE_DEVICE_UNKNOWN, F_GET_DEV_STAT, METHOD_BUFFERED, FILE_ANY_ACCESS) 123 | #define GET_DRV_INFO CTL_CODE (FILE_DEVICE_UNKNOWN, F_GET_DRV_INFO, METHOD_BUFFERED, FILE_ANY_ACCESS) 124 | #define RESET_DEV CTL_CODE (FILE_DEVICE_UNKNOWN, F_RESET_DEV, METHOD_BUFFERED, FILE_WRITE_ACCESS) 125 | 126 | #ifndef __HIDPORT_H__ 127 | // Copied from hidport.h 128 | #define IOCTL_HID_SET_FEATURE 0xB0191 129 | #define IOCTL_HID_WRITE_REPORT 0xB000F 130 | 131 | #define MAX_N_DEVICES 16 // Maximum number of vJoy devices 132 | 133 | 134 | typedef struct _HID_DEVICE_ATTRIBUTES { 135 | 136 | ULONG Size; 137 | // 138 | // sizeof (struct _HID_DEVICE_ATTRIBUTES) 139 | // 140 | 141 | // 142 | // Vendor ids of this hid device 143 | // 144 | USHORT VendorID; 145 | USHORT ProductID; 146 | USHORT VersionNumber; 147 | USHORT Reserved[11]; 148 | 149 | } HID_DEVICE_ATTRIBUTES, * PHID_DEVICE_ATTRIBUTES; 150 | #endif 151 | 152 | // Device Type 153 | //enum DevType { vJoy, vXbox }; 154 | 155 | // Error levels for status report 156 | enum ERRLEVEL {INFO, WARN, ERR, FATAL, APP}; 157 | // Status report function prototype 158 | #ifdef WINAPI 159 | typedef BOOL (WINAPI *StatusMessageFunc)(void * output, TCHAR * buffer, enum ERRLEVEL level); 160 | #endif 161 | 162 | /////////////////////////////////////////////////////////////// 163 | 164 | /////////////////////// Joystick Position /////////////////////// 165 | // 166 | // This structure holds data that is passed to the device from 167 | // an external application such as SmartPropoPlus. 168 | // 169 | // Usage example: 170 | // JOYSTICK_POSITION iReport; 171 | // : 172 | // DeviceIoControl (hDevice, 100, &iReport, sizeof(HID_INPUT_REPORT), NULL, 0, &bytes, NULL) 173 | typedef struct _JOYSTICK_POSITION 174 | { 175 | BYTE bDevice; // Index of device. 1-based. 176 | LONG wThrottle; 177 | LONG wRudder; 178 | LONG wAileron; 179 | LONG wAxisX; 180 | LONG wAxisY; 181 | LONG wAxisZ; 182 | LONG wAxisXRot; 183 | LONG wAxisYRot; 184 | LONG wAxisZRot; 185 | LONG wSlider; 186 | LONG wDial; 187 | LONG wWheel; 188 | LONG wAxisVX; 189 | LONG wAxisVY; 190 | LONG wAxisVZ; 191 | LONG wAxisVBRX; 192 | LONG wAxisVBRY; 193 | LONG wAxisVBRZ; 194 | LONG lButtons; // 32 buttons: 0x00000001 means button1 is pressed, 0x80000000 -> button32 is pressed 195 | DWORD bHats; // Lower 4 bits: HAT switch or 16-bit of continuous HAT switch 196 | DWORD bHatsEx1; // 16-bit of continuous HAT switch 197 | DWORD bHatsEx2; // 16-bit of continuous HAT switch 198 | DWORD bHatsEx3; // 16-bit of continuous HAT switch 199 | } JOYSTICK_POSITION, *PJOYSTICK_POSITION; 200 | 201 | // Superset of JOYSTICK_POSITION 202 | // Extension of JOYSTICK_POSITION with Buttons 33-128 appended to the end of the structure. 203 | typedef struct _JOYSTICK_POSITION_V2 204 | { 205 | /// JOYSTICK_POSITION 206 | BYTE bDevice; // Index of device. 1-based. 207 | LONG wThrottle; 208 | LONG wRudder; 209 | LONG wAileron; 210 | LONG wAxisX; 211 | LONG wAxisY; 212 | LONG wAxisZ; 213 | LONG wAxisXRot; 214 | LONG wAxisYRot; 215 | LONG wAxisZRot; 216 | LONG wSlider; 217 | LONG wDial; 218 | LONG wWheel; 219 | LONG wAxisVX; 220 | LONG wAxisVY; 221 | LONG wAxisVZ; 222 | LONG wAxisVBRX; 223 | LONG wAxisVBRY; 224 | LONG wAxisVBRZ; 225 | LONG lButtons; // 32 buttons: 0x00000001 means button1 is pressed, 0x80000000 -> button32 is pressed 226 | DWORD bHats; // Lower 4 bits: HAT switch or 16-bit of continuous HAT switch 227 | DWORD bHatsEx1; // Lower 4 bits: HAT switch or 16-bit of continuous HAT switch 228 | DWORD bHatsEx2; // Lower 4 bits: HAT switch or 16-bit of continuous HAT switch 229 | DWORD bHatsEx3; // Lower 4 bits: HAT switch or 16-bit of continuous HAT switch LONG lButtonsEx1; // Buttons 33-64 230 | 231 | /// JOYSTICK_POSITION_V2 Extenssion 232 | LONG lButtonsEx1; // Buttons 33-64 233 | LONG lButtonsEx2; // Buttons 65-96 234 | LONG lButtonsEx3; // Buttons 97-128 235 | } JOYSTICK_POSITION_V2, *PJOYSTICK_POSITION_V2; 236 | 237 | 238 | // HID Descriptor definitions - Axes 239 | #define HID_USAGE_X 0x30 240 | #define HID_USAGE_Y 0x31 241 | #define HID_USAGE_Z 0x32 242 | #define HID_USAGE_RX 0x33 243 | #define HID_USAGE_RY 0x34 244 | #define HID_USAGE_RZ 0x35 245 | #define HID_USAGE_SL0 0x36 246 | #define HID_USAGE_SL1 0x37 247 | #define HID_USAGE_WHL 0x38 248 | #define HID_USAGE_POV 0x39 249 | 250 | // HID Descriptor definitions - FFB Effects 251 | #define HID_USAGE_CONST 0x26 // Usage ET Constant Force 252 | #define HID_USAGE_RAMP 0x27 // Usage ET Ramp 253 | #define HID_USAGE_SQUR 0x30 // Usage ET Square 254 | #define HID_USAGE_SINE 0x31 // Usage ET Sine 255 | #define HID_USAGE_TRNG 0x32 // Usage ET Triangle 256 | #define HID_USAGE_STUP 0x33 // Usage ET Sawtooth Up 257 | #define HID_USAGE_STDN 0x34 // Usage ET Sawtooth Down 258 | #define HID_USAGE_SPRNG 0x40 // Usage ET Spring 259 | #define HID_USAGE_DMPR 0x41 // Usage ET Damper 260 | #define HID_USAGE_INRT 0x42 // Usage ET Inertia 261 | #define HID_USAGE_FRIC 0x43 // Usage ET Friction 262 | 263 | 264 | // HID Descriptor definitions - FFB Report IDs 265 | #define HID_ID_STATE 0x02 // Usage PID State report 266 | #define HID_ID_EFFREP 0x01 // Usage Set Effect Report 267 | #define HID_ID_ENVREP 0x02 // Usage Set Envelope Report 268 | #define HID_ID_CONDREP 0x03 // Usage Set Condition Report 269 | #define HID_ID_PRIDREP 0x04 // Usage Set Periodic Report 270 | #define HID_ID_CONSTREP 0x05 // Usage Set Constant Force Report 271 | #define HID_ID_RAMPREP 0x06 // Usage Set Ramp Force Report 272 | #define HID_ID_CSTMREP 0x07 // Usage Custom Force Data Report 273 | #define HID_ID_SMPLREP 0x08 // Usage Download Force Sample 274 | #define HID_ID_EFOPREP 0x0A // Usage Effect Operation Report 275 | #define HID_ID_BLKFRREP 0x0B // Usage PID Block Free Report 276 | #define HID_ID_CTRLREP 0x0C // Usage PID Device Control 277 | #define HID_ID_GAINREP 0x0D // Usage Device Gain Report 278 | #define HID_ID_SETCREP 0x0E // Usage Set Custom Force Report 279 | #define HID_ID_NEWEFREP 0x01 // Usage Create New Effect Report 280 | #define HID_ID_BLKLDREP 0x02 // Usage Block Load Report 281 | #define HID_ID_POOLREP 0x03 // Usage PID Pool Report 282 | 283 | #endif 284 | -------------------------------------------------------------------------------- /MouseToVJoy/vJoy.cpp: -------------------------------------------------------------------------------- 1 | #include "vjoy.h" 2 | #include 3 | //Tests if the driver version is equal to dll version. 4 | int VJoy::testDriver() noexcept { 5 | printf("Mouse to vJoy Feeder\n"); 6 | printf("==================================\n"); 7 | printf("Author: R1per / xCuri0\n"); 8 | printf("Version: 1.91\n"); 9 | // Get the driver attributes (Vendor ID, Product ID, Version Number) 10 | if (!vJoyEnabled()) 11 | { 12 | printf("Failed Getting vJoy attributes.\n"); 13 | return -2; 14 | } 15 | else 16 | { 17 | printf("vJoy Version Number: %S\n", (wchar_t*)TEXT(GetvJoySerialNumberString())); 18 | }; 19 | // Test interface DLL matches vJoy driver 20 | // Compare versions 21 | WORD VerDll, VerDrv; 22 | if (!DriverMatch(&VerDll, &VerDrv)) 23 | printf("vJoy Driver (version %04x) does not match\ 24 | vJoyInterface DLL (version %04x)\n", VerDrv, VerDll); 25 | else { 26 | printf("vJoyInterface DLL Version: %04x\n", VerDrv); 27 | printf("OK - Driver and DLL match\n"); 28 | } 29 | return 0; 30 | } 31 | //Tests if UINT iInterface is existing. 32 | int VJoy::testVirtualDevices(UINT iInterface) noexcept { 33 | // Get the state of the requested device (iInterface) 34 | _status = GetVJDStatus(iInterface); 35 | switch (_status) 36 | { 37 | case VJD_STAT_OWN: 38 | printf("vJoy Device %u is already owned by this feeder\n", iInterface); 39 | return 0; 40 | case VJD_STAT_FREE: 41 | printf("vJoy Device %u is free\n", iInterface); 42 | return 0; 43 | case VJD_STAT_BUSY: 44 | printf("vJoy Device %u is already owned by another feeder\n\ 45 | Cannot continue\n", iInterface); 46 | return -3; 47 | case VJD_STAT_MISS: 48 | printf("vJoy Device %u is not installed or disabled\n\ 49 | Cannot continue\n", iInterface); 50 | return -4; 51 | default: 52 | printf("vJoy Device %u general error\nCannot continue\n", iInterface); 53 | return -1; 54 | }; 55 | } 56 | //If UINT iInterface is existing, tries to accuire it. 57 | int VJoy::accuireDevice(UINT iInterface) noexcept { 58 | // Acquire the target if not already owned 59 | if ((_status == VJD_STAT_OWN) || \ 60 | ((_status == VJD_STAT_FREE) && (!AcquireVJD(iInterface)))) 61 | { 62 | printf("Failed to acquire vJoy device number %u.\n", iInterface); 63 | return -1; 64 | } 65 | else 66 | { 67 | printf("Acquired: vJoy device number %u.\n", iInterface); 68 | return 0; 69 | } 70 | } 71 | //If UINT iInterface exist, enable FFB to device. 72 | int VJoy::enableFFB(UINT iInterface) noexcept { 73 | printf("Started FFB on vJoy device number %u - OK\n", iInterface); 74 | return 0; 75 | } 76 | //When UINT iInterface is accuired, feeds vars X Y Z RX to Axises X Y Z RX. 77 | void VJoy::feedDevice(UINT iInterface, INT X, INT Y, INT Z, INT RX, INT GEAR, BOOL BUTTON1, BOOL BUTTON2, BOOL BUTTON3, const std::vector &buttons) noexcept { 78 | //Reports all axies to virtual joystick. 79 | _iReport.bDevice = iInterface; 80 | _iReport.wAxisX = X; 81 | _iReport.wAxisY = Y; 82 | _iReport.wAxisZ = Z; 83 | _iReport.wAxisXRot = RX; 84 | _iReport.lButtons = 0; 85 | 86 | if (BUTTON1) _iReport.lButtons |= 0x1; 87 | if (BUTTON2) _iReport.lButtons |= 0x2; 88 | if (BUTTON3) _iReport.lButtons |= 0x4; 89 | 90 | if (GEAR != 0) 91 | _iReport.lButtons |= (1 << (4 + GEAR)); 92 | 93 | for each (int i in buttons) 94 | _iReport.lButtons |= (1 << i); 95 | 96 | PVOID pPositionMessage = (PVOID)(&_iReport); 97 | UpdateVJD(iInterface, pPositionMessage); 98 | } 99 | 100 | -------------------------------------------------------------------------------- /MouseToVJoy/vjoy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef VJOY_H 3 | #define VJOY_H 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "public.h" 11 | #pragma warning( disable : 26812 ) 12 | #include "vjoyinterface.h" 13 | /* Class that does everything with the vjoy, testing, accuiring, feeding.*/ 14 | 15 | 16 | class VJoy { 17 | public: 18 | VJoy() noexcept { 19 | _status = VJD_STAT_OWN; 20 | } 21 | //Tests if the driver version is equal to dll version. 22 | int testDriver() noexcept; 23 | //Tests if UINT iInterface is existing. 24 | int testVirtualDevices(UINT iInterface) noexcept; 25 | //If UINT iInterface is existing, tries to accuire it. 26 | int accuireDevice(UINT iInterface) noexcept; 27 | //If UINT iInterface exist, enable FFB to device. 28 | int enableFFB(UINT iInterface) noexcept; 29 | //When UINT iInterface is accuired, feeds vars X Y Z RX to Axises X Y Z RX. 30 | void feedDevice(UINT iInterface, INT X, INT Y, INT Z, INT RX, INT GEAR, BOOL BUTTON1, BOOL BUTTON2, BOOL BUTTON3, const std::vector &buttons) noexcept; 31 | private: 32 | //Gets status from vjoy device using vjoyinterface.dll. 33 | VjdStat _status; 34 | //Creates new joystick position array named iReport, used to feed all the data at the same time. 35 | JOYSTICK_POSITION_V2 _iReport = { 0 }; 36 | }; 37 | #endif -------------------------------------------------------------------------------- /MouseToVJoy/vjoyinterface.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xCuri0/MouseToVJoy/a2f2b311f87e44c755e66eed4a45f7ee46aef5c0/MouseToVJoy/vjoyinterface.h -------------------------------------------------------------------------------- /MouseToVjoy.ini: -------------------------------------------------------------------------------- 1 | 2 | [HEADER] 3 | INPUT_METHOD=WHEEL 4 | 5 | [ADVANCED] 6 | COMBINE_WITH_KEYBOARD_CONTROL=1 7 | 8 | [X360] 9 | STEER_THUMB=LEFT 10 | STEER_GAMMA=3.01 11 | STEER_FILTER=0.600999 12 | SPEED_SENSITIVITY=0.5 13 | STEER_DEADZONE=0.05 14 | STEER_SPEED=0.2 15 | RUMBLE_INTENSITY=1.0 16 | 17 | [KEYBOARD] 18 | MINIMUM_STEERING=0 19 | STEERING_SPEED=1.75 20 | STEERING_OPPOSITE_DIRECTION_SPEED=2.5 21 | STEER_GAIN=0.18 22 | STEER_RESET_SPEED=1.8 23 | LOOKAHEAD_POINTS=6 24 | GAS=-1 25 | BRAKE=-1 26 | RIGHT=-1 27 | LEFT=-1 28 | MOUSE_STEER=1 29 | MOUSE_ACCELERATOR_BRAKE=0 30 | MOUSE_SPEED=0.6 31 | 32 | [CONTROLLERS] 33 | CON0=vJoy Device 34 | 35 | [STEER] 36 | JOY=0 37 | AXLE=0 38 | SCALE=1 39 | LOCK=900 40 | FF_GAIN=1 41 | FILTER_FF=0 42 | STEER_GAMMA=1 43 | STEER_FILTER=0 44 | SPEED_SENSITIVITY=0 45 | DEBOUNCING_MS=0 46 | 47 | [FF_TWEAKS] 48 | MIN_FF=0.05 49 | CENTER_BOOST_GAIN=0 50 | CENTER_BOOST_RANGE=0.1 51 | 52 | [FF_ENHANCEMENT] 53 | CURBS=0.4 54 | ROAD=0.5 55 | SLIPS=0 56 | 57 | [FF_ENHANCEMENT_2] 58 | UNDERSTEER=0 59 | 60 | [FF_SKIP_STEPS] 61 | VALUE=0 62 | 63 | [THROTTLE] 64 | JOY=0 65 | AXLE=1 66 | MIN=-1 67 | MAX=1 68 | 69 | [BRAKES] 70 | JOY=0 71 | AXLE=2 72 | MIN=-1 73 | MAX=1 74 | GAMMA=2.4 75 | 76 | [CLUTCH] 77 | JOY=0 78 | AXLE=3 79 | MIN=-1 80 | MAX=1 81 | 82 | [BALANCEUP] 83 | JOY=-1 84 | BUTTON=-1 85 | KEY=0xDB; OemOpenBrackets 86 | XBOXBUTTON=-1 87 | 88 | [BALANCEDN] 89 | JOY=-1 90 | BUTTON=-1 91 | KEY=0xDD; Oem6 92 | XBOXBUTTON=-1 93 | 94 | [KERS] 95 | JOY=-1 96 | BUTTON=-1 97 | KEY=0x44; D 98 | XBOXBUTTON=-1 99 | 100 | [DRS] 101 | JOY=-1 102 | BUTTON=-1 103 | KEY=-1 104 | XBOXBUTTON=-1 105 | 106 | [GEARUP] 107 | JOY=0 108 | BUTTON=0 109 | KEY=-1 110 | XBOXBUTTON=A 111 | 112 | [GEARDN] 113 | JOY=0 114 | BUTTON=1 115 | KEY=-1 116 | XBOXBUTTON=X 117 | 118 | [STARTER] 119 | JOY=-1 120 | BUTTON=-1 121 | KEY=-1 122 | XBOXBUTTON=-1 123 | 124 | [HANDBRAKE] 125 | JOY=0 126 | BUTTON=2 127 | AXLE=-1 128 | KEY=0x20; Space 129 | XBOXBUTTON=B 130 | MAX=1 131 | MIN=-1 132 | 133 | [SHIFTER] 134 | ACTIVE=1 135 | JOY=0 136 | GEAR_1=5 137 | GEAR_2=6 138 | GEAR_3=7 139 | GEAR_4=8 140 | GEAR_5=9 141 | GEAR_6=10 142 | GEAR_7=11 143 | GEAR_R=3 144 | 145 | [ACTION_HEADLIGHTS] 146 | JOY=-1 147 | BUTTON=-1 148 | XBOXBUTTON=DPAD_UP 149 | KEY=0x54; T 150 | 151 | [ACTION_HORN] 152 | JOY=-1 153 | BUTTON=-1 154 | XBOXBUTTON=Y 155 | KEY=0x47; G 156 | 157 | [GLANCELEFT] 158 | JOY=-1 159 | BUTTON=-1 160 | XBOXBUTTON=DPAD_LEFT 161 | KEY=0x56; V 162 | 163 | [GLANCERIGHT] 164 | JOY=-1 165 | BUTTON=-1 166 | XBOXBUTTON=DPAD_RIGHT 167 | KEY=0x42; B 168 | 169 | [GLANCEBACK] 170 | JOY=-1 171 | BUTTON=-1 172 | XBOXBUTTON=DPAD_DOWN 173 | KEY=0x4A; J 174 | 175 | [ACTION_CHANGE_CAMERA] 176 | JOY=-1 177 | BUTTON=-1 178 | XBOXBUTTON=BACK 179 | KEY=0x43; C 180 | 181 | [ACTION_CELEBRATE] 182 | JOY=-1 183 | BUTTON=-1 184 | XBOXBUTTON=LSHOULDER 185 | KEY=0x45; E 186 | 187 | [ACTION_CLAIM] 188 | JOY=-1 189 | BUTTON=-1 190 | XBOXBUTTON=RSHOULDER 191 | KEY=0x52; R 192 | 193 | [TURBODN] 194 | JOY=-1 195 | BUTTON=-1 196 | XBOXBUTTON=-1 197 | KEY=0xBD; OemMinus 198 | 199 | [TURBOUP] 200 | JOY=-1 201 | BUTTON=-1 202 | XBOXBUTTON=-1 203 | KEY=0xBB; OemPlus 204 | 205 | [ABSUP] 206 | JOY=-1 207 | BUTTON=-1 208 | XBOXBUTTON=-1 209 | KEY=0xBA; Oem1 210 | 211 | [ABSDN] 212 | JOY=-1 213 | BUTTON=-1 214 | XBOXBUTTON=-1 215 | KEY=0xDE; OemQuotes 216 | 217 | [TCUP] 218 | JOY=-1 219 | BUTTON=-1 220 | XBOXBUTTON=-1 221 | KEY=0x51; Q 222 | 223 | [TCDN] 224 | JOY=-1 225 | BUTTON=-1 226 | XBOXBUTTON=-1 227 | KEY=0x41; A 228 | 229 | [ACTION_HEADLIGHTS_FLASH] 230 | JOY=-1 231 | BUTTON=-1 232 | XBOXBUTTON=-1 233 | KEY=0x46; F 234 | 235 | [ENGINE_BRAKE_UP] 236 | JOY=-1 237 | BUTTON=-1 238 | XBOXBUTTON=-1 239 | KEY=-1 240 | 241 | [ENGINE_BRAKE_DN] 242 | JOY=-1 243 | BUTTON=-1 244 | XBOXBUTTON=-1 245 | KEY=-1 246 | 247 | [MGUK_DELIVERY_UP] 248 | JOY=-1 249 | BUTTON=-1 250 | XBOXBUTTON=-1 251 | KEY=-1 252 | 253 | [MGUK_DELIVERY_DN] 254 | JOY=-1 255 | BUTTON=-1 256 | XBOXBUTTON=-1 257 | KEY=-1 258 | 259 | [MGUK_RECOVERY_UP] 260 | JOY=-1 261 | BUTTON=-1 262 | XBOXBUTTON=-1 263 | KEY=-1 264 | 265 | [MGUK_RECOVERY_DN] 266 | JOY=-1 267 | BUTTON=-1 268 | XBOXBUTTON=-1 269 | KEY=-1 270 | 271 | [MGUH_MODE] 272 | JOY=-1 273 | BUTTON=-1 274 | XBOXBUTTON=-1 275 | KEY=-1 276 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MouseToVJoy 2 | Use mouse/touchpad/android/keyboard input in games as a input device using vJoy. 3 | 4 | ![](header.PNG) 5 | Assetto Corsa using MouseToVjoy with Android touchpad 6 | 7 | ## Features 8 | * Steering center multiplier 9 | * H-Shifter emulation 10 | * Scroll wheel throttle 11 | * Shifter using scroll wheel 12 | * Mouse locking and cursor hiding 13 | * Force Feedback 14 | * Below 1ms low latency 15 | * Content Manager integration 16 | * Handbrake key 17 | * Mouse center key 18 | * Smooth key attack/release/gamma 19 | * Keyboard input 20 | * Precision touchpad input 21 | * Android touchpad app input (supporting volume keys) 22 | * Drawing tablet input 23 | 24 | ## Guide 25 | * Install [Microsoft Visual C++ Redistrutable 2015-19 x86](https://aka.ms/vs/16/release/vc_redist.x86.exe) if not already installed 26 | * Install [vJoy](https://sourceforge.net/projects/vjoystick/) 2.1.9 on Windows 10. If you have Windows 7/8.1 download vJoy 2.1.8 27 | * Open **Configure vJoy** and set **Number of Buttons** to **32** on vJoy Device 1 28 | * Download latest from releases on GitHub https://github.com/xCuri0/MouseToVJoy/releases. If you have vJoy 2.1.8 download the -Win7 zip 29 | * Extract downloaded zip file, configure if needed and run MouseToVjoy.exe 30 | * Configure game to use the vJoy device 31 | * You can use the preset input configuration file for Assetto Corsa which can be downloaded [here](https://github.com/xCuri0/MouseToVJoy/raw/master/MouseToVjoy.ini) and placed in cfg/controllers/presets 32 | * If game is not receiving input but vJoy Monitor is run MouseToVjoy as administrator 33 | 34 | ## Configuration 35 | ### [Content Manager](https://acstuff.ru/app/) integration 36 | Copy all files in MouseToVjoy folder to ```Documents\Assetto Corsa``` and change **Settings > Content Manager > Drive > AC-related events** to 37 | 38 | ![](contentmanager.PNG) 39 | 40 | ### Android touchpad setup 41 | You can use an Android device as a touchpad if your computer doesn't have one. Download MouseToVjoy APK from [here](https://github.com/xCuri0/MouseToVjoyAndroid/releases) and install. The app uses USB tethering to communicate so you will be prompted to enable it. To prevent computer from using internet through phone set **Interface Metric** to **75** on the USB Tethering network. 42 | 43 | Use [keycode.info](https://keycode.info) to get keycodes. Keycodes for mouse are left click = 1, right click = 2 and middle click = 4. 44 | 45 | ### config.txt 46 | |Value|Description|Example| 47 | |-------|-------------|---------| 48 | |Sensitivity|The main sensitivity multiplier.
Raw data from mouse is multiplied by this value and then added to X axis.| 6.0| 49 | |AttackTimeThrottle|Throttle value when pressed.
When throttle is pressed, every 2 ms value is added to Y axis.
The greater the steaper slope of attack.| 200| 50 | |ReleaseTimeThrottle|Throttle value when released.
When throttle is released, every 2 ms value is subtracted from Y axis.
The greater the steaper slope of release.|100| 51 | |AttackTimeBrake|Brake value when pressed.
When brake is pressed, every 2 ms value is added to Z axis.
The greater the steeper slope of attack.|200| 52 | |ReleaseTimeBrake|Brake value when released.
When brake is released, every 2 ms value is subtracted from Z axis.
The greater the steeper slope of release.|100| 53 | |AttackTimeClutch|Clutch value when pressed.
When clutch is pressed, every 2 ms value is added to RX axis.
The greater the steeper slope of attack.
|200| 54 | |ReleaseTimeClutch|Clutch value when released.
When clutch is released, every 2 ms value is subtracted from RX axis.
The greater the steeper slope of release.|100| 55 | |AccelerationThrottle|Add linear acceleration on throttle axis.
0 to disable, greater then 0 to enable.|1.01| 56 | |AccelerationBrake|Add linear acceleration on brake axis.
0 to disable, greater then 0 to enable.|1.01| 57 | |AccelerationClutch|Add linear acceleration on clutch axis.
0 to disable, greater then 0 to enable.|1.01| 58 | |ThrottleKey|Keycode responsible for throttle control.
Works only when UseMouse is equal to 0.|87
= W| 59 | |BrakeKey|Key responsible for brake control.
Works only when UseMouse is equal to 0.|83
= S| 60 | |ClutchKey|Key responsible for clutch control.|67
= C| 61 | |GearShiftUpKey|Key responsible for gear shift up.|65
= A| 62 | |GearShiftDownKey|Key responsible for gear shift down.|68
= D| 63 | |HandBrakeKey|Key responsible for handbrake.|68
= Space| 64 | |MouseLockKey|Key responsible for locking mouse.|80
= P| 65 | |MouseCenterKey|Key responsible for centering steering axis.|79
= O| 66 | |ForceFeedbackKey|When this key is held down enable force feedback
Requires ForceFeedback = 1
Use 0 to disable and always use force feedback if it's enabled|78
= N| 67 | |UseMouse|Use mouse buttons as throttle and brake.|0| 68 | |UseCenterReduction|Reduce mouse sensitivity when closer to center of axis.|1| 69 | |UseForceFeedback|Use force feedback.|0| 70 | |RequireLocked|Requires the mouse to be locked.|1| 71 | |MouseHook|Use a global mouse hook to prevent mouse movement/clicking while locked.
Doesn't always work properly so disabled by default|0| 72 | |UseWheelAsShifter|Use mouse wheel as a sequential shifter.
Mouse wheel up for next gear and mouse wheel down for lower gear.|1| 73 | |UseWheelAsThrottle|Number of steps to use for mouse wheel as throttle.
0 to disable|10| 74 | |WheelThrottleMiddle|Number of steps to use for mouse wheel as throttle when middle button held.
0 to Disable.|30| 75 | |CenterMultiplier|How much center reduction to use.
Greater then 1 to make center less sensitive while making ends more sensitive.
Lesser then 1 to make center more sensitive while making ends less sensitive.|1.20| 76 | |RequireClutch|Percentage of clutch in required for H-Shifter to shift.
Max value 100|0| 77 | |VJoyID|VJoy device ID to use|1| 78 | |DisableKeys|Disable keyboard when touchpad active|1| 79 | |Touchpad|Use precision touchpad as touchpad (Z and RX axis).
Requires precision touchpad drivers which can usually be installed if your laptop didn't come with them.|1| 80 | |TouchpadApp|Use MouseToVjoy app on an Android device connected over USB as touchpad (Z and RX axis).
0 to disable, 1 to enable and 2 to open background picker in touchpad app|0| 81 | |TouchpadTablet|Use drawing tablet as touchpad (Z and RX axis)|1| 82 | |TouchpadXInvert|Invert the touchpad X axis.|0| 83 | |TouchpadYInvert|Invert the touchpad Y axis.|1| 84 | |TouchpadXPercent|Percentage of touchpad X axis to use such as 100 for full and 50 for half.|65| 85 | |TouchpadYPercent|Percentage of touchpad y axis to use such as 100 for full and 50 for half.|70| 86 | |TouchpadXStartPercent|Percentage of touchpad X axis to start at.|30| 87 | |TouchpadYStartPercent|Percentage of touchpad Y axis to start at.|25| 88 | |TouchpadAxisDisable|Disable a touchpad axis.
0 = none, 1 = rx, 2 = z|0| 89 | |TouchpadButtonsH|Number of horizontal touchpad buttons.|4| 90 | |TouchpadButtonsV|Number of vertical touchpad buttons.|3| 91 | |TouchpadButtons|List of touchpad buttons to enable. **Seperate with commas and make sure there are no spaces**
0 to disable and 1 to enable all.
Use VjoyMonitor with **TouchpadButtons = 1** to find the buttons you need enabled and then put them seperated by commas.|13,14| 92 | 93 | ## Release History 94 | * 1.91 95 | * FIX: Throttle not pressing fully 96 | * FIX: Acceleration curve 97 | * FIX: Android protocol issues 98 | * ADD: RequireClutch 99 | * 1.90 100 | * ADD: Content Manager integration 101 | * ADD: Drawing tablet support 102 | * ADD: MouseHook 103 | * ADD: WheelThrottleMiddle 104 | * ADD: TouchpadAxisDisable 105 | * ADD: DisableKeys 106 | * ADD: Optimizations for reduced CPU usage and latency 107 | * ADD: Use Android app volume keys 108 | * ADD: Set vJoy device ID 109 | * ADD: Improved default config.txt 110 | * FIX: Keyboard attack/release/acceleration 111 | * FIX: H-Shifter lag 112 | * FIX: Crash when file error 113 | * FIX: Setting cursor to blank 114 | * FIX: Variable initialization 115 | * FIX: Possible app version mismatch 116 | * TODO: Test Precision Touchpad support. It was last tested with 1.85 117 | * TODO: Test Windows 7 and 8.1 118 | * 1.89 119 | * FIX: Paddle shift doubleclicking 120 | * FIX: Touchpad getting stuck when unlock 121 | * FIX: Broken input while touchpad reconnecting 122 | * 1.88 123 | * ADD: Multiple performance improvements and bug fixes 124 | * ADD: Check if vJoy device has enough available buttons 125 | * FIX: Android touchpad not holding down 126 | * FIX: Acceleration when set to 0 127 | * 1.87 128 | * ADD: Zero input latency from new event based system 129 | * ADD: Use Android device as touchpad 130 | * ADD: Touchpad buttons 131 | * FIX: Improved touchpad splitting 132 | * FIX: Broken input on some computers 133 | * FIX: Broken touchpad start percent 134 | * BUG: Keyboard Attack/Release 135 | * BUG: Precision touchpad 136 | * 1.86 137 | * ADD: RequireLocked 138 | * ADD: ForceFeedbackKey 139 | * FIX: Cursor hiding 140 | * FIX: Starting multiple instances 141 | * ADD: Reduced CPU usage to near zero 142 | * 1.85 143 | * ADD: Using two fingers on touchpad 144 | * ADD: Require ALT for mouse lock key 145 | * ADD: TouchpadXStartPercent and TouchpadYStartPercent 146 | * ADD: TouchpadXPercent and TouchpadYPercent 147 | * FIX: Touchpad interference with mouse 148 | * 1.84 149 | * FIX: High latency 150 | * ADD: Option to use touchpad as Z and RX axis 151 | * 1.83 152 | * FIX: Scroll wheel issues. 153 | * ADD: `Use Wheel As Throttle`. Set UseWheelAsThrottle to the number of steps to use (0 to disable). 154 | * ADD: When using scroll wheel as shifter put gear in neutral by holding middle. You can change gears in this mode and when you release it will shift to it. 155 | * 1.82 156 | * FIX: Keyboard filtering. 157 | * ADD: H-Shifter emulation. 158 | * ADD: Assetto Corsa configuration .ini (put in cfg\controllers\presets). 159 | * 1.81 160 | * FIX: Buggy mouse lock key. 161 | * FIX: Cursor not restored on exit. 162 | * 1.8 163 | * ADD: 1000hz polling. 164 | * ADD: Set high priority. 165 | * ADD: Filter Assetto Corsa keyboard shortcuts. 166 | * ADD: Improved mouse locking. 167 | * ADD: Allow acceleration to be fully disabled. 168 | * ADD: Updated vJoy. 169 | * FIX: Cleaned source code. 170 | * 1.7 171 | * ADD: Support for 'ForceFeedback' on Assetto Corsa. 172 | * ADD: `Use Wheel as Shifter`. 173 | * 1.68 174 | * FIX: `ForceFeedback` not working. 175 | * 1.67 176 | * FIX: Issue with center reduction not working. 177 | * 1.66 178 | * FIX: Issue with self moving steering wheel. 179 | * 1.65 180 | * FIX: `ForceFeedback` not working. 181 | * 1.64 182 | * ADD: Command line support, '-noconsole' to launch without console. 183 | * FIX: Code structure, made it more pleasant to read. 184 | * 1.63 185 | * ADD: `Force Feedback` Working for Periodic Force. 186 | * 1.62 187 | * ADD: Ability to use mouse buttons on other functions than breake and throttle. 188 | * 1.61 189 | * FIX: `UseMouse` Not Working (Thanks nonical) 190 | * 1.6 191 | * ADD: `Force Feedback` Working only for Constant Force 192 | * 1.5 193 | * ADD: 3 Configurable buttons. 194 | * 1.41 195 | * FIX: `Sensitivity Center Reduction` not working. 196 | * 1.4 197 | * ADD: `Sensitivity Center Reduction`. 198 | * 1.3 199 | * ADD: `Center Mouse Steering Axis`. 200 | * 1.21 201 | * FIX: Typo in Breaking logic. 202 | * 1.2 203 | * ADD: Acceleration options. 204 | * 1.1 205 | * ADD: Configurable buttons. 206 | * 1.0 207 | * First working release. 208 | 209 | ## Latency 210 | Mouse click to shift button latency (50ms interval * 100) measured using [this](https://gist.github.com/xCuri0/488c911c212b4d9f62d88da2f5784447) 211 | 212 | Windows 10 20H2, i5-3470 and vJoy 2.1.9: 0.77ms 213 | 214 | ## Meta 215 | 216 | [Sebastian Waluś](https://github.com/R1per/) – sebastian.walus@op.pl 217 | 218 | [xCuri0](https://github.com/xCuri0/) - zkqri0@gmail.com 219 | 220 | ## Contributing 221 | 222 | 1. Fork it () 223 | 2. Create your feature branch (`git checkout -b feature/fooBar`) 224 | 3. Commit your changes (`git commit -am 'Add some fooBar'`) 225 | 4. Push to the branch (`git push origin feature/fooBar`) 226 | 5. Create a new Pull Request 227 | 228 | 229 | ## Built With 230 | 231 | * [Vjoy](http://vjoystick.sourceforge.net/site/) - Virtual Joystick 232 | * [VjoyInterface](http://vjoystick.sourceforge.net/site/) - Virtual Joystick Comminucation Library 233 | 234 | ## Acknowledgments 235 | * Sebastian Waluś for the orignal MouseToVJoy 236 | * Hat tip to anyone who's code was used 237 | 238 | -------------------------------------------------------------------------------- /contentmanager.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xCuri0/MouseToVJoy/a2f2b311f87e44c755e66eed4a45f7ee46aef5c0/contentmanager.PNG -------------------------------------------------------------------------------- /header.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xCuri0/MouseToVJoy/a2f2b311f87e44c755e66eed4a45f7ee46aef5c0/header.PNG -------------------------------------------------------------------------------- /lib/x64/vJoyInterface.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xCuri0/MouseToVJoy/a2f2b311f87e44c755e66eed4a45f7ee46aef5c0/lib/x64/vJoyInterface.dll -------------------------------------------------------------------------------- /lib/x64/vJoyInterface.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xCuri0/MouseToVJoy/a2f2b311f87e44c755e66eed4a45f7ee46aef5c0/lib/x64/vJoyInterface.lib -------------------------------------------------------------------------------- /lib/x86/vJoyInterface.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xCuri0/MouseToVJoy/a2f2b311f87e44c755e66eed4a45f7ee46aef5c0/lib/x86/vJoyInterface.dll -------------------------------------------------------------------------------- /lib/x86/vJoyInterface.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xCuri0/MouseToVJoy/a2f2b311f87e44c755e66eed4a45f7ee46aef5c0/lib/x86/vJoyInterface.lib -------------------------------------------------------------------------------- /lib/x86/vJoyInterface218.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xCuri0/MouseToVJoy/a2f2b311f87e44c755e66eed4a45f7ee46aef5c0/lib/x86/vJoyInterface218.dll --------------------------------------------------------------------------------