ref: 15cbe82d5d62725b6bb2b936be21fad79bb46ce1
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);
}