SDL/src/events/SDL_keyboard.c

724 lines
22 KiB
C

/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
/* General keyboard handling code for SDL */
#include "SDL_events_c.h"
#include "SDL_keymap_c.h"
#include "../video/SDL_sysvideo.h"
/* #define DEBUG_KEYBOARD */
/* Global keyboard information */
#define KEYBOARD_HARDWARE 0x01
#define KEYBOARD_VIRTUAL 0x02
#define KEYBOARD_AUTORELEASE 0x04
#define KEYBOARD_IGNOREMODIFIERS 0x08
#define KEYBOARD_SOURCE_MASK (KEYBOARD_HARDWARE | KEYBOARD_AUTORELEASE)
#define KEYCODE_OPTION_APPLY_MODIFIERS 0x01
#define KEYCODE_OPTION_FRENCH_NUMBERS 0x02
#define KEYCODE_OPTION_LATIN_LETTERS 0x04
#define DEFAULT_KEYCODE_OPTIONS (KEYCODE_OPTION_APPLY_MODIFIERS | KEYCODE_OPTION_FRENCH_NUMBERS)
typedef struct SDL_KeyboardInstance
{
SDL_KeyboardID instance_id;
char *name;
} SDL_KeyboardInstance;
typedef struct SDL_Keyboard
{
/* Data common to all keyboards */
SDL_Window *focus;
SDL_Keymod modstate;
Uint8 keysource[SDL_NUM_SCANCODES];
Uint8 keystate[SDL_NUM_SCANCODES];
SDL_Keymap *keymap;
SDL_bool french_numbers;
SDL_bool non_latin_letters;
Uint32 keycode_options;
SDL_bool autorelease_pending;
Uint64 hardware_timestamp;
} SDL_Keyboard;
static SDL_Keyboard SDL_keyboard;
static int SDL_keyboard_count;
static SDL_KeyboardInstance *SDL_keyboards;
static void SDLCALL SDL_KeycodeOptionsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
SDL_Keyboard *keyboard = (SDL_Keyboard *)userdata;
if (hint && *hint) {
keyboard->keycode_options = 0;
if (SDL_strstr(hint, "unmodified")) {
keyboard->keycode_options &= ~KEYCODE_OPTION_APPLY_MODIFIERS;
} else if (SDL_strstr(hint, "modified")) {
keyboard->keycode_options |= KEYCODE_OPTION_APPLY_MODIFIERS;
}
if (SDL_strstr(hint, "french_numbers")) {
keyboard->keycode_options |= KEYCODE_OPTION_FRENCH_NUMBERS;
}
if (SDL_strstr(hint, "latin_letters")) {
keyboard->keycode_options |= KEYCODE_OPTION_LATIN_LETTERS;
}
} else {
keyboard->keycode_options = DEFAULT_KEYCODE_OPTIONS;
}
}
/* Public functions */
int SDL_InitKeyboard(void)
{
SDL_AddHintCallback(SDL_HINT_KEYCODE_OPTIONS,
SDL_KeycodeOptionsChanged, &SDL_keyboard);
return 0;
}
SDL_bool SDL_IsKeyboard(Uint16 vendor, Uint16 product, int num_keys)
{
const int REAL_KEYBOARD_KEY_COUNT = 50;
if (num_keys > 0 && num_keys < REAL_KEYBOARD_KEY_COUNT) {
return SDL_FALSE;
}
/* Eventually we'll have a blacklist of devices that enumerate as keyboards but aren't really */
return SDL_TRUE;
}
static int SDL_GetKeyboardIndex(SDL_KeyboardID keyboardID)
{
for (int i = 0; i < SDL_keyboard_count; ++i) {
if (keyboardID == SDL_keyboards[i].instance_id) {
return i;
}
}
return -1;
}
void SDL_AddKeyboard(SDL_KeyboardID keyboardID, const char *name, SDL_bool send_event)
{
int keyboard_index = SDL_GetKeyboardIndex(keyboardID);
if (keyboard_index >= 0) {
/* We already know about this keyboard */
return;
}
SDL_assert(keyboardID != 0);
SDL_KeyboardInstance *keyboards = (SDL_KeyboardInstance *)SDL_realloc(SDL_keyboards, (SDL_keyboard_count + 1) * sizeof(*keyboards));
if (!keyboards) {
return;
}
SDL_KeyboardInstance *instance = &keyboards[SDL_keyboard_count];
instance->instance_id = keyboardID;
instance->name = SDL_strdup(name ? name : "");
SDL_keyboards = keyboards;
++SDL_keyboard_count;
if (send_event) {
SDL_Event event;
SDL_zero(event);
event.type = SDL_EVENT_KEYBOARD_ADDED;
event.kdevice.which = keyboardID;
SDL_PushEvent(&event);
}
}
void SDL_RemoveKeyboard(SDL_KeyboardID keyboardID, SDL_bool send_event)
{
int keyboard_index = SDL_GetKeyboardIndex(keyboardID);
if (keyboard_index < 0) {
/* We don't know about this keyboard */
return;
}
SDL_FreeLater(SDL_keyboards[keyboard_index].name);
if (keyboard_index != SDL_keyboard_count - 1) {
SDL_memcpy(&SDL_keyboards[keyboard_index], &SDL_keyboards[keyboard_index + 1], (SDL_keyboard_count - keyboard_index - 1) * sizeof(SDL_keyboards[keyboard_index]));
}
--SDL_keyboard_count;
if (send_event) {
SDL_Event event;
SDL_zero(event);
event.type = SDL_EVENT_KEYBOARD_REMOVED;
event.kdevice.which = keyboardID;
SDL_PushEvent(&event);
}
}
SDL_bool SDL_HasKeyboard(void)
{
return (SDL_keyboard_count > 0);
}
SDL_KeyboardID *SDL_GetKeyboards(int *count)
{
int i;
SDL_KeyboardID *keyboards;
keyboards = (SDL_JoystickID *)SDL_malloc((SDL_keyboard_count + 1) * sizeof(*keyboards));
if (keyboards) {
if (count) {
*count = SDL_keyboard_count;
}
for (i = 0; i < SDL_keyboard_count; ++i) {
keyboards[i] = SDL_keyboards[i].instance_id;
}
keyboards[i] = 0;
} else {
if (count) {
*count = 0;
}
}
return keyboards;
}
const char *SDL_GetKeyboardInstanceName(SDL_KeyboardID instance_id)
{
int keyboard_index = SDL_GetKeyboardIndex(instance_id);
if (keyboard_index < 0) {
return NULL;
}
return SDL_keyboards[keyboard_index].name;
}
void SDL_ResetKeyboard(void)
{
SDL_Keyboard *keyboard = &SDL_keyboard;
SDL_Scancode scancode;
#ifdef DEBUG_KEYBOARD
printf("Resetting keyboard\n");
#endif
for (scancode = (SDL_Scancode)0; scancode < SDL_NUM_SCANCODES; ++scancode) {
if (keyboard->keystate[scancode] == SDL_PRESSED) {
SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, 0, scancode, SDL_RELEASED);
}
}
}
void SDL_SetKeymap(SDL_Keymap *keymap, SDL_bool send_event)
{
SDL_Keyboard *keyboard = &SDL_keyboard;
if (keyboard->keymap) {
SDL_DestroyKeymap(keyboard->keymap);
}
keyboard->keymap = keymap;
// Detect French number row (all symbols)
keyboard->french_numbers = SDL_TRUE;
for (int i = SDL_SCANCODE_1; i <= SDL_SCANCODE_0; ++i) {
if (SDL_isdigit(SDL_GetKeymapKeycode(keymap, (SDL_Scancode)i, SDL_KMOD_NONE)) ||
!SDL_isdigit(SDL_GetKeymapKeycode(keymap, (SDL_Scancode)i, SDL_KMOD_SHIFT))) {
keyboard->french_numbers = SDL_FALSE;
break;
}
}
// Detect non-Latin keymap
keyboard->non_latin_letters = SDL_TRUE;
for (int i = SDL_SCANCODE_A; i <= SDL_SCANCODE_D; ++i) {
if (SDL_GetKeymapKeycode(keymap, (SDL_Scancode)i, SDL_KMOD_NONE) <= 0xFF) {
keyboard->non_latin_letters = SDL_FALSE;
break;
}
}
if (send_event) {
SDL_SendKeymapChangedEvent();
}
}
SDL_Window *SDL_GetKeyboardFocus(void)
{
SDL_Keyboard *keyboard = &SDL_keyboard;
return keyboard->focus;
}
int SDL_SetKeyboardFocus(SDL_Window *window)
{
SDL_VideoDevice *video = SDL_GetVideoDevice();
SDL_Keyboard *keyboard = &SDL_keyboard;
if (window) {
if (!SDL_ObjectValid(window, SDL_OBJECT_TYPE_WINDOW) || window->is_destroying) {
return SDL_SetError("Invalid window");
}
}
if (keyboard->focus && !window) {
/* We won't get anymore keyboard messages, so reset keyboard state */
SDL_ResetKeyboard();
}
/* See if the current window has lost focus */
if (keyboard->focus && keyboard->focus != window) {
/* new window shouldn't think it has mouse captured. */
SDL_assert(window == NULL || !(window->flags & SDL_WINDOW_MOUSE_CAPTURE));
/* old window must lose an existing mouse capture. */
if (keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE) {
SDL_Mouse *mouse = SDL_GetMouse();
if (mouse->CaptureMouse) {
SDL_CaptureMouse(SDL_FALSE); /* drop the capture. */
SDL_UpdateMouseCapture(SDL_TRUE);
SDL_assert(!(keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE));
} else {
keyboard->focus->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
}
}
SDL_SendWindowEvent(keyboard->focus, SDL_EVENT_WINDOW_FOCUS_LOST, 0, 0);
/* Ensures IME compositions are committed */
if (SDL_TextInputActive(keyboard->focus)) {
if (video && video->StopTextInput) {
video->StopTextInput(video, keyboard->focus);
}
}
}
keyboard->focus = window;
if (keyboard->focus) {
SDL_SendWindowEvent(keyboard->focus, SDL_EVENT_WINDOW_FOCUS_GAINED, 0, 0);
if (SDL_TextInputActive(keyboard->focus)) {
if (video && video->StartTextInput) {
video->StartTextInput(video, keyboard->focus);
}
}
}
return 0;
}
static SDL_Keycode SDL_GetEventKeycode(SDL_Keyboard *keyboard, SDL_Scancode scancode, SDL_Keymod modstate)
{
SDL_Keycode keycode;
if (scancode >= SDL_SCANCODE_A && scancode <= SDL_SCANCODE_Z) {
if (keyboard->non_latin_letters && (keyboard->keycode_options & KEYCODE_OPTION_LATIN_LETTERS)) {
if (keyboard->keycode_options & KEYCODE_OPTION_APPLY_MODIFIERS) {
keycode = SDL_GetDefaultKeyFromScancode(scancode, modstate);
} else {
keycode = SDL_GetDefaultKeyFromScancode(scancode, SDL_KMOD_NONE);
}
return keycode;
}
}
if (scancode >= SDL_SCANCODE_1 && scancode <= SDL_SCANCODE_0) {
if (keyboard->french_numbers && (keyboard->keycode_options & KEYCODE_OPTION_FRENCH_NUMBERS)) {
// Invert the shift state to generate the correct keycode
if (modstate & SDL_KMOD_SHIFT) {
modstate &= ~SDL_KMOD_SHIFT;
} else {
modstate |= SDL_KMOD_SHIFT;
}
}
}
if (keyboard->keycode_options & KEYCODE_OPTION_APPLY_MODIFIERS) {
keycode = SDL_GetKeyFromScancode(scancode, modstate);
} else {
keycode = SDL_GetKeyFromScancode(scancode, SDL_KMOD_NONE);
}
return keycode;
}
static int SDL_SendKeyboardKeyInternal(Uint64 timestamp, Uint32 flags, SDL_KeyboardID keyboardID, int rawcode, SDL_Scancode scancode, SDL_Keycode keycode, Uint8 state)
{
SDL_Keyboard *keyboard = &SDL_keyboard;
int posted;
SDL_Keymod modifier;
Uint32 type;
Uint8 repeat = SDL_FALSE;
const Uint8 source = flags & KEYBOARD_SOURCE_MASK;
#ifdef DEBUG_KEYBOARD
printf("The '%s' key has been %s\n", SDL_GetScancodeName(scancode),
state == SDL_PRESSED ? "pressed" : "released");
#endif
/* Figure out what type of event this is */
switch (state) {
case SDL_PRESSED:
type = SDL_EVENT_KEY_DOWN;
break;
case SDL_RELEASED:
type = SDL_EVENT_KEY_UP;
break;
default:
/* Invalid state -- bail */
return 0;
}
if (scancode != SDL_SCANCODE_UNKNOWN && scancode < SDL_NUM_SCANCODES) {
/* Drop events that don't change state */
if (state) {
if (keyboard->keystate[scancode]) {
if (!(keyboard->keysource[scancode] & source)) {
keyboard->keysource[scancode] |= source;
return 0;
}
repeat = SDL_TRUE;
}
keyboard->keysource[scancode] |= source;
} else {
if (!keyboard->keystate[scancode]) {
return 0;
}
keyboard->keysource[scancode] = 0;
}
/* Update internal keyboard state */
keyboard->keystate[scancode] = state;
if (keycode == SDLK_UNKNOWN) {
keycode = SDL_GetEventKeycode(keyboard, scancode, keyboard->modstate);
}
} else if (keycode == SDLK_UNKNOWN && rawcode == 0) {
/* Nothing to do! */
return 0;
}
if (source == KEYBOARD_HARDWARE) {
keyboard->hardware_timestamp = SDL_GetTicks();
} else if (source == KEYBOARD_AUTORELEASE) {
keyboard->autorelease_pending = SDL_TRUE;
}
/* Update modifiers state if applicable */
if (!(flags & KEYBOARD_IGNOREMODIFIERS) && !repeat) {
switch (keycode) {
case SDLK_LCTRL:
modifier = SDL_KMOD_LCTRL;
break;
case SDLK_RCTRL:
modifier = SDL_KMOD_RCTRL;
break;
case SDLK_LSHIFT:
modifier = SDL_KMOD_LSHIFT;
break;
case SDLK_RSHIFT:
modifier = SDL_KMOD_RSHIFT;
break;
case SDLK_LALT:
modifier = SDL_KMOD_LALT;
break;
case SDLK_RALT:
modifier = SDL_KMOD_RALT;
break;
case SDLK_LGUI:
modifier = SDL_KMOD_LGUI;
break;
case SDLK_RGUI:
modifier = SDL_KMOD_RGUI;
break;
case SDLK_MODE:
modifier = SDL_KMOD_MODE;
break;
default:
modifier = SDL_KMOD_NONE;
break;
}
if (SDL_EVENT_KEY_DOWN == type) {
switch (keycode) {
case SDLK_NUMLOCKCLEAR:
keyboard->modstate ^= SDL_KMOD_NUM;
break;
case SDLK_CAPSLOCK:
keyboard->modstate ^= SDL_KMOD_CAPS;
break;
case SDLK_SCROLLLOCK:
keyboard->modstate ^= SDL_KMOD_SCROLL;
break;
default:
keyboard->modstate |= modifier;
break;
}
} else {
keyboard->modstate &= ~modifier;
}
}
/* Post the event, if desired */
posted = 0;
if (SDL_EventEnabled(type)) {
SDL_Event event;
event.type = type;
event.common.timestamp = timestamp;
event.key.scancode = scancode;
event.key.key = keycode;
event.key.mod = keyboard->modstate;
event.key.raw = (Uint16)rawcode;
event.key.state = state;
event.key.repeat = repeat;
event.key.windowID = keyboard->focus ? keyboard->focus->id : 0;
event.key.which = keyboardID;
posted = (SDL_PushEvent(&event) > 0);
}
/* If the keyboard is grabbed and the grabbed window is in full-screen,
minimize the window when we receive Alt+Tab, unless the application
has explicitly opted out of this behavior. */
if (keycode == SDLK_TAB &&
state == SDL_PRESSED &&
(keyboard->modstate & SDL_KMOD_ALT) &&
keyboard->focus &&
(keyboard->focus->flags & SDL_WINDOW_KEYBOARD_GRABBED) &&
(keyboard->focus->flags & SDL_WINDOW_FULLSCREEN) &&
SDL_GetHintBoolean(SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED, SDL_TRUE)) {
/* We will temporarily forfeit our grab by minimizing our window,
allowing the user to escape the application */
SDL_MinimizeWindow(keyboard->focus);
}
return posted;
}
int SDL_SendKeyboardUnicodeKey(Uint64 timestamp, Uint32 ch)
{
SDL_Keymod modstate = SDL_KMOD_NONE;
SDL_Scancode scancode = SDL_GetDefaultScancodeFromKey(ch, &modstate);
if (modstate & SDL_KMOD_SHIFT) {
/* If the character uses shift, press shift down */
SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, SDL_SCANCODE_LSHIFT, SDLK_LSHIFT, SDL_PRESSED);
}
/* Send a keydown and keyup for the character */
SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, scancode, ch, SDL_PRESSED);
SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, scancode, ch, SDL_RELEASED);
if (modstate & SDL_KMOD_SHIFT) {
/* If the character uses shift, release shift */
SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, SDL_SCANCODE_LSHIFT, SDLK_LSHIFT, SDL_RELEASED);
}
return 0;
}
int SDL_SendVirtualKeyboardKey(Uint64 timestamp, Uint8 state, SDL_Scancode scancode)
{
return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, scancode, SDLK_UNKNOWN, state);
}
int SDL_SendKeyboardKey(Uint64 timestamp, SDL_KeyboardID keyboardID, int rawcode, SDL_Scancode scancode, Uint8 state)
{
return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE, keyboardID, rawcode, scancode, SDLK_UNKNOWN, state);
}
int SDL_SendKeyboardKeyAndKeycode(Uint64 timestamp, SDL_KeyboardID keyboardID, int rawcode, SDL_Scancode scancode, SDL_Keycode keycode, Uint8 state)
{
return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE, keyboardID, rawcode, scancode, keycode, state);
}
int SDL_SendKeyboardKeyAutoRelease(Uint64 timestamp, SDL_Scancode scancode)
{
return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_AUTORELEASE, SDL_GLOBAL_KEYBOARD_ID, 0, scancode, SDLK_UNKNOWN, SDL_PRESSED);
}
int SDL_SendKeyboardKeyIgnoreModifiers(Uint64 timestamp, SDL_KeyboardID keyboardID, int rawcode, SDL_Scancode scancode, Uint8 state)
{
return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE | KEYBOARD_IGNOREMODIFIERS, keyboardID, rawcode, scancode, SDLK_UNKNOWN, state);
}
void SDL_ReleaseAutoReleaseKeys(void)
{
SDL_Keyboard *keyboard = &SDL_keyboard;
SDL_Scancode scancode;
if (keyboard->autorelease_pending) {
for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_NUM_SCANCODES; ++scancode) {
if (keyboard->keysource[scancode] == KEYBOARD_AUTORELEASE) {
SDL_SendKeyboardKeyInternal(0, KEYBOARD_AUTORELEASE, SDL_GLOBAL_KEYBOARD_ID, 0, scancode, SDLK_UNKNOWN, SDL_RELEASED);
}
}
keyboard->autorelease_pending = SDL_FALSE;
}
if (keyboard->hardware_timestamp) {
/* Keep hardware keyboard "active" for 250 ms */
if (SDL_GetTicks() >= keyboard->hardware_timestamp + 250) {
keyboard->hardware_timestamp = 0;
}
}
}
SDL_bool SDL_HardwareKeyboardKeyPressed(void)
{
SDL_Keyboard *keyboard = &SDL_keyboard;
SDL_Scancode scancode;
for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_NUM_SCANCODES; ++scancode) {
if (keyboard->keysource[scancode] & KEYBOARD_HARDWARE) {
return SDL_TRUE;
}
}
return keyboard->hardware_timestamp ? SDL_TRUE : SDL_FALSE;
}
int SDL_SendKeyboardText(const char *text)
{
SDL_Keyboard *keyboard = &SDL_keyboard;
int posted;
if (!SDL_TextInputActive(keyboard->focus)) {
return 0;
}
if (!text || !*text) {
return 0;
}
/* Don't post text events for unprintable characters */
if (SDL_iscntrl((unsigned char)*text)) {
return 0;
}
/* Post the event, if desired */
posted = 0;
if (SDL_EventEnabled(SDL_EVENT_TEXT_INPUT)) {
SDL_Event event;
event.type = SDL_EVENT_TEXT_INPUT;
event.common.timestamp = 0;
event.text.windowID = keyboard->focus ? keyboard->focus->id : 0;
event.text.text = SDL_AllocateEventString(text);
if (!event.text.text) {
return 0;
}
posted = (SDL_PushEvent(&event) > 0);
}
return posted;
}
int SDL_SendEditingText(const char *text, int start, int length)
{
SDL_Keyboard *keyboard = &SDL_keyboard;
int posted;
if (!SDL_TextInputActive(keyboard->focus)) {
return 0;
}
if (!text) {
return 0;
}
/* Post the event, if desired */
posted = 0;
if (SDL_EventEnabled(SDL_EVENT_TEXT_EDITING)) {
SDL_Event event;
event.type = SDL_EVENT_TEXT_EDITING;
event.common.timestamp = 0;
event.edit.windowID = keyboard->focus ? keyboard->focus->id : 0;
event.edit.start = start;
event.edit.length = length;
event.edit.text = SDL_AllocateEventString(text);
if (!event.edit.text) {
return 0;
}
posted = (SDL_PushEvent(&event) > 0);
}
return posted;
}
void SDL_QuitKeyboard(void)
{
for (int i = SDL_keyboard_count; i--;) {
SDL_RemoveKeyboard(SDL_keyboards[i].instance_id, SDL_FALSE);
}
SDL_free(SDL_keyboards);
SDL_keyboards = NULL;
if (SDL_keyboard.keymap) {
SDL_DestroyKeymap(SDL_keyboard.keymap);
SDL_keyboard.keymap = NULL;
}
SDL_DelHintCallback(SDL_HINT_KEYCODE_OPTIONS,
SDL_KeycodeOptionsChanged, &SDL_keyboard);
}
const Uint8 *SDL_GetKeyboardState(int *numkeys)
{
SDL_Keyboard *keyboard = &SDL_keyboard;
if (numkeys != (int *)0) {
*numkeys = SDL_NUM_SCANCODES;
}
return keyboard->keystate;
}
SDL_Keymod SDL_GetModState(void)
{
SDL_Keyboard *keyboard = &SDL_keyboard;
return (SDL_Keymod)keyboard->modstate;
}
void SDL_SetModState(SDL_Keymod modstate)
{
SDL_Keyboard *keyboard = &SDL_keyboard;
keyboard->modstate = modstate;
}
/* Note that SDL_ToggleModState() is not a public API. SDL_SetModState() is. */
void SDL_ToggleModState(const SDL_Keymod modstate, const SDL_bool toggle)
{
SDL_Keyboard *keyboard = &SDL_keyboard;
if (toggle) {
keyboard->modstate |= modstate;
} else {
keyboard->modstate &= ~modstate;
}
}
SDL_Keycode SDL_GetKeyFromScancode(SDL_Scancode scancode, SDL_Keymod modstate)
{
return SDL_GetKeymapKeycode(SDL_keyboard.keymap, scancode, modstate);
}
SDL_Scancode SDL_GetScancodeFromKey(SDL_Keycode key, SDL_Keymod *modstate)
{
return SDL_GetKeymapScancode(SDL_keyboard.keymap, key, modstate);
}