Skip to content

Commit 62f974a

Browse files
committed
[client,sdl] add shortcut config file
Allow keyboard shortcuts to be configured via config file.
1 parent 118f43b commit 62f974a

14 files changed

+442
-70
lines changed

client/SDL/CMakeLists.txt

+9-1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,14 @@ endif()
6262
find_package(SDL2 REQUIRED COMPONENTS)
6363
include_directories(${SDL2_INCLUDE_DIR})
6464
include_directories(${SDL2_INCLUDE_DIRS})
65+
find_package(cJSON)
66+
67+
set(LIBS "")
68+
if (cJSON_FOUND)
69+
include_directories(${CJSON_INCLUDE_DIRS})
70+
list(APPEND LIBS ${CJSON_LIBRARIES})
71+
add_compile_definitions(CJSON_FOUND)
72+
endif()
6573

6674
find_package(Threads REQUIRED)
6775

@@ -89,7 +97,7 @@ set(SRCS
8997
)
9098

9199
add_subdirectory(aad)
92-
set(LIBS
100+
list(APPEND LIBS
93101
winpr
94102
freerdp
95103
freerdp-client

client/SDL/man/CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
set(DEPS
22
sdl-freerdp-channels.1.xml
3+
sdl-freerdp-config.1.xml
34
sdl-freerdp-examples.1.xml
45
sdl-freerdp-envvar.1.xml
56
)
@@ -8,4 +9,4 @@ set(MANPAGE_NAME ${PROJECT_NAME})
89
if (WITH_BINARY_VERSIONING)
910
set(MANPAGE_NAME ${PROJECT_NAME}${PROJECT_VERSION_MAJOR})
1011
endif()
11-
generate_and_install_freerdp_man_from_xml(${PROJECT_NAME}.1 ${MANPAGE_NAME}.1 ${DEPS})
12+
generate_and_install_freerdp_man_from_xml(${PROJECT_NAME}.1 ${MANPAGE_NAME}.1 "${DEPS}")

client/SDL/man/sdl-freerdp-channels.1.xml

Whitespace-only changes.
+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<refsect1>
2+
<title>Configuration file</title>
3+
4+
<variablelist>
5+
<varlistentry>
6+
<term>Format and Location:</term>
7+
<listitem>
8+
<para>The configuration file is stored per user.<sbr/>
9+
The <replaceable>XDG_CONFIG_HOME</replaceable> environment variable can be used to override the base directory.<sbr/>
10+
This defaults to <replaceable>~/.config</replaceable>
11+
The location relative to <replaceable>XDG_CONFIG_HOME</replaceable> is <replaceable>$XDG_CONFIG_HOME/@VENDOR@/@PRODUCT@/@[email protected]</replaceable><sbr/>
12+
The configuration is stored in JSON format</para>
13+
</listitem>
14+
</varlistentry>
15+
<varlistentry>
16+
<term>Supported options:</term>
17+
<listitem>
18+
<varlistentry>
19+
<term><replaceable>SDL_KeyModMask</replaceable></term>
20+
<listitem>
21+
<varlistentry>
22+
<listitem>
23+
<para>Defines the key combination required for SDL client shortcuts.<sbr/>
24+
Default <replaceable>KMOD_RSHIFT</replaceable><sbr/>
25+
An array of <replaceable>SDL_Keymod</replaceable> strings as defined at <replaceable>https://wiki.libsdl.org/SDL2/SDL_Keymod</replaceable></para>
26+
</listitem>
27+
</varlistentry>
28+
</listitem>
29+
</varlistentry>
30+
<varlistentry>
31+
<term><replaceable>SDL_Fullscreen</replaceable></term>
32+
<listitem>
33+
<varlistentry>
34+
<listitem>
35+
<para>Toggles client fullscreen state.<sbr/>
36+
Default <replaceable>SDL_SCANCODE_RETURN</replaceable>.<sbr/>
37+
A string as defined at <replaceable>https://wiki.libsdl.org/SDL2/SDLScancodeLookup</replaceable></para>
38+
</listitem>
39+
</varlistentry>
40+
</listitem>
41+
</varlistentry>
42+
<varlistentry>
43+
<term><replaceable>SDL_Resizeable</replaceable></term>
44+
<listitem>
45+
<varlistentry>
46+
<listitem>
47+
<para>Toggles local window resizeable state.<sbr/>
48+
Default <replaceable>SDL_SCANCODE_R</replaceable>.<sbr/>
49+
A string as defined at <replaceable>https://wiki.libsdl.org/SDL2/SDLScancodeLookup</replaceable></para>
50+
</listitem>
51+
</varlistentry>
52+
</listitem>
53+
</varlistentry>
54+
<varlistentry>
55+
<term><replaceable>SDL_Grab</replaceable></term>
56+
<listitem>
57+
<varlistentry>
58+
<listitem>
59+
<para>Toggles keyboard and mouse grab state.<sbr/>
60+
Default <replaceable>SDL_SCANCODE_G</replaceable>.<sbr/>
61+
A string as defined at <replaceable>https://wiki.libsdl.org/SDL2/SDLScancodeLookup</replaceable></para>
62+
</listitem>
63+
</varlistentry>
64+
</listitem>
65+
</varlistentry>
66+
<varlistentry>
67+
<term><replaceable>SDL_Disconnect</replaceable></term>
68+
<listitem>
69+
<varlistentry>
70+
<listitem>
71+
<para>Disconnects from the RDP session.<sbr/>
72+
Default <replaceable>SDL_SCANCODE_D</replaceable>.<sbr/>
73+
A string as defined at <replaceable>https://wiki.libsdl.org/SDL2/SDLScancodeLookup</replaceable></para>
74+
</listitem>
75+
</varlistentry>
76+
</listitem>
77+
</varlistentry>
78+
</listitem>
79+
</varlistentry>
80+
</variablelist>
81+
</refsect1>

client/SDL/man/sdl-freerdp.1.xml.in

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
44
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
55
<!ENTITY syntax SYSTEM "freerdp-argument.1.xml">
66
<!ENTITY channels SYSTEM "sdl-freerdp-channels.1.xml">
7+
<!ENTITY config SYSTEM "sdl-freerdp-config.1.xml">
78
<!ENTITY envvar SYSTEM "sdl-freerdp-envvar.1.xml">
89
<!ENTITY examples SYSTEM "sdl-freerdp-examples.1.xml">
910
]
@@ -51,6 +52,8 @@ PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
5152

5253
&channels;
5354

55+
&config;
56+
5457
&envvar;
5558

5659
&examples;

client/SDL/sdl_freerdp.cpp

+54
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include <memory>
2121
#include <mutex>
22+
#include <iostream>
2223

2324
#include <freerdp/config.h>
2425

@@ -1600,6 +1601,58 @@ static void SDLCALL winpr_LogOutputFunction(void* userdata, int category, SDL_Lo
16001601
category2str(category), message);
16011602
}
16021603

