FreeRDP
Loading...
Searching...
No Matches
sdlInput Class Reference

#include <sdl_kbd.hpp>

Public Member Functions

 sdlInput (SdlContext *sdl)
 
 sdlInput (const sdlInput &other)=delete
 
 sdlInput (sdlInput &&other)=delete
 
sdlInput & operator= (const sdlInput &other)=delete
 
sdlInput & operator= (sdlInput &&other)=delete
 
BOOL keyboard_sync_state ()
 
BOOL keyboard_focus_in ()
 
BOOL keyboard_handle_event (const SDL_KeyboardEvent *ev)
 
BOOL keyboard_grab (Uint32 windowID, bool enable)
 
BOOL mouse_focus (Uint32 windowID)
 
BOOL mouse_grab (Uint32 windowID, SDL_bool enable)
 
 sdlInput (SdlContext *sdl)
 
 sdlInput (const sdlInput &other)=delete
 
 sdlInput (sdlInput &&other)=delete
 
sdlInput & operator= (const sdlInput &other)=delete
 
sdlInput & operator= (sdlInput &&other)=delete
 
bool initialize ()
 
bool keyboard_sync_state ()
 
bool keyboard_focus_in ()
 
bool handleEvent (const SDL_KeyboardEvent &ev)
 
bool keyboard_grab (Uint32 windowID, bool enable)
 
bool mouse_focus (Uint32 windowID)
 
bool mouse_grab (Uint32 windowID, bool enable)
 
bool prefToEnabled ()
 
uint32_t prefToMask ()
 

Static Public Member Functions

static BOOL keyboard_set_indicators (rdpContext *context, UINT16 led_flags)
 
static BOOL keyboard_set_ime_status (rdpContext *context, UINT16 imeId, UINT32 imeState, UINT32 imeConvMode)
 
static bool prefToEnabled ()
 
static uint32_t prefToMask ()
 
static uint32_t prefKeyValue (const std::string &key, uint32_t fallback=SDL_SCANCODE_UNKNOWN)
 
static BOOL keyboard_set_indicators (rdpContext *context, UINT16 led_flags)
 
static BOOL keyboard_set_ime_status (rdpContext *context, UINT16 imeId, UINT32 imeState, UINT32 imeConvMode)
 
static uint32_t prefKeyValue (const std::string &key, uint32_t fallback=SDL_SCANCODE_UNKNOWN)
 

Detailed Description

FreeRDP: A Remote Desktop Protocol Implementation SDL Client keyboard helper

Copyright 2022 Armin Novak armin.nosp@m..nov.nosp@m.ak@th.nosp@m.inca.nosp@m.st.co.nosp@m.m

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.

Definition at line 34 of file sdl_kbd.hpp.

Constructor & Destructor Documentation

◆ sdlInput()

sdlInput::sdlInput ( SdlContext *  sdl)
explicit

Definition at line 598 of file sdl_kbd.cpp.

599 : _sdl(sdl), _lastWindowID(UINT32_MAX), _hotkeysEnabled(prefToEnabled()),
600 _hotkeyModmask(prefToMask())
601{
602 auto list =
603 freerdp_settings_get_string(_sdl->context()->settings, FreeRDP_KeyboardRemappingList);
604 _remapTable = freerdp_keyboard_remap_string_to_list(list);
605 assert(_remapTable);
606 _hotkeyFullscreen = prefKeyValue("SDL_Fullscreen", SDL_SCANCODE_RETURN);
607 _hotkeyResizable = prefKeyValue("SDL_Resizeable", SDL_SCANCODE_R);
608 _hotkeyGrab = prefKeyValue("SDL_Grab", SDL_SCANCODE_G);
609 _hotkeyDisconnect = prefKeyValue("SDL_Disconnect", SDL_SCANCODE_D);
610 _hotkeyMinimize = prefKeyValue("SDL_Minimize", SDL_SCANCODE_M);
611}
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.

◆ ~sdlInput()

sdlInput::~sdlInput ( )

Definition at line 613 of file sdl_kbd.cpp.

614{
615 freerdp_keyboard_remap_free(_remapTable);
616}

Member Function Documentation

◆ handleEvent()

bool sdlInput::handleEvent ( const SDL_KeyboardEvent &  ev)

Definition at line 574 of file SDL3/sdl_input.cpp.

