1
0
Fork 0
forked from fte/fteqw

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:
Spoike 2016-07-29 16:10:28 +00:00
parent 74a7dff814
commit 0173e797aa
2 changed files with 146 additions and 30 deletions

View file

@ -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);
} }

View file

@ -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)