Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
717
third_party/FreeRDP/client/SDL/SDL3/sdl_input.cpp
vendored
Normal file
717
third_party/FreeRDP/client/SDL/SDL3/sdl_input.cpp
vendored
Normal file
@@ -0,0 +1,717 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* FreeRDP SDL keyboard helper
|
||||
*
|
||||
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "sdl_input.hpp"
|
||||
#include "sdl_disp.hpp"
|
||||
#include "sdl_context.hpp"
|
||||
#include "sdl_utils.hpp"
|
||||
#include "sdl_prefs.hpp"
|
||||
#include "sdl_touch.hpp"
|
||||
|
||||
#include <SDL3/SDL_oldnames.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <freerdp/utils/string.h>
|
||||
#include <freerdp/scancode.h>
|
||||
#include <freerdp/locale/keyboard.h>
|
||||
#include <freerdp/locale/locale.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Uint32 sdl;
|
||||
const char* sdl_name;
|
||||
UINT32 rdp;
|
||||
const char* rdp_name;
|
||||
} scancode_entry_t;
|
||||
|
||||
#define STR(x) #x
|
||||
#define ENTRY(x, y) { x, STR(x), y, #y }
|
||||
static const scancode_entry_t map[] = {
|
||||
ENTRY(SDL_SCANCODE_UNKNOWN, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_A, RDP_SCANCODE_KEY_A),
|
||||
ENTRY(SDL_SCANCODE_B, RDP_SCANCODE_KEY_B),
|
||||
ENTRY(SDL_SCANCODE_C, RDP_SCANCODE_KEY_C),
|
||||
ENTRY(SDL_SCANCODE_D, RDP_SCANCODE_KEY_D),
|
||||
ENTRY(SDL_SCANCODE_E, RDP_SCANCODE_KEY_E),
|
||||
ENTRY(SDL_SCANCODE_F, RDP_SCANCODE_KEY_F),
|
||||
ENTRY(SDL_SCANCODE_G, RDP_SCANCODE_KEY_G),
|
||||
ENTRY(SDL_SCANCODE_H, RDP_SCANCODE_KEY_H),
|
||||
ENTRY(SDL_SCANCODE_I, RDP_SCANCODE_KEY_I),
|
||||
ENTRY(SDL_SCANCODE_J, RDP_SCANCODE_KEY_J),
|
||||
ENTRY(SDL_SCANCODE_K, RDP_SCANCODE_KEY_K),
|
||||
ENTRY(SDL_SCANCODE_L, RDP_SCANCODE_KEY_L),
|
||||
ENTRY(SDL_SCANCODE_M, RDP_SCANCODE_KEY_M),
|
||||
ENTRY(SDL_SCANCODE_N, RDP_SCANCODE_KEY_N),
|
||||
ENTRY(SDL_SCANCODE_O, RDP_SCANCODE_KEY_O),
|
||||
ENTRY(SDL_SCANCODE_P, RDP_SCANCODE_KEY_P),
|
||||
ENTRY(SDL_SCANCODE_Q, RDP_SCANCODE_KEY_Q),
|
||||
ENTRY(SDL_SCANCODE_R, RDP_SCANCODE_KEY_R),
|
||||
ENTRY(SDL_SCANCODE_S, RDP_SCANCODE_KEY_S),
|
||||
ENTRY(SDL_SCANCODE_T, RDP_SCANCODE_KEY_T),
|
||||
ENTRY(SDL_SCANCODE_U, RDP_SCANCODE_KEY_U),
|
||||
ENTRY(SDL_SCANCODE_V, RDP_SCANCODE_KEY_V),
|
||||
ENTRY(SDL_SCANCODE_W, RDP_SCANCODE_KEY_W),
|
||||
ENTRY(SDL_SCANCODE_X, RDP_SCANCODE_KEY_X),
|
||||
ENTRY(SDL_SCANCODE_Y, RDP_SCANCODE_KEY_Y),
|
||||
ENTRY(SDL_SCANCODE_Z, RDP_SCANCODE_KEY_Z),
|
||||
ENTRY(SDL_SCANCODE_1, RDP_SCANCODE_KEY_1),
|
||||
ENTRY(SDL_SCANCODE_2, RDP_SCANCODE_KEY_2),
|
||||
ENTRY(SDL_SCANCODE_3, RDP_SCANCODE_KEY_3),
|
||||
ENTRY(SDL_SCANCODE_4, RDP_SCANCODE_KEY_4),
|
||||
ENTRY(SDL_SCANCODE_5, RDP_SCANCODE_KEY_5),
|
||||
ENTRY(SDL_SCANCODE_6, RDP_SCANCODE_KEY_6),
|
||||
ENTRY(SDL_SCANCODE_7, RDP_SCANCODE_KEY_7),
|
||||
ENTRY(SDL_SCANCODE_8, RDP_SCANCODE_KEY_8),
|
||||
ENTRY(SDL_SCANCODE_9, RDP_SCANCODE_KEY_9),
|
||||
ENTRY(SDL_SCANCODE_0, RDP_SCANCODE_KEY_0),
|
||||
ENTRY(SDL_SCANCODE_RETURN, RDP_SCANCODE_RETURN),
|
||||
ENTRY(SDL_SCANCODE_ESCAPE, RDP_SCANCODE_ESCAPE),
|
||||
ENTRY(SDL_SCANCODE_BACKSPACE, RDP_SCANCODE_BACKSPACE),
|
||||
ENTRY(SDL_SCANCODE_TAB, RDP_SCANCODE_TAB),
|
||||
ENTRY(SDL_SCANCODE_SPACE, RDP_SCANCODE_SPACE),
|
||||
ENTRY(SDL_SCANCODE_MINUS, RDP_SCANCODE_OEM_MINUS),
|
||||
ENTRY(SDL_SCANCODE_CAPSLOCK, RDP_SCANCODE_CAPSLOCK),
|
||||
ENTRY(SDL_SCANCODE_F1, RDP_SCANCODE_F1),
|
||||
ENTRY(SDL_SCANCODE_F2, RDP_SCANCODE_F2),
|
||||
ENTRY(SDL_SCANCODE_F3, RDP_SCANCODE_F3),
|
||||
ENTRY(SDL_SCANCODE_F4, RDP_SCANCODE_F4),
|
||||
ENTRY(SDL_SCANCODE_F5, RDP_SCANCODE_F5),
|
||||
ENTRY(SDL_SCANCODE_F6, RDP_SCANCODE_F6),
|
||||
ENTRY(SDL_SCANCODE_F7, RDP_SCANCODE_F7),
|
||||
ENTRY(SDL_SCANCODE_F8, RDP_SCANCODE_F8),
|
||||
ENTRY(SDL_SCANCODE_F9, RDP_SCANCODE_F9),
|
||||
ENTRY(SDL_SCANCODE_F10, RDP_SCANCODE_F10),
|
||||
ENTRY(SDL_SCANCODE_F11, RDP_SCANCODE_F11),
|
||||
ENTRY(SDL_SCANCODE_F12, RDP_SCANCODE_F12),
|
||||
ENTRY(SDL_SCANCODE_F13, RDP_SCANCODE_F13),
|
||||
ENTRY(SDL_SCANCODE_F14, RDP_SCANCODE_F14),
|
||||
ENTRY(SDL_SCANCODE_F15, RDP_SCANCODE_F15),
|
||||
ENTRY(SDL_SCANCODE_F16, RDP_SCANCODE_F16),
|
||||
ENTRY(SDL_SCANCODE_F17, RDP_SCANCODE_F17),
|
||||
ENTRY(SDL_SCANCODE_F18, RDP_SCANCODE_F18),
|
||||
ENTRY(SDL_SCANCODE_F19, RDP_SCANCODE_F19),
|
||||
ENTRY(SDL_SCANCODE_F20, RDP_SCANCODE_F20),
|
||||
ENTRY(SDL_SCANCODE_F21, RDP_SCANCODE_F21),
|
||||
ENTRY(SDL_SCANCODE_F22, RDP_SCANCODE_F22),
|
||||
ENTRY(SDL_SCANCODE_F23, RDP_SCANCODE_F23),
|
||||
ENTRY(SDL_SCANCODE_F24, RDP_SCANCODE_F24),
|
||||
ENTRY(SDL_SCANCODE_NUMLOCKCLEAR, RDP_SCANCODE_NUMLOCK),
|
||||
ENTRY(SDL_SCANCODE_KP_DIVIDE, RDP_SCANCODE_DIVIDE),
|
||||
ENTRY(SDL_SCANCODE_KP_MULTIPLY, RDP_SCANCODE_MULTIPLY),
|
||||
ENTRY(SDL_SCANCODE_KP_MINUS, RDP_SCANCODE_SUBTRACT),
|
||||
ENTRY(SDL_SCANCODE_KP_PLUS, RDP_SCANCODE_ADD),
|
||||
ENTRY(SDL_SCANCODE_KP_ENTER, RDP_SCANCODE_RETURN_KP),
|
||||
ENTRY(SDL_SCANCODE_KP_1, RDP_SCANCODE_NUMPAD1),
|
||||
ENTRY(SDL_SCANCODE_KP_2, RDP_SCANCODE_NUMPAD2),
|
||||
ENTRY(SDL_SCANCODE_KP_3, RDP_SCANCODE_NUMPAD3),
|
||||
ENTRY(SDL_SCANCODE_KP_4, RDP_SCANCODE_NUMPAD4),
|
||||
ENTRY(SDL_SCANCODE_KP_5, RDP_SCANCODE_NUMPAD5),
|
||||
ENTRY(SDL_SCANCODE_KP_6, RDP_SCANCODE_NUMPAD6),
|
||||
ENTRY(SDL_SCANCODE_KP_7, RDP_SCANCODE_NUMPAD7),
|
||||
ENTRY(SDL_SCANCODE_KP_8, RDP_SCANCODE_NUMPAD8),
|
||||
ENTRY(SDL_SCANCODE_KP_9, RDP_SCANCODE_NUMPAD9),
|
||||
ENTRY(SDL_SCANCODE_KP_0, RDP_SCANCODE_NUMPAD0),
|
||||
ENTRY(SDL_SCANCODE_KP_PERIOD, RDP_SCANCODE_DECIMAL),
|
||||
ENTRY(SDL_SCANCODE_LCTRL, RDP_SCANCODE_LCONTROL),
|
||||
ENTRY(SDL_SCANCODE_LSHIFT, RDP_SCANCODE_LSHIFT),
|
||||
ENTRY(SDL_SCANCODE_LALT, RDP_SCANCODE_LMENU),
|
||||
ENTRY(SDL_SCANCODE_LGUI, RDP_SCANCODE_LWIN),
|
||||
ENTRY(SDL_SCANCODE_RCTRL, RDP_SCANCODE_RCONTROL),
|
||||
ENTRY(SDL_SCANCODE_RSHIFT, RDP_SCANCODE_RSHIFT),
|
||||
ENTRY(SDL_SCANCODE_RALT, RDP_SCANCODE_RMENU),
|
||||
ENTRY(SDL_SCANCODE_RGUI, RDP_SCANCODE_RWIN),
|
||||
ENTRY(SDL_SCANCODE_MODE, RDP_SCANCODE_APPS),
|
||||
ENTRY(SDL_SCANCODE_MUTE, RDP_SCANCODE_VOLUME_MUTE),
|
||||
ENTRY(SDL_SCANCODE_VOLUMEUP, RDP_SCANCODE_VOLUME_UP),
|
||||
ENTRY(SDL_SCANCODE_VOLUMEDOWN, RDP_SCANCODE_VOLUME_DOWN),
|
||||
ENTRY(SDL_SCANCODE_GRAVE, RDP_SCANCODE_OEM_3),
|
||||
ENTRY(SDL_SCANCODE_COMMA, RDP_SCANCODE_OEM_COMMA),
|
||||
ENTRY(SDL_SCANCODE_PERIOD, RDP_SCANCODE_OEM_PERIOD),
|
||||
ENTRY(SDL_SCANCODE_SLASH, RDP_SCANCODE_OEM_2),
|
||||
ENTRY(SDL_SCANCODE_BACKSLASH, RDP_SCANCODE_OEM_5),
|
||||
ENTRY(SDL_SCANCODE_SCROLLLOCK, RDP_SCANCODE_SCROLLLOCK),
|
||||
ENTRY(SDL_SCANCODE_INSERT, RDP_SCANCODE_INSERT),
|
||||
ENTRY(SDL_SCANCODE_PRINTSCREEN, RDP_SCANCODE_PRINTSCREEN),
|
||||
ENTRY(SDL_SCANCODE_HOME, RDP_SCANCODE_HOME),
|
||||
ENTRY(SDL_SCANCODE_DELETE, RDP_SCANCODE_DELETE),
|
||||
ENTRY(SDL_SCANCODE_RIGHT, RDP_SCANCODE_RIGHT),
|
||||
ENTRY(SDL_SCANCODE_LEFT, RDP_SCANCODE_LEFT),
|
||||
ENTRY(SDL_SCANCODE_DOWN, RDP_SCANCODE_DOWN),
|
||||
ENTRY(SDL_SCANCODE_UP, RDP_SCANCODE_UP),
|
||||
ENTRY(SDL_SCANCODE_SEMICOLON, RDP_SCANCODE_OEM_1),
|
||||
ENTRY(SDL_SCANCODE_PAUSE, RDP_SCANCODE_PAUSE),
|
||||
ENTRY(SDL_SCANCODE_PAGEUP, RDP_SCANCODE_PRIOR),
|
||||
ENTRY(SDL_SCANCODE_END, RDP_SCANCODE_END),
|
||||
ENTRY(SDL_SCANCODE_PAGEDOWN, RDP_SCANCODE_NEXT),
|
||||
ENTRY(SDL_SCANCODE_MEDIA_NEXT_TRACK, RDP_SCANCODE_MEDIA_NEXT_TRACK),
|
||||
ENTRY(SDL_SCANCODE_MEDIA_PREVIOUS_TRACK, RDP_SCANCODE_MEDIA_PREV_TRACK),
|
||||
ENTRY(SDL_SCANCODE_MEDIA_STOP, RDP_SCANCODE_MEDIA_STOP),
|
||||
ENTRY(SDL_SCANCODE_MEDIA_PLAY, RDP_SCANCODE_MEDIA_PLAY_PAUSE),
|
||||
ENTRY(SDL_SCANCODE_MUTE, RDP_SCANCODE_VOLUME_MUTE),
|
||||
ENTRY(SDL_SCANCODE_MEDIA_SELECT, RDP_SCANCODE_LAUNCH_MEDIA_SELECT),
|
||||
ENTRY(SDL_SCANCODE_SYSREQ, RDP_SCANCODE_SYSREQ),
|
||||
ENTRY(SDL_SCANCODE_LEFTBRACKET, RDP_SCANCODE_OEM_4),
|
||||
ENTRY(SDL_SCANCODE_RIGHTBRACKET, RDP_SCANCODE_OEM_6),
|
||||
ENTRY(SDL_SCANCODE_APOSTROPHE, RDP_SCANCODE_OEM_7),
|
||||
ENTRY(SDL_SCANCODE_NONUSBACKSLASH, RDP_SCANCODE_OEM_102),
|
||||
ENTRY(SDL_SCANCODE_SLEEP, RDP_SCANCODE_SLEEP),
|
||||
ENTRY(SDL_SCANCODE_EQUALS, RDP_SCANCODE_OEM_PLUS),
|
||||
ENTRY(SDL_SCANCODE_KP_COMMA, RDP_SCANCODE_DECIMAL),
|
||||
ENTRY(SDL_SCANCODE_FIND, RDP_SCANCODE_BROWSER_SEARCH),
|
||||
ENTRY(SDL_SCANCODE_RETURN2, RDP_SCANCODE_RETURN_KP),
|
||||
ENTRY(SDL_SCANCODE_AC_SEARCH, RDP_SCANCODE_BROWSER_SEARCH),
|
||||
ENTRY(SDL_SCANCODE_AC_HOME, RDP_SCANCODE_BROWSER_HOME),
|
||||
ENTRY(SDL_SCANCODE_AC_BACK, RDP_SCANCODE_BROWSER_BACK),
|
||||
ENTRY(SDL_SCANCODE_AC_FORWARD, RDP_SCANCODE_BROWSER_FORWARD),
|
||||
ENTRY(SDL_SCANCODE_AC_STOP, RDP_SCANCODE_BROWSER_STOP),
|
||||
|
||||
ENTRY(SDL_SCANCODE_NONUSHASH, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_APPLICATION, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_POWER, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_EQUALS, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_EXECUTE, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_HELP, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_MENU, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_SELECT, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_STOP, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_AGAIN, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_UNDO, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_CUT, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_COPY, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_PASTE, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_EQUALSAS400, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_INTERNATIONAL1, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_INTERNATIONAL2, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_INTERNATIONAL3, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_INTERNATIONAL4, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_INTERNATIONAL5, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_INTERNATIONAL6, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_INTERNATIONAL7, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_INTERNATIONAL8, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_INTERNATIONAL9, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_LANG1, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_LANG2, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_LANG3, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_LANG4, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_LANG5, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_LANG6, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_LANG7, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_LANG8, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_LANG9, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_ALTERASE, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_CANCEL, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_CLEAR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_PRIOR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_SEPARATOR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_OUT, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_OPER, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_CLEARAGAIN, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_CRSEL, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_EXSEL, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_00, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_000, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_THOUSANDSSEPARATOR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_DECIMALSEPARATOR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_CURRENCYUNIT, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_CURRENCYSUBUNIT, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_LEFTPAREN, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_RIGHTPAREN, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_LEFTBRACE, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_RIGHTBRACE, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_TAB, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_BACKSPACE, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_A, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_B, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_C, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_D, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_E, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_F, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_XOR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_POWER, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_PERCENT, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_LESS, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_GREATER, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_AMPERSAND, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_DBLAMPERSAND, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_VERTICALBAR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_DBLVERTICALBAR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_COLON, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_HASH, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_SPACE, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_AT, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_EXCLAM, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_MEMSTORE, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_MEMRECALL, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_MEMCLEAR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_MEMADD, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_MEMSUBTRACT, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_MEMMULTIPLY, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_MEMDIVIDE, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_PLUSMINUS, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_CLEAR, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_CLEARENTRY, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_BINARY, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_OCTAL, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_KP_DECIMAL, RDP_SCANCODE_DECIMAL),
|
||||
ENTRY(SDL_SCANCODE_KP_HEXADECIMAL, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_AC_REFRESH, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_AC_BOOKMARKS, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_MEDIA_EJECT, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_MEDIA_REWIND, RDP_SCANCODE_UNKNOWN),
|
||||
ENTRY(SDL_SCANCODE_MEDIA_FAST_FORWARD, RDP_SCANCODE_UNKNOWN)
|
||||
};
|
||||
|
||||
[[nodiscard]] static UINT32 sdl_get_kbd_flags()
|
||||
{
|
||||
UINT32 flags = 0;
|
||||
|
||||
SDL_Keymod mod = SDL_GetModState();
|
||||
if ((mod & SDL_KMOD_NUM) != 0)
|
||||
flags |= KBD_SYNC_NUM_LOCK;
|
||||
if ((mod & SDL_KMOD_CAPS) != 0)
|
||||
flags |= KBD_SYNC_CAPS_LOCK;
|
||||
if ((mod & SDL_KMOD_SCROLL) != 0)
|
||||
flags |= KBD_SYNC_SCROLL_LOCK;
|
||||
|
||||
// TODO: KBD_SYNC_KANA_LOCK
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
bool sdlInput::keyboard_sync_state()
|
||||
{
|
||||
const UINT32 syncFlags = sdl_get_kbd_flags();
|
||||
return freerdp_input_send_synchronize_event(_sdl->context()->input, syncFlags);
|
||||
}
|
||||
|
||||
bool sdlInput::keyboard_focus_in()
|
||||
{
|
||||
auto input = _sdl->context()->input;
|
||||
WINPR_ASSERT(input);
|
||||
|
||||
auto syncFlags = sdl_get_kbd_flags();
|
||||
if (!freerdp_input_send_focus_in_event(input, WINPR_ASSERTING_INT_CAST(uint16_t, syncFlags)))
|
||||
return false;
|
||||
|
||||
/* finish with a mouse pointer position like mstsc.exe if required */
|
||||
// TODO: fullscreen/remote app
|
||||
float fx = 0.0f;
|
||||
float fy = 0.0f;
|
||||
SDL_GetMouseState(&fx, &fy);
|
||||
|
||||
auto w = SDL_GetMouseFocus();
|
||||
const auto& pos = _sdl->screenToPixel(SDL_GetWindowID(w), SDL_FPoint{ fx, fy });
|
||||
|
||||
return freerdp_client_send_button_event(_sdl->common(), FALSE, PTR_FLAGS_MOVE,
|
||||
static_cast<Sint32>(pos.x), static_cast<Sint32>(pos.y));
|
||||
}
|
||||
|
||||
/* This function is called to update the keyboard indicator LED */
|
||||
BOOL sdlInput::keyboard_set_indicators(rdpContext* context, UINT16 led_flags)
|
||||
{
|
||||
WINPR_UNUSED(context);
|
||||
|
||||
SDL_Keymod state = SDL_KMOD_NONE;
|
||||
|
||||
if ((led_flags & KBD_SYNC_NUM_LOCK) != 0)
|
||||
state |= SDL_KMOD_NUM;
|
||||
if ((led_flags & KBD_SYNC_CAPS_LOCK) != 0)
|
||||
state |= SDL_KMOD_CAPS;
|
||||
if ((led_flags & KBD_SYNC_SCROLL_LOCK) != 0)
|
||||
state |= SDL_KMOD_SCROLL;
|
||||
if ((led_flags & KBD_SYNC_KANA_LOCK) != 0)
|
||||
state |= SDL_KMOD_LEVEL5;
|
||||
|
||||
SDL_SetModState(state);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* This function is called to set the IME state */
|
||||
BOOL sdlInput::keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeState,
|
||||
UINT32 imeConvMode)
|
||||
{
|
||||
auto sdl = reinterpret_cast<SdlContext*>(context);
|
||||
if (!context)
|
||||
return FALSE;
|
||||
|
||||
WLog_Print(sdl->getWLog(), WLOG_WARN,
|
||||
"KeyboardSetImeStatus(unitId=%04" PRIx16 ", imeState=%08" PRIx32
|
||||
", imeConvMode=%08" PRIx32 ") ignored",
|
||||
imeId, imeState, imeConvMode);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
[[nodiscard]] static const std::map<std::string, uint32_t>& getSdlMap()
|
||||
{
|
||||
static std::map<std::string, uint32_t> s_map = {
|
||||
{ "KMOD_LSHIFT", SDL_KMOD_LSHIFT }, { "KMOD_RSHIFT", SDL_KMOD_RSHIFT },
|
||||
{ "KMOD_LCTRL", SDL_KMOD_LCTRL }, { "KMOD_RCTRL", SDL_KMOD_RCTRL },
|
||||
{ "KMOD_LALT", SDL_KMOD_LALT }, { "KMOD_RALT", SDL_KMOD_RALT },
|
||||
{ "KMOD_LGUI", SDL_KMOD_LGUI }, { "KMOD_RGUI", SDL_KMOD_RGUI },
|
||||
{ "KMOD_NUM", SDL_KMOD_NUM }, { "KMOD_CAPS", SDL_KMOD_CAPS },
|
||||
{ "KMOD_MODE", SDL_KMOD_MODE }, { "KMOD_SCROLL", SDL_KMOD_SCROLL },
|
||||
{ "KMOD_CTRL", SDL_KMOD_CTRL }, { "KMOD_SHIFT", SDL_KMOD_SHIFT },
|
||||
{ "KMOD_ALT", SDL_KMOD_ALT }, { "KMOD_GUI", SDL_KMOD_GUI },
|
||||
{ "KMOD_NONE", SDL_KMOD_NONE }, { "SDL_KMOD_LSHIFT", SDL_KMOD_LSHIFT },
|
||||
{ "SDL_KMOD_RSHIFT", SDL_KMOD_RSHIFT }, { "SDL_KMOD_LCTRL", SDL_KMOD_LCTRL },
|
||||
{ "SDL_KMOD_RCTRL", SDL_KMOD_RCTRL }, { "SDL_KMOD_LALT", SDL_KMOD_LALT },
|
||||
{ "SDL_KMOD_RALT", SDL_KMOD_RALT }, { "SDL_KMOD_LGUI", SDL_KMOD_LGUI },
|
||||
{ "SDL_KMOD_RGUI", SDL_KMOD_RGUI }, { "SDL_KMOD_NUM", SDL_KMOD_NUM },
|
||||
{ "SDL_KMOD_CAPS", SDL_KMOD_CAPS }, { "SDL_KMOD_MODE", SDL_KMOD_MODE },
|
||||
{ "SDL_KMOD_SCROLL", SDL_KMOD_SCROLL }, { "SDL_KMOD_CTRL", SDL_KMOD_CTRL },
|
||||
{ "SDL_KMOD_SHIFT", SDL_KMOD_SHIFT }, { "SDL_KMOD_ALT", SDL_KMOD_ALT },
|
||||
{ "SDL_KMOD_GUI", SDL_KMOD_GUI }, { "SDL_KMOD_NONE", SDL_KMOD_NONE }
|
||||
};
|
||||
|
||||
return s_map;
|
||||
}
|
||||
|
||||
[[nodiscard]] static std::string modbyvalue(uint32_t val)
|
||||
{
|
||||
for (const auto& v : getSdlMap())
|
||||
{
|
||||
if (v.second == val)
|
||||
{
|
||||
return v.first;
|
||||
}
|
||||
}
|
||||
return "KMOD_UNKNONW";
|
||||
}
|
||||
|
||||
[[nodiscard]] static std::string masktostr(uint32_t mask)
|
||||
{
|
||||
if (mask == 0)
|
||||
return "<NONE>";
|
||||
|
||||
std::string str = "<";
|
||||
for (uint32_t x = 0; x < 32; x++)
|
||||
{
|
||||
uint32_t cmask = 1 << x;
|
||||
if ((mask & cmask) != 0)
|
||||
{
|
||||
auto s = modbyvalue(cmask);
|
||||
if (str.size() > 1)
|
||||
{
|
||||
str += ">+<";
|
||||
}
|
||||
str += s;
|
||||
}
|
||||
}
|
||||
str += ">";
|
||||
return str;
|
||||
}
|
||||
|
||||
bool sdlInput::prefToEnabled()
|
||||
{
|
||||
bool enabled = true;
|
||||
const auto& m = getSdlMap();
|
||||
for (const auto& val : SdlPref::instance()->get_array("SDL_KeyModMask", { "KMOD_RSHIFT" }))
|
||||
{
|
||||
auto it = m.find(val);
|
||||
if (it != m.end())
|
||||
{
|
||||
if (it->second == SDL_KMOD_NONE)
|
||||
enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_Print(_sdl->getWLog(), WLOG_WARN,
|
||||
"Invalid config::SDL_KeyModMask entry value '%s', disabling hotkeys",
|
||||
val.c_str());
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
return enabled;
|
||||
}
|
||||
|
||||
uint32_t sdlInput::prefToMask()
|
||||
{
|
||||
const auto& m = getSdlMap();
|
||||
uint32_t mod = SDL_KMOD_NONE;
|
||||
for (const auto& val : SdlPref::instance()->get_array("SDL_KeyModMask", { "KMOD_RSHIFT" }))
|
||||
{
|
||||
auto it = m.find(val);
|
||||
if (it != m.end())
|
||||
mod |= it->second;
|
||||
}
|
||||
return mod;
|
||||
}
|
||||
|
||||
[[nodiscard]] static const char* sdl_scancode_name(Uint32 scancode)
|
||||
{
|
||||
for (const auto& cur : map)
|
||||
{
|
||||
if (cur.sdl == scancode)
|
||||
return cur.sdl_name;
|
||||
}
|
||||
|
||||
return "SDL_SCANCODE_UNKNOWN";
|
||||
}
|
||||
|
||||
[[nodiscard]] static Uint32 sdl_scancode_val(const char* scancodeName)
|
||||
{
|
||||
for (const auto& cur : map)
|
||||
{
|
||||
if (strcmp(cur.sdl_name, scancodeName) == 0)
|
||||
return cur.sdl;
|
||||
}
|
||||
|
||||
return SDL_SCANCODE_UNKNOWN;
|
||||
}
|
||||
|
||||
#if defined(WITH_DEBUG_SDL_KBD_EVENTS)
|
||||
[[nodiscard]] static const char* sdl_rdp_scancode_name(UINT32 scancode)
|
||||
{
|
||||
for (const auto& cur : map)
|
||||
{
|
||||
if (cur.rdp == scancode)
|
||||
return cur.rdp_name;
|
||||
}
|
||||
|
||||
return "RDP_SCANCODE_UNKNOWN";
|
||||
}
|
||||
|
||||
[[nodiscard]] static UINT32 sdl_rdp_scancode_val(const char* scancodeName)
|
||||
{
|
||||
for (const auto& cur : map)
|
||||
{
|
||||
if (strcmp(cur.rdp_name, scancodeName) == 0)
|
||||
return cur.rdp;
|
||||
}
|
||||
|
||||
return RDP_SCANCODE_UNKNOWN;
|
||||
}
|
||||
#endif
|
||||
|
||||
UINT32 sdlInput::scancode_to_rdp(Uint32 scancode)
|
||||
{
|
||||
UINT32 rdp = RDP_SCANCODE_UNKNOWN;
|
||||
|
||||
for (const auto& cur : map)
|
||||
{
|
||||
if (cur.sdl == scancode)
|
||||
{
|
||||
rdp = cur.rdp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(WITH_DEBUG_SDL_KBD_EVENTS)
|
||||
auto code = static_cast<SDL_Scancode>(scancode);
|
||||
WLog_Print(_sdl->getWLog(), WLOG_DEBUG, "got %s [%s] -> [%s]", SDL_GetScancodeName(code),
|
||||
sdl_scancode_name(scancode), sdl_rdp_scancode_name(rdp));
|
||||
#endif
|
||||
return rdp;
|
||||
}
|
||||
|
||||
uint32_t sdlInput::prefKeyValue(const std::string& key, uint32_t fallback)
|
||||
{
|
||||
auto item = SdlPref::instance()->get_string(key);
|
||||
if (item.empty())
|
||||
return fallback;
|
||||
auto val = sdl_scancode_val(item.c_str());
|
||||
if (val == SDL_SCANCODE_UNKNOWN)
|
||||
return fallback;
|
||||
return val;
|
||||
}
|
||||
|
||||
std::list<std::string> sdlInput::tokenize(const std::string& data, const std::string& delimiter)
|
||||
{
|
||||
size_t lastpos = 0;
|
||||
size_t pos = 0;
|
||||
std::list<std::string> list;
|
||||
while ((pos = data.find(delimiter, lastpos)) != std::string::npos)
|
||||
{
|
||||
auto token = data.substr(lastpos, pos);
|
||||
lastpos = pos + 1;
|
||||
list.push_back(std::move(token));
|
||||
}
|
||||
auto token = data.substr(lastpos);
|
||||
list.push_back(std::move(token));
|
||||
return list;
|
||||
}
|
||||
|
||||
bool sdlInput::extract(const std::string& token, uint32_t& key, uint32_t& value)
|
||||
{
|
||||
return freerdp_extract_key_value(token.c_str(), &key, &value);
|
||||
}
|
||||
|
||||
bool sdlInput::handleEvent(const SDL_KeyboardEvent& ev)
|
||||
{
|
||||
const UINT32 rdp_scancode = scancode_to_rdp(ev.scancode);
|
||||
const SDL_Keymod mods = SDL_GetModState();
|
||||
|
||||
if (_hotkeysEnabled && (mods & _hotkeyModmask) == _hotkeyModmask)
|
||||
{
|
||||
if (ev.type == SDL_EVENT_KEY_DOWN)
|
||||
{
|
||||
if (ev.scancode == _hotkeyFullscreen)
|
||||
{
|
||||
WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, toggling fullscreen state",
|
||||
masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyFullscreen));
|
||||
if (!keyboard_sync_state())
|
||||
return false;
|
||||
return _sdl->toggleFullscreen();
|
||||
}
|
||||
if (ev.scancode == _hotkeyResizable)
|
||||
{
|
||||
WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, toggling resizeable state",
|
||||
masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyResizable));
|
||||
if (!keyboard_sync_state())
|
||||
return false;
|
||||
return _sdl->toggleResizeable();
|
||||
}
|
||||
|
||||
if (ev.scancode == _hotkeyGrab)
|
||||
{
|
||||
WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, toggling grab state",
|
||||
masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyGrab));
|
||||
if (!keyboard_sync_state())
|
||||
return false;
|
||||
return keyboard_grab(ev.windowID, !_sdl->grabKeyboard());
|
||||
}
|
||||
if (ev.scancode == _hotkeyDisconnect)
|
||||
{
|
||||
WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, disconnecting RDP session",
|
||||
masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyDisconnect));
|
||||
if (!keyboard_sync_state())
|
||||
return false;
|
||||
freerdp_abort_connect_context(_sdl->context());
|
||||
return true;
|
||||
}
|
||||
if (ev.scancode == _hotkeyMinimize)
|
||||
{
|
||||
WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, minimizing client",
|
||||
masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyMinimize));
|
||||
if (!keyboard_sync_state())
|
||||
return false;
|
||||
return _sdl->setMinimized();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(WITH_DEBUG_KBD)
|
||||
{
|
||||
const BOOL ex = RDP_SCANCODE_EXTENDED(rdp_scancode);
|
||||
const DWORD sc = RDP_SCANCODE_CODE(rdp_scancode);
|
||||
WLog_Print(_sdl->getWLog(), WLOG_DEBUG,
|
||||
"SDL keycode: %02" PRIX32 " -> rdp code: [%04" PRIx16 "] %02" PRIX8 "%s",
|
||||
ev.scancode, rdp_scancode, sc, ex ? " extended" : "");
|
||||
}
|
||||
#endif
|
||||
|
||||
auto scancode = freerdp_keyboard_remap_key(_remapTable, rdp_scancode);
|
||||
#if defined(WITH_DEBUG_KBD)
|
||||
{
|
||||
const BOOL ex = RDP_SCANCODE_EXTENDED(scancode);
|
||||
const DWORD sc = RDP_SCANCODE_CODE(scancode);
|
||||
WLog_Print(_sdl->getWLog(), WLOG_DEBUG,
|
||||
"SDL keycode: %02" PRIX32 " -> remapped rdp code: [%04" PRIx16 "] %02" PRIX8
|
||||
"%s",
|
||||
ev.scancode, scancode, sc, ex ? " extended" : "");
|
||||
}
|
||||
#endif
|
||||
return freerdp_input_send_keyboard_event_ex(_sdl->context()->input,
|
||||
ev.type == SDL_EVENT_KEY_DOWN, ev.repeat, scancode);
|
||||
}
|
||||
|
||||
bool sdlInput::keyboard_grab(Uint32 windowID, bool enable)
|
||||
{
|
||||
const auto window = _sdl->getWindowForId(windowID);
|
||||
if (!window)
|
||||
return false;
|
||||
|
||||
auto settings = _sdl->context()->settings;
|
||||
auto kbd_enabled = freerdp_settings_get_bool(settings, FreeRDP_GrabKeyboard);
|
||||
auto status = enable && kbd_enabled;
|
||||
if (!_sdl->setGrabKeyboard(status))
|
||||
WLog_Print(_sdl->getWLog(), WLOG_WARN, "Failed to ungrab keyboard");
|
||||
return window->grabKeyboard(status);
|
||||
}
|
||||
|
||||
bool sdlInput::mouse_focus(Uint32 windowID)
|
||||
{
|
||||
if (_lastWindowID != windowID)
|
||||
{
|
||||
_lastWindowID = windowID;
|
||||
auto window = _sdl->getWindowForId(windowID);
|
||||
if (!window)
|
||||
return false;
|
||||
|
||||
window->raise();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sdlInput::mouse_grab(Uint32 windowID, bool enable)
|
||||
{
|
||||
auto window = _sdl->getWindowForId(windowID);
|
||||
if (!window)
|
||||
return false;
|
||||
if (!_sdl->setGrabMouse(enable))
|
||||
WLog_Print(_sdl->getWLog(), WLOG_WARN, "Failed to ungrab mouse");
|
||||
return window->grabMouse(enable);
|
||||
}
|
||||
|
||||
sdlInput::sdlInput(SdlContext* sdl)
|
||||
: _sdl(sdl), _lastWindowID(UINT32_MAX), _hotkeysEnabled(prefToEnabled()),
|
||||
_hotkeyModmask(prefToMask())
|
||||
{
|
||||
_hotkeyFullscreen = prefKeyValue("SDL_Fullscreen", SDL_SCANCODE_RETURN);
|
||||
_hotkeyResizable = prefKeyValue("SDL_Resizeable", SDL_SCANCODE_R);
|
||||
_hotkeyGrab = prefKeyValue("SDL_Grab", SDL_SCANCODE_G);
|
||||
_hotkeyDisconnect = prefKeyValue("SDL_Disconnect", SDL_SCANCODE_D);
|
||||
_hotkeyMinimize = prefKeyValue("SDL_Minimize", SDL_SCANCODE_M);
|
||||
}
|
||||
|
||||
sdlInput::~sdlInput()
|
||||
{
|
||||
freerdp_keyboard_remap_free(_remapTable);
|
||||
}
|
||||
|
||||
bool sdlInput::initialize()
|
||||
{
|
||||
auto settings = _sdl->context()->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
WINPR_ASSERT(!_remapTable);
|
||||
|
||||
{
|
||||
auto list = freerdp_settings_get_string(settings, FreeRDP_KeyboardRemappingList);
|
||||
_remapTable = freerdp_keyboard_remap_string_to_list(list);
|
||||
if (!_remapTable)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (freerdp_settings_get_uint32(settings, FreeRDP_KeyboardLayout) == 0)
|
||||
{
|
||||
DWORD KeyboardLayout = 0;
|
||||
|
||||
freerdp_detect_keyboard_layout_from_system_locale(&KeyboardLayout);
|
||||
if (KeyboardLayout == 0)
|
||||
KeyboardLayout = ENGLISH_UNITED_STATES;
|
||||
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardLayout, KeyboardLayout))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user