mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-07 21:41:25 +00:00
1993e969b7
SVN r3154 (trunk)
502 lines
12 KiB
C++
502 lines
12 KiB
C++
#include <SDL.h>
|
|
#include <ctype.h>
|
|
#include "doomtype.h"
|
|
#include "c_dispatch.h"
|
|
#include "doomdef.h"
|
|
#include "doomstat.h"
|
|
#include "m_argv.h"
|
|
#include "i_input.h"
|
|
#include "v_video.h"
|
|
|
|
#include "d_main.h"
|
|
#include "d_event.h"
|
|
#include "d_gui.h"
|
|
#include "c_console.h"
|
|
#include "c_cvars.h"
|
|
#include "i_system.h"
|
|
#include "dikeys.h"
|
|
#include "templates.h"
|
|
#include "s_sound.h"
|
|
|
|
static void I_CheckGUICapture ();
|
|
static void I_CheckNativeMouse ();
|
|
|
|
bool GUICapture;
|
|
static bool NativeMouse = true;
|
|
|
|
extern int paused;
|
|
|
|
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, sdl_nokeyrepeat, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|
|
|
EXTERN_CVAR (Bool, fullscreen)
|
|
|
|
extern int WaitingForKey, chatmodeon;
|
|
extern constate_e ConsoleState;
|
|
|
|
extern SDL_Surface *cursorSurface;
|
|
extern SDL_Rect cursorBlit;
|
|
|
|
static BYTE KeySymToDIK[SDLK_LAST], DownState[SDLK_LAST];
|
|
|
|
static WORD DIKToKeySym[256] =
|
|
{
|
|
0, SDLK_ESCAPE, '1', '2', '3', '4', '5', '6',
|
|
'7', '8', '9', '0', '-', '=', SDLK_BACKSPACE, SDLK_TAB,
|
|
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
|
|
'o', 'p', '[', ']', SDLK_RETURN, SDLK_LCTRL, 'a', 's',
|
|
'd', 'f', 'g', 'h', 'j', 'k', 'l', SDLK_SEMICOLON,
|
|
'\'', '`', SDLK_LSHIFT, '\\', 'z', 'x', 'c', 'v',
|
|
'b', 'n', 'm', ',', '.', '/', SDLK_RSHIFT, SDLK_KP_MULTIPLY,
|
|
SDLK_LALT, ' ', SDLK_CAPSLOCK, SDLK_F1, SDLK_F2, SDLK_F3, SDLK_F4, SDLK_F5,
|
|
SDLK_F6, SDLK_F7, SDLK_F8, SDLK_F9, SDLK_F10, SDLK_NUMLOCK, SDLK_SCROLLOCK, SDLK_KP7,
|
|
SDLK_KP8, SDLK_KP9, SDLK_KP_MINUS, SDLK_KP4, SDLK_KP5, SDLK_KP6, SDLK_KP_PLUS, SDLK_KP1,
|
|
SDLK_KP2, SDLK_KP3, SDLK_KP0, SDLK_KP_PERIOD, 0, 0, 0, SDLK_F11,
|
|
SDLK_F12, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, SDLK_F13, SDLK_F14, SDLK_F15, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, SDLK_KP_EQUALS, 0, 0,
|
|
0, SDLK_AT, SDLK_COLON, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, SDLK_KP_ENTER, SDLK_RCTRL, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, SDLK_KP_DIVIDE, 0, SDLK_SYSREQ,
|
|
SDLK_RALT, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, SDLK_PAUSE, 0, SDLK_HOME,
|
|
SDLK_UP, SDLK_PAGEUP, 0, SDLK_LEFT, 0, SDLK_RIGHT, 0, SDLK_END,
|
|
SDLK_DOWN, SDLK_PAGEDOWN, SDLK_INSERT, SDLK_DELETE, 0, 0, 0, 0,
|
|
0, 0, 0, SDLK_LSUPER, SDLK_RSUPER, SDLK_MENU, SDLK_POWER, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0
|
|
};
|
|
|
|
static void FlushDIKState (int low=0, int high=NUM_KEYS-1)
|
|
{
|
|
}
|
|
|
|
static void InitKeySymMap ()
|
|
{
|
|
for (int i = 0; i < 256; ++i)
|
|
{
|
|
KeySymToDIK[DIKToKeySym[i]] = i;
|
|
}
|
|
KeySymToDIK[0] = 0;
|
|
KeySymToDIK[SDLK_RSHIFT] = DIK_LSHIFT;
|
|
KeySymToDIK[SDLK_RCTRL] = DIK_LCONTROL;
|
|
KeySymToDIK[SDLK_RALT] = DIK_LMENU;
|
|
// Depending on your Linux flavor, you may get SDLK_PRINT or SDLK_SYSREQ
|
|
KeySymToDIK[SDLK_PRINT] = DIK_SYSRQ;
|
|
}
|
|
|
|
static void I_CheckGUICapture ()
|
|
{
|
|
bool wantCapt;
|
|
bool repeat;
|
|
int oldrepeat, interval;
|
|
|
|
SDL_GetKeyRepeat(&oldrepeat, &interval);
|
|
|
|
if (menuactive == MENU_Off)
|
|
{
|
|
wantCapt = ConsoleState == c_down || ConsoleState == c_falling || chatmodeon;
|
|
}
|
|
else
|
|
{
|
|
wantCapt = (menuactive == MENU_On || menuactive == MENU_OnNoPause);
|
|
}
|
|
|
|
if (wantCapt != GUICapture)
|
|
{
|
|
GUICapture = wantCapt;
|
|
if (wantCapt)
|
|
{
|
|
int x, y;
|
|
SDL_GetMouseState (&x, &y);
|
|
cursorBlit.x = x;
|
|
cursorBlit.y = y;
|
|
|
|
FlushDIKState ();
|
|
memset (DownState, 0, sizeof(DownState));
|
|
repeat = !sdl_nokeyrepeat;
|
|
SDL_EnableUNICODE (1);
|
|
}
|
|
else
|
|
{
|
|
repeat = false;
|
|
SDL_EnableUNICODE (0);
|
|
}
|
|
}
|
|
if (wantCapt)
|
|
{
|
|
repeat = !sdl_nokeyrepeat;
|
|
}
|
|
else
|
|
{
|
|
repeat = false;
|
|
}
|
|
if (repeat != (oldrepeat != 0))
|
|
{
|
|
if (repeat)
|
|
{
|
|
SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
|
|
}
|
|
else
|
|
{
|
|
SDL_EnableKeyRepeat (0, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void I_SetMouseCapture()
|
|
{
|
|
}
|
|
|
|
void I_ReleaseMouseCapture()
|
|
{
|
|
}
|
|
|
|
static void CenterMouse ()
|
|
{
|
|
SDL_WarpMouse (screen->GetWidth()/2, screen->GetHeight()/2);
|
|
SDL_PumpEvents ();
|
|
SDL_GetRelativeMouseState (NULL, NULL);
|
|
}
|
|
|
|
static void PostMouseMove (int x, int y)
|
|
{
|
|
static int lastx = 0, lasty = 0;
|
|
event_t ev = { 0,0,0,0,0,0,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);
|
|
}
|
|
}
|
|
|
|
static void MouseRead ()
|
|
{
|
|
int x, y;
|
|
|
|
if (NativeMouse)
|
|
{
|
|
return;
|
|
}
|
|
|
|
SDL_GetRelativeMouseState (&x, &y);
|
|
if (!m_noprescale)
|
|
{
|
|
x *= 3;
|
|
y *= 2;
|
|
}
|
|
if (x | y)
|
|
{
|
|
CenterMouse ();
|
|
PostMouseMove (x, -y);
|
|
}
|
|
}
|
|
|
|
static void WheelMoved(event_t *event)
|
|
{
|
|
if (GUICapture)
|
|
{
|
|
if (event->type != EV_KeyUp)
|
|
{
|
|
SDLMod mod = SDL_GetModState();
|
|
event->type = EV_GUI_Event;
|
|
event->subtype = event->data1 == KEY_MWHEELUP ? EV_GUI_WheelUp : EV_GUI_WheelDown;
|
|
event->data1 = 0;
|
|
event->data3 = ((mod & KMOD_SHIFT) ? GKM_SHIFT : 0) |
|
|
((mod & KMOD_CTRL) ? GKM_CTRL : 0) |
|
|
((mod & KMOD_ALT) ? GKM_ALT : 0);
|
|
D_PostEvent(event);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
D_PostEvent(event);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
static void I_CheckNativeMouse ()
|
|
{
|
|
bool focus = (SDL_GetAppState() & (SDL_APPINPUTFOCUS|SDL_APPACTIVE))
|
|
== (SDL_APPINPUTFOCUS|SDL_APPACTIVE);
|
|
bool fs = (SDL_GetVideoSurface ()->flags & SDL_FULLSCREEN) != 0;
|
|
|
|
bool wantNative = !focus || (!use_mouse || GUICapture || paused || demoplayback || !inGame());
|
|
|
|
if (wantNative != NativeMouse)
|
|
{
|
|
NativeMouse = wantNative;
|
|
SDL_ShowCursor (wantNative ? cursorSurface == NULL : 0);
|
|
if (wantNative)
|
|
{
|
|
SDL_WM_GrabInput (SDL_GRAB_OFF);
|
|
FlushDIKState (KEY_MOUSE1, KEY_MOUSE8);
|
|
}
|
|
else
|
|
{
|
|
SDL_WM_GrabInput (SDL_GRAB_ON);
|
|
CenterMouse ();
|
|
}
|
|
}
|
|
}
|
|
|
|
void MessagePump (const SDL_Event &sev)
|
|
{
|
|
static int lastx = 0, lasty = 0;
|
|
int x, y;
|
|
event_t event = { 0,0,0,0,0,0,0 };
|
|
|
|
switch (sev.type)
|
|
{
|
|
case SDL_QUIT:
|
|
exit (0);
|
|
|
|
case SDL_ACTIVEEVENT:
|
|
if (sev.active.state == SDL_APPINPUTFOCUS)
|
|
{
|
|
if (sev.active.gain == 0)
|
|
{ // kill focus
|
|
FlushDIKState ();
|
|
}
|
|
S_SetSoundPaused(sev.active.gain);
|
|
}
|
|
break;
|
|
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
case SDL_MOUSEBUTTONUP:
|
|
case SDL_MOUSEMOTION:
|
|
if (!GUICapture || sev.button.button == 4 || sev.button.button == 5)
|
|
{
|
|
if(sev.type != SDL_MOUSEMOTION)
|
|
{
|
|
event.type = sev.type == SDL_MOUSEBUTTONDOWN ? EV_KeyDown : EV_KeyUp;
|
|
/* These button mappings work with my Gentoo system using the
|
|
* evdev driver and a Logitech MX510 mouse. Whether or not they
|
|
* carry over to other Linux systems, I have no idea, but I sure
|
|
* hope so. (Though buttons 11 and 12 are kind of useless, since
|
|
* they also trigger buttons 4 and 5.)
|
|
*/
|
|
switch (sev.button.button)
|
|
{
|
|
case 1: event.data1 = KEY_MOUSE1; break;
|
|
case 2: event.data1 = KEY_MOUSE3; break;
|
|
case 3: event.data1 = KEY_MOUSE2; break;
|
|
case 4: event.data1 = KEY_MWHEELUP; break;
|
|
case 5: event.data1 = KEY_MWHEELDOWN; break;
|
|
case 6: event.data1 = KEY_MOUSE4; break; /* dunno; not generated by my mouse */
|
|
case 7: event.data1 = KEY_MOUSE5; break; /* ditto */
|
|
case 8: event.data1 = KEY_MOUSE4; break;
|
|
case 9: event.data1 = KEY_MOUSE5; break;
|
|
case 10: event.data1 = KEY_MOUSE6; break;
|
|
case 11: event.data1 = KEY_MOUSE7; break;
|
|
case 12: event.data1 = KEY_MOUSE8; break;
|
|
default: printf("SDL mouse button %s %d\n",
|
|
sev.type == SDL_MOUSEBUTTONDOWN ? "down" : "up", sev.button.button); break;
|
|
}
|
|
if (event.data1 != 0)
|
|
{
|
|
//DIKState[ActiveDIKState][event.data1] = (event.type == EV_KeyDown);
|
|
if (event.data1 == KEY_MWHEELUP || event.data1 == KEY_MWHEELDOWN)
|
|
{
|
|
WheelMoved(&event);
|
|
}
|
|
else
|
|
{
|
|
D_PostEvent(&event);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (sev.type == SDL_MOUSEMOTION || (sev.button.button >= 1 && sev.button.button <= 3))
|
|
{
|
|
int x, y;
|
|
SDL_GetMouseState (&x, &y);
|
|
|
|
cursorBlit.x = event.data1 = x;
|
|
cursorBlit.y = event.data2 = y;
|
|
event.type = EV_GUI_Event;
|
|
if(sev.type == SDL_MOUSEMOTION)
|
|
event.subtype = EV_GUI_MouseMove;
|
|
else
|
|
{
|
|
event.subtype = sev.type == SDL_MOUSEBUTTONDOWN ? EV_GUI_LButtonDown : EV_GUI_LButtonUp;
|
|
event.subtype += (sev.button.button - 1) * 3;
|
|
}
|
|
D_PostEvent(&event);
|
|
}
|
|
break;
|
|
|
|
case SDL_KEYDOWN:
|
|
case SDL_KEYUP:
|
|
if (sev.key.keysym.sym >= SDLK_LAST)
|
|
break;
|
|
|
|
if (!GUICapture)
|
|
{
|
|
event.type = sev.type == SDL_KEYDOWN ? EV_KeyDown : EV_KeyUp;
|
|
event.data1 = KeySymToDIK[sev.key.keysym.sym];
|
|
if (event.data1)
|
|
{
|
|
if (sev.key.keysym.sym < 256)
|
|
{
|
|
event.data2 = sev.key.keysym.sym;
|
|
}
|
|
D_PostEvent (&event);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
event.type = EV_GUI_Event;
|
|
event.subtype = sev.type == SDL_KEYDOWN ? EV_GUI_KeyDown : EV_GUI_KeyUp;
|
|
event.data3 = ((sev.key.keysym.mod & KMOD_SHIFT) ? GKM_SHIFT : 0) |
|
|
((sev.key.keysym.mod & KMOD_CTRL) ? GKM_CTRL : 0) |
|
|
((sev.key.keysym.mod & KMOD_ALT) ? GKM_ALT : 0);
|
|
|
|
if (sev.key.keysym.sym < SDLK_LAST)
|
|
{
|
|
if (event.subtype == EV_GUI_KeyDown)
|
|
{
|
|
if (DownState[sev.key.keysym.sym])
|
|
{
|
|
event.subtype = EV_GUI_KeyRepeat;
|
|
}
|
|
DownState[sev.key.keysym.sym] = 1;
|
|
}
|
|
else
|
|
{
|
|
DownState[sev.key.keysym.sym] = 0;
|
|
}
|
|
}
|
|
|
|
switch (sev.key.keysym.sym)
|
|
{
|
|
case SDLK_KP_ENTER: event.data1 = GK_RETURN; break;
|
|
case SDLK_PAGEUP: event.data1 = GK_PGUP; break;
|
|
case SDLK_PAGEDOWN: event.data1 = GK_PGDN; break;
|
|
case SDLK_END: event.data1 = GK_END; break;
|
|
case SDLK_HOME: event.data1 = GK_HOME; break;
|
|
case SDLK_LEFT: event.data1 = GK_LEFT; break;
|
|
case SDLK_RIGHT: event.data1 = GK_RIGHT; break;
|
|
case SDLK_UP: event.data1 = GK_UP; break;
|
|
case SDLK_DOWN: event.data1 = GK_DOWN; break;
|
|
case SDLK_DELETE: event.data1 = GK_DEL; break;
|
|
case SDLK_ESCAPE: event.data1 = GK_ESCAPE; break;
|
|
case SDLK_F1: event.data1 = GK_F1; break;
|
|
case SDLK_F2: event.data1 = GK_F2; break;
|
|
case SDLK_F3: event.data1 = GK_F3; break;
|
|
case SDLK_F4: event.data1 = GK_F4; break;
|
|
case SDLK_F5: event.data1 = GK_F5; break;
|
|
case SDLK_F6: event.data1 = GK_F6; break;
|
|
case SDLK_F7: event.data1 = GK_F7; break;
|
|
case SDLK_F8: event.data1 = GK_F8; break;
|
|
case SDLK_F9: event.data1 = GK_F9; break;
|
|
case SDLK_F10: event.data1 = GK_F10; break;
|
|
case SDLK_F11: event.data1 = GK_F11; break;
|
|
case SDLK_F12: event.data1 = GK_F12; break;
|
|
default:
|
|
if (sev.key.keysym.sym < 256)
|
|
{
|
|
event.data1 = sev.key.keysym.sym;
|
|
}
|
|
break;
|
|
}
|
|
event.data2 = sev.key.keysym.unicode & 0xff;
|
|
if (event.data1 < 128)
|
|
{
|
|
event.data1 = toupper(event.data1);
|
|
D_PostEvent (&event);
|
|
}
|
|
if (!iscntrl(event.data2) && event.subtype != EV_GUI_KeyUp)
|
|
{
|
|
event.subtype = EV_GUI_Char;
|
|
event.data1 = event.data2;
|
|
event.data2 = sev.key.keysym.mod & KMOD_ALT;
|
|
event.data3 = 0;
|
|
D_PostEvent (&event);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SDL_JOYBUTTONDOWN:
|
|
case SDL_JOYBUTTONUP:
|
|
if (!GUICapture)
|
|
{
|
|
event.type = sev.type == SDL_JOYBUTTONDOWN ? EV_KeyDown : EV_KeyUp;
|
|
event.data1 = KEY_FIRSTJOYBUTTON + sev.jbutton.button;
|
|
if(event.data1 != 0)
|
|
D_PostEvent(&event);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void I_GetEvent ()
|
|
{
|
|
SDL_Event sev;
|
|
|
|
while (SDL_PollEvent (&sev))
|
|
{
|
|
MessagePump (sev);
|
|
}
|
|
if (use_mouse)
|
|
{
|
|
MouseRead ();
|
|
}
|
|
}
|
|
|
|
void I_StartTic ()
|
|
{
|
|
I_CheckGUICapture ();
|
|
I_CheckNativeMouse ();
|
|
I_GetEvent ();
|
|
}
|
|
|
|
void I_StartFrame ()
|
|
{
|
|
if (KeySymToDIK[SDLK_BACKSPACE] == 0)
|
|
{
|
|
InitKeySymMap ();
|
|
}
|
|
}
|