Skip to content

Commit

Permalink
add ctrl+alt+space shortcut to toggle keyboard hook mode
Browse files Browse the repository at this point in the history
  • Loading branch information
Marc-André Moreau authored and awakecoding committed Jan 10, 2025
1 parent 6e0bad2 commit 103bab0
Show file tree
Hide file tree
Showing 6 changed files with 319 additions and 0 deletions.
57 changes: 57 additions & 0 deletions dll/ApiHooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <MsRdpEx/MsRdpEx.h>

#include <MsRdpEx/Sspi.h>
#include <MsRdpEx/KeyMaps.h>
#include <MsRdpEx/NameResolver.h>
#include <MsRdpEx/RdpInstance.h>
#include <MsRdpEx/Environment.h>
Expand Down Expand Up @@ -894,6 +895,62 @@ LRESULT CALLBACK Hook_IHWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
{
instance->SetLastMousePosition(mousePosX, mousePosY);
}
}
else if (uMsg == WM_KEYDOWN)
{
// https://learn.microsoft.com/en-us/windows/win32/termserv/imsrdpclientsecuredsettings-keyboardhookmode

bool ctrlAltDown = ((GetKeyState(VK_CONTROL) & 0x8000) && (GetKeyState(VK_MENU) & 0x8000));
bool KeyboardHookToggleShortcutEnabled = pExtendedSettings ? pExtendedSettings->GetKeyboardHookToggleShortcutEnabled() : false;
const char* KeyboardHookToggleShortcutKey = pExtendedSettings ? pExtendedSettings->GetKeyboardHookToggleShortcutKey() : "";

if (KeyboardHookToggleShortcutEnabled && ctrlAltDown &&
(wParam == MsRdpEx_KeyNameToVKCode(KeyboardHookToggleShortcutKey)))
{
IUnknown* pUnknown = NULL;
IMsRdpClient9* pMsRdpClient9 = NULL;
IMsRdpClientSecuredSettings* pMsRdpClientSecuredSettings = NULL;

if (instance)
instance->GetRdpClient((LPVOID*)&pUnknown);

if (pUnknown)
pUnknown->QueryInterface(IID_IMsRdpClient9, (LPVOID*)&pMsRdpClient9);

if (pMsRdpClient9)
pMsRdpClient9->get_SecuredSettings2(&pMsRdpClientSecuredSettings);

LONG keyboardHookMode = 0;
pMsRdpClientSecuredSettings->get_KeyboardHookMode(&keyboardHookMode);

// toggle keyboard hook mode between local and remote

switch (keyboardHookMode)
{
case 0: // Apply key combinations only locally at the client computer.
keyboardHookMode = 1;
break;

case 1: // Apply key combinations at the remote server.
case 2: // Apply key combinations to the remote server only when the client is running in full-screen mode
default:
keyboardHookMode = 0;
break;
}

MsRdpEx_LogPrint(DEBUG, "New KeyboardHookMode: %d", keyboardHookMode);
pMsRdpClientSecuredSettings->put_KeyboardHookMode(keyboardHookMode);

if (pMsRdpClient9)
pMsRdpClient9->Release();

if (pMsRdpClientSecuredSettings)
pMsRdpClientSecuredSettings->Release();
}
}
else if (uMsg == WM_KEYUP)
{

}
else if (uMsg == WM_NCDESTROY)
{
Expand Down
2 changes: 2 additions & 0 deletions dll/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ set(MSRDPEX_HEADERS
"${MSRDPEX_INCLUDE_DIR}/Pcap.h"
"${MSRDPEX_INCLUDE_DIR}/ArrayList.h"
"${MSRDPEX_INCLUDE_DIR}/HashTable.h"
"${MSRDPEX_INCLUDE_DIR}/KeyMaps.h"
"${MSRDPEX_INCLUDE_DIR}/Environment.h"
"${MSRDPEX_INCLUDE_DIR}/NameResolver.h"
"${MSRDPEX_INCLUDE_DIR}/RdpFile.h"
Expand All @@ -36,6 +37,7 @@ set(MSRDPEX_HEADERS
set(MSRDPEX_SOURCES
ArrayList.c
HashTable.c
KeyMaps.cpp
Environment.c
NameResolver.c
DpiHelper.cpp
Expand Down
187 changes: 187 additions & 0 deletions dll/KeyMaps.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
#include <MsRdpEx/KeyMaps.h>

typedef struct {
const char* keyName;
uint32_t vkCode;
} KeyCodeMapping;

#define VK_UNKNOWN 0

#define VK_KEY_0 0x30 /* '0' key */
#define VK_KEY_1 0x31 /* '1' key */
#define VK_KEY_2 0x32 /* '2' key */
#define VK_KEY_3 0x33 /* '3' key */
#define VK_KEY_4 0x34 /* '4' key */
#define VK_KEY_5 0x35 /* '5' key */
#define VK_KEY_6 0x36 /* '6' key */
#define VK_KEY_7 0x37 /* '7' key */
#define VK_KEY_8 0x38 /* '8' key */
#define VK_KEY_9 0x39 /* '9' key */

#define VK_KEY_A 0x41 /* 'A' key */
#define VK_KEY_B 0x42 /* 'B' key */
#define VK_KEY_C 0x43 /* 'C' key */
#define VK_KEY_D 0x44 /* 'D' key */
#define VK_KEY_E 0x45 /* 'E' key */
#define VK_KEY_F 0x46 /* 'F' key */
#define VK_KEY_G 0x47 /* 'G' key */
#define VK_KEY_H 0x48 /* 'H' key */
#define VK_KEY_I 0x49 /* 'I' key */
#define VK_KEY_J 0x4A /* 'J' key */
#define VK_KEY_K 0x4B /* 'K' key */
#define VK_KEY_L 0x4C /* 'L' key */
#define VK_KEY_M 0x4D /* 'M' key */
#define VK_KEY_N 0x4E /* 'N' key */
#define VK_KEY_O 0x4F /* 'O' key */
#define VK_KEY_P 0x50 /* 'P' key */
#define VK_KEY_Q 0x51 /* 'Q' key */
#define VK_KEY_R 0x52 /* 'R' key */
#define VK_KEY_S 0x53 /* 'S' key */
#define VK_KEY_T 0x54 /* 'T' key */
#define VK_KEY_U 0x55 /* 'U' key */
#define VK_KEY_V 0x56 /* 'V' key */
#define VK_KEY_W 0x57 /* 'W' key */
#define VK_KEY_X 0x58 /* 'X' key */
#define VK_KEY_Y 0x59 /* 'Y' key */
#define VK_KEY_Z 0x5A /* 'Z' key */

#define VK_ABNT_C1 0xC1 /* Brazilian (ABNT) Keyboard */
#define VK_ABNT_C2 0xC2 /* Brazilian (ABNT) Keyboard */

// https://github.com/microsoft/vscode/blob/main/src/vs/base/common/keyCodes.ts

static const KeyCodeMapping keyCodeTable[] =
{
{ "None", VK_UNKNOWN },
{ "Hyper", VK_UNKNOWN },
{ "Super", VK_UNKNOWN },
{ "Fn", VK_UNKNOWN },
{ "FnLock", VK_UNKNOWN },
{ "Suspend", VK_UNKNOWN },
{ "Resume", VK_UNKNOWN },
{ "Turbo", VK_UNKNOWN },
{ "Sleep", VK_SLEEP },
{ "WakeUp", VK_UNKNOWN },

{ "Ctrl", VK_CONTROL },
{ "Shift", VK_SHIFT },
{ "Alt", VK_MENU },

{ "A", VK_KEY_A },
{ "B", VK_KEY_B },
{ "C", VK_KEY_C },
{ "D", VK_KEY_D },
{ "E", VK_KEY_E },
{ "F", VK_KEY_F },
{ "G", VK_KEY_G },
{ "H", VK_KEY_H },
{ "I", VK_KEY_I },
{ "J", VK_KEY_J },
{ "K", VK_KEY_K },
{ "L", VK_KEY_L },
{ "M", VK_KEY_M },
{ "N", VK_KEY_N },
{ "O", VK_KEY_O },
{ "P", VK_KEY_P },
{ "Q", VK_KEY_Q },
{ "R", VK_KEY_R },
{ "S", VK_KEY_S },
{ "T", VK_KEY_T },
{ "U", VK_KEY_U },
{ "V", VK_KEY_V },
{ "W", VK_KEY_W },
{ "X", VK_KEY_X },
{ "Y", VK_KEY_Y },
{ "Z", VK_KEY_Z },

{ "0", VK_KEY_0 },
{ "1", VK_KEY_1 },
{ "2", VK_KEY_2 },
{ "3", VK_KEY_3 },
{ "4", VK_KEY_4 },
{ "5", VK_KEY_5 },
{ "6", VK_KEY_6 },
{ "7", VK_KEY_7 },
{ "8", VK_KEY_8 },
{ "9", VK_KEY_9 },

{ "Enter", VK_RETURN },
{ "Escape", VK_ESCAPE },
{ "Backspace", VK_BACK },
{ "Tab", VK_TAB },
{ "Space", VK_SPACE },
{ "-", VK_OEM_MINUS },
{ "=", VK_OEM_PLUS },
{ "[", VK_OEM_4 },
{ "]", VK_OEM_6 },
{ "\\", VK_OEM_5 },
{ ";", VK_OEM_1 },
{ "\'", VK_OEM_7 },
{ "`", VK_OEM_3 },
{ ",", VK_OEM_COMMA },
{ ".", VK_OEM_PERIOD },
{ "/", VK_OEM_2 },
{ "CapsLock", VK_CAPITAL },

{ "F1", VK_F1 },
{ "F2", VK_F2 },
{ "F3", VK_F3 },
{ "F4", VK_F4 },
{ "F5", VK_F5 },
{ "F6", VK_F6 },
{ "F7", VK_F7 },
{ "F8", VK_F8 },
{ "F9", VK_F9 },
{ "F10", VK_F10 },
{ "F11", VK_F11 },
{ "F12", VK_F12 },

{ "PrintScreen", VK_UNKNOWN },
{ "ScrollLock", VK_SCROLL },
{ "PauseBreak", VK_PAUSE },
{ "Insert", VK_INSERT },
{ "Home", VK_HOME },
{ "PageUp", VK_PRIOR },
{ "Delete", VK_DELETE },
{ "End", VK_END },
{ "PageDown", VK_NEXT },
{ "RightArrow", VK_RIGHT },
{ "LeftArrow", VK_LEFT },
{ "DownArrow", VK_DOWN },
{ "UpArrow", VK_UP },

{ "NumLock", VK_NUMLOCK },
{ "NumPad_Divide", VK_DIVIDE },
{ "NumPad_Subtract", VK_SUBTRACT },
{ "NumPad_Add", VK_ADD },
{ "NumPad_Enter", VK_UNKNOWN },

{ "Numpad0", VK_NUMPAD0 },
{ "Numpad1", VK_NUMPAD1 },
{ "Numpad2", VK_NUMPAD2 },
{ "Numpad3", VK_NUMPAD3 },
{ "Numpad4", VK_NUMPAD4 },
{ "Numpad5", VK_NUMPAD5 },
{ "Numpad6", VK_NUMPAD6 },
{ "Numpad7", VK_NUMPAD7 },
{ "Numpad8", VK_NUMPAD8 },
{ "Numpad9", VK_NUMPAD9 },

{ "NumPad_Decimal", VK_DECIMAL },
{ "Numpad_Equal", VK_UNKNOWN },
{ "Numpad_Separator", VK_SEPARATOR },
{ "Numpad_Clear", VK_CLEAR },
};

uint32_t MsRdpEx_KeyNameToVKCode(const char* keyName)
{
int numMappings = sizeof(keyCodeTable) / sizeof(keyCodeTable[0]);

for (int i = 0; i < numMappings; i++) {
if (_stricmp(keyCodeTable[i].keyName, keyName) == 0) {
return keyCodeTable[i].vkCode;
}
}

return VK_UNKNOWN;
}
53 changes: 53 additions & 0 deletions dll/RdpSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,8 @@ CMsRdpExtendedSettings::CMsRdpExtendedSettings(IUnknown* pUnknown, GUID* pSessio

MsRdpEx_GuidCopy(&m_sessionId, pSessionId);

strncpy_s(m_KeyboardHookToggleShortcutKey, "Space", sizeof(m_KeyboardHookToggleShortcutKey) - 1);

hr = pUnknown->QueryInterface(IID_IMsRdpClient7, (LPVOID*)&m_pMsRdpClient7);

if (SUCCEEDED(hr) && m_pMsRdpClient7)
Expand Down Expand Up @@ -523,6 +525,24 @@ HRESULT __stdcall CMsRdpExtendedSettings::put_Property(BSTR bstrPropertyName, VA
m_MouseJigglerMethod = (uint32_t) pValue->uintVal;
hr = S_OK;
}
else if (MsRdpEx_StringEquals(propName, "KeyboardHookToggleShortcutEnabled"))
{
if (pValue->vt != VT_BOOL)
goto end;

m_KeyboardHookToggleShortcutEnabled = pValue->boolVal ? true : false;
hr = S_OK;
}
else if (MsRdpEx_StringEquals(propName, "KeyboardHookToggleShortcutKey"))
{
if (pValue->vt != VT_BSTR)
goto end;

char* propValueA = _com_util::ConvertBSTRToString((BSTR)pValue->bstrVal);
strncpy_s(m_KeyboardHookToggleShortcutKey, propValueA, sizeof(m_KeyboardHookToggleShortcutKey) - 1);

hr = S_OK;
}
else
{
if (pValue->vt == VT_BSTR) {
Expand Down Expand Up @@ -604,6 +624,16 @@ HRESULT __stdcall CMsRdpExtendedSettings::get_Property(BSTR bstrPropertyName, VA
pValue->intVal = (INT) m_MouseJigglerMethod;
hr = S_OK;
}
else if (MsRdpEx_StringEquals(propName, "KeyboardHookToggleShortcutEnabled")) {
pValue->vt = VT_BOOL;
pValue->boolVal = m_KeyboardHookToggleShortcutEnabled ? VARIANT_TRUE : VARIANT_FALSE;
hr = S_OK;
}
else if (MsRdpEx_StringEquals(propName, "KeyboardHookToggleShortcutKey")) {
pValue->vt = VT_BSTR;
pValue->bstrVal = _com_util::ConvertStringToBSTR(m_KeyboardHookToggleShortcutKey);
hr = S_OK;
}
else if (MsRdpEx_StringEquals(propName, "MsRdpEx_SessionId")) {
pValue->vt = VT_BSTR;
char sessionId[MSRDPEX_GUID_STRING_SIZE];
Expand Down Expand Up @@ -884,6 +914,19 @@ HRESULT CMsRdpExtendedSettings::ApplyRdpFile(void* rdpFilePtr)
pMsRdpExtendedSettings->put_Property(propName, &value);
}
}
else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 'i', "KeyboardHookToggleShortcutEnabled")) {
if (MsRdpEx_RdpFileEntry_GetVBoolValue(entry, &value)) {
bstr_t propName = _com_util::ConvertStringToBSTR(entry->name);
pMsRdpExtendedSettings->put_Property(propName, &value);
}
}
else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 's', "KeyboardHookToggleShortcutKey")) {
bstr_t propName = _com_util::ConvertStringToBSTR("KeyboardHookToggleShortcutKey");
bstr_t propValue = _com_util::ConvertStringToBSTR(entry->value);
value.bstrVal = propValue;
value.vt = VT_BSTR;
pMsRdpExtendedSettings->put_Property(propName, &value);
}
else if (MsRdpEx_RdpFileEntry_IsMatch(entry, 's', "TargetUserName")) {
bstr_t propName = _com_util::ConvertStringToBSTR("UserName");
bstr_t propValue = _com_util::ConvertStringToBSTR(entry->value);
Expand Down Expand Up @@ -1113,6 +1156,16 @@ uint32_t CMsRdpExtendedSettings::GetMouseJigglerMethod()
return m_MouseJigglerMethod;
}

bool CMsRdpExtendedSettings::GetKeyboardHookToggleShortcutEnabled()
{
return m_KeyboardHookToggleShortcutEnabled;
}

const char* CMsRdpExtendedSettings::GetKeyboardHookToggleShortcutKey()
{
return (const char*) m_KeyboardHookToggleShortcutKey;
}

bool CMsRdpExtendedSettings::GetExtraSystemMenuEnabled()
{
return m_ExtraSystemMenuEnabled;
Expand Down
16 changes: 16 additions & 0 deletions include/MsRdpEx/KeyMaps.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef MSRDPEX_KEYMAPS_H
#define MSRDPEX_KEYMAPS_H

#include <MsRdpEx/MsRdpEx.h>

#ifdef __cplusplus
extern "C" {
#endif

uint32_t MsRdpEx_KeyNameToVKCode(const char* keyName);

#ifdef __cplusplus
}
#endif

#endif // MSRDPEX_KEYMAPS_H
4 changes: 4 additions & 0 deletions include/MsRdpEx/RdpSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class CMsRdpExtendedSettings : public IMsRdpExtendedSettings
bool GetMouseJigglerEnabled();
uint32_t GetMouseJigglerInterval();
uint32_t GetMouseJigglerMethod();
bool GetKeyboardHookToggleShortcutEnabled();
const char* GetKeyboardHookToggleShortcutKey();
bool GetExtraSystemMenuEnabled();

private:
Expand All @@ -71,6 +73,8 @@ class CMsRdpExtendedSettings : public IMsRdpExtendedSettings
uint32_t m_MouseJigglerInterval = 60;
uint32_t m_MouseJigglerMethod = 0;
bool m_ExtraSystemMenuEnabled = true;
bool m_KeyboardHookToggleShortcutEnabled = false;
char m_KeyboardHookToggleShortcutKey[32];
IUnknown* m_pWTSPlugin = NULL;
};

Expand Down

0 comments on commit 103bab0

Please sign in to comment.