#include #include "../renderer/r_local.h" #include "../client/keys.h" #include "../ui/ui_local.h" #include #include "glw_unix.h" glwstate_t glw_state; int mx, my; qboolean mouse_active = false; int GLimp_Init(void *hinstance, void *wndproc) { /* No-op */ return 1; } void GLimp_Shutdown(void) { SDL_SetRelativeMouseMode(SDL_FALSE); mouse_active = false; } void GLimp_BeginFrame(float camera_seperation) { /* No-op */ } void GLimp_EndFrame(void) { SDL_GL_SwapWindow(glw_state.glWindow); } int GLimp_SetMode(int *pwidth, int *pheight, int mode, dispType_t fullscreen) { int width, height; if (!VID_GetModeInfo(&width, &height, mode)) { Com_Printf(" invalid mode\n"); return rserr_invalid_mode; } if (fullscreen == dt_fullscreen) { /* Override the vidmode with the desktop resolution. * If we wanted to be fancy we could use a faux-backbuffer to * simulate lower resolutions, but the engine is smart and lets * us override, so in 2021 let's just assume your PC can run * Quake 2. * -flibit */ SDL_DisplayMode mode; SDL_SetWindowFullscreen( glw_state.glWindow, SDL_WINDOW_FULLSCREEN_DESKTOP ); SDL_GetCurrentDisplayMode( SDL_GetWindowDisplayIndex(glw_state.glWindow), &mode ); *pwidth = mode.w; *pheight = mode.h; } else { SDL_SetWindowSize(glw_state.glWindow, width, height); SDL_SetWindowBordered( glw_state.glWindow, fullscreen != dt_borderless ); *pwidth = width; *pheight = height; } SDL_ShowWindow(glw_state.glWindow); VID_NewWindow(*pwidth, *pheight); return rserr_ok; } void UpdateGammaRamp(void) { /* Unsupported in 2021 */ } char *Sys_GetClipboardData(void) { return SDL_GetClipboardText(); } void IN_Activate(qboolean active) { if (active) { if (!mouse_active) { mx = my = 0; SDL_SetRelativeMouseMode(SDL_TRUE); mouse_active = true; } } else { if (mouse_active) { SDL_SetRelativeMouseMode(SDL_FALSE); mouse_active = false; } } } /* IN_Translate functions taken from yquake2 */ /* * This creepy function translates SDL keycodes into * the id Tech 2 engines interal representation. */ static int IN_TranslateSDLtoQ2Key(unsigned int keysym) { int key = 0; /* These must be translated */ switch (keysym) { case SDLK_TAB: key = K_TAB; break; case SDLK_RETURN: key = K_ENTER; break; case SDLK_ESCAPE: key = K_ESCAPE; break; case SDLK_BACKSPACE: key = K_BACKSPACE; break; case SDLK_CAPSLOCK: key = K_CAPSLOCK; break; case SDLK_PAUSE: key = K_PAUSE; break; case SDLK_UP: key = K_UPARROW; break; case SDLK_DOWN: key = K_DOWNARROW; break; case SDLK_LEFT: key = K_LEFTARROW; break; case SDLK_RIGHT: key = K_RIGHTARROW; break; case SDLK_RALT: case SDLK_LALT: key = K_ALT; break; case SDLK_LCTRL: case SDLK_RCTRL: key = K_CTRL; break; case SDLK_LSHIFT: case SDLK_RSHIFT: key = K_SHIFT; break; case SDLK_INSERT: key = K_INS; break; case SDLK_DELETE: key = K_DEL; break; case SDLK_PAGEDOWN: key = K_PGDN; break; case SDLK_PAGEUP: key = K_PGUP; break; case SDLK_HOME: key = K_HOME; break; case SDLK_END: key = K_END; break; case SDLK_F1: key = K_F1; break; case SDLK_F2: key = K_F2; break; case SDLK_F3: key = K_F3; break; case SDLK_F4: key = K_F4; break; case SDLK_F5: key = K_F5; break; case SDLK_F6: key = K_F6; break; case SDLK_F7: key = K_F7; break; case SDLK_F8: key = K_F8; break; case SDLK_F9: key = K_F9; break; case SDLK_F10: key = K_F10; break; case SDLK_F11: key = K_F11; break; case SDLK_F12: key = K_F12; break; case SDLK_KP_7: key = K_KP_HOME; break; case SDLK_KP_8: key = K_KP_UPARROW; break; case SDLK_KP_9: key = K_KP_PGUP; break; case SDLK_KP_4: key = K_KP_LEFTARROW; break; case SDLK_KP_5: key = K_KP_5; break; case SDLK_KP_6: key = K_KP_RIGHTARROW; break; case SDLK_KP_1: key = K_KP_END; break; case SDLK_KP_2: key = K_KP_DOWNARROW; break; case SDLK_KP_3: key = K_KP_PGDN; break; case SDLK_KP_ENTER: key = K_KP_ENTER; break; case SDLK_KP_0: key = K_KP_INS; break; case SDLK_KP_PERIOD: key = K_KP_DEL; break; case SDLK_KP_DIVIDE: key = K_KP_SLASH; break; case SDLK_KP_MINUS: key = K_KP_MINUS; break; case SDLK_KP_PLUS: key = K_KP_PLUS; break; case SDLK_KP_MULTIPLY: key = K_KP_MULT; break; default: break; } return key; } void HandleEvents(void) { int multiclicktime = 750; SDL_Event evt; while (SDL_PollEvent(&evt) == 1) { if (evt.type == SDL_QUIT) { Cbuf_ExecuteText(EXEC_NOW, "quit"); } else if (evt.type == SDL_KEYDOWN || evt.type == SDL_KEYUP) { /* KEYDOWN/KEYUP events taken from yquake2 */ qboolean down = (evt.type == SDL_KEYDOWN); /* workaround for AZERTY-keyboards, which don't have 1, 2, ..., 9, 0 in first row: * always map those physical keys (scancodes) to those keycodes anyway * see also https://bugzilla.libsdl.org/show_bug.cgi?id=3188 */ SDL_Scancode sc = evt.key.keysym.scancode; if (sc >= SDL_SCANCODE_1 && sc <= SDL_SCANCODE_0) { /* Note that the SDL_SCANCODEs are SDL_SCANCODE_1, _2, ..., _9, SDL_SCANCODE_0 * while in ASCII it's '0', '1', ..., '9' => handle 0 and 1-9 separately * (quake2 uses the ASCII values for those keys) */ int key = '0'; /* implicitly handles SDL_SCANCODE_0 */ if (sc <= SDL_SCANCODE_9) { key = '1' + (sc - SDL_SCANCODE_1); } Key_Event(key, down, Sys_Milliseconds()); } else { SDL_Keycode kc = evt.key.keysym.sym; if(sc == SDL_SCANCODE_GRAVE && kc != '\'' && kc != '"') { // special case/hack: open the console with the "console key" // (beneath Esc, left of 1, above Tab) // but not if the keycode for this is a quote (like on Brazilian // keyboards) - otherwise you couldn't type them in the console if((evt.key.keysym.mod & (KMOD_CAPS|KMOD_SHIFT|KMOD_ALT|KMOD_CTRL|KMOD_GUI)) == 0) { // also, only do this if no modifiers like shift or AltGr or whatever are pressed // so kc will most likely be the ascii char generated by this and can be ignored // in case SDL_TEXTINPUT above (so we don't get ^ or whatever as text in console) // (can't just check for mod == 0 because numlock is a KMOD too) Key_Event('`', down, Sys_Milliseconds()); } } else if ((kc >= SDLK_SPACE) && (kc < SDLK_DELETE)) { Key_Event(kc, down, false); } else { int key = IN_TranslateSDLtoQ2Key(kc); /* yquake2 has this, km does not if(key == 0) { // fallback to scancodes if we don't know the keycode key = IN_TranslateScancodeToQ2Key(sc); } */ if(key != 0) { Key_Event(key, down, Sys_Milliseconds()); } else { Com_DPrintf("Pressed unknown key with SDL_Keycode %d, SDL_Scancode %d.\n", kc, (int)sc); } } } } else if (evt.type == SDL_MOUSEMOTION) { if (mouse_active) { /* Relative should be on here */ mx += evt.motion.xrel; my += evt.motion.yrel; } } else if (evt.type == SDL_MOUSEBUTTONDOWN) { int mouse_button = evt.button.button - 1; if (mouse_button == 1) { mouse_button = 2; } else if (mouse_button == 2) { mouse_button = 1; } if (Sys_Milliseconds() - ui_mousecursor.buttontime[mouse_button] < multiclicktime) { ui_mousecursor.buttonclicks[mouse_button] += 1; } else { ui_mousecursor.buttonclicks[mouse_button] = 1; } if (ui_mousecursor.buttonclicks[mouse_button] > 3) { ui_mousecursor.buttonclicks[mouse_button] = 3; } ui_mousecursor.buttontime[mouse_button] = Sys_Milliseconds(); ui_mousecursor.buttondown[mouse_button] = true; ui_mousecursor.buttonused[mouse_button] = false; ui_mousecursor.mouseaction = true; Key_Event(K_MOUSE1 + mouse_button, 1, Sys_Milliseconds()); } else if (evt.type == SDL_MOUSEBUTTONUP) { int mouse_button = evt.button.button - 1; if (mouse_button == 1) { mouse_button = 2; } else if (mouse_button == 2) { mouse_button = 1; } ui_mousecursor.buttondown[mouse_button] = false; ui_mousecursor.buttonused[mouse_button] = false; ui_mousecursor.mouseaction = true; Key_Event(K_MOUSE1 + mouse_button, 0, Sys_Milliseconds()); } else if (evt.type == SDL_MOUSEWHEEL) { int dir; if (evt.wheel.y > 0) { dir = K_MWHEELUP; } else { dir = K_MWHEELDOWN; } /* We only get one event per wheel change, so instantly press/release */ Key_Event(dir, 1, Sys_Milliseconds()); Key_Event(dir, 0, Sys_Milliseconds()); } } }