Skip to content

Commit

Permalink
Add experimental support for emulating joystick.
Browse files Browse the repository at this point in the history
  • Loading branch information
rdoeffinger committed Jun 4, 2016
1 parent ecae9ee commit 63e9253
Show file tree
Hide file tree
Showing 10 changed files with 242 additions and 5 deletions.
2 changes: 1 addition & 1 deletion impl11/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ all: ddraw.dll
i686-w64-mingw32-windres -o $@ -i $<

ddraw.dll: ddraw/*.cpp ddraw/ddraw.rc.o ddraw/ddraw.def
i686-w64-mingw32-g++ $(WARN_FLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ -lgdiplus -ld3d11 -ldxgi -ldxguid
i686-w64-mingw32-g++ $(WARN_FLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ -lgdiplus -ld3d11 -ldxgi -ldxguid -lwinmm

clean:
rm -f ddraw.dll ddraw/ddraw.rc.o xwing_ddraw_d3d11_*.zip
Expand Down
75 changes: 75 additions & 0 deletions impl11/ddraw/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include <algorithm>
#include <cctype>

#include "joystick.h"

// Wrapper to avoid undefined behaviour due to
// sign-extending char to int when passing to isspace.
// That would be undefined behaviour and crashes with table
Expand All @@ -33,6 +35,8 @@ Config::Config()
this->Fullscreen = 0;
this->Width = 0;
this->Height = 0;
this->MouseSensitivity = 0.5f;
this->KbdSensitivity = 1.0f;
this->XWAMode = true;
int XWAModeInt = -1;
int ProcessAffinity = -1;
Expand Down Expand Up @@ -126,6 +130,18 @@ Config::Config()
{
this->Height = stoi(value);
}
else if (name == "JoystickEmul")
{
this->JoystickEmul = stoi(value);
}
else if (name == "MouseSensitivity")
{
this->MouseSensitivity = stof(value);
}
else if (name == "KbdSensitivity")
{
this->KbdSensitivity = stof(value);
}
else if (name == "XWAMode")
{
XWAModeInt = stoi(value);
Expand Down Expand Up @@ -155,6 +171,10 @@ Config::Config()
bool isXWA = len >= 17 && _stricmp(name + len - 17, "xwingalliance.exe") == 0;
bool isXWing = len >= 11 && _stricmp(name + len - 11, "xwing95.exe") == 0;
bool isTIE = len >= 9 && _stricmp(name + len - 9, "tie95.exe") == 0;
bool isXvT = len >= 11 && _stricmp(name + len - 11, "z_xvt__.exe") == 0 &&
*(const unsigned long long *)0x523aec == 0x54534c2e31505352ull;
bool isBoP = len >= 11 && _stricmp(name + len - 11, "z_xvt__.exe") == 0 &&
*(const unsigned long long *)0x5210bc == 0x54534c2e31505352ull;

if (XWAModeInt == -1)
{
Expand Down Expand Up @@ -193,6 +213,61 @@ Config::Config()
*(unsigned long long *)0x4f084c = 0x00007d00fa000400ull;
}

if (this->JoystickEmul != 0 && isXWing)
{
// TODO: How to check if this is a supported binary?
DWORD old, dummy;
VirtualProtect((void *)0x4c31f0, 0x4c3208 - 0x4c31f0, PAGE_READWRITE, &old);
*(unsigned *)0x4c31f0 = reinterpret_cast<unsigned>(emulJoyGetDevCaps);
*(unsigned *)0x4c3200 = reinterpret_cast<unsigned>(emulJoyGetPosEx);
*(unsigned *)0x4c3204 = reinterpret_cast<unsigned>(emulJoyGetNumDevs);
VirtualProtect((void *)0x4c31f0, 0x4c3208 - 0x4c31f0, old, &dummy);
}

if (this->JoystickEmul != 0 && isTIE)
{
// TODO: How to check if this is a supported binary?
DWORD old, dummy;
VirtualProtect((void *)0x4dc258, 0x4dc264 - 0x4dc258, PAGE_READWRITE, &old);
*(unsigned *)0x4dc258 = reinterpret_cast<unsigned>(emulJoyGetNumDevs);
*(unsigned *)0x4dc25c = reinterpret_cast<unsigned>(emulJoyGetDevCaps);
*(unsigned *)0x4dc260 = reinterpret_cast<unsigned>(emulJoyGetPosEx);
VirtualProtect((void *)0x4dc258, 0x4dc264 - 0x4dc258, old, &dummy);
}

if (this->JoystickEmul != 0 && isXvT)
{
// TODO: How to check if this is a supported binary?
DWORD old, dummy;
VirtualProtect((void *)0x860704, 0x860714 - 0x860704, PAGE_READWRITE, &old);
*(unsigned *)0x860704 = reinterpret_cast<unsigned>(emulJoyGetDevCaps);
*(unsigned *)0x860708 = reinterpret_cast<unsigned>(emulJoyGetNumDevs);
*(unsigned *)0x860710 = reinterpret_cast<unsigned>(emulJoyGetPosEx);
VirtualProtect((void *)0x860704, 0x860714 - 0x860704, old, &dummy);
}

if (this->JoystickEmul != 0 && isBoP)
{
// TODO: How to check if this is a supported binary?
DWORD old, dummy;
VirtualProtect((void *)0xbb969c, 0xbb96b0 - 0xbb969c, PAGE_READWRITE, &old);
*(unsigned *)0xbb969c = reinterpret_cast<unsigned>(emulJoyGetNumDevs);
*(unsigned *)0xbb96a8 = reinterpret_cast<unsigned>(emulJoyGetPosEx);
*(unsigned *)0xbb96ac = reinterpret_cast<unsigned>(emulJoyGetDevCaps);
VirtualProtect((void *)0xbb969c, 0xbb96b0 - 0xbb969c, old, &dummy);
}

if (this->JoystickEmul != 0 && isXWA)
{
// TODO: How to check if this is a supported binary?
DWORD old, dummy;
VirtualProtect((void *)0x5a92a4, 0x5a92b8 - 0x5a92a4, PAGE_READWRITE, &old);
*(unsigned *)0x5a92a4 = reinterpret_cast<unsigned>(emulJoyGetPosEx);
*(unsigned *)0x5a92a8 = reinterpret_cast<unsigned>(emulJoyGetDevCaps);
*(unsigned *)0x5a92b4 = reinterpret_cast<unsigned>(emulJoyGetNumDevs);
VirtualProtect((void *)0x5a92a4, 0x5a92b8 - 0x5a92a4, old, &dummy);
}

if (ProcessAffinity != 0) {
DWORD_PTR CurProcessAffinity, SystemAffinity;
HANDLE mod = GetCurrentProcess();
Expand Down
3 changes: 3 additions & 0 deletions impl11/ddraw/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ class Config
int Fullscreen;
int Width;
int Height;
int JoystickEmul;
float MouseSensitivity;
float KbdSensitivity;
bool XWAMode;

float Concourse3DScale;
Expand Down
18 changes: 18 additions & 0 deletions impl11/ddraw/ddraw.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,24 @@ Fullscreen = 0
Width = 0
Height = 0

; JoystickEmul = -1 (default, auto-detect) or 1 (force on) or 0 (force off)
; EXPERIMENTAL - behaviour is far from optimal.
; Emulates a joystick using keyboard and mouse.
; For auto-detect only enabled if no joystick is detected.
; It is not possible to use a joystick that is plugged in after start.
; Force off to get back the dialog boxes asking you to plug in the joystick.
JoystickEmul = -1

; MouseSensitivity = 0.5 (default)
; How sensitive the mouse is if joystick emulation is enabled.
; Maximum turn speed might only be possible for values >= 1.1
MouseSensitivity = 0.5

; KbdSensitivity = 1.0 (default)
; How sensitive the keyboard is if joystick emulation is enabled.
; Maximum turn speed for 1.0, values above are not useful.
KbdSensitivity = 1.0

; ProcessAffinity = -1 (default), 0 (do not change) or mask
; Sets which processors to allow running on
; When set to -1 (or < 0 in general) tries to auto-detect (currently picks second processor)
Expand Down
2 changes: 2 additions & 0 deletions impl11/ddraw/ddraw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "DeviceResources.h"
#include "DirectDraw.h"

#include "joystick.h"

#pragma comment(lib, "dxguid")
#pragma comment(lib, "dxgi")
#pragma comment(lib, "d3d11")
Expand Down
8 changes: 4 additions & 4 deletions impl11/ddraw/ddraw.rc
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ END
//

1 VERSIONINFO
FILEVERSION 1,4,5
PRODUCTVERSION 1,4,5
FILEVERSION 1,4,6
PRODUCTVERSION 1,4,6
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
Expand All @@ -66,12 +66,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Jérémy Ansel"
VALUE "FileDescription", "Direct3D 11 implementation for X-Wing series"
VALUE "FileVersion", "1.4.5"
VALUE "FileVersion", "1.4.6"
VALUE "InternalName", "ddraw.dll"
VALUE "LegalCopyright", "Copyright (C) Jérémy Ansel 2014, Reimar Döffinger 2015,2016"
VALUE "OriginalFilename", "ddraw.dll"
VALUE "ProductName", "xwa_ddraw_d3d11"
VALUE "ProductVersion", "1.4.5"
VALUE "ProductVersion", "1.4.6"
END
END
BLOCK "VarFileInfo"
Expand Down
2 changes: 2 additions & 0 deletions impl11/ddraw/ddraw.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="ExecuteBufferDumper.cpp" />
<ClCompile Include="FrontbufferSurface.cpp" />
<ClCompile Include="joystick.cpp" />
<ClCompile Include="logger.cpp" />
<ClCompile Include="MipmapSurface.cpp" />
<ClCompile Include="OffscreenSurface.cpp" />
Expand All @@ -142,6 +143,7 @@
<ClInclude Include="DirectDrawPalette.h" />
<ClInclude Include="ExecuteBufferDumper.h" />
<ClInclude Include="FrontbufferSurface.h" />
<ClInclude Include="joystick.h" />
<ClInclude Include="logger.h" />
<ClInclude Include="MipmapSurface.h" />
<ClInclude Include="OffscreenSurface.h" />
Expand Down
6 changes: 6 additions & 0 deletions impl11/ddraw/ddraw.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@
<ClCompile Include="DirectDrawPalette.cpp">
<Filter>Fichiers sources</Filter>
</ClCompile>
<ClCompile Include="joystick.cpp">
<Filter>Fichiers sources</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="BackbufferSurface.h">
Expand Down Expand Up @@ -167,6 +170,9 @@
<ClInclude Include="DirectDrawPalette.h">
<Filter>Fichiers d%27en-tête</Filter>
</ClInclude>
<ClInclude Include="joystick.h">
<Filter>Fichiers d%27en-tête</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="ddraw.rc">
Expand Down
121 changes: 121 additions & 0 deletions impl11/ddraw/joystick.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright (c) 2016 Reimar Döffinger
// Licensed under the MIT license. See LICENSE.txt

#include "config.h"
#include "common.h"

#include <mmsystem.h>

#include "joystick.h"

#pragma comment(lib, "winmm")

#undef min
#undef max
#include <algorithm>

static bool needsJoyEmul()
{
UINT cnt = joyGetNumDevs();
for (unsigned i = 0; i < cnt; ++i)
{
JOYINFOEX jie;
memset(&jie, 0, sizeof(jie));
jie.dwSize = sizeof(jie);
jie.dwFlags = JOY_RETURNALL;
UINT res = joyGetPosEx(0, &jie);
if (res == JOYERR_NOERROR)
return false;
}
return true;
}

UINT WINAPI emulJoyGetNumDevs(void)
{
if (g_config.JoystickEmul < 0) {
g_config.JoystickEmul = needsJoyEmul();
}
if (!g_config.JoystickEmul) {
return joyGetNumDevs();
}
return 1;
}

UINT WINAPI emulJoyGetDevCaps(UINT_PTR joy, struct tagJOYCAPSA *pjc, UINT size)
{
if (!g_config.JoystickEmul) {
return joyGetDevCaps(joy, pjc, size);
}
if (joy != 0) return MMSYSERR_NODRIVER;
if (size != 0x194) return MMSYSERR_INVALPARAM;
memset(pjc, 0, size);
pjc->wXmax = 512;
pjc->wYmax = 512;
pjc->wNumButtons = 5;
pjc->wMaxButtons = 5;
pjc->wNumAxes = 2;
pjc->wMaxAxes = 2;
return JOYERR_NOERROR;
}

static DWORD lastGetPos;

UINT WINAPI emulJoyGetPosEx(UINT joy, struct joyinfoex_tag *pji)
{
if (!g_config.JoystickEmul) {
return joyGetPosEx(joy, pji);
}
if (joy != 0) return MMSYSERR_NODRIVER;
if (pji->dwSize != 0x34) return MMSYSERR_INVALPARAM;
DWORD now = GetTickCount();
// Assume we started a new game
if ((now - lastGetPos) > 5000)
{
SetCursorPos(240, 240);
GetAsyncKeyState(VK_LBUTTON);
GetAsyncKeyState(VK_RBUTTON);
GetAsyncKeyState(VK_MBUTTON);
GetAsyncKeyState(VK_XBUTTON1);
GetAsyncKeyState(VK_XBUTTON2);
}
lastGetPos = now;
POINT pos;
GetCursorPos(&pos);
pji->dwXpos = static_cast<DWORD>(std::min(256.0f + (pos.x - 240.0f) * g_config.MouseSensitivity, 512.0f));
pji->dwYpos = static_cast<DWORD>(std::min(256.0f + (pos.y - 240.0f) * g_config.MouseSensitivity, 512.0f));
pji->dwButtons = 0;
pji->dwButtonNumber = 0;
if (GetAsyncKeyState(VK_LBUTTON)) {
pji->dwButtons |= 1;
++pji->dwButtonNumber;
}
if (GetAsyncKeyState(VK_RBUTTON)) {
pji->dwButtons |= 2;
++pji->dwButtonNumber;
}
if (GetAsyncKeyState(VK_MBUTTON)) {
pji->dwButtons |= 4;
++pji->dwButtonNumber;
}
if (GetAsyncKeyState(VK_XBUTTON1)) {
pji->dwButtons |= 8;
++pji->dwButtonNumber;
}
if (GetAsyncKeyState(VK_XBUTTON2)) {
pji->dwButtons |= 16;
++pji->dwButtonNumber;
}
if (GetAsyncKeyState(VK_LEFT) & 0x8000) {
pji->dwXpos = static_cast<DWORD>(std::max(256 - 256 * g_config.KbdSensitivity, 0.0f));;
}
if (GetAsyncKeyState(VK_RIGHT) & 0x8000) {
pji->dwXpos = static_cast<DWORD>(std::min(256 + 256 * g_config.KbdSensitivity, 512.0f));;
}
if (GetAsyncKeyState(VK_DOWN) & 0x8000) {
pji->dwYpos = static_cast<DWORD>(std::max(256 - 256 * g_config.KbdSensitivity, 0.0f));;
}
if (GetAsyncKeyState(VK_UP) & 0x8000) {
pji->dwYpos = static_cast<DWORD>(std::min(256 + 256 * g_config.KbdSensitivity, 512.0f));;
}
return JOYERR_NOERROR;
}
10 changes: 10 additions & 0 deletions impl11/ddraw/joystick.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (c) 2016 Reimar Döffinger
// Licensed under the MIT license. See LICENSE.txt

#pragma once

#include "common.h"

extern "C" UINT WINAPI emulJoyGetNumDevs(void);
extern "C" UINT WINAPI emulJoyGetDevCaps(UINT_PTR, struct tagJOYCAPSA *, UINT);
extern "C" UINT WINAPI emulJoyGetPosEx(UINT, struct joyinfoex_tag *);

0 comments on commit 63e9253

Please sign in to comment.