#include "global.h" /* This handler is used for odd cases where we don't use SDL for input. */ #include "InputHandler_Linux_tty.h" #include "InputHandler_Linux_tty_keys.h" #include "RageUtil.h" #include "RageLog.h" #include "RageException.h" #include "archutils/Unix/SignalHandler.h" #include "SDL_utils.h" #include #include #include #include #include #include /* Map from keys (ignoring shifts) to SDLK values. */ static int keys[NR_KEYS]; static termios saved_kbd_termios; static int saved_kbd_mode; /* This is normally a singleton. Keep track of it, so we can access it * from our signal handler. */ static InputHandler_Linux_tty *handler = NULL; void InputHandler_Linux_tty::OnCrash(int signo) { /* Make sure we delete the input handler if we crash, so we don't leave * the terminal in raw mode. */ delete handler; handler = NULL; } InputHandler_Linux_tty::InputHandler_Linux_tty() { fd = open("/dev/tty", O_RDWR); if(fd == -1) RageException::Throw("open(\"/dev/tty\"): %s", strerror(errno)); if (tcgetattr(fd, &saved_kbd_termios) == -1) RageException::Throw("tcgetattr(%i) failed: %s", fd, strerror(errno)); termios keyboard_termios = saved_kbd_termios; keyboard_termios.c_lflag &= ~(ICANON | ECHO | ISIG); keyboard_termios.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON); keyboard_termios.c_cc[VMIN] = 0; keyboard_termios.c_cc[VTIME] = 0; if (tcsetattr(fd, TCSAFLUSH, &keyboard_termios) == -1) RageException::Throw("tcsetattr(%i, TCSAFLUSH) failed: %s", fd, strerror(errno)); if (ioctl(fd, KDGKBMODE, &saved_kbd_mode) == -1) RageException::Throw("ioctl(%i, KDGKBMODE) failed: %s", fd, strerror(errno)); if (ioctl(fd, KDSKBMODE, K_MEDIUMRAW) == -1) RageException::Throw("ioctl(%i, KDSKBMODE, K_MEDIUMRAW) failed: %s", fd, strerror(errno)); if (ioctl(fd, KDSETMODE, KD_GRAPHICS) == -1 ) RageException::Throw("ioctl(%i, KDSETMODE, KD_GRAPHICS) failed: %s", fd, strerror(errno)); memset(keys, 0, sizeof(keys)); for (int i = 0; i < NR_KEYS; ++i) { switch(i) { case SCANCODE_PRINTSCREEN: keys[i] = SDLK_PRINT; continue; case SCANCODE_BREAK: keys[i] = SDLK_BREAK; continue; case SCANCODE_BREAK_ALTERNATIVE: keys[i] = SDLK_PAUSE; continue; case SCANCODE_LEFTSHIFT: keys[i] = SDLK_LSHIFT; continue; case SCANCODE_RIGHTSHIFT: keys[i] = SDLK_RSHIFT; continue; case SCANCODE_LEFTCONTROL: keys[i] = SDLK_LCTRL; continue; case SCANCODE_RIGHTCONTROL: keys[i] = SDLK_RCTRL; continue; case SCANCODE_RIGHTWIN: keys[i] = SDLK_RSUPER; continue; case SCANCODE_LEFTWIN: keys[i] = SDLK_LSUPER; continue; case 127: keys[i] = SDLK_MENU; continue; } kbentry entry; entry.kb_table = 0; entry.kb_index = i; if (ioctl(fd, KDGKBENT, &entry)) continue; /* error */ const int kern_map = entry.kb_value; switch(kern_map) { case K_ENTER: keys[i] = SDLK_RETURN; break; case K_F1: keys[i] = SDLK_F1; break; case K_F2: keys[i] = SDLK_F2; break; case K_F3: keys[i] = SDLK_F3; break; case K_F4: keys[i] = SDLK_F4; break; case K_F5: keys[i] = SDLK_F5; break; case K_F6: keys[i] = SDLK_F6; break; case K_F7: keys[i] = SDLK_F7; break; case K_F8: keys[i] = SDLK_F8; break; case K_F9: keys[i] = SDLK_F9; break; case K_F10: keys[i] = SDLK_F10; break; case K_F11: keys[i] = SDLK_F11; break; case K_F12: keys[i] = SDLK_F12; break; case K_UP: keys[i] = SDLK_UP; break; case K_DOWN: keys[i] = SDLK_DOWN; break; case K_LEFT: keys[i] = SDLK_LEFT; break; case K_RIGHT: keys[i] = SDLK_RIGHT; break; case K_P0: keys[i] = SDLK_KP0; break; case K_P1: keys[i] = SDLK_KP1; break; case K_P2: keys[i] = SDLK_KP2; break; case K_P3: keys[i] = SDLK_KP3; break; case K_P4: keys[i] = SDLK_KP4; break; case K_P5: keys[i] = SDLK_KP5; break; case K_P6: keys[i] = SDLK_KP6; break; case K_P7: keys[i] = SDLK_KP7; break; case K_P8: keys[i] = SDLK_KP8; break; case K_P9: keys[i] = SDLK_KP9; break; case K_PPLUS: keys[i] = SDLK_KP_PLUS; break; case K_PMINUS: keys[i] = SDLK_KP_MINUS; break; case K_PSTAR: keys[i] = SDLK_KP_MULTIPLY; break; case K_PSLASH: keys[i] = SDLK_KP_DIVIDE; break; case K_PENTER: keys[i] = SDLK_KP_ENTER; break; case K_PDOT: keys[i] = SDLK_KP_PERIOD; break; case K_ALT: keys[i] = SDLK_LALT; break; case K_ALTGR: keys[i] = SDLK_RALT; break; case K_INSERT: keys[i] = SDLK_INSERT; break; case K_REMOVE: keys[i] = SDLK_DELETE; break; case K_PGUP: keys[i] = SDLK_PAGEUP; break; case K_PGDN: keys[i] = SDLK_PAGEDOWN; break; case K_FIND: keys[i] = SDLK_HOME; break; case K_SELECT: keys[i] = SDLK_END; break; case K_NUM: keys[i] = SDLK_NUMLOCK; break; case K_CAPS: keys[i] = SDLK_CAPSLOCK; break; case K_F13: keys[i] = SDLK_PRINT; break; case K_HOLD: keys[i] = SDLK_SCROLLOCK; break; case K_PAUSE: keys[i] = SDLK_PAUSE; break; case 127: keys[i] = SDLK_BACKSPACE; break; default: keys[i] = KVAL(kern_map); } } handler = this; SignalHandler::OnClose(OnCrash); } InputHandler_Linux_tty::~InputHandler_Linux_tty() { LOG->Trace("~InputHandler_Linux_tty"); ioctl(fd, KDSETMODE, KD_TEXT); ioctl(fd, KDSKBMODE, saved_kbd_mode); tcsetattr(fd, TCSAFLUSH, &saved_kbd_termios); close(fd); handler = NULL; } void InputHandler_Linux_tty::Update() { while (1) { fd_set fdset; FD_ZERO(&fdset); FD_SET(fd, &fdset); struct timeval zero = {0,0}; if ( select(fd+1, &fdset, NULL, NULL, &zero) <= 0 ) return; unsigned char keybuf[BUFSIZ]; SDL_keysym keysym; int ret = read(fd, keybuf, BUFSIZ); for ( int i=0; i < ret; ++i ) { const int key = keybuf[i] & 0x7F; const int butno = keys[key]; const bool pressed = !(keybuf[i] & 0x80); ButtonPressed(DeviceInput(DEVICE_KEYBOARD, butno), pressed); } } InputHandler::UpdateTimer(); } void InputHandler_Linux_tty::GetDevicesAndDescriptions(vector& vDevicesOut, vector& vDescriptionsOut) { vDevicesOut.push_back( InputDevice(DEVICE_KEYBOARD) ); vDescriptionsOut.push_back( "Keyboard" ); } /* * (c) 2003-2004 Glenn Maynard * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, and/or sell copies of the Software, and to permit persons to * whom the Software is furnished to do so, provided that the above * copyright notice(s) and this permission notice appear in all copies of * the Software and that both the above copyright notice(s) and this * permission notice appear in supporting documentation. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */