- SetCursorState() now calls ShowCursor() again, because capturing the mouse

with RIDEV_NOLEGACY apparently prevents SetCursor() from doing anything.
- Split mouse code off from i_input.cpp into i_mouse.cpp and added raw mouse
  handling. (WM_INPUT obsoleted most of DirectInput for XP.)
- Fixed: Similar to the Win32 mouse, using the DirectInput mouse in windowed
  mode, if you alt-tabbed away and then clicked on the window's title bar,
  mouse input would be frozen until the mouse was ungrabbed again.


SVN r1601 (trunk)
This commit is contained in:
Randy Heit 2009-05-24 03:15:04 +00:00
parent 273758344f
commit 0c4c90ac89
10 changed files with 1316 additions and 798 deletions

View File

@ -1,4 +1,13 @@
May 23, 2009 (Changes by Graf Zahl) May 23, 2009
- SetCursorState() now calls ShowCursor() again, because capturing the mouse
with RIDEV_NOLEGACY apparently prevents SetCursor() from doing anything.
- Split mouse code off from i_input.cpp into i_mouse.cpp and added raw mouse
handling. (WM_INPUT obsoleted most of DirectInput for XP.)
- Fixed: Similar to the Win32 mouse, using the DirectInput mouse in windowed
mode, if you alt-tabbed away and then clicked on the window's title bar,
mouse input would be frozen until the mouse was ungrabbed again.
May 23, 2009 (Changes by Graf Zahl)
- Fixed: When setting up a deep water sector with Transfer_Heights the floorclip - Fixed: When setting up a deep water sector with Transfer_Heights the floorclip
information of all actors in the sector needs to be updated. information of all actors in the sector needs to be updated.
@ -6,6 +15,7 @@ May 22, 2009 (Changes by Graf Zahl)
- Fixed: A_CountdownArg and A_Die must ensure a certain kill. - Fixed: A_CountdownArg and A_Die must ensure a certain kill.
May 22, 2009 May 22, 2009
- Moved SetSoundPaused() out of i_input.cpp and into s_sound.cpp.
- Fixed: When using Win32 mouse, windowed mode, alt-tabbing away and then - Fixed: When using Win32 mouse, windowed mode, alt-tabbing away and then
clicking on the window's title bar moved it practically off the screen. clicking on the window's title bar moved it practically off the screen.
- Beginnings of i_input.cpp rewrite: Win32 and DirectInput mouse handling has - Beginnings of i_input.cpp rewrite: Win32 and DirectInput mouse handling has

View File

@ -398,6 +398,7 @@ if( WIN32 )
win32/i_cd.cpp win32/i_cd.cpp
win32/i_crash.cpp win32/i_crash.cpp
win32/i_input.cpp win32/i_input.cpp
win32/i_mouse.cpp
win32/i_main.cpp win32/i_main.cpp
win32/i_movie.cpp win32/i_movie.cpp
win32/i_system.cpp win32/i_system.cpp

View File

@ -112,6 +112,9 @@ typedef enum
BT_USER4 = 1<<24, BT_USER4 = 1<<24,
} buttoncode_t; } buttoncode_t;
// Called by IO functions when input is detected.
void D_PostEvent (const event_t* ev);
// //
// GLOBAL VARIABLES // GLOBAL VARIABLES

View File

@ -38,8 +38,6 @@ struct event_t;
// //
void D_DoomMain (void); void D_DoomMain (void);
// Called by IO functions when input is detected.
void D_PostEvent (const event_t* ev);
void D_Display (); void D_Display ();

View File

@ -21,8 +21,7 @@
static void I_CheckGUICapture (); static void I_CheckGUICapture ();
static void I_CheckNativeMouse (); static void I_CheckNativeMouse ();
static bool GUICapture; bool GUICapture;
static bool NativeMouse = true;
extern int paused; extern int paused;

View File

