/* SDL - Simple DirectMedia Layer Copyright (C) 1997-2006 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Sam Lantinga slouken@libsdl.org */ #include "SDL_config.h" /* General keyboard handling code for SDL */ #include "SDL_timer.h" #include "SDL_events.h" #include "SDL_events_c.h" #include "SDL_sysevents.h" /* Global keyboard information */ static int SDL_num_keyboards; static int SDL_current_keyboard; static SDL_Keyboard **SDL_keyboards; int SDL_TranslateUNICODE = 0; static const char *SDL_keynames[SDLK_LAST]; /* Array of keycode names */ /* Public functions */ int SDL_KeyboardInit(void) { int i; /* Set default mode of UNICODE translation */ SDL_EnableUNICODE(DEFAULT_UNICODE_TRANSLATION); /* Set default keyboard repeat setting */ SDL_EnableKeyRepeat(0, 0); /* Initialize the tables */ for (i = 0; i < SDL_arraysize(SDL_keynames); ++i) { switch (i) { case SDLK_BACKSPACE: SDL_keynames[i] = "backspace"; break; case SDLK_TAB: SDL_keynames[i] = "tab"; break; case SDLK_CLEAR: SDL_keynames[i] = "clear"; break; case SDLK_RETURN: SDL_keynames[i] = "return"; break; case SDLK_PAUSE: SDL_keynames[i] = "pause"; break; case SDLK_ESCAPE: SDL_keynames[i] = "escape"; break; case SDLK_SPACE: SDL_keynames[i] = "space"; break; case SDLK_KP0: SDL_keynames[i] = "[0]"; break; case SDLK_KP1: SDL_keynames[i] = "[1]"; break; case SDLK_KP2: SDL_keynames[i] = "[2]"; break; case SDLK_KP3: SDL_keynames[i] = "[3]"; break; case SDLK_KP4: SDL_keynames[i] = "[4]"; break; case SDLK_KP5: SDL_keynames[i] = "[5]"; break; case SDLK_KP6: SDL_keynames[i] = "[6]"; break; case SDLK_KP7: SDL_keynames[i] = "[7]"; break; case SDLK_KP8: SDL_keynames[i] = "[8]"; break; case SDLK_KP9: SDL_keynames[i] = "[9]"; break; case SDLK_KP_PERIOD: SDL_keynames[i] = "[.]"; break; case SDLK_KP_DIVIDE: SDL_keynames[i] = "[/]"; break; case SDLK_KP_MULTIPLY: SDL_keynames[i] = "[*]"; break; case SDLK_KP_MINUS: SDL_keynames[i] = "[-]"; break; case SDLK_KP_PLUS: SDL_keynames[i] = "[+]"; break; case SDLK_KP_ENTER: SDL_keynames[i] = "enter"; break; case SDLK_KP_EQUALS: SDL_keynames[i] = "equals"; break; case SDLK_UP: SDL_keynames[i] = "up"; break; case SDLK_DOWN: SDL_keynames[i] = "down"; break; case SDLK_RIGHT: SDL_keynames[i] = "right"; break; case SDLK_LEFT: SDL_keynames[i] = "left"; break; case SDLK_DOWN: SDL_keynames[i] = "down"; break; case SDLK_INSERT: SDL_keynames[i] = "insert"; break; case SDLK_HOME: SDL_keynames[i] = "home"; break; case SDLK_END: SDL_keynames[i] = "end"; break; case SDLK_PAGEUP: SDL_keynames[i] = "page up"; break; case SDLK_PAGEDOWN: SDL_keynames[i] = "page down"; break; case SDLK_F1: SDL_keynames[i] = "f1"; break; case SDLK_F2: SDL_keynames[i] = "f2"; break; case SDLK_F3: SDL_keynames[i] = "f3"; break; case SDLK_F4: SDL_keynames[i] = "f4"; break; case SDLK_F5: SDL_keynames[i] = "f5"; break; case SDLK_F6: SDL_keynames[i] = "f6"; break; case SDLK_F7: SDL_keynames[i] = "f7"; break; case SDLK_F8: SDL_keynames[i] = "f8"; break; case SDLK_F9: SDL_keynames[i] = "f9"; break; case SDLK_F10: SDL_keynames[i] = "f10"; break; case SDLK_F11: SDL_keynames[i] = "f11"; break; case SDLK_F12: SDL_keynames[i] = "f12"; break; case SDLK_F13: SDL_keynames[i] = "f13"; break; case SDLK_F14: SDL_keynames[i] = "f14"; break; case SDLK_F15: SDL_keynames[i] = "f15"; break; case SDLK_NUMLOCK: SDL_keynames[i] = "numlock"; break; case SDLK_CAPSLOCK: SDL_keynames[i] = "caps lock"; break; case SDLK_SCROLLOCK: SDL_keynames[i] = "scroll lock"; break; case SDLK_RSHIFT: SDL_keynames[i] = "right shift"; break; case SDLK_LSHIFT: SDL_keynames[i] = "left shift"; break; case SDLK_RCTRL: SDL_keynames[i] = "right ctrl"; break; case SDLK_LCTRL: SDL_keynames[i] = "left ctrl"; break; case SDLK_RALT: SDL_keynames[i] = "right alt"; break; case SDLK_LALT: SDL_keynames[i] = "left alt"; break; case SDLK_RMETA: SDL_keynames[i] = "right meta"; break; case SDLK_LMETA: SDL_keynames[i] = "left meta"; break; case SDLK_LSUPER: SDL_keynames[i] = "left super"; /* "Windows" keys */ break; case SDLK_RSUPER: SDL_keynames[i] = "right super"; break; case SDLK_MODE: SDL_keynames[i] = "alt gr"; break; case SDLK_COMPOSE: SDL_keynames[i] = "compose"; break; case SDLK_HELP: SDL_keynames[i] = "help"; break; case SDLK_PRINT: SDL_keynames[i] = "print screen"; break; case SDLK_SYSREQ: SDL_keynames[i] = "sys req"; break; case SDLK_BREAK: SDL_keynames[i] = "break"; break; case SDLK_MENU: SDL_keynames[i] = "menu"; break; case SDLK_POWER: SDL_keynames[i] = "power"; break; case SDLK_EURO: SDL_keynames[i] = "euro"; break; case SDLK_UNDO: SDL_keynames[i] = "undo"; break; default: SDL_keynames[i] = NULL; break; } } /* Done. Whew. */ return (0); } SDL_Keyboard * SDL_GetKeyboard(int index) { if (index < 0 || index >= SDL_num_keyboards) { return NULL; } return SDL_keyboards[index]; } int SDL_AddKeyboard(const SDL_Keyboard * keyboard, int index) { SDL_Keyboard **keyboards; SDL_Cursor *cursor; int selected_keyboard; /* Add the keyboard to the list of keyboards */ if (index < 0 || index >= SDL_num_keyboards || SDL_keyboards[index]) { keyboards = (SDL_Keyboard **) SDL_realloc(SDL_keyboards, (SDL_num_keyboards + 1) * sizeof(*keyboards)); if (!keyboards) { SDL_OutOfMemory(); return -1; } SDL_keyboards = keyboards; index = SDL_num_keyboards++; } SDL_keyboards[index] = (SDL_Keyboard *) SDL_malloc(sizeof(*SDL_keyboards[index])); if (!SDL_keyboards[index]) { SDL_OutOfMemory(); return -1; } *SDL_keyboards[index] = *keyboard; return index; } void SDL_DelKeyboard(int index) { SDL_Keyboard *keyboard = SDL_GetKeyboard(index); if (!keyboard) { return; } if (keyboard->FreeKeyboard) { keyboard->FreeKeyboard(keyboard); } SDL_free(keyboard); SDL_keyboards[index] = NULL; } void SDL_ResetKeyboard(int index) { SDL_Keyboard *keyboard = SDL_GetKeyboard(index); SDL_keysym keysym; SDLKey key; if (!keyboard) { return; } SDL_memset(&keysym, 0, (sizeof keysym)); for (key = SDLK_FIRST; key < SDLK_LAST; ++key) { if (keyboard->keystate[key] == SDL_PRESSED) { keysym.sym = key; SDL_SendKeyboardKey(index, SDL_RELEASED, &keysym); } } keyboard->keyrepeat.timestamp = 0; } void SDL_KeyboardQuit(void) { int i; for (i = 0; i < SDL_num_keyboards; ++i) { SDL_DelKeyboard(i); } SDL_num_keyboards = 0; SDL_current_keyboard = 0; if (SDL_keyboards) { SDL_free(SDL_keyboards); SDL_keyboards = NULL; } } int SDL_GetNumKeyboards(void) { return SDL_num_keyboards; } int SDL_SelectKeyboard(int index) { if (index >= 0 && index < SDL_num_keyboards) { SDL_current_keyboard = index; } return SDL_current_keyboard; } int SDL_EnableUNICODE(int enable) { int old_mode; old_mode = SDL_TranslateUNICODE; if (enable >= 0) { SDL_TranslateUNICODE = enable; } return (old_mode); } Uint8 * SDL_GetKeyState(int *numkeys) { if (numkeys != (int *) 0) *numkeys = SDLK_LAST; return (SDL_KeyState); } SDLMod SDL_GetModState(void) { SDL_Keyboard *keyboard = SDL_GetKeyboard(index); if (!keyboard) { return KMOD_NONE; } return keyboard->modstate; } void SDL_SetModState(SDLMod modstate) { SDL_Keyboard *keyboard = SDL_GetKeyboard(index); if (!keyboard) { return; } keyboard->modstate = modstate; } const char * SDL_GetKeyName(SDLKey key) { const char *keyname; keyname = keynames[key]; if (keyname == NULL) { if (key < 256) { static char temp[4]; FIXME:Convert to UTF - 8 keyname = temp; } else { keyname = "unknown key"; } } return keyname; } /* These are global for SDL_eventloop.c */ int SDL_SendKeyboardKey(int index, Uint8 state, const SDL_keysym * keysym) { SDL_Event event; int posted, repeatable; Uint16 modstate; SDL_memset(&event, 0, sizeof(event)); #if 0 printf("The '%s' key has been %s\n", SDL_GetKeyName(keysym->sym), state == SDL_PRESSED ? "pressed" : "released"); #endif /* Set up the keysym */ modstate = (Uint16) SDL_ModState; repeatable = 0; if (state == SDL_PRESSED) { keysym->mod = (SDLMod) modstate; switch (keysym->sym) { case SDLK_UNKNOWN: break; case SDLK_NUMLOCK: modstate ^= KMOD_NUM; if (!(modstate & KMOD_NUM)) state = SDL_RELEASED; keysym->mod = (SDLMod) modstate; break; case SDLK_CAPSLOCK: modstate ^= KMOD_CAPS; if (!(modstate & KMOD_CAPS)) state = SDL_RELEASED; keysym->mod = (SDLMod) modstate; break; case SDLK_LCTRL: modstate |= KMOD_LCTRL; break; case SDLK_RCTRL: modstate |= KMOD_RCTRL; break; case SDLK_LSHIFT: modstate |= KMOD_LSHIFT; break; case SDLK_RSHIFT: modstate |= KMOD_RSHIFT; break; case SDLK_LALT: modstate |= KMOD_LALT; break; case SDLK_RALT: modstate |= KMOD_RALT; break; case SDLK_LMETA: modstate |= KMOD_LMETA; break; case SDLK_RMETA: modstate |= KMOD_RMETA; break; case SDLK_MODE: modstate |= KMOD_MODE; break; default: repeatable = 1; break; } } else { switch (keysym->sym) { case SDLK_UNKNOWN: break; case SDLK_NUMLOCK: case SDLK_CAPSLOCK: /* Only send keydown events */ return (0); case SDLK_LCTRL: modstate &= ~KMOD_LCTRL; break; case SDLK_RCTRL: modstate &= ~KMOD_RCTRL; break; case SDLK_LSHIFT: modstate &= ~KMOD_LSHIFT; break; case SDLK_RSHIFT: modstate &= ~KMOD_RSHIFT; break; case SDLK_LALT: modstate &= ~KMOD_LALT; break; case SDLK_RALT: modstate &= ~KMOD_RALT; break; case SDLK_LMETA: modstate &= ~KMOD_LMETA; break; case SDLK_RMETA: modstate &= ~KMOD_RMETA; break; case SDLK_MODE: modstate &= ~KMOD_MODE; break; default: break; } keysym->mod = (SDLMod) modstate; } /* Figure out what type of event this is */ switch (state) { case SDL_PRESSED: event.type = SDL_KEYDOWN; break; case SDL_RELEASED: event.type = SDL_KEYUP; /* * jk 991215 - Added */ if (SDL_KeyRepeat.timestamp && SDL_KeyRepeat.evt.key.keysym.sym == keysym->sym) { SDL_KeyRepeat.timestamp = 0; } break; default: /* Invalid state -- bail */ return (0); } if (keysym->sym != SDLK_UNKNOWN) { /* Drop events that don't change state */ if (SDL_KeyState[keysym->sym] == state) { #if 0 printf("Keyboard event didn't change state - dropped!\n"); #endif return (0); } /* Update internal keyboard state */ SDL_ModState = (SDLMod) modstate; SDL_KeyState[keysym->sym] = state; } /* Post the event, if desired */ posted = 0; if (SDL_ProcessEvents[event.type] == SDL_ENABLE) { event.key.state = state; event.key.keysym = *keysym; /* * jk 991215 - Added */ if (repeatable && (SDL_KeyRepeat.delay != 0)) { SDL_KeyRepeat.evt = event; SDL_KeyRepeat.firsttime = 1; SDL_KeyRepeat.timestamp = SDL_GetTicks(); } if ((SDL_EventOK == NULL) || SDL_EventOK(&event)) { posted = 1; SDL_PushEvent(&event); } } return (posted); } /* * jk 991215 - Added */ void SDL_CheckKeyRepeat(void) { if (SDL_KeyRepeat.timestamp) { Uint32 now, interval; now = SDL_GetTicks(); interval = (now - SDL_KeyRepeat.timestamp); if (SDL_KeyRepeat.firsttime) { if (interval > (Uint32) SDL_KeyRepeat.delay) { SDL_KeyRepeat.timestamp = now; SDL_KeyRepeat.firsttime = 0; } } else { if (interval > (Uint32) SDL_KeyRepeat.interval) { SDL_KeyRepeat.timestamp = now; if ((SDL_EventOK == NULL) || SDL_EventOK(&SDL_KeyRepeat.evt)) { SDL_PushEvent(&SDL_KeyRepeat.evt); } } } } } int SDL_EnableKeyRepeat(int delay, int interval) { if ((delay < 0) || (interval < 0)) { SDL_SetError("keyboard repeat value less than zero"); return (-1); } SDL_KeyRepeat.firsttime = 0; SDL_KeyRepeat.delay = delay; SDL_KeyRepeat.interval = interval; SDL_KeyRepeat.timestamp = 0; return (0); } void SDL_GetKeyRepeat(int *delay, int *interval) { *delay = SDL_KeyRepeat.delay; *interval = SDL_KeyRepeat.interval; } /* vi: set ts=4 sw=4 expandtab: */