575{
576 UINT32 rdp_scancode = scancode_to_rdp(ev.scancode);
577#if defined(_WIN32)
578 /* CJK IMEs on Windows may set the extended bit for Right Shift, producing
579 * the invalid scan code E0 36. SDL maps that event to SDL_SCANCODE_UNKNOWN,
580 * so normalize it in the same way as the native Windows client. */
581 if ((rdp_scancode == RDP_SCANCODE_UNKNOWN) && (ev.raw == 0xE036))
582 rdp_scancode = RDP_SCANCODE_RSHIFT;
583#endif
584 /* The modifiers held when this key was pressed: SDL_GetModState() is the state after every
585 * event already queued, so a hotkey could be missed, or fire on a plain key typed just
586 * before a modifier. */
587 const SDL_Keymod mods = ev.mod;
588
589 if (_hotkeysEnabled && (mods & _hotkeyModmask) == _hotkeyModmask)
590 {
591 if (ev.type == SDL_EVENT_KEY_DOWN)
592 {
593 if (ev.scancode == _hotkeyFullscreen)
594 {
595 WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, toggling fullscreen state",
596 masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyFullscreen));
597 if (!keyboard_sync_state())
598 return false;
599 return _sdl->toggleFullscreen();
600 }
601 if (ev.scancode == _hotkeyResizable)
602 {
603 WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, toggling resizeable state",
604 masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyResizable));
605 if (!keyboard_sync_state())
606 return false;
607 return _sdl->toggleResizeable();
608 }
609
610 if (ev.scancode == _hotkeyGrab)
611 {
612 WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, toggling grab state",
613 masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyGrab));
614 if (!keyboard_sync_state())
615 return false;
616 return keyboard_grab(ev.windowID, !_sdl->grabKeyboard());
617 }
618 if (ev.scancode == _hotkeyDisconnect)
619 {
620 WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, disconnecting RDP session",
621 masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyDisconnect));
622 if (!keyboard_sync_state())
623 return false;
624 freerdp_abort_connect_context(_sdl->context());
625 return true;
626 }
627 if (ev.scancode == _hotkeyMinimize)
628 {
629 WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, minimizing client",
630 masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyMinimize));
631 if (!keyboard_sync_state())
632 return false;
633 return _sdl->setMinimized();
634 }
635 }
636 }
637
638#if defined(WITH_DEBUG_KBD)
639 {
640 const BOOL ex = RDP_SCANCODE_EXTENDED(rdp_scancode);
641 const DWORD sc = RDP_SCANCODE_CODE(rdp_scancode);
642 WLog_Print(_sdl->getWLog(), WLOG_DEBUG,
643 "SDL keycode: %02" PRIX32 " -> rdp code: [%04" PRIx16 "] %02" PRIX8 "%s",
644 ev.scancode, rdp_scancode, sc, ex ? " extended" : "");
645 }
646#endif
647
648 auto scancode = freerdp_keyboard_remap_key(_remapTable, rdp_scancode);
649#if defined(WITH_DEBUG_KBD)
650 {
651 const BOOL ex = RDP_SCANCODE_EXTENDED(scancode);
652 const DWORD sc = RDP_SCANCODE_CODE(scancode);
653 WLog_Print(_sdl->getWLog(), WLOG_DEBUG,
654 "SDL keycode: %02" PRIX32 " -> remapped rdp code: [%04" PRIx16 "] %02" PRIX8
655 "%s",
656 ev.scancode, scancode, sc, ex ? " extended" : "");
657 }
658#endif
659 if (freerdp_settings_get_bool(_sdl->context()->settings, FreeRDP_UnicodeInput))
660 {
661 /* With key_event false the keycode follows the layout, also for non-Latin ones, where key
662 * events carry the QWERTY letter (SDL_HINT_KEYCODE_OPTIONS). */
663 const auto key = SDL_GetKeyFromScancode(ev.scancode, mods, false);
664 std::array<char, 5> str = {};
665 if ((key >= 0x20) && (key != SDLK_DELETE) && (key <= 0x10FFFF))
666 std::ignore = SDL_UCS4ToUTF8(key, str.data());
667 return freerdp_client_send_key_as_unicode(
668 _sdl->common(), (ev.type == SDL_EVENT_KEY_DOWN) ? 0 : KBD_FLAGS_RELEASE, str.data(),
669 scancode, sdl_get_kbd_modmask(mods));
670 }
671 return freerdp_input_send_keyboard_event_ex(_sdl->context()->input,
672 ev.type == SDL_EVENT_KEY_DOWN, ev.repeat, scancode);
673}
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.

◆ initialize()

bool sdlInput::initialize ( )

Definition at line 729 of file SDL3/sdl_input.cpp.

730{
731 auto settings = _sdl->context()->settings;
732 WINPR_ASSERT(settings);
733 WINPR_ASSERT(!_remapTable);
734
735 {
736 auto list = freerdp_settings_get_string(settings, FreeRDP_KeyboardRemappingList);
737 _remapTable = freerdp_keyboard_remap_string_to_list(list);
738 if (!_remapTable)
739 return false;
740 }
741
742 if (freerdp_settings_get_uint32(settings, FreeRDP_KeyboardLayout) == 0)
743 {
744 DWORD KeyboardLayout = 0;
745
746 freerdp_detect_keyboard_layout_from_system_locale(&KeyboardLayout);
747 if (KeyboardLayout == 0)
748 KeyboardLayout = ENGLISH_UNITED_STATES;
749
750 if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardLayout, KeyboardLayout))
751 return false;
752 }
753 return true;
754}
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.

◆ keyboard_focus_in()

bool sdlInput::keyboard_focus_in ( )

Definition at line 323 of file sdl_kbd.cpp.

324{
325 auto input = _sdl->context()->input;
326 WINPR_ASSERT(input);
327
328 auto syncFlags = sdl_get_kbd_flags();
329 freerdp_input_send_focus_in_event(input, WINPR_ASSERTING_INT_CAST(UINT16, syncFlags));
330
331 /* finish with a mouse pointer position like mstsc.exe if required */
332 // TODO: fullscreen/remote app
333 int x = 0;
334 int y = 0;
335 if (_sdl->fullscreen)
336 {
337 SDL_GetGlobalMouseState(&x, &y);
338 }
339 else
340 {
341 SDL_GetMouseState(&x, &y);
342 }
343 auto w = SDL_GetMouseFocus();
344 if (w)
345 {
346 auto id = SDL_GetWindowID(w);
347 sdl_scale_coordinates(_sdl, id, &x, &y, TRUE, TRUE);
348 }
349 return freerdp_client_send_button_event(_sdl->common(), FALSE, PTR_FLAGS_MOVE, x, y);
350}

◆ keyboard_grab()

bool sdlInput::keyboard_grab ( Uint32  windowID,
bool  enable 
)

Definition at line 564 of file sdl_kbd.cpp.

565{
566 auto it = _sdl->windows.find(windowID);
567 if (it == _sdl->windows.end())
568 return FALSE;
569
570 auto status = enable && _sdl->grab_kbd_enabled;
571 _sdl->grab_kbd = status;
572 return it->second.grabKeyboard(status);
573}

◆ keyboard_handle_event()

BOOL sdlInput::keyboard_handle_event ( const SDL_KeyboardEvent *  ev)

Definition at line 517 of file sdl_kbd.cpp.

518{
519 WINPR_ASSERT(ev);
520 const UINT32 rdp_scancode = sdl_scancode_to_rdp(ev->keysym.scancode);
521 /* The modifiers held when this key was pressed: SDL_GetModState() is the state after every
522 * event already queued, so a hotkey could be missed, or fire on a plain key typed just
523 * before a modifier. */
524 const auto mods = static_cast<SDL_Keymod>(ev->keysym.mod);
525
526 if (_hotkeysEnabled && (mods & _hotkeyModmask) == _hotkeyModmask)
527 {
528 if (ev->type == SDL_KEYDOWN)
529 {
530 if (ev->keysym.scancode == _hotkeyFullscreen)
531 {
532 _sdl->update_fullscreen(!_sdl->fullscreen);
533 return TRUE;
534 }
535 if (ev->keysym.scancode == _hotkeyResizable)
536 {
537 _sdl->update_resizeable(!_sdl->resizeable);
538 return TRUE;
539 }
540
541 if (ev->keysym.scancode == _hotkeyGrab)
542 {
543 keyboard_grab(ev->windowID, !_sdl->grab_kbd);
544 return TRUE;
545 }
546 if (ev->keysym.scancode == _hotkeyDisconnect)
547 {
548 freerdp_abort_connect_context(_sdl->context());
549 return TRUE;
550 }
551 if (ev->keysym.scancode == _hotkeyMinimize)
552 {
553 _sdl->update_minimize();
554 return TRUE;
555 }
556 }
557 }
558
559 auto scancode = freerdp_keyboard_remap_key(_remapTable, rdp_scancode);
560 return freerdp_input_send_keyboard_event_ex(_sdl->context()->input, ev->type == SDL_KEYDOWN,
561 ev->repeat, scancode);
562}

◆ keyboard_set_ime_status()

BOOL sdlInput::keyboard_set_ime_status ( rdpContext *  context,
UINT16  imeId,
UINT32  imeState,
UINT32  imeConvMode 
)
static

Definition at line 377 of file sdl_kbd.cpp.

