SDL: try to fix some text-entry issues.
SDL: sanitize finger device ids. SDL: allow remapping of joystick/controller device ids (so you can use them to control different players). git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5012 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
74a7dff814
commit
0173e797aa
2 changed files with 146 additions and 30 deletions
|
@ -14,6 +14,7 @@ extern qboolean vid_isfullscreen;
|
||||||
|
|
||||||
#if SDL_MAJOR_VERSION > 1 || (SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION >= 3)
|
#if SDL_MAJOR_VERSION > 1 || (SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION >= 3)
|
||||||
#define HAVE_SDL_TEXTINPUT
|
#define HAVE_SDL_TEXTINPUT
|
||||||
|
cvar_t sys_osk = CVARD("sys_osk", "1", "Enables support for text input. This will be ignored when the console has focus, but gamecode may end up with composition boxes appearing.");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void IN_ActivateMouse(void)
|
void IN_ActivateMouse(void)
|
||||||
|
@ -47,6 +48,44 @@ void IN_DeactivateMouse(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 2
|
||||||
|
#define MAX_FINGERS 16 //zomg! mutant!
|
||||||
|
static struct sdlfinger_s
|
||||||
|
{
|
||||||
|
qboolean active;
|
||||||
|
SDL_TouchID tid;
|
||||||
|
SDL_FingerID fid;
|
||||||
|
} sdlfinger[MAX_FINGERS];
|
||||||
|
//sanitizes sdl fingers into touch events that our engine can eat.
|
||||||
|
//we don't really deal with different devices, we just munge the lot into a single thing (allowing fingers to be tracked, at least if splitscreen isn't active).
|
||||||
|
static uint32_t SDL_GiveFinger(SDL_TouchID tid, SDL_FingerID fid, qboolean fingerraised)
|
||||||
|
{
|
||||||
|
uint32_t f;
|
||||||
|
for (f = 0; f < countof(sdlfinger); f++)
|
||||||
|
{
|
||||||
|
if (sdlfinger[f].active)
|
||||||
|
{
|
||||||
|
if (sdlfinger[f].tid == tid && sdlfinger[f].fid == fid)
|
||||||
|
{
|
||||||
|
sdlfinger[f].active = !fingerraised;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (f = 0; f < countof(sdlfinger); f++)
|
||||||
|
{
|
||||||
|
if (!sdlfinger[f].active)
|
||||||
|
{
|
||||||
|
sdlfinger[f].active = !fingerraised;
|
||||||
|
sdlfinger[f].tid = tid;
|
||||||
|
sdlfinger[f].fid = fid;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if SDL_MAJOR_VERSION >= 2
|
#if SDL_MAJOR_VERSION >= 2
|
||||||
#define MAX_JOYSTICKS 4
|
#define MAX_JOYSTICKS 4
|
||||||
static struct sdljoy_s
|
static struct sdljoy_s
|
||||||
|
@ -57,14 +96,29 @@ static struct sdljoy_s
|
||||||
SDL_Joystick *joystick;
|
SDL_Joystick *joystick;
|
||||||
SDL_GameController *controller;
|
SDL_GameController *controller;
|
||||||
SDL_JoystickID id;
|
SDL_JoystickID id;
|
||||||
|
unsigned int qdevid;
|
||||||
} sdljoy[MAX_JOYSTICKS];
|
} sdljoy[MAX_JOYSTICKS];
|
||||||
//the enumid is the value for the open function rather than the working id.
|
//the enumid is the value for the open function rather than the working id.
|
||||||
|
static unsigned int J_AllocateDevID(void)
|
||||||
|
{
|
||||||
|
unsigned int id = 0, j;
|
||||||
|
for (j = 0; j < MAX_JOYSTICKS;)
|
||||||
|
{
|
||||||
|
if (sdljoy[j++].qdevid == id)
|
||||||
|
{
|
||||||
|
j = 0;
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
static void J_ControllerAdded(int enumid)
|
static void J_ControllerAdded(int enumid)
|
||||||
{
|
{
|
||||||
const char *cname;
|
const char *cname;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < MAX_JOYSTICKS; i++)
|
for (i = 0; i < MAX_JOYSTICKS; i++)
|
||||||
if (sdljoy[i].controller == NULL)
|
if (sdljoy[i].controller == NULL && sdljoy[i].joystick == NULL)
|
||||||
break;
|
break;
|
||||||
if (i == MAX_JOYSTICKS)
|
if (i == MAX_JOYSTICKS)
|
||||||
return;
|
return;
|
||||||
|
@ -80,13 +134,14 @@ static void J_ControllerAdded(int enumid)
|
||||||
cname = "Unknown Controller";
|
cname = "Unknown Controller";
|
||||||
Con_Printf("Found new controller (%i): %s\n", i, cname);
|
Con_Printf("Found new controller (%i): %s\n", i, cname);
|
||||||
sdljoy[i].devname = Z_StrDup(cname);
|
sdljoy[i].devname = Z_StrDup(cname);
|
||||||
|
sdljoy[i].qdevid = DEVID_UNSET;
|
||||||
}
|
}
|
||||||
static void J_JoystickAdded(int enumid)
|
static void J_JoystickAdded(int enumid)
|
||||||
{
|
{
|
||||||
const char *cname;
|
const char *cname;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < MAX_JOYSTICKS; i++)
|
for (i = 0; i < MAX_JOYSTICKS; i++)
|
||||||
if (sdljoy[i].joystick == NULL)
|
if (sdljoy[i].joystick == NULL && sdljoy[i].controller == NULL)
|
||||||
break;
|
break;
|
||||||
if (i == MAX_JOYSTICKS)
|
if (i == MAX_JOYSTICKS)
|
||||||
return;
|
return;
|
||||||
|
@ -100,8 +155,9 @@ static void J_JoystickAdded(int enumid)
|
||||||
if (!cname)
|
if (!cname)
|
||||||
cname = "Unknown Joystick";
|
cname = "Unknown Joystick";
|
||||||
Con_Printf("Found new joystick (%i): %s\n", i, cname);
|
Con_Printf("Found new joystick (%i): %s\n", i, cname);
|
||||||
|
sdljoy[i].qdevid = DEVID_UNSET;
|
||||||
}
|
}
|
||||||
static struct sdljoy_s *J_DevId(int jid)
|
static struct sdljoy_s *J_DevId(SDL_JoystickID jid)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < MAX_JOYSTICKS; i++)
|
for (i = 0; i < MAX_JOYSTICKS; i++)
|
||||||
|
@ -109,24 +165,24 @@ static struct sdljoy_s *J_DevId(int jid)
|
||||||
return &sdljoy[i];
|
return &sdljoy[i];
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
static void J_ControllerAxis(int jid, int axis, int value)
|
static void J_ControllerAxis(SDL_JoystickID jid, int axis, int value)
|
||||||
{
|
{
|
||||||
int axismap[] = {0,1,3,4,2,5};
|
int axismap[] = {0,1,3,4,2,5};
|
||||||
|
|
||||||
struct sdljoy_s *joy = J_DevId(jid);
|
struct sdljoy_s *joy = J_DevId(jid);
|
||||||
if (joy && axis < sizeof(axismap)/sizeof(axismap[0]))
|
if (joy && axis < sizeof(axismap)/sizeof(axismap[0]) && joy->qdevid != DEVID_UNSET)
|
||||||
IN_JoystickAxisEvent(joy - sdljoy, axismap[axis], value / 32767.0);
|
IN_JoystickAxisEvent(joy->qdevid, axismap[axis], value / 32767.0);
|
||||||
}
|
}
|
||||||
static void J_JoystickAxis(int jid, int axis, int value)
|
static void J_JoystickAxis(SDL_JoystickID jid, int axis, int value)
|
||||||
{
|
{
|
||||||
int axismap[] = {0,1,3,4,2,5};
|
int axismap[] = {0,1,3,4,2,5};
|
||||||
|
|
||||||
struct sdljoy_s *joy = J_DevId(jid);
|
struct sdljoy_s *joy = J_DevId(jid);
|
||||||
if (joy && axis < sizeof(axismap)/sizeof(axismap[0]))
|
if (joy && axis < sizeof(axismap)/sizeof(axismap[0]) && joy->qdevid != DEVID_UNSET)
|
||||||
IN_JoystickAxisEvent(joy - sdljoy, axismap[axis], value / 32767.0);
|
IN_JoystickAxisEvent(joy->qdevid, axismap[axis], value / 32767.0);
|
||||||
}
|
}
|
||||||
//we don't do hats and balls and stuff.
|
//we don't do hats and balls and stuff.
|
||||||
static void J_ControllerButton(int jid, int button, qboolean pressed)
|
static void J_ControllerButton(SDL_JoystickID jid, int button, qboolean pressed)
|
||||||
{
|
{
|
||||||
//controllers have reliable button maps.
|
//controllers have reliable button maps.
|
||||||
//but that doesn't meant that fte has specific k_ names for those buttons, but the mapping should be reliable, at least until they get mapped to proper k_ values.
|
//but that doesn't meant that fte has specific k_ names for those buttons, but the mapping should be reliable, at least until they get mapped to proper k_ values.
|
||||||
|
@ -169,9 +225,17 @@ static void J_ControllerButton(int jid, int button, qboolean pressed)
|
||||||
|
|
||||||
struct sdljoy_s *joy = J_DevId(jid);
|
struct sdljoy_s *joy = J_DevId(jid);
|
||||||
if (joy && button < sizeof(buttonmap)/sizeof(buttonmap[0]))
|
if (joy && button < sizeof(buttonmap)/sizeof(buttonmap[0]))
|
||||||
IN_KeyEvent(joy - sdljoy, pressed, buttonmap[button], 0);
|
{
|
||||||
|
if (joy->qdevid == DEVID_UNSET)
|
||||||
|
{
|
||||||
|
if (!pressed)
|
||||||
|
return;
|
||||||
|
joy->qdevid = J_AllocateDevID();
|
||||||
|
}
|
||||||
|
IN_KeyEvent(joy->qdevid, pressed, buttonmap[button], 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
static void J_JoystickButton(int jid, int button, qboolean pressed)
|
static void J_JoystickButton(SDL_JoystickID jid, int button, qboolean pressed)
|
||||||
{
|
{
|
||||||
//generic joysticks have no specific mappings. they're really random like that.
|
//generic joysticks have no specific mappings. they're really random like that.
|
||||||
int buttonmap[] = {
|
int buttonmap[] = {
|
||||||
|
@ -215,9 +279,17 @@ static void J_JoystickButton(int jid, int button, qboolean pressed)
|
||||||
|
|
||||||
struct sdljoy_s *joy = J_DevId(jid);
|
struct sdljoy_s *joy = J_DevId(jid);
|
||||||
if (joy && button < sizeof(buttonmap)/sizeof(buttonmap[0]))
|
if (joy && button < sizeof(buttonmap)/sizeof(buttonmap[0]))
|
||||||
IN_KeyEvent(joy - sdljoy, pressed, buttonmap[button], 0);
|
{
|
||||||
|
if (joy->qdevid == DEVID_UNSET)
|
||||||
|
{
|
||||||
|
if (!pressed)
|
||||||
|
return;
|
||||||
|
joy->qdevid = J_AllocateDevID();
|
||||||
|
}
|
||||||
|
IN_KeyEvent(joy->qdevid, pressed, buttonmap[button], 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
static void J_Kill(int jid, qboolean verbose)
|
static void J_Kill(SDL_JoystickID jid, qboolean verbose)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct sdljoy_s *joy = J_DevId(jid);
|
struct sdljoy_s *joy = J_DevId(jid);
|
||||||
|
@ -226,20 +298,29 @@ static void J_Kill(int jid, qboolean verbose)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//make sure all the axis are nulled out, to avoid surprises.
|
//make sure all the axis are nulled out, to avoid surprises.
|
||||||
for (i = 0; i < 6; i++)
|
if (joy->qdevid != DEVID_UNSET)
|
||||||
IN_JoystickAxisEvent(joy - sdljoy, i, 0);
|
{
|
||||||
|
for (i = 0; i < 6; i++)
|
||||||
|
IN_JoystickAxisEvent(joy->qdevid, i, 0);
|
||||||
|
if (joy->controller)
|
||||||
|
{
|
||||||
|
for (i = 0; i < 32; i++)
|
||||||
|
J_ControllerButton(jid, i, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; i < 32; i++)
|
||||||
|
J_JoystickButton(jid, i, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (joy->controller)
|
if (joy->controller)
|
||||||
{
|
{
|
||||||
for (i = 0; i < 32; i++)
|
|
||||||
J_ControllerButton(jid, i, false);
|
|
||||||
Con_Printf("Controller unplugged(%i): %s\n", (int)(joy - sdljoy), joy->devname);
|
Con_Printf("Controller unplugged(%i): %s\n", (int)(joy - sdljoy), joy->devname);
|
||||||
SDL_GameControllerClose(joy->controller);
|
SDL_GameControllerClose(joy->controller);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (i = 0; i < 32; i++)
|
|
||||||
J_JoystickButton(jid, i, false);
|
|
||||||
Con_Printf("Joystick unplugged(%i): %s\n", (int)(joy - sdljoy), joy->devname);
|
Con_Printf("Joystick unplugged(%i): %s\n", (int)(joy - sdljoy), joy->devname);
|
||||||
SDL_JoystickClose(joy->joystick);
|
SDL_JoystickClose(joy->joystick);
|
||||||
}
|
}
|
||||||
|
@ -247,6 +328,7 @@ static void J_Kill(int jid, qboolean verbose)
|
||||||
joy->joystick = NULL;
|
joy->joystick = NULL;
|
||||||
Z_Free(joy->devname);
|
Z_Free(joy->devname);
|
||||||
joy->devname = NULL;
|
joy->devname = NULL;
|
||||||
|
joy->qdevid = DEVID_UNSET;
|
||||||
}
|
}
|
||||||
static void J_KillAll(void)
|
static void J_KillAll(void)
|
||||||
{
|
{
|
||||||
|
@ -681,6 +763,22 @@ static unsigned int tbl_sdltoquakemouse[] =
|
||||||
void Sys_SendKeyEvents(void)
|
void Sys_SendKeyEvents(void)
|
||||||
{
|
{
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
|
|
||||||
|
#ifdef HAVE_SDL_TEXTINPUT
|
||||||
|
SDL_bool active = SDL_IsTextInputActive();
|
||||||
|
if (Key_Dest_Has(kdm_console|kdm_message) || (!Key_Dest_Has(~kdm_game) && cls.state == ca_disconnected) || sys_osk.ival)
|
||||||
|
{
|
||||||
|
if (!active)
|
||||||
|
SDL_StartTextInput();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (active)
|
||||||
|
SDL_StopTextInput();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
while(SDL_PollEvent(&event))
|
while(SDL_PollEvent(&event))
|
||||||
{
|
{
|
||||||
switch(event.type)
|
switch(event.type)
|
||||||
|
@ -784,11 +882,17 @@ void Sys_SendKeyEvents(void)
|
||||||
#if SDL_MAJOR_VERSION >= 2
|
#if SDL_MAJOR_VERSION >= 2
|
||||||
case SDL_FINGERDOWN:
|
case SDL_FINGERDOWN:
|
||||||
case SDL_FINGERUP:
|
case SDL_FINGERUP:
|
||||||
IN_MouseMove(event.tfinger.fingerId, true, event.tfinger.x * vid.pixelwidth, event.tfinger.y * vid.pixelheight, 0, event.tfinger.pressure);
|
{
|
||||||
IN_KeyEvent(event.tfinger.fingerId, event.type==SDL_FINGERDOWN, K_MOUSE1, 0);
|
uint32_t thefinger = SDL_GiveFinger(event.tfinger.touchId, event.tfinger.fingerId, event.type==SDL_FINGERUP);
|
||||||
|
IN_MouseMove(thefinger, true, event.tfinger.x * vid.pixelwidth, event.tfinger.y * vid.pixelheight, 0, event.tfinger.pressure);
|
||||||
|
IN_KeyEvent(thefinger, event.type==SDL_FINGERDOWN, K_MOUSE1, 0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case SDL_FINGERMOTION:
|
case SDL_FINGERMOTION:
|
||||||
IN_MouseMove(event.tfinger.fingerId, true, event.tfinger.x * vid.pixelwidth, event.tfinger.y * vid.pixelheight, 0, event.tfinger.pressure);
|
{
|
||||||
|
uint32_t thefinger = SDL_GiveFinger(event.tfinger.touchId, event.tfinger.fingerId, false);
|
||||||
|
IN_MouseMove(thefinger, true, event.tfinger.x * vid.pixelwidth, event.tfinger.y * vid.pixelheight, 0, event.tfinger.pressure);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_DROPFILE:
|
case SDL_DROPFILE:
|
||||||
|
@ -885,11 +989,17 @@ void INS_Shutdown (void)
|
||||||
|
|
||||||
void INS_ReInit (void)
|
void INS_ReInit (void)
|
||||||
{
|
{
|
||||||
|
#if SDL_MAJOR_VERSION >= 2
|
||||||
|
unsigned int i;
|
||||||
|
memset(sdljoy, sizeof(sdljoy), 0);
|
||||||
|
for (i = 0; i < MAX_JOYSTICKS; i++)
|
||||||
|
sdljoy[i].qdevid = DEVID_UNSET;
|
||||||
|
SDL_InitSubSystem(SDL_INIT_JOYSTICK|SDL_INIT_GAMECONTROLLER);
|
||||||
|
#endif
|
||||||
|
|
||||||
IN_ActivateMouse();
|
IN_ActivateMouse();
|
||||||
|
|
||||||
#ifdef HAVE_SDL_TEXTINPUT
|
#ifndef HAVE_SDL_TEXTINPUT
|
||||||
SDL_StartTextInput();
|
|
||||||
#else
|
|
||||||
SDL_EnableUNICODE(SDL_ENABLE);
|
SDL_EnableUNICODE(SDL_ENABLE);
|
||||||
#endif
|
#endif
|
||||||
#if SDL_MAJOR_VERSION >= 2
|
#if SDL_MAJOR_VERSION >= 2
|
||||||
|
@ -903,8 +1013,8 @@ void INS_Move(float *movements, int pnum)
|
||||||
}
|
}
|
||||||
void INS_Init (void)
|
void INS_Init (void)
|
||||||
{
|
{
|
||||||
#if SDL_MAJOR_VERSION >= 2
|
#ifdef HAVE_SDL_TEXTINPUT
|
||||||
SDL_InitSubSystem(SDL_INIT_JOYSTICK|SDL_INIT_GAMECONTROLLER);
|
Cvar_Register(&sys_osk, "input controls");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
void INS_Accumulate(void) //input polling
|
void INS_Accumulate(void) //input polling
|
||||||
|
@ -915,6 +1025,10 @@ void INS_Commands (void) //used to Cbuf_AddText joystick button events in window
|
||||||
}
|
}
|
||||||
void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, unsigned int *qdevid))
|
void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, unsigned int *qdevid))
|
||||||
{
|
{
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < MAX_JOYSTICKS; i++)
|
||||||
|
if (sdljoy[i].controller || sdljoy[i].joystick)
|
||||||
|
callback(ctx, "joy", sdljoy[i].devname, &sdljoy[i].qdevid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -914,7 +914,7 @@ void Key_DefaultLinkClicked(console_t *con, char *text, char *info)
|
||||||
|
|
||||||
void Key_ConsoleRelease(console_t *con, int key, int unicode)
|
void Key_ConsoleRelease(console_t *con, int key, int unicode)
|
||||||
{
|
{
|
||||||
char *buffer;
|
char *buffer;
|
||||||
|
|
||||||
if (key == K_MOUSE1 && con->buttonsdown == CB_SELECT)
|
if (key == K_MOUSE1 && con->buttonsdown == CB_SELECT)
|
||||||
{
|
{
|
||||||
|
@ -1628,7 +1628,7 @@ qboolean Key_Console (console_t *con, unsigned int unicode, int key)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!consolekeys[rkey])
|
if (rkey && !consolekeys[rkey])
|
||||||
{
|
{
|
||||||
if (rkey != '`' || key_linepos==0)
|
if (rkey != '`' || key_linepos==0)
|
||||||
return false;
|
return false;
|
||||||
|
@ -2303,6 +2303,8 @@ Key_Event
|
||||||
|
|
||||||
Called by the system between frames for both key up and key down events
|
Called by the system between frames for both key up and key down events
|
||||||
Should NOT be called during an interrupt!
|
Should NOT be called during an interrupt!
|
||||||
|
|
||||||
|
On some systems, keys and (uni)char codes will be entirely separate events.
|
||||||
===================
|
===================
|
||||||
*/
|
*/
|
||||||
void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down)
|
void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down)
|
||||||
|
|
Loading…
Reference in a new issue