1604+
static void print_config_file_help()
1605+
{
1606+
#if defined(CJSON_FOUND)
1607+
std::cout << "CONFIGURATION FILE" << std::endl;
1608+
std::cout << std::endl;
1609+
std::cout << " The SDL client supports some user defined configuration options." << std::endl;
1610+
std::cout << " Settings are stored in JSON format" << std::endl;
1611+
std::cout << " The location is a per user file. Location for current user is "
1612+
<< sdl_get_pref_file() << std::endl;
1613+
std::cout
1614+
<< " The XDG_CONFIG_HOME environment variable can be used to override the base directory."
1615+
<< std::endl;
1616+
std::cout << std::endl;
1617+
std::cout << " The following configuration options are supported:" << std::endl;
1618+
std::cout << std::endl;
1619+
std::cout << " SDL_KeyModMask" << std::endl;
1620+
std::cout << " Defines the key combination required for SDL client shortcuts."
1621+
<< std::endl;
1622+
std::cout << " Default KMOD_RSHIFT" << std::endl;
1623+
std::cout << " An array of SDL_Keymod strings as defined at "
1624+
"https://wiki.libsdl.org/SDL2/SDL_Keymod"
1625+
<< std::endl;
1626+
std::cout << std::endl;
1627+
std::cout << " SDL_Fullscreen" << std::endl;
1628+
std::cout << " Toggles client fullscreen state." << std::endl;
1629+
std::cout << " Default SDL_SCANCODE_RETURN." << std::endl;
1630+
std::cout << " A string as "
1631+
"defined at https://wiki.libsdl.org/SDL2/SDLScancodeLookup"
1632+
<< std::endl;
1633+
std::cout << std::endl;
1634+
std::cout << " SDL_Resizeable" << std::endl;
1635+
std::cout << " Toggles local window resizeable state." << std::endl;
1636+
std::cout << " Default SDL_SCANCODE_R." << std::endl;
1637+
std::cout << " A string as "
1638+
"defined at https://wiki.libsdl.org/SDL2/SDLScancodeLookup"
1639+
<< std::endl;
1640+
std::cout << std::endl;
1641+
std::cout << " SDL_Grab" << std::endl;
1642+
std::cout << " Toggles keyboard and mouse grab state." << std::endl;
1643+
std::cout << " Default SDL_SCANCODE_G." << std::endl;
1644+
std::cout << " A string as "
1645+
"defined at https://wiki.libsdl.org/SDL2/SDLScancodeLookup"
1646+
<< std::endl;
1647+
std::cout << std::endl;
1648+
std::cout << " SDL_Disconnect" << std::endl;
1649+
std::cout << " Disconnects from the RDP session." << std::endl;
1650+
std::cout << " Default SDL_SCANCODE_D." << std::endl;
1651+
std::cout << " A string as defined at https://wiki.libsdl.org/SDL2/SDLScancodeLookup"
1652+
<< std::endl;
1653+
#endif
1654+
}
1655+
16031656
int main(int argc, char* argv[])
16041657
{
16051658
int rc = -1;
@@ -1624,6 +1677,7 @@ int main(int argc, char* argv[])
16241677
if (status)
16251678
{
16261679
rc = freerdp_client_settings_command_line_status_print(settings, status, argc, argv);
1680+
print_config_file_help();
16271681
if (freerdp_settings_get_bool(settings, FreeRDP_ListMonitors))
16281682
sdl_list_monitors(sdl);
16291683
return rc;

client/SDL/sdl_kbd.cpp

+103-28
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include "sdl_freerdp.hpp"
2323
#include "sdl_utils.hpp"
2424

25+
#include <map>
26+
2527
#include <freerdp/scancode.h>
2628

2729
#include <freerdp/log.h>
@@ -376,40 +378,93 @@ BOOL sdlInput::keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32
376378
return TRUE;
377379
}
378380

381+
uint32_t sdlInput::prefToMask()
382+
{
383+
const std::map<std::string, SDL_Keymod> mapping = {
384+
{ "KMOD_LSHIFT", KMOD_LSHIFT },
385+
{ "KMOD_RSHIFT", KMOD_RSHIFT },
386+
{ "KMOD_LCTRL", KMOD_LCTRL },
387+
{ "KMOD_RCTRL", KMOD_RCTRL },
388+
{ "KMOD_LALT", KMOD_LALT },
389+
{ "KMOD_RALT", KMOD_RALT },
390+
{ "KMOD_LGUI", KMOD_LGUI },
391+
{ "KMOD_RGUI", KMOD_RGUI },
392+
{ "KMOD_NUM", KMOD_NUM },
393+
{ "KMOD_CAPS", KMOD_CAPS },
394+
{ "KMOD_MODE", KMOD_MODE },
395+
#if SDL_VERSION_ATLEAST(2, 0, 18)
396+
{ "KMOD_SCROLL", KMOD_SCROLL },
397+
#endif
398+
{ "KMOD_CTRL", KMOD_CTRL },
399+
{ "KMOD_SHIFT", KMOD_SHIFT },
400+
{ "KMOD_ALT", KMOD_ALT },
401+
{ "KMOD_GUI", KMOD_GUI }
402+
};
403+
uint32_t mod = KMOD_NONE;
404+
for (const auto& val : sdl_get_pref_array("SDL_KeyModMask", { "KMOD_RSHIFT" }))
405+
{
406+
auto it = mapping.find(val);
407+
if (it != mapping.end())
408+
{
409+
mod |= it->second;
410+
}
411+
}
412+
return mod;
413+
}
414+
379415
static const char* sdl_scancode_name(Uint32 scancode)
380416
{
381-
for (size_t x = 0; x < ARRAYSIZE(map); x++)
417+
for (const auto& cur : map)
382418
{
383-
const scancode_entry_t* cur = &map[x];
384-
if (cur->sdl == scancode)
385-
return cur->sdl_name;
419+
if (cur.sdl == scancode)
420+
return cur.sdl_name;
386421
}
387422

388423
return "SDL_SCANCODE_UNKNOWN";
389424
}
390425

426+
static Uint32 sdl_scancode_val(const char* scancodeName)
427+
{
428+
for (const auto& cur : map)
429+
{
430+
if (strcmp(cur.sdl_name, scancodeName) == 0)
431+
return cur.sdl;
432+
}
433+
434+
return SDL_SCANCODE_UNKNOWN;
435+
}
436+
391437
static const char* sdl_rdp_scancode_name(UINT32 scancode)
392438
{
393-
for (size_t x = 0; x < ARRAYSIZE(map); x++)
439+
for (const auto& cur : map)
394440
{
395-
const scancode_entry_t* cur = &map[x];
396-
if (cur->rdp == scancode)
397-
return cur->rdp_name;
441+
if (cur.rdp == scancode)
442+
return cur.rdp_name;
398443
}
399444

400445
return "RDP_SCANCODE_UNKNOWN";
401446
}
402447

448+
static UINT32 sdl_rdp_scancode_val(const char* scancodeName)
449+
{
450+
for (const auto& cur : map)
451+
{
452+
if (strcmp(cur.rdp_name, scancodeName) == 0)
453+
return cur.rdp;
454+
}
455+
456+
return RDP_SCANCODE_UNKNOWN;
457+
}
458+
403459
static UINT32 sdl_scancode_to_rdp(Uint32 scancode)
404460
{
405461
UINT32 rdp = RDP_SCANCODE_UNKNOWN;
406462

407-
for (size_t x = 0; x < ARRAYSIZE(map); x++)
463+
for (const auto& cur : map)
408464
{
409-
const scancode_entry_t* cur = &map[x];
410-
if (cur->sdl == scancode)
465+
if (cur.sdl == scancode)
411466
{
412-
rdp = cur->rdp;
467+
rdp = cur.rdp;
413468
break;
414469
}
415470
}
@@ -422,32 +477,52 @@ static UINT32 sdl_scancode_to_rdp(Uint32 scancode)
422477
return rdp;
423478
}
424479

480+
uint32_t sdlInput::prefKeyValue(const std::string& key, uint32_t fallback)
481+
{
482+
auto item = sdl_get_pref_string(key);
483+
if (item.empty())
484+
return fallback;
485+
auto val = sdl_scancode_val(item.c_str());
486+
if (val == SDL_SCANCODE_UNKNOWN)
487+
return fallback;
488+
return val;
489+
}
490+
425491
BOOL sdlInput::keyboard_handle_event(const SDL_KeyboardEvent* ev)
426492
{
427493
WINPR_ASSERT(ev);
428494
const UINT32 rdp_scancode = sdl_scancode_to_rdp(ev->keysym.scancode);
429495
const SDL_Keymod mods = SDL_GetModState();
430-
const SDL_Keymod mask = KMOD_RSHIFT;
496+
const auto mask = prefToMask();
497+
const auto valFullscreen = prefKeyValue("SDL_Fullscreen", SDL_SCANCODE_RETURN);
498+
const auto valResizeable = prefKeyValue("SDL_Resizeable", SDL_SCANCODE_R);
499+
const auto valGrab = prefKeyValue("SDL_Grab", SDL_SCANCODE_G);
500+
const auto valDisconnect = prefKeyValue("SDL_Disconnect", SDL_SCANCODE_D);
501+
431502
if ((mods & mask) == mask)
432503
{
433504
if (ev->type == SDL_KEYDOWN)
434505
{
435-
switch (ev->keysym.scancode)
506+
if (ev->keysym.scancode == valFullscreen)
507+
{
508+
_sdl->update_fullscreen(!_sdl->fullscreen);
509+
return TRUE;
510+
}
511+
if (ev->keysym.scancode == valResizeable)
512+
{
513+
_sdl->update_resizeable(!_sdl->resizeable);
514+
return TRUE;
515+
}
516+
517+
if (ev->keysym.scancode == valGrab)
518+
{
519+
keyboard_grab(ev->windowID, _sdl->grab_kbd ? SDL_FALSE : SDL_TRUE);
520+
return TRUE;
521+
}
522+
if (ev->keysym.scancode == valDisconnect)
436523
{
437-
case SDL_SCANCODE_RETURN:
438-
_sdl->update_fullscreen(!_sdl->fullscreen);
439-
return TRUE;
440-
case SDL_SCANCODE_R:
441-
_sdl->update_resizeable(!_sdl->resizeable);
442-
return TRUE;
443-
case SDL_SCANCODE_G:
444-
keyboard_grab(ev->windowID, _sdl->grab_kbd ? SDL_FALSE : SDL_TRUE);
445-
return TRUE;
446-
case SDL_SCANCODE_D:
447-
freerdp_abort_connect_context(_sdl->context());
448-
return true;
449-
default:
450-
break;
524+
freerdp_abort_connect_context(_sdl->context());
525+
return TRUE;
451526
}
452527
}
453528
}

0 commit comments

Comments
 (0)