379{
380 if (!context)
381 return FALSE;
382
383 WLog_WARN(TAG,
384 "KeyboardSetImeStatus(unitId=%04" PRIx16 ", imeState=%08" PRIx32
385 ", imeConvMode=%08" PRIx32 ") ignored",
386 imeId, imeState, imeConvMode);
387 return TRUE;
388}

◆ keyboard_set_indicators()

BOOL sdlInput::keyboard_set_indicators ( rdpContext *  context,
UINT16  led_flags 
)
static

Definition at line 353 of file sdl_kbd.cpp.

354{
355 WINPR_UNUSED(context);
356
357 int state = KMOD_NONE;
358
359 if ((led_flags & KBD_SYNC_NUM_LOCK) != 0)
360 state |= KMOD_NUM;
361 if ((led_flags & KBD_SYNC_CAPS_LOCK) != 0)
362 state |= KMOD_CAPS;
363#if SDL_VERSION_ATLEAST(2, 0, 18)
364 if ((led_flags & KBD_SYNC_SCROLL_LOCK) != 0)
365 state |= KMOD_SCROLL;
366#endif
367
368 // TODO: KBD_SYNC_KANA_LOCK
369
370 // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
371 SDL_SetModState(static_cast<SDL_Keymod>(state));
372
373 return TRUE;
374}

◆ keyboard_sync_state()

bool sdlInput::keyboard_sync_state ( )

Definition at line 317 of file sdl_kbd.cpp.

318{
319 const auto syncFlags = sdl_get_kbd_flags();
320 return freerdp_input_send_synchronize_event(_sdl->context()->input, syncFlags);
321}

◆ mouse_focus()

bool sdlInput::mouse_focus ( Uint32  windowID)

Definition at line 575 of file sdl_kbd.cpp.

576{
577 if (_lastWindowID != windowID)
578 {
579 _lastWindowID = windowID;
580 auto it = _sdl->windows.find(windowID);
581 if (it == _sdl->windows.end())
582 return FALSE;
583
584 it->second.raise();
585 }
586 return TRUE;
587}

◆ mouse_grab() [1/2]

bool sdlInput::mouse_grab ( Uint32  windowID,
bool  enable 
)

Definition at line 703 of file SDL3/sdl_input.cpp.

704{
705 auto window = _sdl->getWindowForId(windowID);
706 if (!window)
707 return false;
708 if (!_sdl->setGrabMouse(enable))
709 WLog_Print(_sdl->getWLog(), WLOG_WARN, "Failed to ungrab mouse");
710 return window->grabMouse(enable);
711}

◆ mouse_grab() [2/2]

BOOL sdlInput::mouse_grab ( Uint32  windowID,
SDL_bool  enable 
)

Definition at line 589 of file sdl_kbd.cpp.

590{
591 auto it = _sdl->windows.find(windowID);
592 if (it == _sdl->windows.end())
593 return FALSE;
594 _sdl->grab_mouse = enable;
595 return it->second.grabMouse(enable);
596}

◆ prefKeyValue()

uint32_t sdlInput::prefKeyValue ( const std::string &  key,
uint32_t  fallback = SDL_SCANCODE_UNKNOWN 
)
static

Definition at line 485 of file sdl_kbd.cpp.

486{
487 auto item = SdlPref::instance()->get_string(key);
488 if (item.empty())
489 return fallback;
490 auto val = sdl_scancode_val(item.c_str());
491 if (val == SDL_SCANCODE_UNKNOWN)
492 return fallback;
493 return val;
494}

◆ prefToEnabled()

bool sdlInput::prefToEnabled ( )
static

Definition at line 418 of file sdl_kbd.cpp.

419{
420 bool enable = true;
421 const auto& m = getSdlMap();
422 for (const auto& val : SdlPref::instance()->get_array("SDL_KeyModMask", { "KMOD_RSHIFT" }))
423 {
424 auto it = m.find(val);
425 if (it != m.end())
426 {
427 if (it->second == KMOD_NONE)
428 enable = false;
429 }
430 else
431 {
432 WLog_WARN(TAG, "Invalid config::SDL_KeyModMask entry value '%s', disabling hotkeys",
433 val.c_str());
434 enable = false;
435 }
436 }
437 return enable;
438}

◆ prefToMask()

uint32_t sdlInput::prefToMask ( )
static

Definition at line 440 of file sdl_kbd.cpp.

441{
442 const auto& mapping = getSdlMap();
443 uint32_t mod = KMOD_NONE;
444 for (const auto& val : SdlPref::instance()->get_array("SDL_KeyModMask", { "KMOD_RSHIFT" }))
445 {
446 auto it = mapping.find(val);
447 if (it != mapping.end())
448 mod |= it->second;
449 }
450 return mod;
451}

The documentation for this class was generated from the following files: