// // ID Engine // ID_IN.c - Input Manager // v1.0d1 // By Jason Blochowiak // // // This module handles dealing with the various input devices // // Depends on: Memory Mgr (for demo recording), Sound Mgr (for timing stuff), // User Mgr (for command line parms) // // Globals: // LastScan - The keyboard scan code of the last key pressed // LastASCII - The ASCII value of the last key pressed // DEBUG - there are more globals // #include "wl_def.h" /* ============================================================================= GLOBAL VARIABLES ============================================================================= */ // // configuration variables // boolean MousePresent; boolean forcegrabmouse; // Global variables volatile boolean Keyboard[SDLK_LAST]; volatile boolean Paused; volatile char LastASCII; volatile ScanCode LastScan; //KeyboardDef KbdDefs = {0x1d,0x38,0x47,0x48,0x49,0x4b,0x4d,0x4f,0x50,0x51}; static KeyboardDef KbdDefs = { sc_Control, // button0 sc_Alt, // button1 sc_Home, // upleft sc_UpArrow, // up sc_PgUp, // upright sc_LeftArrow, // left sc_RightArrow, // right sc_End, // downleft sc_DownArrow, // down sc_PgDn // downright }; static SDL_Joystick *Joystick; int JoyNumButtons; static int JoyNumHats; static bool GrabInput = false; static bool NeedRestore = false; /* ============================================================================= LOCAL VARIABLES ============================================================================= */ byte ASCIINames[] = // Unshifted ASCII for scan codes // TODO: keypad { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,8 ,9 ,0 ,0 ,0 ,13 ,0 ,0 , // 0 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,27 ,0 ,0 ,0 , // 1 ' ',0 ,0 ,0 ,0 ,0 ,0 ,39 ,0 ,0 ,'*','+',',','-','.','/', // 2 '0','1','2','3','4','5','6','7','8','9',0 ,';',0 ,'=',0 ,0 , // 3 '`','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o', // 4 'p','q','r','s','t','u','v','w','x','y','z','[',92 ,']',0 ,0 , // 5 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 6 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 // 7 }; byte ShiftNames[] = // Shifted ASCII for scan codes { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,8 ,9 ,0 ,0 ,0 ,13 ,0 ,0 , // 0 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,27 ,0 ,0 ,0 , // 1 ' ',0 ,0 ,0 ,0 ,0 ,0 ,34 ,0 ,0 ,'*','+','<','_','>','?', // 2 ')','!','@','#','$','%','^','&','*','(',0 ,':',0 ,'+',0 ,0 , // 3 '~','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O', // 4 'P','Q','R','S','T','U','V','W','X','Y','Z','{','|','}',0 ,0 , // 5 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 6 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 // 7 }; byte SpecialNames[] = // ASCII for 0xe0 prefixed codes { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 0 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,13 ,0 ,0 ,0 , // 1 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 2 0 ,0 ,0 ,0 ,0 ,'/',0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 3 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 4 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 5 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , // 6 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 // 7 }; static boolean IN_Started; static Direction DirTable[] = // Quick lookup for total direction { dir_NorthWest, dir_North, dir_NorthEast, dir_West, dir_None, dir_East, dir_SouthWest, dir_South, dir_SouthEast }; /////////////////////////////////////////////////////////////////////////// // // INL_GetMouseButtons() - Gets the status of the mouse buttons from the // mouse driver // /////////////////////////////////////////////////////////////////////////// static int INL_GetMouseButtons(void) { int buttons = SDL_GetMouseState(NULL, NULL); int middlePressed = buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE); int rightPressed = buttons & SDL_BUTTON(SDL_BUTTON_RIGHT); buttons &= ~(SDL_BUTTON(SDL_BUTTON_MIDDLE) | SDL_BUTTON(SDL_BUTTON_RIGHT)); if(middlePressed) buttons |= 1 << 2; if(rightPressed) buttons |= 1 << 1; return buttons; } /////////////////////////////////////////////////////////////////////////// // // IN_GetJoyDelta() - Returns the relative movement of the specified // joystick (from +/-127) // /////////////////////////////////////////////////////////////////////////// void IN_GetJoyDelta(int *dx,int *dy) { if(!Joystick) { *dx = *dy = 0; return; } SDL_JoystickUpdate(); #ifdef _arch_dreamcast int x = 0; int y = 0; #else int x = SDL_JoystickGetAxis(Joystick, 0) >> 8; int y = SDL_JoystickGetAxis(Joystick, 1) >> 8; #endif if(param_joystickhat != -1) { uint8_t hatState = SDL_JoystickGetHat(Joystick, param_joystickhat); if(hatState & SDL_HAT_RIGHT) x += 127; else if(hatState & SDL_HAT_LEFT) x -= 127; if(hatState & SDL_HAT_DOWN) y += 127; else if(hatState & SDL_HAT_UP) y -= 127; if(x < -128) x = -128; else if(x > 127) x = 127; if(y < -128) y = -128; else if(y > 127) y = 127; } *dx = x; *dy = y; } /////////////////////////////////////////////////////////////////////////// // // IN_GetJoyFineDelta() - Returns the relative movement of the specified // joystick without dividing the results by 256 (from +/-127) // /////////////////////////////////////////////////////////////////////////// void IN_GetJoyFineDelta(int *dx, int *dy) { if(!Joystick) { *dx = 0; *dy = 0; return; } SDL_JoystickUpdate(); int x = SDL_JoystickGetAxis(Joystick, 0); int y = SDL_JoystickGetAxis(Joystick, 1); if(x < -128) x = -128; else if(x > 127) x = 127; if(y < -128) y = -128; else if(y > 127) y = 127; *dx = x; *dy = y; } /* =================== = = IN_JoyButtons = =================== */ int IN_JoyButtons() { if(!Joystick) return 0; SDL_JoystickUpdate(); int res = 0; for(int i = 0; i < JoyNumButtons && i < 32; i++) res |= SDL_JoystickGetButton(Joystick, i) << i; return res; } boolean IN_JoyPresent() { return Joystick != NULL; } static void processEvent(SDL_Event *event) { switch (event->type) { // exit if the window is closed case SDL_QUIT: Quit(NULL); // check for keypresses case SDL_KEYDOWN: { if(event->key.keysym.sym==SDLK_SCROLLOCK || event->key.keysym.sym==SDLK_F12) { GrabInput = !GrabInput; SDL_WM_GrabInput(GrabInput ? SDL_GRAB_ON : SDL_GRAB_OFF); return; } LastScan = event->key.keysym.sym; SDLMod mod = SDL_GetModState(); if(Keyboard[sc_Alt]) { if(LastScan==SDLK_F4) Quit(NULL); } if(LastScan == SDLK_KP_ENTER) LastScan = SDLK_RETURN; else if(LastScan == SDLK_RSHIFT) LastScan = SDLK_LSHIFT; else if(LastScan == SDLK_RALT) LastScan = SDLK_LALT; else if(LastScan == SDLK_RCTRL) LastScan = SDLK_LCTRL; else { if((mod & KMOD_NUM) == 0) { switch(LastScan) { case SDLK_KP2: LastScan = SDLK_DOWN; break; case SDLK_KP4: LastScan = SDLK_LEFT; break; case SDLK_KP6: LastScan = SDLK_RIGHT; break; case SDLK_KP8: LastScan = SDLK_UP; break; } } } int sym = LastScan; if(sym >= 'a' && sym <= 'z') sym -= 32; // convert to uppercase if(mod & (KMOD_SHIFT | KMOD_CAPS)) { if(sym < lengthof(ShiftNames) && ShiftNames[sym]) LastASCII = ShiftNames[sym]; } else { if(sym < lengthof(ASCIINames) && ASCIINames[sym]) LastASCII = ASCIINames[sym]; } if(LastScankey.keysym.sym; if(key == SDLK_KP_ENTER) key = SDLK_RETURN; else if(key == SDLK_RSHIFT) key = SDLK_LSHIFT; else if(key == SDLK_RALT) key = SDLK_LALT; else if(key == SDLK_RCTRL) key = SDLK_LCTRL; else { if((SDL_GetModState() & KMOD_NUM) == 0) { switch(key) { case SDLK_KP2: key = SDLK_DOWN; break; case SDLK_KP4: key = SDLK_LEFT; break; case SDLK_KP6: key = SDLK_RIGHT; break; case SDLK_KP8: key = SDLK_UP; break; } } } if(keyactive.state & SDL_APPACTIVE) != 0) { if(event->active.gain) { if(NeedRestore) { FreeLatchMem(); LoadLatchMem(); } NeedRestore = false; } else NeedRestore = true; } } #if defined(GP2X) case SDL_JOYBUTTONDOWN: GP2X_ButtonDown(event->jbutton.button); break; case SDL_JOYBUTTONUP: GP2X_ButtonUp(event->jbutton.button); break; #endif } } void IN_WaitAndProcessEvents() { SDL_Event event; if(!SDL_WaitEvent(&event)) return; do { processEvent(&event); } while(SDL_PollEvent(&event)); } void IN_ProcessEvents() { SDL_Event event; while (SDL_PollEvent(&event)) { processEvent(&event); } } /////////////////////////////////////////////////////////////////////////// // // IN_Startup() - Starts up the Input Mgr // /////////////////////////////////////////////////////////////////////////// void IN_Startup(void) { if (IN_Started) return; IN_ClearKeysDown(); if(param_joystickindex >= 0 && param_joystickindex < SDL_NumJoysticks()) { Joystick = SDL_JoystickOpen(param_joystickindex); if(Joystick) { JoyNumButtons = SDL_JoystickNumButtons(Joystick); if(JoyNumButtons > 32) JoyNumButtons = 32; // only up to 32 buttons are supported JoyNumHats = SDL_JoystickNumHats(Joystick); if(param_joystickhat < -1 || param_joystickhat >= JoyNumHats) Quit("The joystickhat param must be between 0 and %i!", JoyNumHats - 1); } } SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); if(fullscreen || forcegrabmouse) { GrabInput = true; SDL_WM_GrabInput(SDL_GRAB_ON); } // I didn't find a way to ask libSDL whether a mouse is present, yet... #if defined(GP2X) MousePresent = false; #elif defined(_arch_dreamcast) MousePresent = DC_MousePresent(); #else MousePresent = true; #endif IN_Started = true; } /////////////////////////////////////////////////////////////////////////// // // IN_Shutdown() - Shuts down the Input Mgr // /////////////////////////////////////////////////////////////////////////// void IN_Shutdown(void) { if (!IN_Started) return; if(Joystick) SDL_JoystickClose(Joystick); IN_Started = false; } /////////////////////////////////////////////////////////////////////////// // // IN_ClearKeysDown() - Clears the keyboard array // /////////////////////////////////////////////////////////////////////////// void IN_ClearKeysDown(void) { LastScan = sc_None; LastASCII = key_None; memset ((void *) Keyboard,0,sizeof(Keyboard)); } /////////////////////////////////////////////////////////////////////////// // // IN_ReadControl() - Reads the device associated with the specified // player and fills in the control info struct // /////////////////////////////////////////////////////////////////////////// void IN_ReadControl(int player,ControlInfo *info) { word buttons; int dx,dy; Motion mx,my; dx = dy = 0; mx = my = motion_None; buttons = 0; IN_ProcessEvents(); if (Keyboard[KbdDefs.upleft]) mx = motion_Left,my = motion_Up; else if (Keyboard[KbdDefs.upright]) mx = motion_Right,my = motion_Up; else if (Keyboard[KbdDefs.downleft]) mx = motion_Left,my = motion_Down; else if (Keyboard[KbdDefs.downright]) mx = motion_Right,my = motion_Down; if (Keyboard[KbdDefs.up]) my = motion_Up; else if (Keyboard[KbdDefs.down]) my = motion_Down; if (Keyboard[KbdDefs.left]) mx = motion_Left; else if (Keyboard[KbdDefs.right]) mx = motion_Right; if (Keyboard[KbdDefs.button0]) buttons += 1 << 0; if (Keyboard[KbdDefs.button1]) buttons += 1 << 1; dx = mx * 127; dy = my * 127; info->x = dx; info->xaxis = mx; info->y = dy; info->yaxis = my; info->button0 = (buttons & (1 << 0)) != 0; info->button1 = (buttons & (1 << 1)) != 0; info->button2 = (buttons & (1 << 2)) != 0; info->button3 = (buttons & (1 << 3)) != 0; info->dir = DirTable[((my + 1) * 3) + (mx + 1)]; } /////////////////////////////////////////////////////////////////////////// // // IN_WaitForKey() - Waits for a scan code, then clears LastScan and // returns the scan code // /////////////////////////////////////////////////////////////////////////// ScanCode IN_WaitForKey(void) { ScanCode result; while ((result = LastScan)==0) IN_WaitAndProcessEvents(); LastScan = 0; return(result); } /////////////////////////////////////////////////////////////////////////// // // IN_WaitForASCII() - Waits for an ASCII char, then clears LastASCII and // returns the ASCII value // /////////////////////////////////////////////////////////////////////////// char IN_WaitForASCII(void) { char result; while ((result = LastASCII)==0) IN_WaitAndProcessEvents(); LastASCII = '\0'; return(result); } /////////////////////////////////////////////////////////////////////////// // // IN_Ack() - waits for a button or key press. If a button is down, upon // calling, it must be released for it to be recognized // /////////////////////////////////////////////////////////////////////////// boolean btnstate[NUMBUTTONS]; void IN_StartAck(void) { IN_ProcessEvents(); // // get initial state of everything // IN_ClearKeysDown(); memset(btnstate, 0, sizeof(btnstate)); int buttons = IN_JoyButtons() << 4; if(MousePresent) buttons |= IN_MouseButtons(); for(int i = 0; i < NUMBUTTONS; i++, buttons >>= 1) if(buttons & 1) btnstate[i] = true; } boolean IN_CheckAck (void) { IN_ProcessEvents(); // // see if something has been pressed // if(LastScan) return true; int buttons = IN_JoyButtons() << 4; if(MousePresent) buttons |= IN_MouseButtons(); for(int i = 0; i < NUMBUTTONS; i++, buttons >>= 1) { if(buttons & 1) { if(!btnstate[i]) { // Wait until button has been released do { IN_WaitAndProcessEvents(); buttons = IN_JoyButtons() << 4; if(MousePresent) buttons |= IN_MouseButtons(); } while(buttons & (1 << i)); return true; } } else btnstate[i] = false; } return false; } void IN_Ack (void) { IN_StartAck (); do { IN_WaitAndProcessEvents(); } while(!IN_CheckAck ()); } /////////////////////////////////////////////////////////////////////////// // // IN_UserInput() - Waits for the specified delay time (in ticks) or the // user pressing a key or a mouse button. If the clear flag is set, it // then either clears the key or waits for the user to let the mouse // button up. // /////////////////////////////////////////////////////////////////////////// boolean IN_UserInput(longword delay) { longword lasttime; lasttime = GetTimeCount(); IN_StartAck (); do { IN_ProcessEvents(); if (IN_CheckAck()) return true; SDL_Delay(5); } while (GetTimeCount() - lasttime < delay); return(false); } //=========================================================================== /* =================== = = IN_MouseButtons = =================== */ int IN_MouseButtons (void) { if (MousePresent) return INL_GetMouseButtons(); else return 0; } bool IN_IsInputGrabbed() { return GrabInput; } void IN_CenterMouse() { SDL_WarpMouse(screenWidth / 2, screenHeight / 2); }