From fb4531ea6c7fbcdfdcdd4957e769850160a50448 Mon Sep 17 00:00:00 2001 From: Spoike Date: Mon, 9 Jan 2023 05:14:38 +0000 Subject: [PATCH] Attempt to improve touchscreen behaviours with onscreen buttons that appear upon touch events (and fade out). Long presses should close menus etc. Likely needs some more work. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@6335 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/cl_input.c | 9 +- engine/client/cl_main.c | 4 +- engine/client/cl_screen.c | 63 ++++++-- engine/client/client.h | 2 +- engine/client/console.c | 50 ++++++- engine/client/in_generic.c | 292 ++++++++++++++++++++----------------- engine/client/in_sdl.c | 59 +++++++- engine/client/input.h | 5 +- engine/client/keys.c | 141 +++++++----------- engine/client/keys.h | 11 +- engine/client/m_download.c | 12 +- engine/client/m_items.c | 29 ++-- engine/client/m_mp3.c | 4 +- engine/client/m_multi.c | 4 +- engine/client/m_options.c | 16 +- engine/client/m_single.c | 2 +- engine/client/menu.c | 18 ++- engine/client/menu.h | 2 + engine/client/pr_clcmd.c | 6 + engine/client/pr_menu.c | 6 +- engine/client/screen.h | 2 +- engine/client/sys_sdl.c | 20 ++- engine/common/cmd.c | 26 +++- engine/common/console.h | 5 +- 24 files changed, 495 insertions(+), 293 deletions(-) diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 36cde239a..8a9715a3a 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -763,13 +763,16 @@ qboolean IN_WeaponWheelIsShown(void) return false; return true; } -qboolean IN_WeaponWheelAccumulate(int pnum, float x, float y) //either mouse or controller +qboolean IN_WeaponWheelAccumulate(int pnum, float x, float y, float threshhold) //either mouse or controller { if (!(in_wwheel.state[pnum]&1) || !weaponinfo_count) return false; - wwheeldir[pnum][0] += x; - wwheeldir[pnum][1] += y; + if (x*x+y*y > threshhold*threshhold) //protects against deadzones. + { + wwheeldir[pnum][0] += x; + wwheeldir[pnum][1] += y; + } return true; } #include "shader.h" diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index be7593af2..54e869d1c 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -96,8 +96,8 @@ cvar_t cfg_save_name = CVARFD("cfg_save_name", "fte", CVAR_ARCHIVE|CVAR_NOTFROMS cvar_t cl_splitscreen = CVARD("cl_splitscreen", "0", "Enables splitscreen support. See also: allow_splitscreen, in_rawinput*, the \"p\" command."); -cvar_t lookspring = CVARF("lookspring","0", CVAR_ARCHIVE); -cvar_t lookstrafe = CVARF("lookstrafe","0", CVAR_ARCHIVE); +cvar_t lookspring = CVARFD("lookspring","0", CVAR_ARCHIVE, "Recentre the camera when the mouse-look is released."); +cvar_t lookstrafe = CVARFD("lookstrafe","0", CVAR_ARCHIVE, "Mouselook enables mouse strafing."); cvar_t sensitivity = CVARF("sensitivity","10", CVAR_ARCHIVE); cvar_t cl_staticsounds = CVARF("cl_staticsounds", "1", CVAR_ARCHIVE); diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index c8f20bf2d..0edaf1003 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -1253,12 +1253,14 @@ typedef struct showpic_s { struct showpic_s *next; qbyte zone; qboolean persist; + float fadedelay; short x, y, w, h; char *name; char *picname; char *tcommand; } showpic_t; showpic_t *showpics; +double showpics_touchtime; static void SP_RecalcXY ( float *xx, float *yy, int origin ) { @@ -1347,7 +1349,7 @@ static void SP_RecalcXY ( float *xx, float *yy, int origin ) void SCR_ShowPics_Draw(void) { downloadlist_t *failed; - float x, y; + float x, y, a = 1; showpic_t *sp; mpic_t *p; for (sp = showpics; sp; sp = sp->next) @@ -1366,23 +1368,48 @@ void SCR_ShowPics_Draw(void) if (failed) continue; + if (sp->fadedelay && showpics_touchtime+sp->fadedelay < realtime) + { + a = 1+(showpics_touchtime+sp->fadedelay-realtime); + if (a > 1) + a = 1; //shouldn't really happen, w/e. + else if (a <= 0) + continue; + R2D_ImageColours(1,1,1,a); + } + else if (a != 1) + R2D_ImageColours(1,1,1,a=1); + p = R2D_SafeCachePic(sp->picname); - if (!p) - continue; - R2D_ScalePic(x, y, sp->w?sp->w:p->width, sp->h?sp->h:p->height, p); + if (!p || !R_GetShaderSizes(p, NULL, NULL, false)) + { + if (sp->h > 8) + Draw_FunStringWidth(x-2, y + (sp->h-8)/2, sp->name, sp->w+4, 2, false); //slightly wider, to try to somewhat deal with 16:10 resolutions... + } + else + R2D_ScalePic(x, y, sp->w?sp->w:p->width, sp->h?sp->h:p->height, p); } + + if (a != 1) + R2D_ImageColours(1,1,1,1); } -char *SCR_ShowPics_ClickCommand(int cx, int cy) +const char *SCR_ShowPics_ClickCommand(float cx, float cy, qboolean istouch) { downloadlist_t *failed; float x, y, w, h; showpic_t *sp; mpic_t *p; + qboolean tryload = !showpics_touchtime; + float bestdist = istouch?16:1; + const char *best = NULL; + showpics_touchtime = realtime; for (sp = showpics; sp; sp = sp->next) { if (!sp->tcommand || !*sp->tcommand) continue; + tryload = false; + x = sp->x; y = sp->y; w = sp->w; @@ -1396,7 +1423,7 @@ char *SCR_ShowPics_ClickCommand(int cx, int cy) for (failed = cl.faileddownloads; failed; failed = failed->next) { //don't try displaying ones that we know to have failed. if (!strcmp(failed->rname, sp->picname)) - break; + break; } if (failed) continue; @@ -1406,11 +1433,22 @@ char *SCR_ShowPics_ClickCommand(int cx, int cy) w = w?w:sp->w; h = h?h:sp->h; } - if (cx >= x && cx < x+w) - if (cy >= y && cy < y+h) - return sp->tcommand; //if they overlap, that's your own damn fault. + + x = bound(x, cx, x+w)-cx; + y = bound(y, cy, y+h)-cy; + x = max(fabs(x),fabs(y)); + if (bestdist > x) + { //looks like this one is closer to the cursor + bestdist = x; + best = sp->tcommand; + if (bestdist <= 0) //use the first that's inside. + break; + } } - return NULL; + + if (tryload) + Cbuf_AddText("exec touch.cfg\n", RESTRICT_LOCAL); + return best; } //all=false clears only server pics, not ones from configs. @@ -1425,6 +1463,8 @@ void SCR_ShowPic_ClearAll(qboolean persistflag) scr_centerprint[pnum].charcount = 0; } + if (!persistflag) + showpics_touchtime = 0; //map change. gamedir may have changed too. for (link = &showpics; (sp=*link); ) { if (sp->persist != persistflag) @@ -1599,6 +1639,7 @@ void SCR_ShowPic_Script_f(void) int x, y, w, h; int zone; showpic_t *sp; + float fadedelay; imgname = Cmd_Argv(1); name = Cmd_Argv(2); @@ -1609,6 +1650,7 @@ void SCR_ShowPic_Script_f(void) w = atoi(Cmd_Argv(6)); h = atoi(Cmd_Argv(7)); tcommand = Cmd_Argv(8); + fadedelay = atof(Cmd_Argv(9)); sp = SCR_ShowPic_Find(name); @@ -1623,6 +1665,7 @@ void SCR_ShowPic_Script_f(void) sp->y = y; sp->w = w; sp->h = h; + sp->fadedelay = fadedelay; if (!sp->persist) sp->persist = !Cmd_FromGamecode(); diff --git a/engine/client/client.h b/engine/client/client.h index b2d3897b9..f90fc0832 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -1216,7 +1216,7 @@ void CL_UpdateWindowTitle(void); #ifdef QUAKESTATS const char *IN_GetPreselectedViewmodelName(unsigned int pnum); -qboolean IN_WeaponWheelAccumulate(int pnum, float x, float y); +qboolean IN_WeaponWheelAccumulate(int pnum, float x, float y, float threshhold); qboolean IN_DrawWeaponWheel(int pnum); qboolean IN_WeaponWheelIsShown(void); //to decide when the game should be auto-paused. #endif diff --git a/engine/client/console.c b/engine/client/console.c index c17919aab..12ec13dc3 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -3294,7 +3294,7 @@ void Con_DrawConsole (int lines, qboolean noback) } selactive = Key_GetConsoleSelectionBox(con_current, &selsx, &selsy, &selex, &seley); - if ((con_current->flags & CONF_KEEPSELECTION) && con_current->selstartline && con_current->selendline) + if ((con_current->flags & CONF_KEEPSELECTION) && con_current->selstartline && con_current->selendline && con_current->buttonsdown != CB_SELECTED) selactive = -1; Font_BeginString(font_console, x, y, &x, &y); @@ -3327,6 +3327,54 @@ void Con_DrawConsole (int lines, qboolean noback) Font_EndString(font_console); mouseconsole = con_mouseover?con_mouseover:con_current; + + + if (con_current->buttonsdown == CB_SELECTED) + { //select was released... + console_t *con = con_current; + char *buffer; + con->buttonsdown = CB_NONE; + if (con->selstartline) + { + con->flags |= CONF_KEEPSELECTION; + if (con->userline) + { + if (con->flags & CONF_BACKSELECTION) + { + con->userline = con->selendline; + con->useroffset = con->selendoffset; + } + else + { + con->userline = con->selstartline; + con->useroffset = con->selstartoffset; + } + } + if (con->selstartline == con->selendline && con->selendoffset <= con->selstartoffset+1) + { + if (keydown[K_LSHIFT] || keydown[K_RSHIFT]) + ; + else + { + buffer = Con_CopyConsole(con, false, true, false); + if (buffer) + { + Key_HandleConsoleLink(con, buffer); + Z_Free(buffer); + } + } + } + else + { + buffer = Con_CopyConsole(con, true, false, true); //don't keep markup if we're copying to the clipboard + if (buffer) + { + Sys_SaveClipboard(CBT_SELECTION, buffer); + Z_Free(buffer); + } + } + } + } } else mouseconsole = con_mouseover?con_mouseover:NULL; diff --git a/engine/client/in_generic.c b/engine/client/in_generic.c index a9769723e..223f1561a 100644 --- a/engine/client/in_generic.c +++ b/engine/client/in_generic.c @@ -15,8 +15,9 @@ extern qboolean mouse_active; static cvar_t m_filter = CVARF("m_filter", "0", CVAR_ARCHIVE); static cvar_t m_forcewheel = CVARD("m_forcewheel", "1", "0: ignore mousewheels in apis where it is abiguous.\n1: Use mousewheel when it is treated as a third axis. Motion above a threshold is ignored, to avoid issues with an unknown threshold.\n2: Like 1, but excess motion is retained. The threshold specifies exact z-axis distance per notice."); static cvar_t m_forcewheel_threshold = CVARD("m_forcewheel_threshold", "32", "Mousewheel graduations smaller than this will not trigger mousewheel deltas."); -static cvar_t m_touchstrafe = CVARAFD("m_touchstrafe", "1", "m_strafeonright", CVAR_ARCHIVE, "0: entire screen changes angles only.\n1: right hand side controls strafing.\n2:left hand side strafes."); -static cvar_t m_fatpressthreshold = CVARFD("m_fatpressthreshold", "0.2", CVAR_ARCHIVE, "How fat your thumb has to be to register a fat press (touchscreens)."); +static cvar_t m_touchstrafe = CVARAFD("m_touchstrafe", "0", "m_strafeonright", CVAR_ARCHIVE, "0: entire screen changes angles only.\n1: right hand side controls strafing.\n2:left hand side strafes."); +//static cvar_t m_fatpressthreshold = CVARFD("m_fatpressthreshold", "0.2", CVAR_ARCHIVE, "How fat your thumb has to be to register a fat press (touchscreens)."); +static cvar_t m_longpressthreshold = CVARFD("m_longpressthreshold", "1", CVAR_ARCHIVE, "How long to press for it to register as a long press (touchscreens)."); static cvar_t m_touchmajoraxis = CVARFD("m_touchmajoraxis", "1", CVAR_ARCHIVE, "When using a touchscreen, use only the major axis for strafing."); static cvar_t m_slidethreshold = CVARFD("m_slidethreshold", "10", CVAR_ARCHIVE, "How far your finger needs to move to be considered a slide event (touchscreens)."); @@ -121,16 +122,27 @@ static cvar_t joy_movethreshold[3] = CVAR("joyupthreshold", "0.118"), //30/255 (trigger) }; -static cvar_t joy_exponent = CVARD("joyexponent", "3", "Scales joystick/controller sensitivity non-linearly to increase precision in the center.\nA value of 1 is linear."); +static cvar_t joy_exponent = CVARD("joyexponent", "1", "Scales joystick/controller sensitivity non-linearly to increase precision in the center.\nA value of 1 is linear."); + +#if defined(__linux__) && defined(FTE_SDL) +#include void joy_radialdeadzone_cb(cvar_t *var, char *oldvalue) { if (!*var->string) { -#if defined(__linux__) && defined(FTE_SDL) - var->ival = 2; //sdl2 provides its own deadzones on linux, by default. FIXME: check SDL_GetHint(SDL_HINT_LINUX_JOYSTICK_DEADZONES), default is "1" -#endif + if (SDL_GetHintBoolean(SDL_HINT_LINUX_JOYSTICK_DEADZONES, true)) + var->ival = 2; //sdl2 provides its own deadzones on linux, by default. + else + var->ival = 1; } } +#else +void joy_radialdeadzone_cb(cvar_t *var, char *oldvalue) +{ + if (!*var->string) + var->ival = 1; +} +#endif static cvar_t joy_radialdeadzone = CVARCD("joyradialdeadzone", "", joy_radialdeadzone_cb, "Treat controller dead zones as a pair, rather than per-axis."); @@ -207,7 +219,8 @@ static struct mouse_s vec2_t delta; //how far its moved recently vec2_t old_delta; //how far its moved previously, for mouse smoothing float wheeldelta; - int held; //button is held (for touch stuff). 1=mouse movements permitted. 2=mouse1 was sent to the game + double touchtime; //0 when not touching, otherwise start time of touch. + unsigned int touchkey; //which other key we generated (so it gets released again. unsigned int updates; //tracks updates per second qboolean updated; } ptr[MAXPOINTERS]; @@ -336,7 +349,7 @@ void IN_Init(void) Cvar_Register (&m_forcewheel, "Input Controls"); Cvar_Register (&m_forcewheel_threshold, "Input Controls"); Cvar_Register (&m_touchstrafe, "input controls"); - Cvar_Register (&m_fatpressthreshold, "input controls"); + Cvar_Register (&m_longpressthreshold, "input controls"); Cvar_Register (&m_slidethreshold, "input controls"); Cvar_Register (&m_touchmajoraxis, "input controls"); Cvar_Register (&m_accel, "input controls"); @@ -367,51 +380,40 @@ void IN_Init(void) INS_Init(); } -//tells the keys.c code whether the cursor is currently active, causing mouse clicks instead of binds. -qboolean IN_MouseDevIsTouch(unsigned int devid) -{ - if (devid < MAXPOINTERS) - return ptr[devid].type == M_TOUCH; - return false; -} //there was no ui to click on at least... -//translates MOUSE1 press events into begin-look-or-strafe events. -//translates to MOUSE2 accordingly -//returns 0 if it ate it completely. -int IN_TranslateMButtonPress(unsigned int devid) +//translates touch press events into ones that are actually bound, according to touchstrafe and position. +int IN_Touch_Fallback(unsigned int devid) { int ret; - if (!ptr[devid].held) + if (devid >= countof(ptr)) + ret = 0; + else switch(m_touchstrafe.ival) //translate touch to mouse2 if its on the strafing side of the screen. { - //set the cursor-pressed state, so we begin to look/strafe around - ptr[devid].held = 1; - ptr[devid].moveddist = 0; - ptr[devid].heldpos[0] = ptr[devid].oldpos[0]; - ptr[devid].heldpos[1] = ptr[devid].oldpos[1]; - ptr[devid].delta[0] = 0; - ptr[devid].delta[1] = 0; - ret = 0; //eat it - } - else - { - //translate touch to mouse2 if its on the strafing side of the screen. - switch(m_touchstrafe.ival) - { - case 2: - ret = ptr[devid].heldpos[0] < vid.pixelwidth/2; - break; - default: - ret = ptr[devid].heldpos[0] > vid.pixelwidth/2; - break; - case 0: - ret = false; - break; - } - ret = ret?K_MOUSE2:K_MOUSE1; + case 2: + ret = ptr[devid].heldpos[0] < vid.pixelwidth/2; + break; + default: + ret = ptr[devid].heldpos[0] > vid.pixelwidth/2; + break; + case 0: + ret = false; + break; } + ret = ret?K_MOUSE2:K_MOUSE1; return ret; } +void IN_Touch_BlockGestures(unsigned int devid) +{ //called via K_TOUCH, blocks K_TOUCHTAP etc gestures + if (devid < countof(ptr)) + ptr[devid].touchkey = 0; //block it all. +} +qboolean IN_Touch_MouseIsAbs(unsigned int devid) +{ //lets the caller know if a mouse1 down event was abs + if (devid < countof(ptr)) + return ptr[devid].type == M_TOUCH; + return false; +} /*a 'pointer' is either a multitouch pointer, or a separate device note that mice use the keyboard button api, but separate devices*/ @@ -428,6 +430,7 @@ void IN_Commands(void) switch(ev->type) { case IEV_KEYRELEASE: +//Con_Printf("IEV_KEYDOWN %i: %i '%c'\n", ev->devid, ev->keyboard.scancode, ev->keyboard.unicode?ev->keyboard.unicode:' '); if (ev->keyboard.scancode == -1) { int i; @@ -435,43 +438,48 @@ void IN_Commands(void) Key_Event(ev->devid, i, 0, false); break; } - case IEV_KEYDOWN: -//Con_Printf("IEV_KEY%s %i: %i '%c'\n", (ev->type==IEV_KEYDOWN)?"DOWN ":"RELEASE", ev->devid, ev->keyboard.scancode, ev->keyboard.unicode?ev->keyboard.unicode:' '); - //on touchscreens, mouse1 is used as up/down state. we have to emulate actual mouse clicks based upon distance moved, so we can get movement events. if ((ev->keyboard.scancode == K_MOUSE1||ev->keyboard.scancode==K_TOUCH) && ev->devid < MAXPOINTERS && (ptr[ev->devid].type == M_TOUCH)) - { - if (ev->type == IEV_KEYDOWN) - { - float fl; - touchcursor = ev->devid; - fl = ptr[ev->devid].oldpos[0] * vid.width / vid.pixelwidth; - mousecursor_x = bound(0, fl, vid.width-1); - fl = ptr[ev->devid].oldpos[1] * vid.height / vid.pixelheight; - mousecursor_y = bound(0, fl, vid.height-1); - } - else if (touchcursor == ev->devid) + { //touch (or abs clicks) + struct mouse_s *m = &ptr[ev->devid]; + if (touchcursor == ev->devid) touchcursor = -1; //revert it to the mouse, or whatever device was 0. - if (Key_MouseShouldBeFree()) - ptr[ev->devid].held = 0; - else if (ptr[ev->devid].held) - { - if (ev->type == IEV_KEYDOWN) - Key_Event(ev->devid, ev->keyboard.scancode, ev->keyboard.unicode, ev->type == IEV_KEYDOWN); + if (ev->keyboard.scancode==K_TOUCH && m->touchtime && m->touchkey==K_TOUCH) + { //convert to tap/longpress if it wasn't already a gesture. don't ever convert mouse. + if (Sys_DoubleTime()-m->touchtime > m_longpressthreshold.value) + m->touchkey = K_TOUCHLONG; else - { - if (ptr[ev->devid].held == 1 && ptr[ev->devid].moveddist < m_slidethreshold.value) - { - ptr[ev->devid].held = 2; //so we don't just flag it as held again - Key_Event(ev->devid, ev->keyboard.scancode, 0, true); - } - Key_Event(ev->devid, ev->keyboard.scancode, 0, false); - ptr[ev->devid].held = 0; - } - break; + m->touchkey = K_TOUCHTAP; + Key_Event(ev->devid, m->touchkey, 0, true); } + if (m->touchkey && m->touchkey!=ev->keyboard.scancode) + Key_Event(ev->devid, m->touchkey, 0, false); //and release... + + //reset it. + m->touchkey = 0; + m->touchtime = 0; + m->moveddist = 0; } - Key_Event(ev->devid, ev->keyboard.scancode, ev->keyboard.unicode, ev->type == IEV_KEYDOWN); + Key_Event(ev->devid, ev->keyboard.scancode, ev->keyboard.unicode, false); + break; + case IEV_KEYDOWN: +//Con_Printf("IEV_KEYDOWN %i: %i '%c'\n", ev->devid, ev->keyboard.scancode, ev->keyboard.unicode?ev->keyboard.unicode:' '); + if ((ev->keyboard.scancode == K_MOUSE1||ev->keyboard.scancode==K_TOUCH) && ev->devid < MAXPOINTERS && (ptr[ev->devid].type == M_TOUCH)) + { //touch (or abs clicks) + struct mouse_s *m = &ptr[ev->devid]; + float fl; + touchcursor = ev->devid; + fl = m->oldpos[0] * vid.width / vid.pixelwidth; mousecursor_x = bound(0, fl, vid.width-1); + fl = m->oldpos[1] * vid.height / vid.pixelheight; mousecursor_y = bound(0, fl, vid.height-1); + + m->touchtime = Sys_DoubleTime(); + m->moveddist = 0; + if (ev->keyboard.scancode==K_TOUCH) + m->touchkey = K_TOUCH; + else + m->touchkey = 0; + } + Key_Event(ev->devid, ev->keyboard.scancode, ev->keyboard.unicode, true); break; case IEV_JOYAXIS: if (ev->devid < MAXJOYSTICKS && ev->joy.axis < MAXJOYAXIS) @@ -541,44 +549,45 @@ void IN_Commands(void) if (ev->devid < MAXPOINTERS) { - if (ptr[ev->devid].type != M_TOUCH) + struct mouse_s *m = &ptr[ev->devid]; + if (m->type != M_TOUCH) { //if its now become an absolute device, clear stuff so we don't get confused. - ptr[ev->devid].type = M_TOUCH; - ptr[ev->devid].held = 0; - ptr[ev->devid].moveddist = 0; - ptr[ev->devid].oldpos[0] = ev->mouse.x; - ptr[ev->devid].oldpos[1] = ev->mouse.y; + m->type = M_TOUCH; + m->touchtime = 0; + m->touchkey = 0; + m->moveddist = 0; + m->oldpos[0] = ev->mouse.x; + m->oldpos[1] = ev->mouse.y; } - if (ptr[ev->devid].held) - { - ptr[ev->devid].delta[0] += ev->mouse.x - ptr[ev->devid].oldpos[0]; - ptr[ev->devid].delta[1] += ev->mouse.y - ptr[ev->devid].oldpos[1]; + if (m->touchtime) + { //only do this when its actually held in some form... + m->delta[0] += ev->mouse.x - m->oldpos[0]; + m->delta[1] += ev->mouse.y - m->oldpos[1]; - ptr[ev->devid].moveddist += fabs(ev->mouse.x - ptr[ev->devid].oldpos[0]) + fabs(ev->mouse.y - ptr[ev->devid].oldpos[1]); + m->moveddist += fabs(ev->mouse.x - m->oldpos[0]) + fabs(ev->mouse.y - m->oldpos[1]); } - if (ev->mouse.x != ptr[ev->devid].oldpos[0] || - ev->mouse.y != ptr[ev->devid].oldpos[1]) + if (ev->mouse.x != m->oldpos[0] || + ev->mouse.y != m->oldpos[1]) { - ptr[ev->devid].updates++; - ptr[ev->devid].updated = true; + m->updates++; + m->updated = true; } - ptr[ev->devid].oldpos[0] = ev->mouse.x; - ptr[ev->devid].oldpos[1] = ev->mouse.y; + m->oldpos[0] = ev->mouse.x; + m->oldpos[1] = ev->mouse.y; - - if (ptr[ev->devid].held > 1 && ev->mouse.tsize < m_fatpressthreshold.value) + if (m->touchtime && m->touchkey == K_TOUCH) { - ptr[ev->devid].held = 1; - Key_Event(ev->devid, K_MOUSE1, 0, false); - } - if (ptr[ev->devid].held == 1 && ev->mouse.tsize > m_fatpressthreshold.value) - { - ptr[ev->devid].held = 2; - Key_Event(ev->devid, K_MOUSE1, 0, true); + if (Sys_DoubleTime()-m->touchtime > 1) + m->touchkey = K_TOUCHLONG; //held for long enough... + else if (m->moveddist >= m_slidethreshold.value) + m->touchkey = K_TOUCHSLIDE; //moved far enough to consitute a slide + else + break; + Key_Event(ev->devid, m->touchkey, 0, true); } } break; @@ -672,6 +681,17 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum, float frame if (mouse->type == M_TOUCH) { qboolean strafing = false; + + if (mouse->touchtime && mouse->touchkey==K_TOUCH) + { //convert to tap/longpress if it wasn't already a gesture. don't ever convert mouse. + if (Sys_DoubleTime()-mouse->touchtime > m_longpressthreshold.value) + { //might as well trigger this here... + mouse->touchkey = K_TOUCHLONG; + Key_Event(mouse-ptr, mouse->touchkey, 0, true); + } + } + + switch(m_touchstrafe.ival) { case 2: @@ -681,13 +701,13 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum, float frame strafing = mouse->heldpos[0] > vid.pixelwidth/2; break; case 0: - strafing = true; + strafing = false; break; } if (strafing && movements != NULL && !Key_Dest_Has(~kdm_game)) { //if they're strafing, calculate the speed to move at based upon their displacement - if (mouse->held) + if (mouse->touchtime) { if (m_touchstrafe.ival == 2) //left side mx = mouse->oldpos[0] - (vid.pixelwidth*1)/4.0; @@ -724,6 +744,9 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum, float frame //boost sensitivity so that the default works okay. mx *= 1.75; my *= 1.75; + + if (IN_WeaponWheelAccumulate(pnum, mx, my, 0)) + mx = my = 0; } } else @@ -778,7 +801,7 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum, float frame //if game is not focused, kill any mouse look if ( #ifdef QUAKESTATS - IN_WeaponWheelAccumulate(pnum, mx, my) || + IN_WeaponWheelAccumulate(pnum, mx, my, 0) || #endif Key_Dest_Has(~kdm_game)) { @@ -879,12 +902,17 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum, float frame //rescales threshold-1 down 0-1 static float joydeadzone(float mag, float deadzone) { + if (joy_radialdeadzone.ival == 2) //hacky overload to disable dead zones where the system provides it instead. + deadzone = 0; + if (mag > 1) //erg? mag = 1; if (mag > deadzone) { mag -= deadzone; mag = mag / (1.f-deadzone); + + mag = pow(mag, joy_exponent.value); } else mag = 0; @@ -949,49 +977,51 @@ void IN_MoveJoystick(struct joy_s *joy, float *movements, int pnum, float framet } } - if (IN_WeaponWheelAccumulate(joy->qdeviceid, jstrafe[1]*50, -jstrafe[0]*50)) - jstrafe[0] = jstrafe[1] = 0; - - if (joy_radialdeadzone.ival == 2) - { //steam or SDL or something is doing deadzone and exponent stuff already. just use identity so we don't get double deadzones. - } - else if (joy_radialdeadzone.ival) + if (joy_radialdeadzone.ival) { //uses a radial deadzone for x+y axis, and separate out the z axis, just because most controllers are 2d affairs with any 3rd axis being a separate knob. //deadzone values are stolen from microsoft's xinput documentation. they seem quite large to me - I guess that means that xbox controllers are just dodgy imprecise crap with excessive amounts of friction and finger grease. - - mag = joydeadzone(sqrt(jlook[0]*jlook[0] + jlook[1]*jlook[1]), sqrt(joy_anglethreshold[0].value*joy_anglethreshold[0].value + joy_anglethreshold[1].value*joy_anglethreshold[1].value)); - mag = pow(mag, joy_exponent.value); - jlook[0] *= mag; - jlook[1] *= mag; - + float basemag = sqrt(jlook[0]*jlook[0] + jlook[1]*jlook[1]); + if (basemag) + { + mag = joydeadzone(basemag, sqrt(joy_anglethreshold[0].value*joy_anglethreshold[0].value + joy_anglethreshold[1].value*joy_anglethreshold[1].value)); + jlook[0] = (jlook[0]/basemag) * mag; + jlook[1] = (jlook[1]/basemag) * mag; + } + else + jlook[0] = jlook[1] = 0; mag = joydeadzone(fabs(jlook[2]), joy_anglethreshold[2].value); - mag = pow(mag, joy_exponent.value); - jlook[2] *= mag; - - mag = joydeadzone(sqrt(jstrafe[0]*jstrafe[0] + jstrafe[1]*jstrafe[1]), sqrt(joy_movethreshold[0].value*joy_movethreshold[0].value + joy_movethreshold[1].value*joy_movethreshold[1].value)); - mag = pow(mag, joy_exponent.value); - jstrafe[0] *= mag; - jstrafe[1] *= mag; + jlook[2] = mag; + basemag = sqrt(jstrafe[0]*jstrafe[0] + jstrafe[1]*jstrafe[1]); + if (basemag) + { + mag = joydeadzone(basemag, sqrt(joy_movethreshold[0].value*joy_movethreshold[0].value + joy_movethreshold[1].value*joy_movethreshold[1].value)); + jstrafe[0] = (jstrafe[0]/basemag) * mag; + jstrafe[1] = (jstrafe[1]/basemag) * mag; + } + else + jstrafe[0] = jstrafe[1] = 0; mag = joydeadzone(fabs(jstrafe[2]), joy_movethreshold[2].value); - mag = pow(mag, joy_exponent.value); - jstrafe[2] *= mag; + jstrafe[2] = mag; } else { for (i = 0; i < 3; i++) { mag = joydeadzone(fabs(jlook[i]), joy_anglethreshold[i].value); - mag = pow(mag, joy_exponent.value); - jlook[i] *= mag; + jlook[i] = ((jlook[i]<0)?-1:1)*mag; mag = joydeadzone(fabs(jstrafe[i]), joy_movethreshold[i].value); - mag = pow(mag, joy_exponent.value); - jstrafe[i] *= mag; + jstrafe[i] = ((jstrafe[i]<0)?-1:1)*mag; } } + if (IN_WeaponWheelAccumulate(joy->qdeviceid, jstrafe[1]*50, -jstrafe[0]*50, 20)) + jstrafe[0] = jstrafe[1] = 0; + if (IN_WeaponWheelAccumulate(joy->qdeviceid, jlook[1]*50, jlook[0]*50, 20)) + jlook[0] = jlook[1] = 0; + if (Key_Dest_Has(~kdm_game)) { VectorClear(jlook); diff --git a/engine/client/in_sdl.c b/engine/client/in_sdl.c index 4977fccbd..866dfe28b 100644 --- a/engine/client/in_sdl.c +++ b/engine/client/in_sdl.c @@ -19,7 +19,7 @@ extern qboolean vid_isfullscreen; #if SDL_MAJOR_VERSION > 1 || (SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION >= 3) #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."); +cvar_t sys_osk = CVARD("sys_osk", "0", "Enables support for text input. This will be ignored when the console has focus, but gamecode may end up with composition boxes appearing."); #endif void IN_ActivateMouse(void) @@ -1053,21 +1053,64 @@ static unsigned int tbl_sdltoquakemouse[] = K_MOUSE10 }; +#ifdef HAVE_SDL_TEXTINPUT +#ifdef __linux__ +#include +static qboolean usesteamosk; +#endif +#endif void Sys_SendKeyEvents(void) { SDL_Event event; + int axis, j; #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) + static SDL_bool active = false; + SDL_bool osk = Key_Dest_Has(kdm_console|kdm_cwindows|kdm_message); + if (Key_Dest_Has(kdm_prompt|kdm_menu)) { + j = Menu_WantOSK(); + if (j < 0) + osk |= sys_osk.ival; + else + osk |= j; + } + else if (Key_Dest_Has(kdm_game)) + osk |= sys_osk.ival; + if (osk) + { + SDL_Rect rect; + rect.x = 0; + rect.y = vid.rotpixelheight/2; + rect.w = vid.rotpixelwidth; + rect.h = vid.rotpixelheight - rect.y; + SDL_SetTextInputRect(&rect); + if (!active) - SDL_StartTextInput(); + { +#ifdef __linux__ + if (usesteamosk) + SDL_OpenURL("steam://open/keyboard?Mode=1"); + else +#endif + SDL_StartTextInput(); + active = true; +// Con_Printf("OSK shown...\n"); + } } else { if (active) - SDL_StopTextInput(); + { +#ifdef __linux__ + if (usesteamosk) + SDL_OpenURL("steam://close/keyboard?Mode=1"); + else +#endif + SDL_StopTextInput(); + active = false; +// Con_Printf("OSK shown... killed\n"); + } } #endif @@ -1411,6 +1454,12 @@ void INS_Init (void) #ifdef HAVE_SDL_TEXTINPUT Cvar_Register(&sys_osk, "input controls"); #endif + +#ifdef HAVE_SDL_TEXTINPUT +#ifdef __linux__ + usesteamosk = SDL_GetHintBoolean("SteamDeck", false); //looks like there's a 'SteamDeck=1' environment setting on the deck (when started via steam itself, at least), so we don't get valve's buggy-as-poop osk on windows etc. +#endif +#endif } void INS_Accumulate(void) //input polling { diff --git a/engine/client/input.h b/engine/client/input.h index e831b9ba7..422d2f83f 100644 --- a/engine/client/input.h +++ b/engine/client/input.h @@ -29,8 +29,9 @@ void IN_Shutdown (void); void IN_Commands (void); // oportunity for devices to stick commands on the script buffer -qboolean IN_MouseDevIsTouch(unsigned int devid); //check if a mouse devid is a touch screen, and thus if we should check the cursor and simulate a ui event or not -int IN_TranslateMButtonPress(unsigned int devid); //allow the touchscreen code to swallow mouse1 as a begin-looking event +void IN_Touch_BlockGestures(unsigned int devid); //prevents any gestures from being generated from the same touch event. +int IN_Touch_Fallback(unsigned int devid); //decides whether a tap should be attack/jump according to m_touchstrafe +qboolean IN_Touch_MouseIsAbs(unsigned int devid); void IN_Move (float *nudgemovements, float *absmovements, int pnum, float frametime); // add additional movement on top of the keyboard move cmd diff --git a/engine/client/keys.c b/engine/client/keys.c index 169b126f1..8b514176c 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -199,6 +199,9 @@ keyname_t keynames[] = {"MWHEELLEFT", K_MWHEELLEFT}, {"MWHEELRIGHT", K_MWHEELRIGHT}, {"TOUCH", K_TOUCH}, + {"TOUCHSLIDE", K_TOUCHSLIDE}, + {"TOUCHTAP", K_TOUCHTAP}, + {"TOUCHLONG", K_TOUCHLONG}, {"LWIN", K_LWIN}, //windows name {"RWIN", K_RWIN}, //windows name @@ -758,7 +761,7 @@ qboolean Key_GetConsoleSelectionBox(console_t *con, int *sx, int *sy, int *ex, i *ey = con->mousecursor[1]; return true; } - else if (con->buttonsdown == CB_COPY || con->buttonsdown == CB_SELECT) + else if (con->buttonsdown == CB_SELECT || con->buttonsdown == CB_SELECTED) { //right-mouse //select. copy-to-clipboard on release. @@ -1208,60 +1211,18 @@ void Key_HandleConsoleLink(console_t *con, char *buffer) } } -#define Key_IsTouchScreen() false void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode) { char *buffer; if (key < 0) key = 0; - if (key == K_MOUSE1 && con->buttonsdown == CB_SELECT) + if ((key == K_TOUCHTAP || key == K_MOUSE1) && con->buttonsdown == CB_SELECT) { - if (con->selstartline) - { - if (con->userline) - { - if (con->flags & CONF_BACKSELECTION) - { - con->userline = con->selendline; - con->useroffset = con->selendoffset; - } - else - { - con->userline = con->selstartline; - con->useroffset = con->selstartoffset; - } - } - if (con->selstartline == con->selendline && con->selendoffset <= con->selstartoffset+1) - { - con->flags &= ~CONF_KEEPSELECTION; - if (keydown[K_LSHIFT] || keydown[K_RSHIFT]) - ; - else - { - buffer = Con_CopyConsole(con, false, true, false); - if (buffer) - { - Key_HandleConsoleLink(con, buffer); - Z_Free(buffer); - } - } - } - else - { - con->flags |= CONF_KEEPSELECTION; - - buffer = Con_CopyConsole(con, true, false, true); //don't keep markup if we're copying to the clipboard - if (buffer) - { - Sys_SaveClipboard(CBT_SELECTION, buffer); - Z_Free(buffer); - } - } - } - con->buttonsdown = CB_NONE; + con->buttonsdown = CB_SELECTED; + return; } - if ((key == K_TOUCH || key == K_MOUSE1) && con->buttonsdown == CB_SCROLL)// || (key == K_MOUSE2 && con->buttonsdown == CB_SCROLL_R)) + if ((key == K_TOUCHSLIDE || key == K_MOUSE1) && con->buttonsdown == CB_SCROLL)// || (key == K_MOUSE2 && con->buttonsdown == CB_SCROLL_R)) { con->buttonsdown = CB_NONE; if (fabs(con->mousedown[0] - con->mousecursor[0]) < 5 && fabs(con->mousedown[1] - con->mousecursor[1]) < 5) @@ -1296,7 +1257,7 @@ void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode) else Con_Footerf(con, false, ""); } - if (key == K_MOUSE2 && con->buttonsdown == CB_COPY) + /*if ((key == K_TOUCHLONG || key == K_MOUSE2) && con->buttonsdown == CB_COPY) { con->buttonsdown = CB_NONE; buffer = Con_CopyConsole(con, true, false, true); //don't keep markup if we're copying to the clipboard @@ -1304,7 +1265,7 @@ void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode) return; Sys_SaveClipboard(CBT_CLIPBOARD, buffer); Z_Free(buffer); - } + }*/ if (con->buttonsdown == CB_CLOSE) { //window X (close) if (con->mousecursor[0] > con->wnd_w-16 && con->mousecursor[1] < 8) @@ -1315,6 +1276,9 @@ void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode) return; } } + if (con->buttonsdown == CB_SELECTED) + ; //will time out in the drawing code. + else // if (con->buttonsdown == CB_MOVE) //window title(move) con->buttonsdown = CB_NONE; @@ -1878,7 +1842,7 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode) } if (con->redirect) { - if (key == K_TOUCH || key == K_MOUSE1 || key == K_MOUSE2) + if (key == K_TOUCHTAP || key == K_TOUCHSLIDE || key == K_TOUCHLONG || key == K_MOUSE1 || key == K_MOUSE2) ; else if (con->redirect(con, unicode, key)) return true; @@ -1893,7 +1857,7 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode) return true; } - if (key == K_TOUCH || key == K_MOUSE1 || key == K_MOUSE2) + if (key == K_TOUCHTAP || key == K_TOUCHSLIDE || key == K_TOUCHLONG || key == K_MOUSE1 || key == K_MOUSE2) { int olddown[2] = {con->mousedown[0],con->mousedown[1]}; if (con->flags & CONF_ISWINDOW) @@ -1910,7 +1874,7 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode) con->mousedown[1] = con->mousecursor[1]; if (con_mouseover && con->mousedown[1] < 8)//(8.0*vid.height)/vid.pixelheight) { - if (key == K_MOUSE2 && !(con->flags & CONF_ISWINDOW)) + if ((key == K_MOUSE2||key==K_TOUCHLONG) && !(con->flags & CONF_ISWINDOW)) { if (con->close && !con->close(con, false)) return true; @@ -1931,10 +1895,7 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode) return true; con->flags &= ~CONF_KEEPSELECTION; - if (key == K_TOUCH) - con->buttonsdown = CB_COPY; - else - con->buttonsdown = CB_SCROLL_R; + con->buttonsdown = CB_SCROLL_R; } else { @@ -1956,7 +1917,7 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode) return true; } #endif - if (key == K_TOUCH || con->mousecursor[0] > ((con->flags & CONF_ISWINDOW)?con->wnd_w-16:vid.width)-8) + if (key == K_TOUCHSLIDE || con->mousecursor[0] > ((con->flags & CONF_ISWINDOW)?con->wnd_w-16:vid.width)-8) { //just scroll the console up/down con->buttonsdown = CB_SCROLL; } @@ -1982,6 +1943,7 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode) con->mousedowntime = realtime; con->buttonsdown = CB_SELECT; + con->flags &= ~CONF_KEEPSELECTION; if (shift) { @@ -1989,15 +1951,16 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode) con->mousedown[1] = olddown[1]; } } - con->flags &= ~CONF_KEEPSELECTION; } } - if ((con->buttonsdown == CB_COPY || con->buttonsdown == CB_SCROLL) && !con->linecount && (!con->linebuffered || con->linebuffered == Con_Navigate)) + if (con->buttonsdown == CB_SCROLL && !con->linecount && (!con->linebuffered || con->linebuffered == Con_Navigate)) con->buttonsdown = CB_NONE; else return true; } + if (key == K_TOUCH) + return true; //eat it, so we don't get any kind of mouse emu junk if (key == K_PGUP || key == K_KP_PGUP || key==K_MWHEELUP || key == K_GP_LEFT_THUMB_UP) { @@ -2289,7 +2252,7 @@ void Key_Message (int key, int unicode) return; } - if (key == K_ESCAPE || key == K_GP_DIAMOND_CANCEL) + if (key == K_ESCAPE || key == K_TOUCHLONG || key == K_GP_DIAMOND_CANCEL) { Key_Dest_Remove(kdm_message); chat_bufferpos = 0; @@ -2950,7 +2913,8 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down { unsigned int devbit = 1u<0)); //if the input line is empty, allow ` to toggle the console, otherwise enter it as actual text. @@ -2984,17 +2948,15 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down shift_down = keydown[K_LSHIFT]|keydown[K_RSHIFT]; } - if (key == K_ESCAPE) + if ((key == K_ESCAPE && (shift_down &devbit)) || + (key == K_GP_MENU && (keydown[K_GP_VIEW]&devbit))) { - if (shift_down) + extern cvar_t con_stayhidden; + if (down && con_stayhidden.ival < 2) { - extern cvar_t con_stayhidden; - if (down && con_stayhidden.ival < 2) - { - if (!Key_Dest_Has(kdm_console)) //don't toggle it when the console is already down. this allows typing blind to not care if its already active. - Con_ToggleConsole_Force(); - return; - } + if (!Key_Dest_Has(kdm_console)) //don't toggle it when the console is already down. this allows typing blind to not care if its already active. + Con_ToggleConsole_Force(); + return; } } @@ -3246,14 +3208,12 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down //gamepad buttons should get fallbacks out of the box, even if they're not initially listed on the binds menu. //these may be redefined later... -// case K_GP_LEFT_SHOULDER: dc = "impulse 12"; goto defaultedbind; //matches QS's default.cfg -// case K_GP_RIGHT_SHOULDER: dc = "impulse 10"; goto defaultedbind; //matches QS's default.cfg - case K_GP_LEFT_SHOULDER: dc = "impulse 10"; goto defaultedbind; - case K_GP_RIGHT_SHOULDER: dc = "+weaponwheel"; goto defaultedbind; - case K_GP_LEFT_TRIGGER: dc = "+button3"; goto defaultedbind; //matches QS's default.cfg - case K_GP_RIGHT_TRIGGER: dc = "+attack"; goto defaultedbind; //matches QS's default.cfg + case K_GP_LEFT_SHOULDER: dc = "+jump"; goto defaultedbind; //qs: impulse 12 (should be 11 for qw...) + case K_GP_RIGHT_SHOULDER: dc = "+weaponwheel"; goto defaultedbind; //qs: impulse 10 + case K_GP_LEFT_TRIGGER: dc = "+button3"; goto defaultedbind; //qs: jump + case K_GP_RIGHT_TRIGGER: dc = "+attack"; goto defaultedbind; //qs: +attack case K_GP_START: dc = "togglemenu"; goto defaultedbind; - case K_GP_A: dc = "+jump"; goto defaultedbind; + case K_GP_A: dc = "impulse 10"; goto defaultedbind; case K_GP_B: dc = "+button4"; goto defaultedbind; case K_GP_X: dc = "+button5"; goto defaultedbind; case K_GP_Y: dc = "+button6"; goto defaultedbind; @@ -3276,9 +3236,9 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down } defaultedbind: - if (key == K_TOUCH || (key == K_MOUSE1 && IN_MouseDevIsTouch(devid))) + if (key == K_TOUCH || (key == K_MOUSE1 && IN_Touch_MouseIsAbs(devid))) { - char *button = SCR_ShowPics_ClickCommand(mousecursor_x, mousecursor_y); + const char *button = SCR_ShowPics_ClickCommand(mousecursor_x, mousecursor_y, key == K_TOUCH); if (button) { dc = button; @@ -3292,17 +3252,18 @@ defaultedbind: dc = keybindings[bkey][modifierstate]; bl = bindcmdlevel[bkey][modifierstate]; } - else - { - bkey = IN_TranslateMButtonPress(devid); - if (bkey) - { - dc = keybindings[bkey][modifierstate]; - bl = bindcmdlevel[bkey][modifierstate]; - } - else if (!Key_MouseShouldBeFree()) - return; - } + else if (!Key_MouseShouldBeFree()) + return; + } + IN_Touch_BlockGestures(devid); + } + if (key == K_TOUCHTAP && !dc) + { //convert to mouse1 or mouse2 when touchstrafe is on and touchtap is unbound + bkey = IN_Touch_Fallback(devid); + if (bkey) + { + dc = keybindings[bkey][modifierstate]; + bl = bindcmdlevel[bkey][modifierstate]; } } diff --git a/engine/client/keys.h b/engine/client/keys.h index f7131554e..2cf736dcb 100644 --- a/engine/client/keys.h +++ b/engine/client/keys.h @@ -236,8 +236,6 @@ typedef enum { K_RSHIFT, K_PRINTSCREEN, - K_TOUCH, - /* multimedia keyboard */ K_MM_BROWSER_BACK, K_MM_BROWSER_FAVORITES, @@ -250,6 +248,14 @@ typedef enum { K_MM_TRACK_PREV, K_MM_TRACK_STOP, K_MM_TRACK_PLAYPAUSE, + + //touchscreen stuff. + K_TOUCH, //initial touch + //will be paired with one of... + K_TOUCHSLIDE, //existing touch became a slide + K_TOUCHTAP, //touched briefly without sliding (treat like a left-click, though fired on final release) + K_TOUCHLONG, //touch lasted a while and without moving (treat like a right-click) + K_MAX, //360 buttons @@ -337,6 +343,7 @@ qboolean Key_Centerprint(int key, int unicode, unsigned int devid); void Key_Unbindall_f (void); //aka: Key_Shutdown void Key_ConsoleReplace(const char *instext); void Key_DefaultLinkClicked(console_t *con, char *text, char *info); +void Key_HandleConsoleLink(console_t *con, char *buffer); qboolean Key_Console (console_t *con, int key, unsigned int unicode); void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode); diff --git a/engine/client/m_download.c b/engine/client/m_download.c index 79ed8893f..8e8235d3a 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -5685,7 +5685,7 @@ static void MD_Source_Draw (int x, int y, struct menucustom_s *c, struct emenu_s } static qboolean MD_Source_Key (struct menucustom_s *c, struct emenu_s *m, int key, unsigned int unicode) { - if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCH) + if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCHTAP) { if (pm_source[c->dint].flags & SRCFL_DISABLED) { @@ -5744,7 +5744,7 @@ static void MD_AutoUpdate_Draw (int x, int y, struct menucustom_s *c, struct eme } static qboolean MD_AutoUpdate_Key (struct menucustom_s *c, struct emenu_s *m, int key, unsigned int unicode) { - if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCH) + if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCHTAP) { char nv[8] = "0"; if (pkg_autoupdate.ival < UPD_TESTING && pkg_autoupdate.ival >= 0) @@ -5759,7 +5759,7 @@ static qboolean MD_AutoUpdate_Key (struct menucustom_s *c, struct emenu_s *m, in static qboolean MD_MarkUpdatesButton (union menuoption_s *mo,struct emenu_s *m,int key) { - if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCH) + if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCHTAP) { PM_MarkUpdates(); return true; @@ -5770,7 +5770,7 @@ static qboolean MD_MarkUpdatesButton (union menuoption_s *mo,struct emenu_s *m,i qboolean MD_PopMenu (union menuoption_s *mo,struct emenu_s *m,int key) { - if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCH) + if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCHTAP) { M_RemoveMenu(m); return true; @@ -5780,7 +5780,7 @@ qboolean MD_PopMenu (union menuoption_s *mo,struct emenu_s *m,int key) static qboolean MD_ApplyDownloads (union menuoption_s *mo,struct emenu_s *m,int key) { - if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCH) + if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCHTAP) { PM_PromptApplyChanges(); return true; @@ -5790,7 +5790,7 @@ static qboolean MD_ApplyDownloads (union menuoption_s *mo,struct emenu_s *m,int static qboolean MD_RevertUpdates (union menuoption_s *mo,struct emenu_s *m,int key) { - if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCH) + if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCHTAP) { PM_RevertChanges(); return true; diff --git a/engine/client/m_items.c b/engine/client/m_items.c index 60c372e8b..3ca167cf5 100644 --- a/engine/client/m_items.c +++ b/engine/client/m_items.c @@ -660,7 +660,7 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, emenu_t *men } else { - if (!keydown[K_MOUSE1] && !keydown[K_TOUCH]) + if (!keydown[K_MOUSE1] && !keydown[K_TOUCHTAP]) option->frame.mousedown = false; option->frame.frac = M_DrawScrollbar(xpos+option->frame.common.posx, ypos+option->common.posy, option->frame.common.width, option->frame.common.height, option->frame.frac, option->frame.mousedown); @@ -803,14 +803,14 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, emenu_t *men if (bindingactive && menu->selecteditem == option) Draw_FunString (x, y, "Press key"); else if (!keycount) - Draw_FunString (x, y, "???"); + Draw_FunString (x, y, "^8??""?"); else { for (j = 0; j < keycount; j++) { /*these offsets are wrong*/ if (j) { - Draw_FunString (x + 8, y, "or"); + Draw_FunString (x + 8, y, "^8or"); x += 32; } keyname = Key_KeynumToLocalString (keys[j], keymods[j]); @@ -854,6 +854,10 @@ static void MenuDraw(emenu_t *menu) menu->xpos = ((vid.width - 320)>>1); if (menu->predraw) menu->predraw(menu); + if (menu->selecteditem && menu->selecteditem->common.type == mt_text) + menu->menu.showosk = true; + else + menu->menu.showosk = false; MenuDrawItems(menu->xpos, menu->ypos, menu->options, menu); // draw tooltip if (menu->mouseitem && menu->tooltip && realtime > menu->tooltiptime) @@ -1639,7 +1643,7 @@ void MC_Slider_Key(menuslider_t *option, int key) range = bound(option->min, range, option->max); option->current = range; } - else if ((key == K_TOUCH || key == K_MOUSE1) && mousecursor_x >= ix-8 && mousecursor_x < ex+8) + else if ((key == K_TOUCHTAP || key == K_MOUSE1) && mousecursor_x >= ix-8 && mousecursor_x < ex+8) { range = (mousecursor_x - ix) / (ex - ix); range = option->min + range*(option->max-option->min); @@ -1649,7 +1653,7 @@ void MC_Slider_Key(menuslider_t *option, int key) range = bound(option->min, range, option->max); option->current = range; } - else if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_START || key == K_MOUSE1 || key == K_TOUCH) + else if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_START || key == K_MOUSE1 || key == K_TOUCHTAP) { if (range == option->max) range = option->min; @@ -1684,7 +1688,7 @@ void MC_Slider_Key(menuslider_t *option, int key) void MC_CheckBox_Key(menucheck_t *option, emenu_t *menu, int key) { - if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_START && key != K_GP_DIAMOND_CONFIRM && key != K_GP_DIAMOND_ALTCONFIRM && key != K_LEFTARROW && key != K_KP_LEFTARROW && key != K_GP_DPAD_LEFT && key != K_GP_LEFT_THUMB_LEFT && key != K_RIGHTARROW && key != K_KP_LEFTARROW && key != K_GP_DPAD_RIGHT && key != K_GP_LEFT_THUMB_RIGHT && key != K_MWHEELUP && key != K_MWHEELDOWN && key != K_MOUSE1 && key != K_TOUCH) + if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_START && key != K_GP_DIAMOND_CONFIRM && key != K_GP_DIAMOND_ALTCONFIRM && key != K_LEFTARROW && key != K_KP_LEFTARROW && key != K_GP_DPAD_LEFT && key != K_GP_LEFT_THUMB_LEFT && key != K_RIGHTARROW && key != K_KP_LEFTARROW && key != K_GP_DPAD_RIGHT && key != K_GP_LEFT_THUMB_RIGHT && key != K_MWHEELUP && key != K_MWHEELDOWN && key != K_MOUSE1 && key != K_TOUCHTAP) return; if (option->func) option->func(option, menu, CHK_TOGGLE); @@ -1750,7 +1754,7 @@ void MC_EditBox_Key(menuedit_t *edit, int key, unsigned int unicode) void MC_Combo_Key(menucombo_t *combo, int key) { - if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_START || key == K_RIGHTARROW || key == K_KP_RIGHTARROW || key == K_GP_DPAD_RIGHT || key == K_GP_LEFT_THUMB_RIGHT ||key == K_GP_DIAMOND_ALTCONFIRM || key == K_MWHEELDOWN || key == K_MOUSE1 || key == K_TOUCH) + if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_START || key == K_RIGHTARROW || key == K_KP_RIGHTARROW || key == K_GP_DPAD_RIGHT || key == K_GP_LEFT_THUMB_RIGHT ||key == K_GP_DIAMOND_ALTCONFIRM || key == K_MWHEELDOWN || key == K_MOUSE1 || key == K_TOUCHTAP) { combo->selectedoption++; if (combo->selectedoption >= combo->numoptions) @@ -1810,7 +1814,7 @@ static qboolean M_KeyEvent(menu_t *m, qboolean isdown, unsigned int devid, int k emenu_t *menu = (emenu_t*)m; if (isdown) { - if (key == K_MOUSE1 || key == K_TOUCH) //mouse clicks are deferred until the release event. this is for touch screens and aiming. + if (key == K_MOUSE1 || key == K_TOUCHTAP) //mouse clicks are deferred until the release event. this is for touch screens and aiming. { if (menu->mouseitem && menu->mouseitem->common.type == mt_frameend) menu->mouseitem->frame.mousedown = true; @@ -1825,7 +1829,7 @@ static qboolean M_KeyEvent(menu_t *m, qboolean isdown, unsigned int devid, int k } else { - if ((key == K_MOUSE1 || key == K_TOUCH) && menu_mousedown) + if ((key == K_MOUSE1 || key == K_TOUCHTAP) && menu_mousedown) M_Complex_Key (menu, key, unicode); else if (key == K_LSHIFT || key == K_RSHIFT || key == K_LALT || key == K_RALT || key == K_LCTRL || key == K_RCTRL) M_Complex_Key (menu, key, unicode); @@ -2088,6 +2092,7 @@ void M_Complex_Key(emenu_t *currentmenu, int key, int unicode) case K_MOUSE2: //right case K_MOUSE4: //back case K_ESCAPE: + case K_TOUCHLONG: case K_GP_BACK: case K_GP_START: case K_GP_DIAMOND_CANCEL: @@ -2193,7 +2198,7 @@ void M_Complex_Key(emenu_t *currentmenu, int key, int unicode) goto goup; else goto godown; } - case K_TOUCH: + case K_TOUCHTAP: case K_MOUSE1: case K_MOUSE3: case K_MOUSE5: @@ -2239,7 +2244,7 @@ void M_Complex_Key(emenu_t *currentmenu, int key, int unicode) case mt_qbuttonbigfont: if (!currentmenu->selecteditem->button.command) currentmenu->selecteditem->button.key(currentmenu->selecteditem, currentmenu, key); - else if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_GP_DIAMOND_ALTCONFIRM || key == K_MOUSE1 || key == K_TOUCH) + else if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_GP_DIAMOND_ALTCONFIRM || key == K_MOUSE1 || key == K_TOUCHTAP) { Cbuf_AddText(currentmenu->selecteditem->button.command, RESTRICT_LOCAL); #ifdef HEXEN2 @@ -2261,7 +2266,7 @@ void M_Complex_Key(emenu_t *currentmenu, int key, int unicode) MC_Combo_Key(¤tmenu->selecteditem->combo, key); break; case mt_bind: - if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCH) + if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCHTAP) bindingactive = true; else if (key == K_BACKSPACE || key == K_DEL || key == K_GP_DIAMOND_ALTCONFIRM) M_UnbindCommand (currentmenu->selecteditem->bind.command); diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index e2ff40f31..75a2d4fe8 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -1266,7 +1266,7 @@ qboolean M_Media_Key (int key, emenu_t *menu) } } } - else if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCH) + else if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCHTAP) { if (key == K_MOUSE1) { @@ -2549,7 +2549,7 @@ static void MediaView_DrawFilm(menu_t *m) } static qboolean MediaView_KeyEvent(menu_t *m, qboolean isdown, unsigned int devid, int key, int unicode) { - if (isdown && key == K_ESCAPE) + if (isdown && (key == K_ESCAPE || key == K_GP_GUIDE || key == K_GP_DIAMOND_CANCEL || key == K_TOUCHLONG)) { Media_StopFilm(false); //skip to the next. return true; diff --git a/engine/client/m_multi.c b/engine/client/m_multi.c index b7e2219e4..cf99a56d1 100644 --- a/engine/client/m_multi.c +++ b/engine/client/m_multi.c @@ -234,7 +234,7 @@ qboolean SetupMenuColour (union menuoption_s *option,struct emenu_s *menu, int k //but we give the top free reign. //unless they hold shift, in which case it switches around //this allows for whatever you want - if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_RIGHTARROW || key == K_KP_RIGHTARROW || key == K_MOUSE1 || key == K_TOUCH || key == K_GP_DPAD_RIGHT) + if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_RIGHTARROW || key == K_KP_RIGHTARROW || key == K_MOUSE1 || key == K_TOUCHTAP || key == K_GP_DPAD_RIGHT) { if ((keydown[K_LSHIFT] || keydown[K_RSHIFT]) ^ (ptr == &info->topcolour)) { @@ -570,7 +570,7 @@ qboolean MultiBeginGame (union menuoption_s *option,struct emenu_s *menu, int ke { newmultimenu_t *info = menu->data; char quoted[1024]; - if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_DIAMOND_CONFIRM && key != K_MOUSE1 && key != K_TOUCH) + if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_DIAMOND_CONFIRM && key != K_MOUSE1 && key != K_TOUCHTAP) return false; if (cls.state) diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 7fd8ac40b..69d268f38 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -1510,7 +1510,7 @@ qboolean M_PresetApply (union menuoption_s *op, struct emenu_s *menu, int key) { fpsmenuinfo_t *info = (fpsmenuinfo_t*)menu->data; - if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_DIAMOND_CONFIRM && key != K_MOUSE1 && key != K_TOUCH) + if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_DIAMOND_CONFIRM && key != K_MOUSE1 && key != K_TOUCHTAP) return false; Cbuf_AddText("fps_preset ", RESTRICT_LOCAL); @@ -1771,7 +1771,7 @@ qboolean M_VideoApplyShadowLighting (union menuoption_s *op,struct emenu_s *menu { lightingmenuinfo_t *info = (lightingmenuinfo_t*)menu->data; - if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_DIAMOND_CONFIRM && key != K_MOUSE1 && key != K_TOUCH) + if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_DIAMOND_CONFIRM && key != K_MOUSE1 && key != K_TOUCHTAP) return false; #ifdef RTLIGHTS @@ -2230,7 +2230,7 @@ qboolean M_Apply_SP_Cheats (union menuoption_s *op,struct emenu_s *menu,int key) { singleplayerinfo_t *info = menu->data; - if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_DIAMOND_CONFIRM && key != K_MOUSE1 && key != K_TOUCH) + if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_DIAMOND_CONFIRM && key != K_MOUSE1 && key != K_TOUCHTAP) return false; switch(info->skillcombo->selectedoption) @@ -2348,7 +2348,7 @@ qboolean M_Apply_SP_Cheats_Q2 (union menuoption_s *op,struct emenu_s *menu,int k { singleplayerq2info_t *info = menu->data; - if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_DIAMOND_CONFIRM && key != K_MOUSE1 && key != K_TOUCH) + if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_DIAMOND_CONFIRM && key != K_MOUSE1 && key != K_TOUCHTAP) return false; switch(info->skillcombo->selectedoption) @@ -2554,7 +2554,7 @@ qboolean M_Apply_SP_Cheats_H2 (union menuoption_s *op,struct emenu_s *menu,int k { singleplayerh2info_t *info = menu->data; - if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_DIAMOND_CONFIRM && key != K_MOUSE1 && key != K_TOUCH) + if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_DIAMOND_CONFIRM && key != K_MOUSE1 && key != K_TOUCHTAP) return false; #ifdef HAVE_SERVER @@ -2810,7 +2810,7 @@ qboolean M_VideoApply (union menuoption_s *op, struct emenu_s *menu, int key) extern cvar_t vid_desktopsettings; videomenuinfo_t *info = (videomenuinfo_t*)menu->data; - if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_DIAMOND_CONFIRM && key != K_MOUSE1 && key != K_TOUCH) + if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_DIAMOND_CONFIRM && key != K_MOUSE1 && key != K_TOUCHTAP) return false; // force update display options @@ -4381,7 +4381,7 @@ static void Mods_Draw(int x, int y, struct menucustom_s *c, struct emenu_s *m) static qboolean Mods_Key(struct menucustom_s *c, struct emenu_s *m, int key, unsigned int unicode) { int gameidx = c->dint; - if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCH) + if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCHTAP) { qboolean wasgameless = !*FS_GetGamedir(false); if (!Mods_GetMod(c->dint)) @@ -4447,7 +4447,7 @@ static qboolean Installer_Go(menuoption_t *opt, menu_t *menu, int key) { struct installermenudata *md = menu->data; - if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCH) + if (key == K_ENTER || key == K_KP_ENTER || key == K_GP_DIAMOND_CONFIRM || key == K_MOUSE1 || key == K_TOUCHTAP) { extern int startuppending; vfsfile_t *f; diff --git a/engine/client/m_single.c b/engine/client/m_single.c index 8254e13ef..7caf330d8 100644 --- a/engine/client/m_single.c +++ b/engine/client/m_single.c @@ -739,7 +739,7 @@ static qboolean M_DemoKey(menucustom_t *control, emenu_t *menu, int key, unsigne info->selected = info->selected->next; } break; - case K_TOUCH: + case K_TOUCHTAP: case K_MOUSE1: if (info->dragscroll == 2) { diff --git a/engine/client/menu.c b/engine/client/menu.c index 5893a9abb..1015cbc17 100644 --- a/engine/client/menu.c +++ b/engine/client/menu.c @@ -153,6 +153,15 @@ void Menu_PopAll(void) Menu_Unlink(menus[i], true); } +int Menu_WantOSK(void) +{ + if (promptmenu) + return promptmenu->showosk; + if (topmenu) + return topmenu->showosk; + return -1; +} + void Menu_Draw(void) { #ifdef MENU_DAT @@ -443,7 +452,7 @@ static qboolean Prompt_MenuKeyEvent(struct menu_s *gm, qboolean isdown, unsigned void (*callback)(void *, promptbutton_t) = m->callback; void *ctx = m->ctx; - if (key == K_MOUSE1 || key == K_TOUCH) + if (key == K_MOUSE1 || key == K_TOUCHTAP) { //mouse events fire their action on release. if (isdown) { @@ -495,10 +504,10 @@ static qboolean Prompt_MenuKeyEvent(struct menu_s *gm, qboolean isdown, unsigned } else if (key == K_ESCAPE || key == K_GP_BACK || key == K_MOUSE2 || key == K_MOUSE4 || key == K_GP_DIAMOND_CANCEL) action = PROMPT_CANCEL; - else if (key == K_ENTER || key == K_KP_ENTER || key == K_MOUSE1 || key == K_TOUCH || key == K_GP_DIAMOND_CONFIRM) + else if (key == K_ENTER || key == K_KP_ENTER || key == K_MOUSE1 || key == K_TOUCHTAP || key == K_GP_DIAMOND_CONFIRM) { int button; - if (key == K_MOUSE1 || key == K_TOUCH) + if (key == K_MOUSE1 || key == K_TOUCHTAP) button = m->mbutton; else button = m->kbutton; @@ -1048,7 +1057,10 @@ void M_Help_Draw (emenu_t *m) pic = NULL; } if (!pic) + { + m->postdraw = M_RemoveMenu; M_Menu_Main_f (); + } else { //define default aspect ratio diff --git a/engine/client/menu.h b/engine/client/menu.h index 044579942..3fd4a8abb 100644 --- a/engine/client/menu.h +++ b/engine/client/menu.h @@ -111,10 +111,12 @@ typedef struct menu_s { qboolean lowpriority; //appears underneath other menus. qboolean isopaque; //guarentees an opaque background qboolean persist; //try really hard to not kill this. + qboolean showosk; } menu_t; extern menu_t *topmenu; //the currently visible menu. extern menu_t *promptmenu; //the currently visible prompt (separate from menus, so they always appear over the top of consoles too, they also always show the menu underneath) void Menu_KeyEvent(qboolean down, int qdeviceid, int key, int unicode); +int Menu_WantOSK(void); void Menu_Draw(void); void Prompts_Draw(void); void Menu_PopAll(void); //attempts to pop all menus (this is for map starts, some might linger) diff --git a/engine/client/pr_clcmd.c b/engine/client/pr_clcmd.c index fd62f8119..9edaa5705 100644 --- a/engine/client/pr_clcmd.c +++ b/engine/client/pr_clcmd.c @@ -90,6 +90,9 @@ int MP_TranslateFTEtoQCCodes(keynum_t code) // case K_MOUSE15: return 528; // case K_MOUSE16: return 529; case K_TOUCH: return 600; + case K_TOUCHSLIDE: return 601; + case K_TOUCHTAP: return 602; + case K_TOUCHLONG: return 603; case K_JOY1: return 768; case K_JOY2: return 769; @@ -288,6 +291,9 @@ keynum_t MP_TranslateQCtoFTECodes(int code) // case 528: return K_MOUSE15; // case 529: return K_MOUSE16; case 600: return K_TOUCH; + case 601: return K_TOUCHSLIDE; + case 602: return K_TOUCHTAP; + case 603: return K_TOUCHLONG; case 768: return K_JOY1; case 769: return K_JOY2; diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 744e1f7fb..e89109309 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -2893,7 +2893,7 @@ static qboolean MP_KeyEvent(menu_t *menu, qboolean isdown, unsigned int devid, i PR_ExecuteProgram(menu_world.progs, mpfuncs.inputevent); result = G_FLOAT(OFS_RETURN); if (!result && key == K_TOUCH) - { + { //convert touches to mouse, for compat. gestures are untranslated but expected to be ignored. G_FLOAT(OFS_PARM0) = isdown?CSIE_KEYDOWN:CSIE_KEYUP; G_FLOAT(OFS_PARM1) = MP_TranslateFTEtoQCCodes(K_MOUSE1); G_FLOAT(OFS_PARM2) = unicode; @@ -2908,7 +2908,7 @@ static qboolean MP_KeyEvent(menu_t *menu, qboolean isdown, unsigned int devid, i { void *pr_globals = PR_globals(menu_world.progs, PR_CURRENT); if (key == K_TOUCH) - key = K_MOUSE1; + key = K_MOUSE1; //old api doesn't expect touches nor provides feedback for emulation. make sure stuff works. G_FLOAT(OFS_PARM0) = MP_TranslateFTEtoQCCodes(key); G_FLOAT(OFS_PARM1) = unicode; PR_ExecuteProgram(menu_world.progs, mpfuncs.keydown); @@ -2918,7 +2918,7 @@ static qboolean MP_KeyEvent(menu_t *menu, qboolean isdown, unsigned int devid, i { void *pr_globals = PR_globals(menu_world.progs, PR_CURRENT); if (key == K_TOUCH) - key = K_MOUSE1; + key = K_MOUSE1; //old api doesn't expect touches. G_FLOAT(OFS_PARM0) = MP_TranslateFTEtoQCCodes(key); G_FLOAT(OFS_PARM1) = unicode; PR_ExecuteProgram(menu_world.progs, mpfuncs.keyup); diff --git a/engine/client/screen.h b/engine/client/screen.h index cb9ad4f2d..d558ac3af 100644 --- a/engine/client/screen.h +++ b/engine/client/screen.h @@ -82,7 +82,7 @@ void SCR_ShowPic_Hide(void); void SCR_ShowPic_Move(void); void SCR_ShowPic_Update(void); void SCR_ShowPic_ClearAll(qboolean persistflag); -char *SCR_ShowPics_ClickCommand(int cx, int cy); +const char *SCR_ShowPics_ClickCommand(float cx, float cy, qboolean loadtouch); void SCR_ShowPic_Script_f(void); void SCR_ShowPic_Remove_f(void); diff --git a/engine/client/sys_sdl.c b/engine/client/sys_sdl.c index c94103559..74e0a8736 100644 --- a/engine/client/sys_sdl.c +++ b/engine/client/sys_sdl.c @@ -969,7 +969,8 @@ int QDECL main(int argc, char **argv) TL_InitLanguages(parms.basedir); - Sys_Printf ("Host_Init\n"); + if (parms.binarydir) + Sys_Printf("Binary is located at \"%s\"\n", parms.binarydir); Host_Init (&parms); oldtime = Sys_DoubleTime (); @@ -1071,11 +1072,24 @@ qboolean Sys_GetDesktopParameters(int *width, int *height, int *bpp, int *refres #include void Sys_Clipboard_PasteText(clipboardtype_t cbt, void (*callback)(void *cb, const char *utf8), void *ctx) { - callback(ctx, SDL_GetClipboardText()); + char *txt; +#if SDL_VERSION_ATLEAST(2,26,0) + if (cbt == CBT_SELECTION) + txt = SDL_GetPrimarySelectionText(); + else +#endif + txt = SDL_GetClipboardText(); + callback(ctx, txt); + SDL_free(txt); } void Sys_SaveClipboard(clipboardtype_t cbt, const char *text) { - SDL_SetClipboardText(text); +#if SDL_VERSION_ATLEAST(2,26,0) + if (cbt == CBT_SELECTION) + SDL_SetPrimarySelectionText(text); + else +#endif + SDL_SetClipboardText(text); } #else static char *clipboard_buffer; diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 0f9e11b2e..c4cd01f94 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -700,6 +700,20 @@ static const char *replacementq1binds = // "bind F11 +zoom\n" "bind F12 screenshot\n" ; +static const char *defaulttouchcfg = + "showpic_removeall\n" +// "sv_aim 0.90\n" //quake style, avoid needing to pitch too much + "showpic touch_moveforward.tga fwd -128 -112 bm 32 32 +forward 5\n" + "showpic touch_moveback.tga back -128 -80 bm 32 32 +back 5\n" + "showpic touch_moveleft.tga left -160 -88 bm 32 32 +moveleft 5\n" + "showpic touch_moveright.tga rght -96 -88 bm 32 32 +moveright 5\n" + + "showpic touch_attack.tga fire -160 -160 bm 32 32 +attack 5\n" + "showpic touch_jump.tga jump 128 -80 bm 32 32 +jump 5\n" + + "showpic touch_weapons.tga weap 80 -80 bm 32 32 +weaponwheel 5\n" + "showpic touch_menu.tga menu -32 0 tr 32 32 togglemenu 10\n" + ; #endif /* @@ -785,9 +799,9 @@ static void Cmd_Exec_f (void) if (!strncmp(name, "../", 3) || !strncmp(name, "..\\", 3) || !strncmp(name, "./", 2) || !strncmp(name, ".\\", 2)) { //filesystem will correctly block this (and more), but it does look dodgy when servers try doing this dodgy shit anyway. if (Cmd_IsInsecure()) - Con_TPrintf ("exec: %s is an invalid path (from server)\n", name); + Con_TPrintf ("%s: %s is an invalid path (from server)\n", Cmd_Argv(0), name); else - Con_TPrintf ("exec: %s is an invalid path\n", name); + Con_TPrintf ("%s: %s is an invalid path\n", Cmd_Argv(0), name); return; } @@ -796,7 +810,7 @@ static void Cmd_Exec_f (void) file = FS_OpenReadLocation(name, &loc); if (!file) { - Con_TPrintf ("couldn't exec %s. check permissions.\n", name); + Con_TPrintf ("couldn't %s %s. check permissions.\n", Cmd_Argv(0), name); return; } @@ -815,6 +829,12 @@ static void Cmd_Exec_f (void) untrusted = false; l = 0; } + else if (!strcmp(name, "touch.cfg")) //auto-execed if they touch a touchscreen. + { + f = Z_StrDup(defaulttouchcfg); + untrusted = false; + l = 0; + } #endif else { diff --git a/engine/common/console.h b/engine/common/console.h index 734209365..898c20a36 100644 --- a/engine/common/console.h +++ b/engine/common/console.h @@ -119,14 +119,15 @@ enum { CB_NONE = 0, CB_SCROLL = 1, - CB_COPY = 2, + CB_SCROLL_R = 2, CB_CLOSE = 3, CB_MOVE = 4, CB_ACTIONBAR = 5, CB_SELECT = 6, - CB_SCROLL_R = 7, + CB_SELECTED = 7, //the flags part + CB_STALE = (1u<<28), //WAS held last frame - to make sure we still do stuff when released on the same frame. CB_SIZELEFT = (1u<<29), CB_SIZERIGHT = (1u<<30), CB_SIZEBOTTOM = (1u<<31),