-
Notifications
You must be signed in to change notification settings - Fork 0
/
DirectInputDevice8.cs
167 lines (136 loc) · 7.46 KB
/
DirectInputDevice8.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/*
This file is part of Mithos
Copyright (C) 2013 Lawrence Sebald
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 3 as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Yggdrasill;
namespace Sylverant
{
public unsafe class IDirectInputDevice8
{
#region Variables
// A pointer to the native IDirectInputDevice8 object that we are providing overrides for.
public DirectInput8.IDirectInputDevice8* Device
{
get;
private set;
}
// Our link back to the launcher
private YggdrasillInterface Interface;
// Pointers to any of the old functions we override.
private IntPtr oldGetDeviceState;
private IntPtr oldSetCooperativeLevel;
// Delegate storage
private DGetDeviceState del_gds;
private DSetCooperativeLevel del_scl;
// Mouse stuff...
private byte buttonState;
#endregion
#region Constructors
public unsafe IDirectInputDevice8(DirectInput8.IDirectInputDevice8* InDevice, YggdrasillInterface iface)
{
Device = InDevice;
Interface = iface;
/* Hook up any functions we care about */
OverrideFunctions();
}
private void OverrideFunctions()
{
// List of functions in the IDirectInputDevice8 interface:
// 0: STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj) PURE;
// 1: STDMETHOD_(ULONG,AddRef)(THIS) PURE;
// 2: STDMETHOD_(ULONG,Release)(THIS) PURE;
// 3: STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS) PURE;
// 4: STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKA,LPVOID,DWORD) PURE;
// 5: STDMETHOD(GetProperty)(THIS_ REFGUID,LPDIPROPHEADER) PURE;
// 6: STDMETHOD(SetProperty)(THIS_ REFGUID,LPCDIPROPHEADER) PURE;
// 7: STDMETHOD(Acquire)(THIS) PURE;
// 8: STDMETHOD(Unacquire)(THIS) PURE;
// 9: STDMETHOD(GetDeviceState)(THIS_ DWORD,LPVOID) PURE;
// 10: STDMETHOD(GetDeviceData)(THIS_ DWORD,LPDIDEVICEOBJECTDATA,LPDWORD,DWORD) PURE;
// 11: STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT) PURE;
// 12: STDMETHOD(SetEventNotification)(THIS_ HANDLE) PURE;
// 13: STDMETHOD(SetCooperativeLevel)(THIS_ HWND,DWORD) PURE;
// 14: STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEA,DWORD,DWORD) PURE;
// 15: STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEA) PURE;
// 16: STDMETHOD(RunControlPanel)(THIS_ HWND,DWORD) PURE;
// 17: STDMETHOD(Initialize)(THIS_ HINSTANCE,DWORD,REFGUID) PURE;
// 18: STDMETHOD(CreateEffect)(THIS_ REFGUID,LPCDIEFFECT,LPDIRECTINPUTEFFECT *,LPUNKNOWN) PURE;
// 19: STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKA,LPVOID,DWORD) PURE;
// 20: STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOA,REFGUID) PURE;
// 21: STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD) PURE;
// 22: STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD) PURE;
// 23: STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK,LPVOID,DWORD) PURE;
// 24: STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE) PURE;
// 25: STDMETHOD(Poll)(THIS) PURE;
// 26: STDMETHOD(SendDeviceData)(THIS_ DWORD,LPCDIDEVICEOBJECTDATA,LPDWORD,DWORD) PURE;
// 27: STDMETHOD(EnumEffectsInFile)(THIS_ LPCSTR,LPDIENUMEFFECTSINFILECALLBACK,LPVOID,DWORD) PURE;
// 28: STDMETHOD(WriteEffectToFile)(THIS_ LPCSTR,DWORD,LPDIFILEEFFECT,DWORD) PURE;
// 29: STDMETHOD(BuildActionMap)(THIS_ LPDIACTIONFORMATA,LPCSTR,DWORD) PURE;
// 30: STDMETHOD(SetActionMap)(THIS_ LPDIACTIONFORMATA,LPCSTR,DWORD) PURE;
// 31: STDMETHOD(GetImageInfo)(THIS_ LPDIDEVICEIMAGEINFOHEADERA) PURE;
oldGetDeviceState = Device->vtable[9];
del_gds = new DGetDeviceState(GetDeviceState);
IntPtr ptr = Marshal.GetFunctionPointerForDelegate(del_gds);
Device->vtable[9] = ptr;
oldSetCooperativeLevel = Device->vtable[13];
del_scl = new DSetCooperativeLevel(SetCooperativeLevel);
ptr = Marshal.GetFunctionPointerForDelegate(del_scl);
Device->vtable[13] = ptr;
}
#endregion
#region IDirectInputDevice8 Interface Function Implementations
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi, SetLastError = true)]
public unsafe delegate int DGetDeviceState(DirectInput8.IDirectInputDevice8* This, UInt32 cbData, IntPtr lpData);
public unsafe int GetDeviceState(DirectInput8.IDirectInputDevice8* This, UInt32 cbData, IntPtr lpData)
{
DGetDeviceState del = (DGetDeviceState)Marshal.GetDelegateForFunctionPointer(oldGetDeviceState, typeof(DGetDeviceState));
int rv = del(This, cbData, lpData);
/* XXXX: HACK!! 20 is the size of mouse data... Hopefully it isn't the size of anything else we care about. */
if (cbData == 20)
{
DirectInput8.DIMOUSESTATE2* ms = (DirectInput8.DIMOUSESTATE2*)lpData;
Process p = Process.GetCurrentProcess();
/* We only care when we go from not clicked to clicked... */
if (buttonState == 0 && ms->rgbButtons_0 != 0)
{
User32.RECT wndRect = new User32.RECT();
User32.POINT point = new User32.POINT();
User32.GetWindowRect(p.MainWindowHandle, ref wndRect);
User32.GetCursorPos(out point);
/* Check bounds. */
if (point.X < wndRect.Left || point.X > wndRect.Right || point.Y < wndRect.Top || point.Y > wndRect.Bottom)
{
ms->rgbButtons_0 = 0;
ms->rgbButtons_1 = 0;
}
}
buttonState = ms->rgbButtons_0;
}
/* La de dah... Imma collect some garbage now. */
GC.Collect();
return rv;
}
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi, SetLastError = true)]
public unsafe delegate int DSetCooperativeLevel(DirectInput8.IDirectInputDevice8* This, IntPtr hWnd, UInt32 dwFlags);
public unsafe int SetCooperativeLevel(DirectInput8.IDirectInputDevice8* This, IntPtr hWnd, UInt32 dwFlags)
{
DSetCooperativeLevel del = (DSetCooperativeLevel)Marshal.GetDelegateForFunctionPointer(oldSetCooperativeLevel, typeof(DSetCooperativeLevel));
/* Ask for non-exclusive, foreground-only access. Might need to revisit this for gamepads... */
dwFlags = DirectInput8.DISCL_NONEXCLUSIVE | DirectInput8.DISCL_FOREGROUND;
return del(This, hWnd, dwFlags);
}
#endregion
}
}