diff --git a/neo/CMakeLists.txt b/neo/CMakeLists.txt index bde800ee..d19fed0f 100644 --- a/neo/CMakeLists.txt +++ b/neo/CMakeLists.txt @@ -675,6 +675,7 @@ else() set(src_sys_base sys/cpu.cpp sys/threads.cpp + sys/events.cpp sys/sys_local.cpp sys/posix/posix_net.cpp sys/posix/posix_signal.cpp @@ -685,8 +686,6 @@ else() set(src_sys_core ${src_stub_util} sys/glimp.cpp - sys/posix/posix_input.cpp - sys/linux/input.cpp ) endif() diff --git a/neo/framework/Common.cpp b/neo/framework/Common.cpp index 45db61be..52b49285 100644 --- a/neo/framework/Common.cpp +++ b/neo/framework/Common.cpp @@ -2797,6 +2797,14 @@ idCommonLocal::Init ================= */ void idCommonLocal::Init( int argc, char **argv ) { +#ifdef ID_DEDICATED + // we want to use the SDL event queue for dedicated servers. That + // requires video to be initialized, so we just use the dummy + // driver for headless boxen + char dummy[] = "SDL_VIDEODRIVER=dummy\0"; + SDL_putenv(dummy); +#endif + if (SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO)) Sys_Error("Error while initializing SDL: %s", SDL_GetError()); diff --git a/neo/sys/events.cpp b/neo/sys/events.cpp new file mode 100644 index 00000000..34abb127 --- /dev/null +++ b/neo/sys/events.cpp @@ -0,0 +1,565 @@ +/* +=========================================================================== + +Doom 3 GPL Source Code +Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. + +This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). + +Doom 3 Source Code is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Doom 3 Source Code is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Doom 3 Source Code. If not, see . + +In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. + +If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. + +=========================================================================== +*/ + +#include + +#include "sys/platform.h" +#include "idlib/containers/List.h" +#include "idlib/Heap.h" +#include "framework/Common.h" +#include "framework/KeyInput.h" + +#include "sys/sys_public.h" + +const char *kbdNames[] = { + "english", "french", "german", "italian", "turkish", NULL +}; + +idCVar in_nograb("in_nograb", "0", CVAR_SYSTEM | CVAR_NOCHEAT, "prevents input grabbing"); +idCVar in_kbd("in_kbd", "english", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT, "keyboard layout", kbdNames, idCmdSystem::ArgCompletion_String ); + +struct kbd_poll_t { + int key; + bool state; + + kbd_poll_t() { + } + + kbd_poll_t(int k, bool s) { + key = k; + state = s; + } +}; + +struct mouse_poll_t { + int action; + int value; + + mouse_poll_t() { + } + + mouse_poll_t(int a, int v) { + action = a; + value = v; + } +}; + +static idList kbd_polls; +static idList mouse_polls; +static bool grabbed = false; + +static byte mapkey(SDLKey key) { + switch (key) { + case SDLK_BACKSPACE: + return K_BACKSPACE; + case SDLK_PAUSE: + return K_PAUSE; + } + + if (key <= SDLK_z) + return key & 0xff; + + switch (key) { + case SDLK_COMPOSE: + return K_COMMAND; + case SDLK_CAPSLOCK: + return K_CAPSLOCK; + case SDLK_SCROLLOCK: + return K_SCROLL; + case SDLK_POWER: + return K_POWER; + + case SDLK_UP: + return K_UPARROW; + case SDLK_DOWN: + return K_DOWNARROW; + case SDLK_LEFT: + return K_LEFTARROW; + case SDLK_RIGHT: + return K_RIGHTARROW; + + case SDLK_LSUPER: + return K_LWIN; + case SDLK_RSUPER: + return K_RWIN; + case SDLK_MENU: + return K_MENU; + + case SDLK_LALT: + return K_ALT; + case SDLK_RCTRL: + case SDLK_LCTRL: + return K_CTRL; + case SDLK_RSHIFT: + case SDLK_LSHIFT: + return K_SHIFT; + case SDLK_INSERT: + return K_INS; + case SDLK_DELETE: + return K_DEL; + case SDLK_PAGEDOWN: + return K_PGDN; + case SDLK_PAGEUP: + return K_PGUP; + case SDLK_HOME: + return K_HOME; + case SDLK_END: + return K_END; + + case SDLK_F1: + return K_F1; + case SDLK_F2: + return K_F2; + case SDLK_F3: + return K_F3; + case SDLK_F4: + return K_F4; + case SDLK_F5: + return K_F5; + case SDLK_F6: + return K_F6; + case SDLK_F7: + return K_F7; + case SDLK_F8: + return K_F8; + case SDLK_F9: + return K_F9; + case SDLK_F10: + return K_F10; + case SDLK_F11: + return K_F11; + case SDLK_F12: + return K_F12; + // K_INVERTED_EXCLAMATION; + case SDLK_F13: + return K_F13; + case SDLK_F14: + return K_F14; + case SDLK_F15: + return K_F15; + + case SDLK_KP7: + return K_KP_HOME; + case SDLK_KP8: + return K_KP_UPARROW; + case SDLK_KP9: + return K_KP_PGUP; + case SDLK_KP4: + return K_KP_LEFTARROW; + case SDLK_KP5: + return K_KP_5; + case SDLK_KP6: + return K_KP_RIGHTARROW; + case SDLK_KP1: + return K_KP_END; + case SDLK_KP2: + return K_KP_DOWNARROW; + case SDLK_KP3: + return K_KP_PGDN; + case SDLK_KP_ENTER: + return K_KP_ENTER; + case SDLK_KP0: + return K_KP_INS; + case SDLK_KP_PERIOD: + return K_KP_DEL; + case SDLK_KP_DIVIDE: + return K_KP_SLASH; + // K_SUPERSCRIPT_TWO; + case SDLK_KP_MINUS: + return K_KP_MINUS; + // K_ACUTE_ACCENT; + case SDLK_KP_PLUS: + return K_KP_PLUS; + case SDLK_NUMLOCK: + return K_KP_NUMLOCK; + case SDLK_KP_MULTIPLY: + return K_KP_STAR; + case SDLK_KP_EQUALS: + return K_KP_EQUALS; + + // K_MASCULINE_ORDINATOR; + // K_GRAVE_A; + // K_AUX1; + // K_CEDILLA_C; + // K_GRAVE_E; + // K_AUX2; + // K_AUX3; + // K_AUX4; + // K_GRAVE_I; + // K_AUX5; + // K_AUX6; + // K_AUX7; + // K_AUX8; + // K_TILDE_N; + // K_GRAVE_O; + // K_AUX9; + // K_AUX10; + // K_AUX11; + // K_AUX12; + // K_AUX13; + // K_AUX14; + // K_GRAVE_U; + // K_AUX15; + // K_AUX16; + + case SDLK_PRINT: + return K_PRINT_SCR; + case SDLK_MODE: + return K_RIGHT_ALT; + } + + return 0; +} + +static void GrabInput(bool grab, bool hide_cursor, bool set_state) { +#if defined(ID_DEDICATED) + return; +#else + if (set_state) + grabbed = grab; + + if (hide_cursor) + SDL_ShowCursor(SDL_DISABLE); + else + SDL_ShowCursor(SDL_ENABLE); + + if (in_nograb.GetBool()) + grab = false; + + if (grab) + SDL_WM_GrabInput(SDL_GRAB_ON); + else + SDL_WM_GrabInput(SDL_GRAB_OFF); +#endif +} + +/* +================= +Sys_InitInput +================= +*/ +void Sys_InitInput() { + kbd_polls.SetGranularity(64); + mouse_polls.SetGranularity(64); + + SDL_EnableUNICODE(1); + SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); + + in_kbd.SetModified(); +} + +/* +================= +Sys_ShutdownInput +================= +*/ +void Sys_ShutdownInput() { + kbd_polls.Clear(); + mouse_polls.Clear(); +} + +/* +=========== +Sys_InitScanTable +=========== +*/ +void Sys_InitScanTable() { +} + +/* +=============== +Sys_GetConsoleKey +=============== +*/ +unsigned char Sys_GetConsoleKey(bool shifted) { + static unsigned char keys[2] = { '`', '~' }; + + if (in_kbd.IsModified()) { + idStr lang = in_kbd.GetString(); + + if (lang.Length()) { + if (!lang.Icmp("french")) { + keys[0] = '<'; + keys[1] = '>'; + } else if (!lang.Icmp("german")) { + keys[0] = '^'; + keys[1] = 176; // ° + } else if (!lang.Icmp("italian")) { + keys[0] = '\\'; + keys[1] = '|'; + } else if (!lang.Icmp("turkish")) { + keys[0] = '"'; + keys[1] = 233; // é + } + } + + in_kbd.ClearModified(); + } + + return shifted ? keys[1] : keys[0]; +} + +/* +=============== +Sys_MapCharForKey +=============== +*/ +unsigned char Sys_MapCharForKey(int key) { + return key & 0xff; +} + +/* +=============== +Sys_GrabMouseCursor +=============== +*/ +void Sys_GrabMouseCursor(bool grabIt) { + GrabInput(grabIt, grabIt, true); +} + +/* +================ +Sys_GetEvent +================ +*/ +sysEvent_t Sys_GetEvent() { + SDL_Event ev; + sysEvent_t res = { }; + byte key; + + static const sysEvent_t res_none = { SE_NONE, 0, 0, 0, NULL }; + static byte c = 0; + + if (c) { + res.evType = SE_CHAR; + res.evValue = c; + + c = 0; + + return res; + } + + if (SDL_PollEvent(&ev)) { + switch (ev.type) { + case SDL_ACTIVEEVENT: + GrabInput(grabbed && ev.active.gain == 1, ev.active.gain == 1, false); + return res_none; + + case SDL_VIDEOEXPOSE: + return res_none; + + case SDL_KEYDOWN: + case SDL_KEYUP: + key = mapkey(ev.key.keysym.sym); + + if (!key) { + common->Warning("unmapped SDL key %d", ev.key.keysym.sym); + return res_none; + } + + res.evType = SE_KEY; + res.evValue = key; + res.evValue2 = ev.key.state == SDL_PRESSED ? 1 : 0; + + kbd_polls.Append(kbd_poll_t(key, ev.key.state == SDL_PRESSED)); + + if (ev.key.state == SDL_PRESSED && (ev.key.keysym.unicode & 0xff00) == 0) + c = ev.key.keysym.unicode & 0xff; + + return res; + + case SDL_MOUSEMOTION: + res.evType = SE_MOUSE; + res.evValue = ev.motion.xrel; + res.evValue2 = ev.motion.yrel; + + mouse_polls.Append(mouse_poll_t(M_DELTAX, ev.motion.xrel)); + mouse_polls.Append(mouse_poll_t(M_DELTAY, ev.motion.yrel)); + + return res; + + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + res.evType = SE_KEY; + + switch (ev.button.button) { + case SDL_BUTTON_LEFT: + res.evValue = K_MOUSE1; + mouse_polls.Append(mouse_poll_t(M_ACTION1, ev.button.state == SDL_PRESSED ? 1 : 0)); + break; + case SDL_BUTTON_MIDDLE: + res.evValue = K_MOUSE3; + mouse_polls.Append(mouse_poll_t(M_ACTION3, ev.button.state == SDL_PRESSED ? 1 : 0)); + break; + case SDL_BUTTON_RIGHT: + res.evValue = K_MOUSE2; + mouse_polls.Append(mouse_poll_t(M_ACTION2, ev.button.state == SDL_PRESSED ? 1 : 0)); + break; + case SDL_BUTTON_WHEELUP: + res.evValue = K_MWHEELUP; + if (ev.button.state == SDL_PRESSED) + mouse_polls.Append(mouse_poll_t(M_DELTAZ, 1)); + break; + case SDL_BUTTON_WHEELDOWN: + res.evValue = K_MWHEELDOWN; + if (ev.button.state == SDL_PRESSED) + mouse_polls.Append(mouse_poll_t(M_DELTAZ, -1)); + break; + } + + res.evValue2 = ev.button.state == SDL_PRESSED ? 1 : 0; + + return res; + + case SDL_USEREVENT: + switch (ev.user.code) { + case SE_CONSOLE: + res.evType = SE_CONSOLE; + res.evPtrLength = (intptr_t)ev.user.data1; + res.evPtr = ev.user.data2; + return res; + default: + common->Warning("unknown user event %u", ev.user.code); + return res_none; + } + default: + common->Warning("unknown event %u", ev.type); + return res_none; + } + } + + return res_none; +} + +/* +================ +Sys_ClearEvents +================ +*/ +void Sys_ClearEvents() { + SDL_Event ev; + + while (SDL_PollEvent(&ev)) + ; + + kbd_polls.SetNum(0, false); + mouse_polls.SetNum(0, false); +} + +/* +================ +Sys_GenerateEvents +================ +*/ +void Sys_GenerateEvents() { + char *s = Sys_ConsoleInput(); + + if (s) { + char *b; + size_t len; + + len = strlen(s) + 1; + b = (char *)Mem_Alloc(len); + strcpy(b, s); + + SDL_Event event; + + event.type = SDL_USEREVENT; + event.user.code = SE_CONSOLE; + event.user.data1 = (void *)len; + event.user.data2 = b; + + SDL_PushEvent(&event); + } + + SDL_PumpEvents(); +} + +/* +================ +Sys_PollKeyboardInputEvents +================ +*/ +int Sys_PollKeyboardInputEvents() { + return kbd_polls.Num(); +} + +/* +================ +Sys_ReturnKeyboardInputEvent +================ +*/ +int Sys_ReturnKeyboardInputEvent(const int n, int &key, bool &state) { + if (n >= kbd_polls.Num()) + return 0; + + key = kbd_polls[n].key; + state = kbd_polls[n].state; + return 1; +} + +/* +================ +Sys_EndKeyboardInputEvents +================ +*/ +void Sys_EndKeyboardInputEvents() { + kbd_polls.SetNum(0, false); +} + +/* +================ +Sys_PollMouseInputEvents +================ +*/ +int Sys_PollMouseInputEvents() { + return mouse_polls.Num(); +} + +/* +================ +Sys_ReturnMouseInputEvent +================ +*/ +int Sys_ReturnMouseInputEvent(const int n, int &action, int &value) { + if (n >= mouse_polls.Num()) + return 0; + + action = mouse_polls[n].action; + value = mouse_polls[n].value; + return 1; +} + +/* +================ +Sys_EndMouseInputEvents +================ +*/ +void Sys_EndMouseInputEvents() { + mouse_polls.SetNum(0, false); +} diff --git a/neo/sys/glimp.cpp b/neo/sys/glimp.cpp index 9a14e399..741e6493 100644 --- a/neo/sys/glimp.cpp +++ b/neo/sys/glimp.cpp @@ -36,13 +36,6 @@ If you have questions concerning this license or the applicable additional terms idCVar sys_videoRam("sys_videoRam", "0", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_INTEGER, "Texture memory on the video card (in megabytes) - 0: autodetect", 0, 512); -#ifdef __unix__ -// workaround until events are ported to sdl -Display *dpy = NULL; -Window win = 0; -bool dga_found = false; -#endif - /* =================== GLimp_Init @@ -166,19 +159,6 @@ bool GLimp_Init(glimpParms_t parms) { glConfig.wgl_extensions_string = ""; - SDL_SysWMinfo info; - SDL_VERSION(&info.version); - - if (SDL_GetWMInfo(&info)) { -#if defined(__unix__) - // workaround until events are ported to sdl - if (info.subsystem == SDL_SYSWM_X11) { - dpy = info.info.x11.display; - win = info.info.x11.window; - } -#endif - } - return true; } diff --git a/neo/sys/linux/dedicated.cpp b/neo/sys/linux/dedicated.cpp index f23e15e2..7cb09f2e 100644 --- a/neo/sys/linux/dedicated.cpp +++ b/neo/sys/linux/dedicated.cpp @@ -32,32 +32,6 @@ If you have questions concerning this license or the applicable additional terms #include "sys/linux/local.h" -/* -========== -input -========== -*/ - -void Sys_InitInput( void ) { } - -void Sys_ShutdownInput( void ) { } - -void Sys_GrabMouseCursor( bool ) { } - -int Sys_PollMouseInputEvents( void ) { return 0; } - -void Sys_EndMouseInputEvents( void ) { } - -int Sys_ReturnMouseInputEvent( const int n, int &action, int &value ) { return 0; } - -int Sys_PollKeyboardInputEvents( void ) { return 0; } - -void Sys_EndKeyboardInputEvents( void ) { } - -int Sys_ReturnKeyboardInputEvent( const int n, int &action, bool &state ) { return 0; } - -unsigned char Sys_MapCharForKey( int key ) { return (unsigned char)key; } - /* ================ Sys_GetVideoRam diff --git a/neo/sys/linux/input.cpp b/neo/sys/linux/input.cpp deleted file mode 100644 index c3405141..00000000 --- a/neo/sys/linux/input.cpp +++ /dev/null @@ -1,563 +0,0 @@ -/* -=========================================================================== - -Doom 3 GPL Source Code -Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. - -This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). - -Doom 3 Source Code is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Doom 3 Source Code is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Doom 3 Source Code. If not, see . - -In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below. - -If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. - -=========================================================================== -*/ - -#include "sys/platform.h" -#include "framework/KeyInput.h" -#include "sys/posix/posix_public.h" - -#include "sys/linux/local.h" - -idCVar in_mouse( "in_mouse", "1", CVAR_SYSTEM | CVAR_ARCHIVE, "" ); -idCVar in_dgamouse( "in_dgamouse", "1", CVAR_SYSTEM | CVAR_ARCHIVE, "" ); -idCVar in_nograb( "in_nograb", "0", CVAR_SYSTEM | CVAR_NOCHEAT, "" ); - -// have a working xkb extension -static bool have_xkb = false; - -// toggled by grab calls - decides if we ignore MotionNotify events -static bool mouse_active = false; - -// non-DGA pointer-warping mouse input -static int mwx, mwy; -static int mx = 0, my = 0; - -// time mouse was last reset, we ignore the first 50ms of the mouse to allow settling of events -static unsigned int mouse_reset_time = 0; -#define MOUSE_RESET_DELAY 50 - -// backup original values for pointer grab/ungrab -static int mouse_accel_numerator; -static int mouse_accel_denominator; -static int mouse_threshold; - -static byte s_scantokey[128] = { -/* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, -/* 8 */ 0, 27, '1', '2', '3', '4', '5', '6', // 27 - ESC -/* 10 */ '7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 9 - TAB -/* 18 */ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', -/* 20 */ 'o', 'p', '[', ']', K_ENTER, K_CTRL, 'a', 's', -/* 28 */ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', -/* 30 */ '\'', '`', K_SHIFT, '\\', 'z', 'x', 'c', 'v', -/* 38 */ 'b', 'n', 'm', ',', '.', '/', K_SHIFT, K_KP_STAR, -/* 40 */ K_ALT, ' ', K_CAPSLOCK, K_F1, K_F2, K_F3, K_F4, K_F5, -/* 48 */ K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, 0, K_HOME, -/* 50 */ K_UPARROW, K_PGUP, K_KP_MINUS, K_LEFTARROW, K_KP_5, K_RIGHTARROW, K_KP_PLUS, K_END, -/* 58 */ K_DOWNARROW, K_PGDN, K_INS, K_DEL, 0, 0, '\\', K_F11, -/* 60 */ K_F12, K_HOME, K_UPARROW, K_PGUP, K_LEFTARROW, 0, K_RIGHTARROW, K_END, -/* 68 */ K_DOWNARROW, K_PGDN, K_INS, K_DEL, K_ENTER, K_CTRL, K_PAUSE, 0, -/* 70 */ '/', K_ALT, 0, 0, 0, 0, 0, 0, -/* 78 */ 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* -================= -IN_Clear_f -================= -*/ -void IN_Clear_f( const idCmdArgs &args ) { - idKeyInput::ClearStates(); -} - -/* -================= -Sys_InitInput -================= -*/ -void Sys_InitInput(void) { - int major_in_out, minor_in_out, opcode_rtrn, event_rtrn, error_rtrn; - bool ret; - - common->Printf( "\n------- Input Initialization -------\n" ); - assert( dpy ); - cmdSystem->AddCommand( "in_clear", IN_Clear_f, CMD_FL_SYSTEM, "reset the input keys" ); - major_in_out = XkbMajorVersion; - minor_in_out = XkbMinorVersion; - ret = XkbLibraryVersion( &major_in_out, &minor_in_out ); - common->Printf( "XKB extension: compile time 0x%x:0x%x, runtime 0x%x:0x%x: %s\n", XkbMajorVersion, XkbMinorVersion, major_in_out, minor_in_out, ret ? "OK" : "Not compatible" ); - if ( ret ) { - ret = XkbQueryExtension( dpy, &opcode_rtrn, &event_rtrn, &error_rtrn, &major_in_out, &minor_in_out ); - if ( ret ) { - common->Printf( "XKB extension present on server ( 0x%x:0x%x )\n", major_in_out, minor_in_out ); - have_xkb = true; - } else { - common->Printf( "XKB extension not present on server\n" ); - have_xkb = false; - } - } else { - have_xkb = false; - } - common->Printf( "------------------------------------\n" ); -} - -//#define XEVT_DBG -//#define XEVT_DBG2 - -static Cursor Sys_XCreateNullCursor( Display *display, Window root ) { - Pixmap cursormask; - XGCValues xgc; - GC gc; - XColor dummycolour; - Cursor cursor; - - cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/); - xgc.function = GXclear; - gc = XCreateGC(display, cursormask, GCFunction, &xgc); - XFillRectangle(display, cursormask, gc, 0, 0, 1, 1); - dummycolour.pixel = 0; - dummycolour.red = 0; - dummycolour.flags = 04; - cursor = XCreatePixmapCursor(display, cursormask, cursormask, - &dummycolour,&dummycolour, 0,0); - XFreePixmap(display,cursormask); - XFreeGC(display,gc); - return cursor; -} - -static void Sys_XInstallGrabs( void ) { - assert( dpy ); - - XWarpPointer( dpy, None, win, - 0, 0, 0, 0, - glConfig.vidWidth / 2, glConfig.vidHeight / 2 ); - - XSync( dpy, False ); - - XDefineCursor( dpy, win, Sys_XCreateNullCursor( dpy, win ) ); - - XGrabPointer( dpy, win, - False, - MOUSE_MASK, - GrabModeAsync, GrabModeAsync, - win, - None, - CurrentTime ); - - XGetPointerControl( dpy, &mouse_accel_numerator, &mouse_accel_denominator, - &mouse_threshold ); - - XChangePointerControl( dpy, True, True, 1, 1, 0 ); - - XSync( dpy, False ); - - mouse_reset_time = Sys_Milliseconds (); - - if ( in_dgamouse.GetBool() && !dga_found ) { - common->Printf("XF86DGA not available, forcing DGA mouse off\n"); - in_dgamouse.SetBool( false ); - } - - if ( in_dgamouse.GetBool() ) { -#if defined( ID_ENABLE_DGA ) - XF86DGADirectVideo( dpy, DefaultScreen( dpy ), XF86DGADirectMouse ); - XWarpPointer( dpy, None, win, 0, 0, 0, 0, 0, 0 ); -#endif - } else { - mwx = glConfig.vidWidth / 2; - mwy = glConfig.vidHeight / 2; - mx = my = 0; - } - - XGrabKeyboard( dpy, win, - False, - GrabModeAsync, GrabModeAsync, - CurrentTime ); - - XSync( dpy, False ); - - mouse_active = true; -} - -void Sys_XUninstallGrabs(void) { - assert( dpy ); - -#if defined( ID_ENABLE_DGA ) - if ( in_dgamouse.GetBool() ) { - common->DPrintf( "DGA Mouse - Disabling DGA DirectVideo\n" ); - XF86DGADirectVideo( dpy, DefaultScreen( dpy ), 0 ); - } -#endif - - XChangePointerControl( dpy, true, true, mouse_accel_numerator, - mouse_accel_denominator, mouse_threshold ); - - XUngrabPointer( dpy, CurrentTime ); - XUngrabKeyboard( dpy, CurrentTime ); - - XWarpPointer( dpy, None, win, - 0, 0, 0, 0, - glConfig.vidWidth / 2, glConfig.vidHeight / 2); - - XUndefineCursor( dpy, win ); - - mouse_active = false; -} - -void Sys_GrabMouseCursor( bool grabIt ) { - -#if defined( ID_DEDICATED ) - return; -#endif - - if ( !dpy ) { - #ifdef XEVT_DBG - common->DPrintf("Sys_GrabMouseCursor: !dpy\n"); - #endif - return; - } - - if ( glConfig.isFullscreen ) { - if ( !grabIt ) { - return; // never ungrab while fullscreen - } - if ( in_nograb.GetBool() ) { - common->DPrintf("forcing in_nograb 0 while running fullscreen\n"); - in_nograb.SetBool( false ); - } - } - - if ( in_nograb.GetBool() ) { - if ( in_dgamouse.GetBool() ) { - common->DPrintf("in_nograb 1, forcing forcing DGA mouse off\n"); - in_dgamouse.SetBool( false ); - } - if (grabIt) { - mouse_active = true; - } else { - mouse_active = false; - } - return; - } - - if ( grabIt && !mouse_active ) { - Sys_XInstallGrabs(); - } else if ( !grabIt && mouse_active ) { - Sys_XUninstallGrabs(); - } -} - -/** - * XPending() actually performs a blocking read - * if no events available. From Fakk2, by way of - * Heretic2, by way of SDL, original idea GGI project. - * The benefit of this approach over the quite - * badly behaved XAutoRepeatOn/Off is that you get - * focus handling for free, which is a major win - * with debug and windowed mode. It rests on the - * assumption that the X server will use the - * same timestamp on press/release event pairs - * for key repeats. - */ -static bool Sys_XPendingInput( void ) { - // Flush the display connection - // and look to see if events are queued - XFlush( dpy ); - if ( XEventsQueued( dpy, QueuedAlready) ) { - return true; - } - - // More drastic measures are required -- see if X is ready to talk - static struct timeval zero_time; - int x11_fd; - fd_set fdset; - - x11_fd = ConnectionNumber( dpy ); - FD_ZERO( &fdset ); - FD_SET( x11_fd, &fdset ); - if ( select( x11_fd+1, &fdset, NULL, NULL, &zero_time ) == 1 ) { - return XPending( dpy ); - } - - // Oh well, nothing is ready .. - return false; -} - -/** - * Intercept a KeyRelease-KeyPress sequence and ignore - */ -static bool Sys_XRepeatPress( XEvent *event ) { - XEvent peekevent; - bool repeated = false; - int lookupRet; - char buf[5]; - KeySym keysym; - - if ( Sys_XPendingInput() ) { - XPeekEvent( dpy, &peekevent ); - - if ((peekevent.type == KeyPress) && - (peekevent.xkey.keycode == event->xkey.keycode) && - (peekevent.xkey.time == event->xkey.time)) { - repeated = true; - XNextEvent( dpy, &peekevent ); - // emit an SE_CHAR for the repeat - lookupRet = XLookupString( (XKeyEvent*)&peekevent, buf, sizeof(buf), &keysym, NULL ); - if (lookupRet > 0) { - Posix_QueEvent( SE_CHAR, buf[ 0 ], 0, 0, NULL); - } else { - // shouldn't we be doing a release/press in this order rather? - // ( doesn't work .. but that's what I would have expected to do though ) - Posix_QueEvent( SE_KEY, s_scantokey[peekevent.xkey.keycode], true, 0, NULL); - Posix_QueEvent( SE_KEY, s_scantokey[peekevent.xkey.keycode], false, 0, NULL); - } - } - } - - return repeated; -} - -/* -========================== -Posix_PollInput -========================== -*/ -void Posix_PollInput() { - static char buf[16]; - static XEvent event; - static XKeyEvent *key_event = (XKeyEvent*)&event; - int lookupRet; - int b, dx, dy; - KeySym keysym; - - if ( !dpy ) { - return; - } - - // NOTE: Sys_GetEvent only calls when there are no events left - // but here we pump all X events that have accumulated - // pump one by one? or use threaded input? - while ( XPending( dpy ) ) { - XNextEvent( dpy, &event ); - switch (event.type) { - case KeyPress: - #ifdef XEVT_DBG - if (key_event->keycode > 0x7F) - common->DPrintf("WARNING: KeyPress keycode > 0x7F"); - #endif - key_event->keycode &= 0x7F; - #ifdef XEVT_DBG2 - printf("SE_KEY press %d\n", key_event->keycode); - #endif - Posix_QueEvent( SE_KEY, s_scantokey[key_event->keycode], true, 0, NULL); - lookupRet = XLookupString(key_event, buf, sizeof(buf), &keysym, NULL); - if (lookupRet > 0) { - char s = buf[0]; - #ifdef XEVT_DBG - if (buf[1]!=0) - common->DPrintf("WARNING: got XLookupString buffer '%s' (%d)\n", buf, strlen(buf)); - #endif - #ifdef XEVT_DBG2 - printf("SE_CHAR %s\n", buf); - #endif - Posix_QueEvent( SE_CHAR, s, 0, 0, NULL); - } - if (!Posix_AddKeyboardPollEvent( s_scantokey[key_event->keycode], true )) - return; - break; - - case KeyRelease: - if (Sys_XRepeatPress(&event)) { - #ifdef XEVT_DBG2 - printf("RepeatPress\n"); - #endif - continue; - } - #ifdef XEVT_DBG - if (key_event->keycode > 0x7F) - common->DPrintf("WARNING: KeyRelease keycode > 0x7F"); - #endif - key_event->keycode &= 0x7F; - #ifdef XEVT_DBG2 - printf("SE_KEY release %d\n", key_event->keycode); - #endif - Posix_QueEvent( SE_KEY, s_scantokey[key_event->keycode], false, 0, NULL); - if (!Posix_AddKeyboardPollEvent( s_scantokey[key_event->keycode], false )) - return; - break; - - case ButtonPress: - if (event.xbutton.button == 4) { - Posix_QueEvent( SE_KEY, K_MWHEELUP, true, 0, NULL); - if (!Posix_AddMousePollEvent( M_DELTAZ, 1 )) - return; - } else if (event.xbutton.button == 5) { - Posix_QueEvent( SE_KEY, K_MWHEELDOWN, true, 0, NULL); - if (!Posix_AddMousePollEvent( M_DELTAZ, -1 )) - return; - } else { - b = -1; - if (event.xbutton.button == 1) { - b = 0; // K_MOUSE1 - } else if (event.xbutton.button == 2) { - b = 2; // K_MOUSE3 - } else if (event.xbutton.button == 3) { - b = 1; // K_MOUSE2 - } else if (event.xbutton.button == 6) { - b = 3; // K_MOUSE4 - } else if (event.xbutton.button == 7) { - b = 4; // K_MOUSE5 - } - if (b == -1 || b > 4) { - common->DPrintf("X ButtonPress %d not supported\n", event.xbutton.button); - } else { - Posix_QueEvent( SE_KEY, K_MOUSE1 + b, true, 0, NULL); - if (!Posix_AddMousePollEvent( M_ACTION1 + b, true )) - return; - } - } - break; - - case ButtonRelease: - if (event.xbutton.button == 4) { - Posix_QueEvent( SE_KEY, K_MWHEELUP, false, 0, NULL); - } else if (event.xbutton.button == 5) { - Posix_QueEvent( SE_KEY, K_MWHEELDOWN, false, 0, NULL); - } else { - b = -1; - if (event.xbutton.button == 1) { - b = 0; - } else if (event.xbutton.button == 2) { - b = 2; - } else if (event.xbutton.button == 3) { - b = 1; - } else if (event.xbutton.button == 6) { - b = 3; // K_MOUSE4 - } else if (event.xbutton.button == 7) { - b = 4; // K_MOUSE5 - } - if (b == -1 || b > 4) { - common->DPrintf("X ButtonRelease %d not supported\n", event.xbutton.button); - } else { - Posix_QueEvent( SE_KEY, K_MOUSE1 + b, false, 0, NULL); - if (!Posix_AddMousePollEvent( M_ACTION1 + b, false )) - return; - } - } - break; - - case MotionNotify: - if (!mouse_active) - break; - if (in_dgamouse.GetBool()) { - dx = event.xmotion.x_root; - dy = event.xmotion.y_root; - - Posix_QueEvent( SE_MOUSE, dx, dy, 0, NULL); - - // if we overflow here, we'll get a warning, but the delta will be completely processed anyway - Posix_AddMousePollEvent( M_DELTAX, dx ); - if (!Posix_AddMousePollEvent( M_DELTAY, dy )) - return; - } else { - // if it's a center motion, we've just returned from our warp - // FIXME: we generate mouse delta on wrap return, but that lags us quite a bit from the initial event.. - if (event.xmotion.x == glConfig.vidWidth / 2 && - event.xmotion.y == glConfig.vidHeight / 2) { - mwx = glConfig.vidWidth / 2; - mwy = glConfig.vidHeight / 2; - - Posix_QueEvent( SE_MOUSE, mx, my, 0, NULL); - - Posix_AddMousePollEvent( M_DELTAX, mx ); - if (!Posix_AddMousePollEvent( M_DELTAY, my )) - return; - mx = my = 0; - break; - } - - dx = ((int) event.xmotion.x - mwx); - dy = ((int) event.xmotion.y - mwy); - mx += dx; - my += dy; - - mwx = event.xmotion.x; - mwy = event.xmotion.y; - XWarpPointer(dpy,None,win,0,0,0,0, (glConfig.vidWidth/2),(glConfig.vidHeight/2)); - } - break; - } - } -} - -/* -================= -Sys_ShutdownInput -================= -*/ -void Sys_ShutdownInput( void ) { } - -/* -=============== -Sys_MapCharForKey -=============== -*/ -unsigned char Sys_MapCharForKey( int _key ) { - int key; // scan key ( != doom key ) - XkbStateRec kbd_state; - XEvent event; - KeySym keysym; - int lookupRet; - char buf[5]; - - if ( !have_xkb || !dpy ) { - return (unsigned char)_key; - } - - // query the current keyboard group, must be passed as bit 13-14 in the constructed XEvent - // see X Keyboard Extension library specifications - XkbGetState( dpy, XkbUseCoreKbd, &kbd_state ); - - // lookup scancode from doom key code. unique hits - for ( key = 0; key < 128; key++ ) { - if ( _key == s_scantokey[ key ] ) { - break; - } - } - if ( key == 128 ) { - // it happens. these, we can't convert - common->DPrintf( "Sys_MapCharForKey: doom key %d -> keycode failed\n", _key ); - return (unsigned char)_key; - } - - memset( &event, 0, sizeof( XEvent ) ); - event.xkey.type = KeyPress; - event.xkey.display = dpy; - event.xkey.time = CurrentTime; - event.xkey.keycode = key; - event.xkey.state = kbd_state.group << 13; - - lookupRet = XLookupString( (XKeyEvent *)&event, buf, sizeof( buf ), &keysym, NULL ); - if ( lookupRet <= 0 ) { - Sys_Printf( "Sys_MapCharForKey: XLookupString key 0x%x failed\n", key ); - return (unsigned char)_key; - } - if ( lookupRet > 1 ) { - // only ever expecting 1 char.. - Sys_Printf( "Sys_MapCharForKey: XLookupString returned '%s'\n", buf ); - } - return buf[ 0 ]; -} diff --git a/neo/sys/linux/main.cpp b/neo/sys/linux/main.cpp index 7f5cb5d4..26e369ad 100644 --- a/neo/sys/linux/main.cpp +++ b/neo/sys/linux/main.cpp @@ -49,15 +49,6 @@ If you have questions concerning this license or the applicable additional terms static idStr basepath; static idStr savepath; -/* -=========== -Sys_InitScanTable -=========== -*/ -void Sys_InitScanTable( void ) { - common->DPrintf( "TODO: Sys_InitScanTable\n" ); -} - /* ============== Sys_DefaultSavePath @@ -128,15 +119,6 @@ const char *Sys_DefaultBasePath(void) { return LINUX_DEFAULT_PATH; } -/* -=============== -Sys_GetConsoleKey -=============== -*/ -unsigned char Sys_GetConsoleKey( bool shifted ) { - return shifted ? '~' : '`'; -} - /* =============== Sys_Shutdown diff --git a/neo/sys/posix/posix_main.cpp b/neo/sys/posix/posix_main.cpp index 77c515d2..bdbf0234 100644 --- a/neo/sys/posix/posix_main.cpp +++ b/neo/sys/posix/posix_main.cpp @@ -223,6 +223,7 @@ int Sys_ListFiles( const char *directory, const char *extension, idStrList &list return list.Num(); } +#ifdef MACOS_X /* ============================================================================ EVENT LOOP @@ -298,6 +299,7 @@ Sys_ClearEvents void Sys_ClearEvents( void ) { eventHead = eventTail = 0; } +#endif /* ================ @@ -912,6 +914,7 @@ char *Sys_ConsoleInput( void ) { return NULL; } +#ifdef MACOS_X /* called during frame loops, pacifier updates etc. this is only for console input polling and misc mouse grab tasks @@ -929,6 +932,7 @@ void Sys_GenerateEvents( void ) { Posix_QueEvent( SE_CONSOLE, 0, 0, len, b ); } } +#endif /* =============== diff --git a/neo/sys/scons/SConscript.core b/neo/sys/scons/SConscript.core index 1760fb63..4ce95c84 100644 --- a/neo/sys/scons/SConscript.core +++ b/neo/sys/scons/SConscript.core @@ -204,8 +204,7 @@ sys_string = ' \ if ( local_dedicated == 0 ): sys_string += ' \ glimp.cpp \ - posix/posix_input.cpp \ - linux/input.cpp' + events.cpp' else: sys_string += ' \ stub/stub_gl.cpp \