From 55d71fbae737acf859a592911e5ffe50e777f79f Mon Sep 17 00:00:00 2001 From: havoc Date: Sun, 27 Feb 2011 18:38:25 +0000 Subject: [PATCH] experimental touchscreen support, intended for mobile devices, not very playable yet some hacks for keyboard input on ios because SDL 1.3 has some bugs still git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10868 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_screen.c | 31 ++++++ screen.h | 11 ++ vid_sdl.c | 289 ++++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 288 insertions(+), 43 deletions(-) diff --git a/cl_screen.c b/cl_screen.c index d6d82d0d..e152f425 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -81,6 +81,8 @@ cvar_t scr_screenshot_name_in_mapdir = {CVAR_SAVE, "scr_screenshot_name_in_mapdi cvar_t shownetgraph = {CVAR_SAVE, "shownetgraph", "0", "shows a graph of packet sizes and other information, 0 = off, 1 = show client netgraph, 2 = show client and server netgraphs (when hosting a server)"}; cvar_t cl_demo_mousegrab = {0, "cl_demo_mousegrab", "0", "Allows reading the mouse input while playing demos. Useful for camera mods developed in csqc. (0: never, 1: always)"}; cvar_t timedemo_screenshotframelist = {0, "timedemo_screenshotframelist", "", "when performing a timedemo, take screenshots of each frame in this space-separated list - example: 1 201 401"}; +cvar_t vid_touchscreen_outlinealpha = {0, "vid_touchscreen_outlinealpha", "0.25", "opacity of touchscreen area outlines"}; +cvar_t vid_touchscreen_overlayalpha = {0, "vid_touchscreen_overlayalpha", "0.25", "opacity of touchscreen area icons"}; extern cvar_t v_glslgamma; extern cvar_t sbar_info_pos; @@ -956,6 +958,8 @@ void CL_Screen_Init(void) Cvar_RegisterVariable(&shownetgraph); Cvar_RegisterVariable(&cl_demo_mousegrab); Cvar_RegisterVariable(&timedemo_screenshotframelist); + Cvar_RegisterVariable(&vid_touchscreen_outlinealpha); + Cvar_RegisterVariable(&vid_touchscreen_overlayalpha); Cmd_AddCommand ("sizeup",SCR_SizeUp_f, "increase view size (increases viewsize cvar)"); Cmd_AddCommand ("sizedown",SCR_SizeDown_f, "decrease view size (decreases viewsize cvar)"); @@ -1574,6 +1578,31 @@ qboolean SCR_ScreenShot(char *filename, unsigned char *buffer1, unsigned char *b //============================================================================= +int scr_numtouchscreenareas; +scr_touchscreenarea_t scr_touchscreenareas[16]; + +static void SCR_DrawTouchscreenOverlay(void) +{ + int i; + scr_touchscreenarea_t *a; + cachepic_t *pic; + for (i = 0, a = scr_touchscreenareas;i < scr_numtouchscreenareas;i++, a++) + { + if (vid_touchscreen_outlinealpha.value > 0 && a->rect[0] >= 0 && a->rect[1] >= 0 && a->rect[2] >= 4 && a->rect[3] >= 4) + { + DrawQ_Fill(a->rect[0] + 2, a->rect[1] , a->rect[2] - 4, 1 , 1, 1, 1, vid_touchscreen_outlinealpha.value * (0.5f + 0.5f * a->active), 0); + DrawQ_Fill(a->rect[0] + 1, a->rect[1] + 1, a->rect[2] - 2, 1 , 1, 1, 1, vid_touchscreen_outlinealpha.value * (0.5f + 0.5f * a->active), 0); + DrawQ_Fill(a->rect[0] , a->rect[1] + 2, 2 , a->rect[3] - 2, 1, 1, 1, vid_touchscreen_outlinealpha.value * (0.5f + 0.5f * a->active), 0); + DrawQ_Fill(a->rect[0] + a->rect[2] - 2, a->rect[1] + 2, 2 , a->rect[3] - 2, 1, 1, 1, vid_touchscreen_outlinealpha.value * (0.5f + 0.5f * a->active), 0); + DrawQ_Fill(a->rect[0] + 1, a->rect[1] + a->rect[3] - 2, a->rect[2] - 2, 1 , 1, 1, 1, vid_touchscreen_outlinealpha.value * (0.5f + 0.5f * a->active), 0); + DrawQ_Fill(a->rect[0] + 2, a->rect[1] + a->rect[3] - 1, a->rect[2] - 4, 1 , 1, 1, 1, vid_touchscreen_outlinealpha.value * (0.5f + 0.5f * a->active), 0); + } + pic = a->pic ? Draw_CachePic(a->pic) : NULL; + if (pic && pic->tex != r_texture_notexture) + DrawQ_Pic(a->rect[0], a->rect[1], Draw_CachePic(a->pic), a->rect[2], a->rect[3], 1, 1, 1, vid_touchscreen_overlayalpha.value * (0.5f + 0.5f * a->active), 0); + } +} + extern void R_UpdateFogColor(void); void R_ClearScreen(qboolean fogcolor) { @@ -1771,6 +1800,8 @@ void SCR_DrawScreen (void) SCR_DrawInfobar(); + SCR_DrawTouchscreenOverlay(); + if (r_timereport_active) R_TimeReport("2d"); diff --git a/screen.h b/screen.h index 7574d40d..b88a80d5 100644 --- a/screen.h +++ b/screen.h @@ -71,5 +71,16 @@ extern cvar_t r_stereo_angle; qboolean R_Stereo_Active(void); extern int r_stereo_side; +typedef struct scr_touchscreenarea_s +{ + const char *pic; + float rect[4]; + float active; +} +scr_touchscreenarea_t; + +extern int scr_numtouchscreenareas; +extern scr_touchscreenarea_t scr_touchscreenareas[16]; + #endif diff --git a/vid_sdl.c b/vid_sdl.c index 84e27472..26c49f1e 100644 --- a/vid_sdl.c +++ b/vid_sdl.c @@ -258,7 +258,11 @@ static int MapKey( unsigned int sdlkey ) case SDLK_INSERT: return K_INS; case SDLK_HOME: return K_HOME; case SDLK_PAGEUP: return K_PGUP; +#ifdef __IPHONEOS__ + case SDLK_DELETE: return K_BACKSPACE; +#else case SDLK_DELETE: return K_DEL; +#endif case SDLK_END: return K_END; case SDLK_PAGEDOWN: return K_PGDN; case SDLK_RIGHT: return K_RIGHTARROW; @@ -408,10 +412,17 @@ static int MapKey( unsigned int sdlkey ) } } -void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecursor) +#ifdef __IPHONEOS__ +int SDL_iPhoneKeyboardShow(SDL_Window * window); // reveals the onscreen keyboard. Returns 0 on success and -1 on error. +int SDL_iPhoneKeyboardHide(SDL_Window * window); // hides the onscreen keyboard. Returns 0 on success and -1 on error. +SDL_bool SDL_iPhoneKeyboardIsShown(SDL_Window * window); // returns whether or not the onscreen keyboard is currently visible. +int SDL_iPhoneKeyboardToggle(SDL_Window * window); // toggles the visibility of the onscreen keyboard. Returns 0 on success and -1 on error. +#endif + +void VID_ShowKeyboard(qboolean show) { #ifdef __IPHONEOS__ - if (key_consoleactive || key_dest != key_game) + if (show) { if (!SDL_iPhoneKeyboardIsShown(window)) SDL_iPhoneKeyboardShow(window); @@ -421,7 +432,19 @@ void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecurso if (SDL_iPhoneKeyboardIsShown(window)) SDL_iPhoneKeyboardHide(window); } -#else +#endif +} + +qboolean VID_ShowingKeyboard(void) +{ +#ifdef __IPHONEOS__ + return SDL_iPhoneKeyboardIsShown(window); +#endif +} + +void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecursor) +{ +#ifndef __IPHONEOS__ #ifdef MACOSX if(relative) if(vid_usingmouse && (vid_usingnoaccel != !!apple_mouse_noaccel.integer)) @@ -571,6 +594,61 @@ static qboolean IN_JoystickBlockDoubledKeyEvents(int keycode) return false; } +// multitouch[10][] represents the mouse pointer +// X and Y coordinates are 0-32767 as per SDL spec +#define MAXFINGERS 11 +int multitouch[MAXFINGERS][3]; + +qboolean VID_TouchscreenArea(float x, float y, float width, float height, const char *icon, float *resultmove, qboolean *resultbutton, keynum_t key) +{ + int finger; + float rel[3]; + qboolean button = false; + VectorClear(rel); + if (width > 0 && height > 0 && (key == '`' || key == K_ESCAPE || !VID_ShowingKeyboard())) + { + x *= 32768.0f / 320.0f; + y *= 32768.0f / 480.0f; + width *= 32768.0f / 320.0f; + height *= 32768.0f / 480.0f; + for (finger = 0;finger < MAXFINGERS;finger++) + { + if (multitouch[finger][0] && multitouch[finger][1] >= x && multitouch[finger][2] >= y && multitouch[finger][1] < x + width && multitouch[finger][2] < y + height) + { + rel[0] = (multitouch[finger][1] - (x + 0.5f * width)) * (2.0f / width); + rel[1] = (multitouch[finger][2] - (y + 0.5f * height)) * (2.0f / height); + rel[2] = 0; + button = true; + break; + } + } + if (scr_numtouchscreenareas < 16) + { + scr_touchscreenareas[scr_numtouchscreenareas].pic = icon; + scr_touchscreenareas[scr_numtouchscreenareas].rect[0] = x * vid_conwidth.value / 32768.0f; + scr_touchscreenareas[scr_numtouchscreenareas].rect[1] = y * vid_conheight.value / 32768.0f; + scr_touchscreenareas[scr_numtouchscreenareas].rect[2] = width * vid_conwidth.value / 32768.0f; + scr_touchscreenareas[scr_numtouchscreenareas].rect[3] = height * vid_conheight.value / 32768.0f; + scr_touchscreenareas[scr_numtouchscreenareas].active = button; + scr_numtouchscreenareas++; + } + } + if (resultmove) + { + if (button) + VectorCopy(rel, resultmove); + else + VectorClear(resultmove); + } + if (resultbutton) + { + if (*resultbutton != button && (int)key > 0) + Key_Event(key, 0, button); + *resultbutton = button; + } + return button; +} + ///////////////////// // Movement handling //// @@ -582,61 +660,113 @@ void IN_Move( void ) static int stuck = 0; int x, y, numaxes, numballs; - if (vid_usingmouse) + scr_numtouchscreenareas = 0; + if (vid_touchscreen.integer) { - if (vid_touchscreen.integer) + vec3_t move, aim, click; + static qboolean buttons[16]; + static int oldkeydest; + keydest_t keydest = (key_consoleactive & KEY_CONSOLEACTIVE_USER) ? key_console : key_dest; + multitouch[MAXFINGERS-1][0] = SDL_GetMouseState(&x, &y); + multitouch[MAXFINGERS-1][1] = x * 32768 / vid.width; + multitouch[MAXFINGERS-1][2] = y * 32768 / vid.height; + if (oldkeydest != keydest) { - // touchscreen controls... - if (SDL_GetRelativeMouseState(&x,&y)) + switch(keydest) { - in_mouse_x = x; - in_mouse_y = y; + case key_game: VID_ShowKeyboard(false);break; + case key_console: VID_ShowKeyboard(true);break; + case key_message: VID_ShowKeyboard(true);break; + default: break; } - else + } + oldkeydest = keydest; + // top of screen is toggleconsole and K_ESCAPE + VID_TouchscreenArea( 0, 0, 50, 50, NULL , NULL, &buttons[13], '`'); + VID_TouchscreenArea( 50, 0, 270, 50, "gfx/touch_menu.tga" , NULL, &buttons[14], K_ESCAPE); + switch(keydest) + { + case key_console: + if (!VID_ShowingKeyboard()) + { + // user entered a command, close the console now + Con_ToggleConsole_f(); + } + break; + case key_game: + VID_TouchscreenArea( 0, 380, 100, 100, "gfx/touch_movebutton.tga" , move, &buttons[0], K_MOUSE4); + VID_TouchscreenArea(220, 380, 100, 100, "gfx/touch_aimbutton.tga" , aim, &buttons[1], K_MOUSE5); + VID_TouchscreenArea(110, 380, 100, 100, "gfx/touch_attackbutton.tga" , NULL, &buttons[2], K_MOUSE1); + VID_TouchscreenArea( 0, 330, 100, 50, "gfx/touch_jumpbutton.tga" , NULL, &buttons[3], K_SPACE); + VID_TouchscreenArea(220, 330, 100, 50, "gfx/touch_attack2button.tga", NULL, &buttons[4], K_MOUSE2); + buttons[15] = false; + break; + default: + // in menus, an icon in the corner activates keyboard + VID_TouchscreenArea( 0, 430, 50, 50, "gfx/touch_keyboard.tga" , NULL, &buttons[15], 0); + if (buttons[15]) + VID_ShowKeyboard(true); + VID_TouchscreenArea( 0, 0, 0, 0, NULL , move, &buttons[0], K_MOUSE4); + VID_TouchscreenArea( 0, 0, 0, 0, NULL , aim, &buttons[1], K_MOUSE5); + VID_TouchscreenArea(-320,-480,640, 960, NULL , click,&buttons[2], K_MOUSE1); + VID_TouchscreenArea( 0, 0, 0, 0, NULL , NULL, &buttons[3], K_SPACE); + VID_TouchscreenArea( 0, 0, 0, 0, NULL , NULL, &buttons[4], K_MOUSE2); + if (buttons[2]) { - in_mouse_x = 0; - in_mouse_y = 0; + in_windowmouse_x = x; + in_windowmouse_y = y; } + break; } - else if (vid_stick_mouse.integer) + cl.cmd.forwardmove -= move[1] * cl_forwardspeed.value; + cl.cmd.sidemove += move[0] * cl_sidespeed.value; + cl.viewangles[0] += aim[1] * cl_pitchspeed.value * cl.realframetime; + cl.viewangles[1] -= aim[0] * cl_yawspeed.value * cl.realframetime; + } + else + { + if (vid_usingmouse) { - // have the mouse stuck in the middle, example use: prevent expose effect of beryl during the game when not using - // window grabbing. --blub - - // we need 2 frames to initialize the center position - if(!stuck) + if (vid_stick_mouse.integer) { + // have the mouse stuck in the middle, example use: prevent expose effect of beryl during the game when not using + // window grabbing. --blub + + // we need 2 frames to initialize the center position + if(!stuck) + { #if SETVIDEOMODE - SDL_WarpMouse(win_half_width, win_half_height); + SDL_WarpMouse(win_half_width, win_half_height); #else - SDL_WarpMouseInWindow(window, win_half_width, win_half_height); + SDL_WarpMouseInWindow(window, win_half_width, win_half_height); #endif - SDL_GetMouseState(&x, &y); - SDL_GetRelativeMouseState(&x, &y); - ++stuck; - } else { - SDL_GetRelativeMouseState(&x, &y); - in_mouse_x = x + old_x; - in_mouse_y = y + old_y; - SDL_GetMouseState(&x, &y); - old_x = x - win_half_width; - old_y = y - win_half_height; + SDL_GetMouseState(&x, &y); + SDL_GetRelativeMouseState(&x, &y); + ++stuck; + } else { + SDL_GetRelativeMouseState(&x, &y); + in_mouse_x = x + old_x; + in_mouse_y = y + old_y; + SDL_GetMouseState(&x, &y); + old_x = x - win_half_width; + old_y = y - win_half_height; #if SETVIDEOMODE - SDL_WarpMouse(win_half_width, win_half_height); + SDL_WarpMouse(win_half_width, win_half_height); #else - SDL_WarpMouseInWindow(window, win_half_width, win_half_height); + SDL_WarpMouseInWindow(window, win_half_width, win_half_height); #endif + } + } else { + SDL_GetRelativeMouseState( &x, &y ); + in_mouse_x = x; + in_mouse_y = y; } - } else { - SDL_GetRelativeMouseState( &x, &y ); - in_mouse_x = x; - in_mouse_y = y; } - } - SDL_GetMouseState(&x, &y); - in_windowmouse_x = x; - in_windowmouse_y = y; + SDL_GetMouseState(&x, &y); + in_windowmouse_x = x; + in_windowmouse_y = y; + } if (vid_numjoysticks && joy_enable.integer && joy_index.integer >= 0 && joy_index.integer < vid_numjoysticks) { @@ -821,7 +951,11 @@ void Sys_SendKeyEvents( void ) void Sys_SendKeyEvents( void ) { static qboolean sound_active = true; + static qboolean missingunicodehack = true; int keycode; + int i; + int j; + int unicode; SDL_Event event; while( SDL_PollEvent( &event ) ) @@ -833,12 +967,23 @@ void Sys_SendKeyEvents( void ) case SDL_KEYUP: keycode = MapKey(event.key.keysym.sym); if (!IN_JoystickBlockDoubledKeyEvents(keycode)) +#ifdef __IPHONEOS__ + // the virtual keyboard seems to produce no unicode values... + if (missingunicodehack && keycode >= ' ' && keycode < 0x7F && event.key.keysym.unicode == 0) + { + Con_DPrintf("SDL hack: no unicode value reported, substituting ascii value %i\n", keycode); + Key_Event(keycode, keycode, (event.key.state == SDL_PRESSED)); + } + else +#endif Key_Event(keycode, 0, (event.key.state == SDL_PRESSED)); break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: +#ifndef __IPHONEOS__ if (event.button.button <= 18) Key_Event( buttonremap[event.button.button - 1], 0, event.button.state == SDL_PRESSED ); +#endif break; case SDL_JOYBUTTONDOWN: if (!joy_enable.integer) @@ -915,10 +1060,8 @@ void Sys_SendKeyEvents( void ) break; case SDL_TEXTINPUT: // we have some characters to parse + missingunicodehack = false; { - int unicode; - int i; - int j; unicode = 0; for (i = 0;event.text.text[i];) { @@ -943,6 +1086,64 @@ void Sys_SendKeyEvents( void ) break; case SDL_MOUSEMOTION: break; + case SDL_FINGERDOWN: + Con_DPrintf("SDL_FINGERDOWN for finger %i\n", (int)event.tfinger.fingerId); + for (i = 0;i < MAXFINGERS-1;i++) + { + if (!multitouch[i][0]) + { + multitouch[i][0] = event.tfinger.fingerId; + multitouch[i][1] = event.tfinger.x; + multitouch[i][2] = event.tfinger.y; + // TODO: use event.tfinger.pressure? + break; + } + } + if (i == MAXFINGERS-1) + Con_DPrintf("Too many fingers at once!\n"); + break; + case SDL_FINGERUP: + Con_DPrintf("SDL_FINGERUP for finger %i\n", (int)event.tfinger.fingerId); + for (i = 0;i < MAXFINGERS-1;i++) + { + if (multitouch[i][0] == event.tfinger.fingerId) + { + multitouch[i][0] = 0; + break; + } + } + if (i == MAXFINGERS-1) + Con_DPrintf("No SDL_FINGERDOWN event matches this SDL_FINGERMOTION event\n"); + break; + case SDL_FINGERMOTION: + Con_DPrintf("SDL_FINGERMOTION for finger %i\n", (int)event.tfinger.fingerId); + for (i = 0;i < MAXFINGERS-1;i++) + { + if (multitouch[i][0] == event.tfinger.fingerId) + { + multitouch[i][1] = event.tfinger.x; + multitouch[i][2] = event.tfinger.y; + break; + } + } + if (i == MAXFINGERS-1) + Con_DPrintf("No SDL_FINGERDOWN event matches this SDL_FINGERMOTION event\n"); + break; + case SDL_TOUCHBUTTONDOWN: + // not sure what to do with this... + break; + case SDL_TOUCHBUTTONUP: + // not sure what to do with this... + break; + case SDL_JOYAXISMOTION: + // we poll the joystick instead + break; + case SDL_JOYBALLMOTION: + // we poll the joystick instead + break; + case SDL_JOYHATMOTION: + // we poll the joystick instead + break; default: Con_DPrintf("Received unrecognized SDL_Event type 0x%x\n", event.type); break; @@ -2026,6 +2227,7 @@ qboolean VID_InitModeGL(viddef_mode_t *mode) vid_hidden = false; vid_activewindow = false; + vid_hasfocus = true; vid_usingmouse = false; vid_usinghidecursor = false; @@ -2203,6 +2405,7 @@ qboolean VID_InitModeSoft(viddef_mode_t *mode) vid_hidden = false; vid_activewindow = false; + vid_hasfocus = true; vid_usingmouse = false; vid_usinghidecursor = false; -- 2.39.2