diff --git a/client/X11/xf_keyboard.c b/client/X11/xf_keyboard.c index 175e83643..cda758d49 100644 --- a/client/X11/xf_keyboard.c +++ b/client/X11/xf_keyboard.c @@ -196,13 +196,13 @@ void xf_keyboard_send_key(xfContext* xfc, BOOL down, BYTE keycode) else if (rdp_scancode == RDP_SCANCODE_PAUSE && !xf_keyboard_key_pressed(xfc, XK_Control_L) && !xf_keyboard_key_pressed(xfc, XK_Control_R)) { - /* Pause without Ctrl has to be sent as Ctrl + NumLock. */ + /* Pause without Ctrl has to be sent as a series of keycodes + * in a single input PDU. Pause only happens on "press"; + * no code is sent on "release". + */ if (down) { - freerdp_input_send_keyboard_event_ex(input, TRUE, RDP_SCANCODE_LCONTROL); - freerdp_input_send_keyboard_event_ex(input, TRUE, RDP_SCANCODE_NUMLOCK); - freerdp_input_send_keyboard_event_ex(input, FALSE, RDP_SCANCODE_LCONTROL); - freerdp_input_send_keyboard_event_ex(input, FALSE, RDP_SCANCODE_NUMLOCK); + freerdp_input_send_keyboard_pause_event(input); } } else diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 480f9f21b..7bda76a9c 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -1360,17 +1360,17 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "kbd") { - int id; + unsigned long int id; char* pEnd; - id = strtol(arg->Value, &pEnd, 16); + id = strtoul(arg->Value, &pEnd, 16); if (pEnd != (arg->Value + strlen(arg->Value))) id = 0; if (id == 0) { - id = freerdp_map_keyboard_layout_name_to_id(arg->Value); + id = (unsigned long int) freerdp_map_keyboard_layout_name_to_id(arg->Value); if (!id) { @@ -1378,7 +1378,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } } - settings->KeyboardLayout = id; + settings->KeyboardLayout = (UINT32) id; } CommandLineSwitchCase(arg, "kbd-type") { diff --git a/include/freerdp/input.h b/include/freerdp/input.h index 87324f0ab..0ee3ee188 100644 --- a/include/freerdp/input.h +++ b/include/freerdp/input.h @@ -64,6 +64,7 @@ typedef struct rdp_input_proxy rdpInputProxy; typedef void (*pSynchronizeEvent)(rdpInput* input, UINT32 flags); typedef void (*pKeyboardEvent)(rdpInput* input, UINT16 flags, UINT16 code); +typedef void (*pKeyboardPauseEvent)(rdpInput* input); typedef void (*pUnicodeKeyboardEvent)(rdpInput* input, UINT16 flags, UINT16 code); typedef void (*pMouseEvent)(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y); typedef void (*pExtendedMouseEvent)(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y); @@ -81,8 +82,9 @@ struct rdp_input pMouseEvent MouseEvent; /* 19 */ pExtendedMouseEvent ExtendedMouseEvent; /* 20 */ pFocusInEvent FocusInEvent; /*21 */ + pKeyboardPauseEvent KeyboardPauseEvent; /* 22 */ - UINT32 paddingB[32 - 22]; /* 22 */ + UINT32 paddingB[32 - 23]; /* 23 */ /* Internal */ @@ -98,6 +100,7 @@ extern "C" { FREERDP_API void freerdp_input_send_synchronize_event(rdpInput* input, UINT32 flags); FREERDP_API void freerdp_input_send_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code); FREERDP_API void freerdp_input_send_keyboard_event_ex(rdpInput* input, BOOL down, UINT32 rdp_scancode); +FREERDP_API void freerdp_input_send_keyboard_pause_event(rdpInput* input); FREERDP_API void freerdp_input_send_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code); FREERDP_API void freerdp_input_send_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y); FREERDP_API void freerdp_input_send_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y); diff --git a/libfreerdp/core/fastpath.h b/libfreerdp/core/fastpath.h index 7f1c59cab..05e96422f 100644 --- a/libfreerdp/core/fastpath.h +++ b/libfreerdp/core/fastpath.h @@ -108,7 +108,8 @@ enum FASTPATH_INPUT_EVENT_CODE enum FASTPATH_INPUT_KBDFLAGS { FASTPATH_INPUT_KBDFLAGS_RELEASE = 0x01, - FASTPATH_INPUT_KBDFLAGS_EXTENDED = 0x02 + FASTPATH_INPUT_KBDFLAGS_EXTENDED = 0x02, + FASTPATH_INPUT_KBDFLAGS_PREFIX_E1 = 0x04 /* for pause sequence */ }; struct _FASTPATH_UPDATE_PDU_HEADER diff --git a/libfreerdp/core/input.c b/libfreerdp/core/input.c index a929b0d96..c7a880f8b 100644 --- a/libfreerdp/core/input.c +++ b/libfreerdp/core/input.c @@ -166,6 +166,27 @@ void input_send_focus_in_event(rdpInput* input, UINT16 toggleStates, UINT16 x, U input_send_mouse_event(input, PTR_FLAGS_MOVE, x, y); } +static void input_send_keyboard_pause_event(rdpInput* input) +{ + /* In ancient days, pause-down without control sent E1 1D 45 E1 9D C5, + * and pause-up sent nothing. However, reverse engineering mstsc shows + * it sending the following sequence: + */ + + /* Control down (0x1D) */ + input_send_keyboard_event(input, 0, + RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL)); + /* Numlock down (0x45) */ + input_send_keyboard_event(input, 0, + RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK)); + /* Control up (0x1D) */ + input_send_keyboard_event(input, KBD_FLAGS_RELEASE, + RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL)); + /* Numlock up (0x45) */ + input_send_keyboard_event(input, KBD_FLAGS_RELEASE, + RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK)); +} + void input_send_fastpath_synchronize_event(rdpInput* input, UINT32 flags) { wStream* s; @@ -250,6 +271,39 @@ void input_send_fastpath_focus_in_event(rdpInput* input, UINT16 toggleStates, UI fastpath_send_multiple_input_pdu(rdp->fastpath, s, 4); } +static void input_send_fastpath_keyboard_pause_event(rdpInput* input) +{ + /* In ancient days, pause-down without control sent E1 1D 45 E1 9D C5, + * and pause-up sent nothing. However, reverse engineering mstsc shows + * it sending the following sequence: + */ + wStream* s; + rdpRdp* rdp = input->context->rdp; + const BYTE keyDownEvent = FASTPATH_INPUT_EVENT_SCANCODE << 5; + const BYTE keyUpEvent = (FASTPATH_INPUT_EVENT_SCANCODE << 5) + | FASTPATH_INPUT_KBDFLAGS_RELEASE; + + s = fastpath_input_pdu_init_header(rdp->fastpath); + + /* Control down (0x1D) */ + Stream_Write_UINT8(s, keyDownEvent | FASTPATH_INPUT_KBDFLAGS_PREFIX_E1); + Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL)); + + /* Numlock down (0x45) */ + Stream_Write_UINT8(s, keyDownEvent); + Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK)); + + /* Control up (0x1D) */ + Stream_Write_UINT8(s, keyUpEvent | FASTPATH_INPUT_KBDFLAGS_PREFIX_E1); + Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL)); + + /* Numlock down (0x45) */ + Stream_Write_UINT8(s, keyUpEvent); + Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK)); + + fastpath_send_multiple_input_pdu(rdp->fastpath, s, 4); +} + static BOOL input_recv_sync_event(rdpInput* input, wStream* s) { UINT32 toggleFlags; @@ -420,6 +474,7 @@ void input_register_client_callbacks(rdpInput* input) { input->SynchronizeEvent = input_send_fastpath_synchronize_event; input->KeyboardEvent = input_send_fastpath_keyboard_event; + input->KeyboardPauseEvent = input_send_fastpath_keyboard_pause_event; input->UnicodeKeyboardEvent = input_send_fastpath_unicode_keyboard_event; input->MouseEvent = input_send_fastpath_mouse_event; input->ExtendedMouseEvent = input_send_fastpath_extended_mouse_event; @@ -429,6 +484,7 @@ void input_register_client_callbacks(rdpInput* input) { input->SynchronizeEvent = input_send_synchronize_event; input->KeyboardEvent = input_send_keyboard_event; + input->KeyboardPauseEvent = input_send_keyboard_pause_event; input->UnicodeKeyboardEvent = input_send_unicode_keyboard_event; input->MouseEvent = input_send_mouse_event; input->ExtendedMouseEvent = input_send_extended_mouse_event; @@ -481,6 +537,11 @@ void freerdp_input_send_focus_in_event(rdpInput* input, UINT16 toggleStates, UIN IFCALL(input->FocusInEvent, input, toggleStates, x, y); } +void freerdp_input_send_keyboard_pause_event(rdpInput* input) +{ + IFCALL(input->KeyboardPauseEvent, input); +} + int input_process_events(rdpInput* input) { return input_message_queue_process_pending_messages(input);