ref: 9c3d852db282e59996933316e65141504a756edd
dir: /src/i_input.c/
// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program 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 2 // of the License, or (at your option) any later version. // // This program 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. // // DESCRIPTION: // SDL implementation of system-specific input interface. // #include "SDL.h" #include "doomkeys.h" #include "doomtype.h" #include "d_event.h" #include "i_input.h" #include "m_argv.h" #include "m_config.h" static const int scancode_translate_table[] = SCANCODE_TO_KEYS_ARRAY; // Lookup table for mapping ASCII characters to their equivalent when // shift is pressed on an American layout keyboard: static const char shiftxform[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, ' ', '!', '"', '#', '$', '%', '&', '"', // shift-' '(', ')', '*', '+', '<', // shift-, '_', // shift-- '>', // shift-. '?', // shift-/ ')', // shift-0 '!', // shift-1 '@', // shift-2 '#', // shift-3 '$', // shift-4 '%', // shift-5 '^', // shift-6 '&', // shift-7 '*', // shift-8 '(', // shift-9 ':', ':', // shift-; '<', '+', // shift-= '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', // shift-[ '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK ']', // shift-] '"', '_', '\'', // shift-` 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', 127 }; // Bit mask of mouse button state. static unsigned int mouse_button_state = 0; // Disallow mouse and joystick movement to cause forward/backward // motion. Specified with the '-novert' command line parameter. // This is an int to allow saving to config file int novert = 0; // If true, keyboard mapping is ignored, like in Vanilla Doom. // The sensible thing to do is to disable this if you have a non-US // keyboard. int vanilla_keyboard_mapping = true; // Mouse acceleration // // This emulates some of the behavior of DOS mouse drivers by increasing // the speed when the mouse is moved fast. // // The mouse input values are input directly to the game, but when // the values exceed the value of mouse_threshold, they are multiplied // by mouse_acceleration to increase the speed. float mouse_acceleration = 2.0; int mouse_threshold = 10; // // Translates the SDL key // static int TranslateKey(SDL_Keysym *sym) { int scancode = sym->scancode; switch (scancode) { case SDL_SCANCODE_LCTRL: case SDL_SCANCODE_RCTRL: return KEY_RCTRL; case SDL_SCANCODE_LSHIFT: case SDL_SCANCODE_RSHIFT: return KEY_RSHIFT; case SDL_SCANCODE_LALT: return KEY_LALT; case SDL_SCANCODE_RALT: return KEY_RALT; default: if (scancode >= 0 && scancode < arrlen(scancode_translate_table)) { return scancode_translate_table[scancode]; } else { return 0; } } } // Get the equivalent ASCII (Unicode?) character for a keypress. static int GetTypedChar(SDL_Event *event) { // If we're strictly emulating Vanilla, we should always act like // we're using a US layout keyboard (in ev_keydown, data1=data2). // Otherwise we should use the native key mapping. if (vanilla_keyboard_mapping) { int result = TranslateKey(&event->key.keysym); // If shift is held down, apply the original uppercase // translation table used under DOS. if ((SDL_GetModState() & KMOD_SHIFT) != 0 && result >= 0 && result < arrlen(shiftxform)) { result = shiftxform[result]; } return result; } else { int unicode = event->key.keysym.sym; if (unicode < 128) { return unicode; } else { return 0; } } } void I_HandleKeyboardEvent(SDL_Event *sdlevent) { event_t event; switch (sdlevent->type) { case SDL_KEYDOWN: // data1 has the key pressed, data2 has the character // (shift-translated, etc) event.type = ev_keydown; event.data1 = TranslateKey(&sdlevent->key.keysym); event.data2 = GetTypedChar(sdlevent); if (event.data1 != 0) { D_PostEvent(&event); } break; case SDL_KEYUP: event.type = ev_keyup; event.data1 = TranslateKey(&sdlevent->key.keysym); // data2 is just initialized to zero for ev_keyup. // For ev_keydown it's the shifted Unicode character // that was typed, but if something wants to detect // key releases it should do so based on data1 // (key ID), not the printable char. event.data2 = 0; if (event.data1 != 0) { D_PostEvent(&event); } break; default: break; } } static void UpdateMouseButtonState(unsigned int button, boolean on) { event_t event; if (button < SDL_BUTTON_LEFT || button > MAX_MOUSE_BUTTONS) { return; } // Note: button "0" is left, button "1" is right, // button "2" is middle for Doom. This is different // to how SDL sees things. switch (button) { case SDL_BUTTON_LEFT: button = 0; break; case SDL_BUTTON_RIGHT: button = 1; break; case SDL_BUTTON_MIDDLE: button = 2; break; default: // SDL buttons are indexed from 1. --button; break; } // Turn bit representing this button on or off. if (on) { mouse_button_state |= (1 << button); } else { mouse_button_state &= ~(1 << button); } // Post an event with the new button state. event.type = ev_mouse; event.data1 = mouse_button_state; event.data2 = event.data3 = 0; D_PostEvent(&event); } void I_HandleMouseEvent(SDL_Event *sdlevent) { switch (sdlevent->type) { case SDL_MOUSEBUTTONDOWN: UpdateMouseButtonState(sdlevent->button.button, true); break; case SDL_MOUSEBUTTONUP: UpdateMouseButtonState(sdlevent->button.button, false); break; default: break; } } static int AccelerateMouse(int val) { if (val < 0) return -AccelerateMouse(-val); if (val > mouse_threshold) { return (int)((val - mouse_threshold) * mouse_acceleration + mouse_threshold); } else { return val; } } // // Read the change in mouse state to generate mouse motion events // // This is to combine all mouse movement for a tic into one mouse // motion event. void I_ReadMouse(void) { int x, y; event_t ev; SDL_GetRelativeMouseState(&x, &y); if (x != 0 || y != 0) { ev.type = ev_mouse; ev.data1 = mouse_button_state; ev.data2 = AccelerateMouse(x); if (!novert) { ev.data3 = -AccelerateMouse(y); } else { ev.data3 = 0; } D_PostEvent(&ev); } } void I_InputCheckCommandLine(void) { //! // @category video // // Disable vertical mouse movement. // if (M_CheckParm("-novert")) { novert = true; } //! // @category video // // Enable vertical mouse movement. // if (M_CheckParm("-nonovert")) { novert = false; } } // Bind all variables controlling input options. void I_BindInputVariables(void) { M_BindFloatVariable("mouse_acceleration", &mouse_acceleration); M_BindIntVariable("mouse_threshold", &mouse_threshold); M_BindIntVariable("vanilla_keyboard_mapping", &vanilla_keyboard_mapping); M_BindIntVariable("novert", &novert); }