@ -103,34 +103,14 @@
#include "d_event.h" #include "d_event.h"
#include "v_text.h" #include "v_text.h"
#define DINPUT_BUFFERSIZE 32 // Prototypes and declarations.
#include "rawinput.h"
// Definitions
#define RIF(name, ret, args) \
name##Proto My##name;
#include "rawinput.h"
class FInputDevice
{
public:
virtual bool GetDevice() = 0;
virtual void ProcessInput() = 0;
virtual bool WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result);
};
class FMouse : public FInputDevice
{
public:
FMouse();
virtual void Grab() = 0;
virtual void Ungrab() = 0;
protected:
void PostMouseMove(int x, int y);
void WheelMoved(int wheelmove);
void PostButtonEvent(int button, bool down);
void ClearButtonState();
int LastX, LastY; // for m_filter
WORD ButtonState; // bit mask of current button states (1=down, 0=up)
};
#ifdef _DEBUG #ifdef _DEBUG
#define INGAME_PRIORITY_CLASS NORMAL_PRIORITY_CLASS #define INGAME_PRIORITY_CLASS NORMAL_PRIORITY_CLASS
@ -139,6 +119,7 @@ protected:
#define INGAME_PRIORITY_CLASS NORMAL_PRIORITY_CLASS #define INGAME_PRIORITY_CLASS NORMAL_PRIORITY_CLASS
#endif #endif
static void FindRawInputFunctions();
BOOL DI_InitJoy (void); BOOL DI_InitJoy (void);
extern HINSTANCE g_hInst; extern HINSTANCE g_hInst;
@ -151,15 +132,10 @@ static HMODULE DInputDLL;
static void KeyRead (); static void KeyRead ();
static BOOL I_StartupKeyboard (); static BOOL I_StartupKeyboard ();
static void I_StartupMouse ();
static void CenterMouse_Win32 (LONG curx, LONG cury);
static void DI_Acquire (LPDIRECTINPUTDEVICE8 mouse);
static void DI_Unacquire (LPDIRECTINPUTDEVICE8 mouse);
static void SetCursorState (bool visible);
static HRESULT InitJoystick (); static HRESULT InitJoystick ();
static bool GUICapture; bool GUICapture;
static bool NativeMouse; extern FMouse *Mouse;
bool VidResizing; bool VidResizing;
@ -175,15 +151,12 @@ EXTERN_CVAR (String, language)
EXTERN_CVAR (Bool, lookstrafe) EXTERN_CVAR (Bool, lookstrafe)
typedef enum { none, win32, dinput } mousemode_t;
static mousemode_t mousemode = none;
extern BOOL paused; extern BOOL paused;
static bool HaveFocus = false; bool HaveFocus;
static bool noidle = false; static bool noidle = false;
static LPDIRECTINPUT8 g_pdi; LPDIRECTINPUT8 g_pdi;
static LPDIRECTINPUT g_pdi3; LPDIRECTINPUT g_pdi3;
static LPDIRECTINPUTDEVICE8 g_pJoy; static LPDIRECTINPUTDEVICE8 g_pJoy;
@ -194,10 +167,6 @@ static LPDIRECTINPUTDEVICE8 g_pJoy;
static LPDIRECTINPUTDEVICE8 g_pKey; static LPDIRECTINPUTDEVICE8 g_pKey;
FMouse *Mouse;
HCURSOR TheArrowCursor, TheInvisibleCursor;
TArray<GUIDName> JoystickNames; TArray<GUIDName> JoystickNames;
static DIDEVCAPS JoystickCaps; static DIDEVCAPS JoystickCaps;
@ -225,10 +194,6 @@ static const BYTE POVButtons[9] = { 0x01, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x
BOOL AppActive = TRUE; BOOL AppActive = TRUE;
int SessionState = 0; int SessionState = 0;
CVAR (Bool, use_mouse, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, m_noprescale, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, m_filter, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, use_joystick, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, use_joystick, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR (GUID, joy_guid, NULL, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) CUSTOM_CVAR (GUID, joy_guid, NULL, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
@ -347,26 +312,6 @@ static FBaseCVar * const JoyConfigVars[] =
&joy_upspeed &joy_upspeed
}; };
CUSTOM_CVAR (Int, in_mouse, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
{
if (self < 0)
{
self = 0;
}
else if (self > 2)
{
self = 2;
}
else if (g_pdi == NULL && g_pdi3 == NULL)
{
return;
}
else
{
I_StartupMouse();
}
}
static BYTE KeyState[256]; static BYTE KeyState[256];
static BYTE DIKState[2][NUM_KEYS]; static BYTE DIKState[2][NUM_KEYS];
static int KeysReadCount; static int KeysReadCount;
@ -439,53 +384,11 @@ static void I_CheckGUICapture ()
} }
} }
CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG|CVAR_ARCHIVE)
{
if (self < 0) self = 0;
else if (self > 2) self = 2;
}
static bool inGame()
{
switch (mouse_capturemode)
{
default:
case 0:
return gamestate == GS_LEVEL;
case 1:
return gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_FINALE;
case 2:
return true;
}
}
void I_CheckNativeMouse(bool preferNative)
{
bool wantNative = !HaveFocus ||
((!screen || !screen->IsFullscreen()) &&
(!inGame() || GUICapture || paused || preferNative || !use_mouse || demoplayback));
//Printf ("%d %d %d\n", wantNative, preferNative, NativeMouse);
if (wantNative != NativeMouse)
{
if (wantNative)
{
Mouse->Ungrab();
}
else
{
Mouse->Grab();
}
NativeMouse = wantNative;
}
}
LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{ {
if (Mouse != NULL) if (Mouse != NULL)
{ {
LRESULT result; LRESULT result = 0;
if (Mouse->WndProcHook(hWnd, message, wParam, lParam, &result)) if (Mouse->WndProcHook(hWnd, message, wParam, lParam, &result))
{ {
@ -507,6 +410,8 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_HOTKEY: case WM_HOTKEY:
break; break;
case WM_INPUT:
case WM_PAINT: case WM_PAINT:
if (screen != NULL && 0) if (screen != NULL && 0)
{ {
@ -1278,14 +1183,13 @@ bool I_InitInput (void *hwnd)
Printf ("I_InitInput\n"); Printf ("I_InitInput\n");
atterm (I_ShutdownInput); atterm (I_ShutdownInput);
NativeMouse = true;
noidle = !!Args->CheckParm ("-noidle"); noidle = !!Args->CheckParm ("-noidle");
g_pdi = NULL; g_pdi = NULL;
g_pdi3 = NULL; g_pdi3 = NULL;
// Try for DirectInput 8 first, then DirectInput 3 for NT 4's benefit. FindRawInputFunctions();
// Try for DirectInput 8 first, then DirectInput 3 for NT 4's benefit.
DInputDLL = LoadLibrary("dinput8.dll"); DInputDLL = LoadLibrary("dinput8.dll");
if (DInputDLL != NULL) if (DInputDLL != NULL)
{ {
@ -1383,16 +1287,6 @@ void I_ShutdownInput ()
} }
} }
static void SetCursorState(bool visible)
{
HCURSOR usingCursor = visible ? TheArrowCursor : TheInvisibleCursor;
SetClassLongPtr(Window, GCLP_HCURSOR, (LONG_PTR)usingCursor);
if (HaveFocus)
{
SetCursor(usingCursor);
}
}
// Initialize the keyboard // Initialize the keyboard
static BOOL I_StartupKeyboard (void) static BOOL I_StartupKeyboard (void)
{ {
@ -1619,6 +1513,16 @@ CCMD (playmovie)
I_PlayMovie (argv[1]); I_PlayMovie (argv[1]);
} }
//==========================================================================
//
// FInputDevice - Destructor
//
//==========================================================================
FInputDevice::~FInputDevice()
{
}
//========================================================================== //==========================================================================
// //
// FInputDevice :: WndProcHook // FInputDevice :: WndProcHook
@ -1634,678 +1538,21 @@ bool FInputDevice::WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP
//========================================================================== //==========================================================================
// //
// FMouse - Constructor // FindRawInputFunctions
//
// Finds functions for raw input, if available.
// //
//========================================================================== //==========================================================================
FMouse::FMouse() static void FindRawInputFunctions()
{ {
LastX = LastY = 0; HMODULE user32 = GetModuleHandle("user32.dll");
ButtonState = 0;
}
//==========================================================================
//
// FMouse :: PostMouseMove
//
// Posts a mouse movement event, potentially averaging it with the previous
// movement. If there is no movement to post, then no event is generated.
//
//==========================================================================
void FMouse::PostMouseMove(int x, int y)
{
event_t ev = { 0 };
if (m_filter)
{
ev.x = (x + LastX) / 2;
ev.y = (y + LastY) / 2;
}
else
{
ev.x = x;
ev.y = y;
}
LastX = x;
LastY = y;
if (ev.x | ev.y)
{
ev.type = EV_Mouse;
D_PostEvent(&ev);
}
}
//==========================================================================
//
// FMouse :: WheelMoved
//
// Generates events for a wheel move. Events are generated for every
// WHEEL_DELTA units that the wheel has moved. In normal mode, each move
// generates both a key down and a key up event. In GUI mode, only one
// event is generated for each unit of movement.
//
//==========================================================================
void FMouse::WheelMoved(int wheelmove)
{
event_t ev = { 0 };
int dir;
if (GUICapture) if (user32 == NULL)
{ {
ev.type = EV_GUI_Event; return; // WTF kind of broken system are we running on?
if (wheelmove < 0)
{
dir = WHEEL_DELTA;
ev.subtype = EV_GUI_WheelDown;
}
else
{
dir = -WHEEL_DELTA;
ev.subtype = EV_GUI_WheelUp;
}
ev.data3 = ((KeyState[VK_SHIFT]&128) ? GKM_SHIFT : 0) |
((KeyState[VK_CONTROL]&128) ? GKM_CTRL : 0) |
((KeyState[VK_MENU]&128) ? GKM_ALT : 0);
while (abs(wheelmove) >= WHEEL_DELTA)
{
D_PostEvent(&ev);
wheelmove += dir;
}
}
else
{
if (wheelmove < 0)
{
dir = WHEEL_DELTA;
ev.data1 = KEY_MWHEELDOWN;
}
else
{
dir = -WHEEL_DELTA;
ev.data1 = KEY_MWHEELUP;
}
while (abs(wheelmove) >= WHEEL_DELTA)
{
ev.type = EV_KeyDown;
D_PostEvent(&ev);
ev.type = EV_KeyUp;
D_PostEvent(&ev);
wheelmove += dir;
}
}
}
//==========================================================================
//
// FMouse :: PostButtonEvent
//
// Posts a mouse button up/down event. Down events are always posted. Up
// events will only be sent if the button is currently marked as down.
//
//==========================================================================
void FMouse::PostButtonEvent(int button, bool down)
{
event_t ev = { 0 };
int mask = 1 << button;
ev.data1 = KEY_MOUSE1 + button;
if (down)
{
ButtonState |= mask;
ev.type = EV_KeyDown;
D_PostEvent(&ev);
}
else if (ButtonState & mask)
{
ButtonState &= ~mask;
ev.type = EV_KeyUp;
D_PostEvent(&ev);
}
}
//==========================================================================
//
// FMouse :: ClearButtonState
//
// Sends key up events for all buttons that are currently down and marks
// them as up. Used when focus is lost and we can no longer track up events,
// so get them marked up right away.
//
//==========================================================================
void FMouse::ClearButtonState()
{
if (ButtonState != 0)
{
int i, mask;
event_t ev = { 0 };
ev.type = EV_KeyUp;
for (i = sizeof(ButtonState) * 8, mask = 1; i > 0; --i, mask <<= 1)
{
if (ButtonState & mask)
{
ev.data1 = KEY_MOUSE1 + (int)sizeof(ButtonState) * 8 - i;
D_PostEvent(&ev);
}
}
ButtonState = 0;
}
}
class FDInputMouse : public FMouse
{
public:
FDInputMouse();
~FDInputMouse();
bool GetDevice();
void ProcessInput();
void Grab();
void Ungrab();
protected:
LPDIRECTINPUTDEVICE8 Device;
};
//==========================================================================
//
// FDInputMouse - Constructor
//
//==========================================================================
FDInputMouse::FDInputMouse()
{
Device = NULL;
}
//==========================================================================
//
// FDInputMouse - Destructor
//
//==========================================================================
FDInputMouse::~FDInputMouse()
{
if (Device != NULL)
{
Device->Release();
Device = NULL;
}
}
//==========================================================================
//
// FDInputMouse :: GetDevice
//
// Create the device interface and initialize it.
//
//==========================================================================
bool FDInputMouse::GetDevice()
{
HRESULT hr;
if (g_pdi3)
{ // DirectInput3 interface
hr = g_pdi3->CreateDevice(GUID_SysMouse, (LPDIRECTINPUTDEVICE*)&Device, NULL);
}
else
{ // DirectInput8 interface
hr = g_pdi->CreateDevice(GUID_SysMouse, &Device, NULL);
}
if (FAILED(hr))
{
return false;
}
// How many buttons does this mouse have?
DIDEVCAPS_DX3 caps = { sizeof(caps) };
hr = Device->GetCapabilities((DIDEVCAPS *)&caps);
// If that failed, just assume four buttons.
if (FAILED(hr))
{
caps.dwButtons = 4;
}
// Now select the data format with enough buttons for this mouse.
// (Can we use c_dfDIMouse2 with DirectInput3? If so, then we could just set
// that unconditionally.)
hr = Device->SetDataFormat(caps.dwButtons <= 4 ? &c_dfDIMouse : &c_dfDIMouse2);
if (FAILED(hr))
{
ufailit:
Device->Release();
Device = NULL;
return false;
}
// Set cooperative level.
hr = Device->SetCooperativeLevel(Window, DISCL_EXCLUSIVE | DISCL_FOREGROUND);
if (FAILED(hr))
{
goto ufailit;
}
// Set buffer size so we can use buffered input.
DIPROPDWORD prop;
prop.diph.dwSize = sizeof(prop);
prop.diph.dwHeaderSize = sizeof(prop.diph);
prop.diph.dwObj = 0;
prop.diph.dwHow = DIPH_DEVICE;
prop.dwData = DINPUT_BUFFERSIZE;
hr = Device->SetProperty(DIPROP_BUFFERSIZE, &prop.diph);
if (FAILED(hr))
{
goto ufailit;
}
return true;
}
//==========================================================================
//
// FDInputMouse :: ProcessInput
//
// Posts any events that have accumulated since the previous call.
//
//==========================================================================
void FDInputMouse::ProcessInput()
{
DIDEVICEOBJECTDATA od;
DWORD dwElements;
HRESULT hr;
int count = 0;
int dx, dy;
dx = 0;
dy = 0;
if (!HaveFocus || NativeMouse)
return;
event_t ev = { 0 };
for (;;)
{
DWORD cbObjectData = g_pdi3 ? sizeof(DIDEVICEOBJECTDATA_DX3) : sizeof(DIDEVICEOBJECTDATA);
dwElements = 1;
hr = Device->GetDeviceData(cbObjectData, &od, &dwElements, 0);
if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED)
{
Grab();
hr = Device->GetDeviceData(cbObjectData, &od, &dwElements, 0);
}
/* Unable to read data or no data available */
if (FAILED(hr) || !dwElements)
break;
count++;
/* Look at the element to see what happened */
// GCC does not like putting the DIMOFS_ macros in case statements,
// so use ifs instead.
if (od.dwOfs == (DWORD)DIMOFS_X)
{
dx += od.dwData;
}
else if (od.dwOfs == (DWORD)DIMOFS_Y)
{
dy += od.dwData;
}
else if (od.dwOfs == (DWORD)DIMOFS_Z)
{
WheelMoved(od.dwData);
}
else if (od.dwOfs >= (DWORD)DIMOFS_BUTTON0 && od.dwOfs <= (DWORD)DIMOFS_BUTTON7)
{
/* [RH] Mouse button events mimic keydown/up events */
if (!GUICapture)
{
PostButtonEvent(od.dwOfs - DIMOFS_BUTTON0, !!(od.dwData & 0x80));
}
}
}
PostMouseMove(m_noprescale ? dx : dx<<2, -dy);
}
//==========================================================================
//
// FDInputMouse :: Grab
//
//==========================================================================
void FDInputMouse::Grab()
{
Device->Acquire();
SetCursorState(NativeMouse);
}
//==========================================================================
//
// FDInputMouse :: Ungrab
//
//==========================================================================
void FDInputMouse::Ungrab()
{
Device->Unacquire();
SetCursorState(true);
ClearButtonState();
}
class FWin32Mouse : public FMouse
{
public:
FWin32Mouse();
~FWin32Mouse();
bool GetDevice();
void ProcessInput();
bool WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result);
void Grab();
void Ungrab();
protected:
void CenterMouse(int x, int y);
POINT UngrabbedPointerPos;
LONG PrevX, PrevY;
bool Grabbed;
};
//==========================================================================
//
// FWin32Mouse - Constructor
//
//==========================================================================
FWin32Mouse::FWin32Mouse()
{
GetCursorPos(&UngrabbedPointerPos);
Grabbed = false;
}
//==========================================================================
//
// FWin32Mouse - Destructor
//
//==========================================================================
FWin32Mouse::~FWin32Mouse()
{
Ungrab();
}
//==========================================================================
//
// FWin32Mouse :: GetDevice
//
// The Win32 mouse is always available, since it is the lowest common
// denominator. (Even if it's not connected, it is still considered as
// "available"; it just won't generate any events.)
//
//==========================================================================
bool FWin32Mouse::GetDevice()
{
return true;
}
//==========================================================================
//
// FWin32Mouse :: ProcessInput
//
// Get current mouse position and post events if the mouse has moved from
// last time.
//
//==========================================================================
void FWin32Mouse::ProcessInput()
{
POINT pt;
int x, y;
if (!HaveFocus || !Grabbed || !GetCursorPos(&pt))
{
return;
}
x = pt.x - PrevX;
y = PrevY - pt.y;
if (!m_noprescale)
{
x *= 3;
y *= 2;
}
if (x | y)
{
CenterMouse(pt.x, pt.y);
}
PostMouseMove(x, y);
}
//==========================================================================
//
// FWin32Mouse :: WndProcHook
//
// Intercepts mouse-related window messages if the mouse is grabbed.
//
//==========================================================================
bool FWin32Mouse::WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result)
{
if (!Grabbed)
{
return false;
}
if (message == WM_SIZE)
{
if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED)
{
CenterMouse(-1, -1);
*result = 0;
return true;
}
}
else if (message == WM_MOVE)
{
CenterMouse(-1, -1);
*result = 0;
return true;
}
else if (message == WM_SYSCOMMAND)
{
// Do not enter the window moving and sizing modes while grabbed,
// because those require the mouse.
wParam &= 0xFFF0;
if (wParam == SC_MOVE || wParam == SC_SIZE)
{
*result = 0;
return true;
}
}
else if (message == WM_MOUSEWHEEL)
{
WheelMoved(HIWORD(wParam));
return true;
}
else if (message >= WM_LBUTTONDOWN && message <= WM_MBUTTONUP)
{
int action = (message - WM_LBUTTONDOWN) % 3;
int button = (message - WM_LBUTTONDOWN) / 3;
if (action == 2)
{ // double clicking we care not about.
return false;
}
event_t ev = { 0 };
ev.type = action ? EV_KeyUp : EV_KeyDown;
ev.data1 = KEY_MOUSE1 + button;
if (action)
{
ButtonState &= ~(1 << button);
}
else
{
ButtonState |= 1 << button;
}
D_PostEvent(&ev);
return true;
}
else if (message >= WM_XBUTTONDOWN && message <= WM_XBUTTONUP)
{
// Microsoft's (lack of) documentation for the X buttons is unclear on whether
// or not simultaneous pressing of multiple X buttons will ever be merged into
// a single message. Winuser.h describes the button field as being filled with
// flags, which suggests that it could merge them. My testing
// indicates it does not, but I will assume it might in the future.
WORD xbuttons = GET_XBUTTON_WPARAM(wParam);
event_t ev = { 0 };
ev.type = (message == WM_XBUTTONDOWN) ? EV_KeyDown : EV_KeyUp;
// There are only two X buttons defined presently, so I extrapolate from
// the current winuser.h values to support up to 8 mouse buttons.
for (int i = 0; i < 5; ++i, xbuttons >>= 1)
{
if (xbuttons & 1)
{
ev.data1 = KEY_MOUSE4 + i;
if (ev.type == EV_KeyDown)
{
ButtonState |= 1 << (i + 4);
}
else
{
ButtonState &= ~(1 << (i + 4));
}
D_PostEvent(&ev);
}
}
*result = TRUE;
return true;
}
return false;
}
//==========================================================================
//
// FWin32Mouse :: Grab
//
// Hides the mouse and locks it inside the window boundaries.
//
//==========================================================================
void FWin32Mouse::Grab()
{
RECT rect;
if (Grabbed)
{
return;
}
GetCursorPos(&UngrabbedPointerPos);
ClipCursor(NULL); // helps with Win95?
GetClientRect(Window, &rect);
// Reposition the rect so that it only covers the client area.
ClientToScreen(Window, (LPPOINT)&rect.left);
ClientToScreen(Window, (LPPOINT)&rect.right);
ClipCursor(&rect);
SetCursorState(false);
CenterMouse(-1, -1);
Grabbed = true;
}
//==========================================================================
//
// FWin32Mouse :: Ungrab
//
// Shows the mouse and lets it roam free.
//
//==========================================================================
void FWin32Mouse::Ungrab()
{
if (!Grabbed)
{
return;
}
ClipCursor(NULL);
SetCursorPos(UngrabbedPointerPos.x, UngrabbedPointerPos.y);
SetCursorState(true);
Grabbed = false;
ClearButtonState();
}
//==========================================================================
//
// FWin32Mouse :: CenterMouse
//
// Moves the mouse to the center of the window, but only if the current
// position isn't already in the center.
//
//==========================================================================
void FWin32Mouse::CenterMouse(int curx, int cury)
{
RECT rect;
GetWindowRect (Window, &rect);
int centx = (rect.left + rect.right) >> 1;
int centy = (rect.top + rect.bottom) >> 1;
// Reduce the number of WM_MOUSEMOVE messages that get sent
// by only calling SetCursorPos when we really need to.
if (centx != curx || centy != cury)
{
PrevX = centx;
PrevY = centy;
SetCursorPos (centx, centy);
}
}
static void I_StartupMouse ()
{
mousemode_t new_mousemode;
if (in_mouse == 1 || (in_mouse == 0 && OSPlatform == os_WinNT4))
new_mousemode = win32;
else
new_mousemode = dinput;
if (new_mousemode != mousemode)
{
if (new_mousemode == dinput)
{
Mouse = new FDInputMouse();
}
else
{
Mouse = new FWin32Mouse();
}
if (!Mouse->GetDevice())
{
delete Mouse;
if (new_mousemode == dinput)
{
new_mousemode = win32;
Mouse = new FWin32Mouse();
if (!Mouse->GetDevice())
{
Mouse = NULL;
new_mousemode = none;
}
}
}
mousemode = new_mousemode;
} }
HaveFocus = GetFocus() == Window; #define RIF(name,ret,args) \
My##name = (name##Proto)GetProcAddress(user32, #name);
#include "rawinput.h"
} }

View File

@ -54,4 +54,67 @@ extern char *JoyAxisNames[8];
extern void DI_EnumJoy (); extern void DI_EnumJoy ();
#ifdef USE_WINDOWS_DWORD
// Don't make these definitions available to the main body of the source code.
class FInputDevice
{
public:
virtual ~FInputDevice() = 0;
virtual bool GetDevice() = 0;
virtual void ProcessInput() = 0;
virtual bool WndProcHook(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result);
};
class FMouse : public FInputDevice
{
public:
FMouse();
virtual void Grab() = 0;
virtual void Ungrab() = 0;
protected:
void PostMouseMove(int x, int y);
void WheelMoved(int wheelmove);
void PostButtonEvent(int button, bool down);
void ClearButtonState();
int LastX, LastY; // for m_filter
WORD ButtonState; // bit mask of current button states (1=down, 0=up)
};
void I_StartupMouse();
void I_CheckNativeMouse(bool prefer_native);
// USB HID usage page numbers
#define HID_GENERIC_DESKTOP_PAGE 0x01
#define HID_SIMULATION_CONTROLS_PAGE 0x02
#define HID_VR_CONTROLS_PAGE 0x03
#define HID_SPORT_CONTROLS_PAGE 0x04
#define HID_GAME_CONTROLS_PAGE 0x05
#define HID_GENERIC_DEVICE_CONTROLS_PAGE 0x06
#define HID_KEYBOARD_PAGE 0x07
#define HID_LED_PAGE 0x08
#define HID_BUTTON_PAGE 0x09
#define HID_ORDINAL_PAGE 0x0a
#define HID_TELEPHONY_DEVICE_PAGE 0x0b
#define HID_CONSUMER_PAGE 0x0c
#define HID_DIGITIZERS_PAGE 0x0d
#define HID_UNICODE_PAGE 0x10
#define HID_ALPHANUMERIC_DISPLAY_PAGE 0x14
#define HID_MEDICAL_INSTRUMENT_PAGE 0x40
// HID Generic Desktop Page usages
#define HID_GDP_UNDEFINED 0x00
#define HID_GDP_POINTER 0x01
#define HID_GDP_MOUSE 0x02
#define HID_GDP_JOYSTICK 0x04
#define HID_GDP_GAMEPAD 0x05
#define HID_GDP_KEYBOARD 0x06
#define HID_GDP_KEYPAD 0x07
#define HID_GDP_MULTIAXIS_CONTROLLER 0x08
#endif
#endif #endif

1171
src/win32/i_mouse.cpp Normal file

File diff suppressed because it is too large Load Diff

18
src/win32/rawinput.h Normal file
View File

@ -0,0 +1,18 @@
// Pointers to raw-input related functions. They were introduced with XP,
// so we can't use static linking with them.
#ifndef RIF
#define RIF(name,ret,args) \
typedef ret (WINAPI *name##Proto)args; \
extern name##Proto My##name;
#endif
RIF(DefRawInputProc, LRESULT, (PRAWINPUT *paRawInput, INT nInput, UINT cbSizeHeader))
RIF(GetRawInputBuffer, UINT, (PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader))
RIF(GetRawInputData, UINT, (HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader))
RIF(GetRawInputDeviceInfoA, UINT, (HANDLE hDevice, UINT uiCommand, LPVOID pData, PUINT pcbSize))
RIF(GetRawInputDeviceInfoW, UINT, (HANDLE hDevice, UINT uiCommand, LPVOID pData, PUINT pcbSize))
RIF(GetRawInputDeviceList, UINT, (PRAWINPUTDEVICELIST pRawInputDeviceList, PUINT puiNumDevices, UINT cbSize))
RIF(GetRegisteredRawInputDevices, UINT, (PRAWINPUTDEVICE pRawInputDevices, PUINT puiNumDevices, UINT cbSize))
RIF(RegisterRawInputDevices, BOOL, (PCRAWINPUTDEVICE pRawInputDevices, UINT uiNumDevices, UINT cbSize))
#undef RIF

View File

@ -1980,6 +1980,10 @@
RelativePath=".\src\win32\i_main.cpp" RelativePath=".\src\win32\i_main.cpp"
> >
</File> </File>
<File
RelativePath=".\src\win32\i_mouse.cpp"
>
</File>
<File <File
RelativePath=".\src\win32\i_movie.cpp" RelativePath=".\src\win32\i_movie.cpp"
> >
@ -2000,6 +2004,10 @@
RelativePath=".\src\win32\icon2.ico" RelativePath=".\src\win32\icon2.ico"
> >
</File> </File>
<File
RelativePath=".\src\win32\rawinput.h"
>
</File>
<File <File
RelativePath=".\src\win32\resource.h" RelativePath=".\src\win32\resource.h"
> >