diff --git a/client/X11/xf_interface.c b/client/X11/xf_interface.c index 7a84adc4f..b1caf4243 100644 --- a/client/X11/xf_interface.c +++ b/client/X11/xf_interface.c @@ -1190,7 +1190,6 @@ void* xf_thread(void* param) exit_code = XF_EXIT_CONN_FAILED; ExitThread(exit_code); } - channels = instance->context->channels; settings = instance->context->settings; @@ -1219,6 +1218,11 @@ void* xf_thread(void* param) rcount = 0; wcount = 0; + if (freerdp_focus_required(instance)) + { + xf_kbd_focus_in(xfi); + } + if (!async_transport) { if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) diff --git a/client/X11/xf_keyboard.c b/client/X11/xf_keyboard.c index 73ae107da..a7ff67ce0 100644 --- a/client/X11/xf_keyboard.c +++ b/client/X11/xf_keyboard.c @@ -191,15 +191,16 @@ void xf_kbd_focus_in(xfInfo* xfi) { rdpInput* input; UINT32 syncFlags; + int dummy, mouseX, mouseY; + Window wdummy; + UINT32 state = 0; input = xfi->instance->input; - /* on focus in send a tab up like mstsc.exe */ - input->KeyboardEvent(input, KBD_FLAGS_RELEASE, 0x0F); - - /* synchronize toggle keys */ syncFlags = xf_kbd_get_toggle_keys_state(xfi); - input->SynchronizeEvent(input, syncFlags); + XQueryPointer(xfi->display, xfi->window->handle, &wdummy, &wdummy, &mouseX, &mouseY, &dummy, &dummy, &state); + + input->FocusInEvent(input, syncFlags, mouseX, mouseY); } BOOL xf_kbd_handle_special_keys(xfInfo* xfi, KeySym keysym) diff --git a/include/freerdp/freerdp.h b/include/freerdp/freerdp.h index 0a3beb346..cef859d5b 100644 --- a/include/freerdp/freerdp.h +++ b/include/freerdp/freerdp.h @@ -218,6 +218,7 @@ FREERDP_API void freerdp_get_version(int* major, int* minor, int* revision); FREERDP_API freerdp* freerdp_new(void); FREERDP_API void freerdp_free(freerdp* instance); +FREERDP_API BOOL freerdp_focus_required(freerdp* instance); #ifdef __cplusplus } #endif diff --git a/include/freerdp/input.h b/include/freerdp/input.h index a08637e1d..87324f0ab 100644 --- a/include/freerdp/input.h +++ b/include/freerdp/input.h @@ -67,6 +67,7 @@ typedef void (*pKeyboardEvent)(rdpInput* input, UINT16 flags, UINT16 code); 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); +typedef void (*pFocusInEvent)(rdpInput* input, UINT16 toggleStates, UINT16 x, UINT16 y); struct rdp_input { @@ -79,7 +80,9 @@ struct rdp_input pUnicodeKeyboardEvent UnicodeKeyboardEvent; /* 18 */ pMouseEvent MouseEvent; /* 19 */ pExtendedMouseEvent ExtendedMouseEvent; /* 20 */ - UINT32 paddingB[32 - 21]; /* 21 */ + pFocusInEvent FocusInEvent; /*21 */ + + UINT32 paddingB[32 - 22]; /* 22 */ /* Internal */ @@ -98,6 +101,7 @@ FREERDP_API void freerdp_input_send_keyboard_event_ex(rdpInput* input, BOOL down 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); +FREERDP_API void freerdp_input_send_focus_in_event(rdpInput* input, UINT16 toggleStates, UINT16 x, UINT16 y); #ifdef __cplusplus } diff --git a/libfreerdp/core/activation.c b/libfreerdp/core/activation.c index 61c7007dd..4ba621a79 100644 --- a/libfreerdp/core/activation.c +++ b/libfreerdp/core/activation.c @@ -129,6 +129,7 @@ BOOL rdp_recv_server_control_pdu(rdpRdp* rdp, wStream* s) case CTRLACTION_GRANTED_CONTROL: rdp->finalize_sc_pdus |= FINALIZE_SC_CONTROL_GRANTED_PDU; + rdp->resendFocus = TRUE; break; } diff --git a/libfreerdp/core/fastpath.c b/libfreerdp/core/fastpath.c index 8a680d7e7..50e1ab0d6 100644 --- a/libfreerdp/core/fastpath.c +++ b/libfreerdp/core/fastpath.c @@ -243,6 +243,7 @@ static int fastpath_recv_update(rdpFastPath* fastpath, BYTE updateCode, UINT32 s case FASTPATH_UPDATETYPE_PTR_DEFAULT: update->pointer->pointer_system.type = SYSPTR_DEFAULT; IFCALL(pointer->PointerSystem, context, &pointer->pointer_system); + break; case FASTPATH_UPDATETYPE_PTR_POSITION: @@ -578,7 +579,7 @@ static UINT32 fastpath_get_sec_bytes(rdpRdp* rdp) return sec_bytes; } -wStream* fastpath_input_pdu_init(rdpFastPath* fastpath, BYTE eventFlags, BYTE eventCode) +wStream* fastpath_input_pdu_init_header(rdpFastPath* fastpath) { rdpRdp *rdp; wStream* s; @@ -587,17 +588,31 @@ wStream* fastpath_input_pdu_init(rdpFastPath* fastpath, BYTE eventFlags, BYTE ev s = transport_send_stream_init(rdp->transport, 256); stream_seek(s, 3); /* fpInputHeader, length1 and length2 */ - if (rdp->do_crypt) { + + if (rdp->do_crypt) + { rdp->sec_flags |= SEC_ENCRYPT; if (rdp->do_secure_checksum) rdp->sec_flags |= SEC_SECURE_CHECKSUM; } stream_seek(s, fastpath_get_sec_bytes(rdp)); + + return s; +} + +wStream* fastpath_input_pdu_init(rdpFastPath* fastpath, BYTE eventFlags, BYTE eventCode) +{ + rdpRdp *rdp; + wStream* s; + + rdp = fastpath->rdp; + + s = fastpath_input_pdu_init_header(fastpath); stream_write_BYTE(s, eventFlags | (eventCode << 5)); /* eventHeader (1 byte) */ return s; } -BOOL fastpath_send_input_pdu(rdpFastPath* fastpath, wStream* s) +BOOL fastpath_send_multiple_input_pdu(rdpFastPath* fastpath, wStream* s, int iNumEvents) { rdpRdp *rdp; UINT16 length; @@ -614,7 +629,7 @@ BOOL fastpath_send_input_pdu(rdpFastPath* fastpath, wStream* s) } eventHeader = FASTPATH_INPUT_ACTION_FASTPATH; - eventHeader |= (1 << 2); /* numberEvents */ + eventHeader |= (iNumEvents << 2); /* numberEvents */ if (rdp->sec_flags & SEC_ENCRYPT) eventHeader |= (FASTPATH_INPUT_ENCRYPTED << 6); if (rdp->sec_flags & SEC_SECURE_CHECKSUM) @@ -654,6 +669,11 @@ BOOL fastpath_send_input_pdu(rdpFastPath* fastpath, wStream* s) return TRUE; } +BOOL fastpath_send_input_pdu(rdpFastPath* fastpath, wStream* s) +{ + return fastpath_send_multiple_input_pdu(fastpath, s, 1); +} + wStream* fastpath_update_pdu_init(rdpFastPath* fastpath) { wStream* s; diff --git a/libfreerdp/core/fastpath.h b/libfreerdp/core/fastpath.h index e7bcab46c..9c0b20732 100644 --- a/libfreerdp/core/fastpath.h +++ b/libfreerdp/core/fastpath.h @@ -109,7 +109,9 @@ BOOL fastpath_read_header_rdp(rdpFastPath* fastpath, wStream* s, UINT16 *length) int fastpath_recv_updates(rdpFastPath* fastpath, wStream* s); int fastpath_recv_inputs(rdpFastPath* fastpath, wStream* s); +wStream* fastpath_input_pdu_init_header(rdpFastPath* fastpath); wStream* fastpath_input_pdu_init(rdpFastPath* fastpath, BYTE eventFlags, BYTE eventCode); +BOOL fastpath_send_multiple_input_pdu(rdpFastPath* fastpath, wStream* s, int iEventCount); BOOL fastpath_send_input_pdu(rdpFastPath* fastpath, wStream* s); wStream* fastpath_update_pdu_init(rdpFastPath* fastpath); diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 6770a1ab3..3bf0adabe 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -272,6 +272,22 @@ BOOL freerdp_shall_disconnect(freerdp* instance) return instance->context->rdp->disconnect; } +FREERDP_API BOOL freerdp_focus_required(freerdp* instance) +{ + rdpRdp* rdp; + BOOL bRetCode = FALSE; + + rdp = instance->context->rdp; + + if (rdp->resendFocus) + { + bRetCode = TRUE; + rdp->resendFocus = FALSE; + } + + return bRetCode; +} + void freerdp_get_version(int* major, int* minor, int* revision) { if (major != NULL) diff --git a/libfreerdp/core/input.c b/libfreerdp/core/input.c index 06e31f84d..30b82dd0b 100644 --- a/libfreerdp/core/input.c +++ b/libfreerdp/core/input.c @@ -151,6 +151,21 @@ void input_send_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UI rdp_send_client_input_pdu(rdp, s); } +void input_send_focus_in_event(rdpInput* input, UINT16 toggleStates, UINT16 x, UINT16 y) +{ + /* send a tab up like mstsc.exe */ + input_send_keyboard_event(input, KBD_FLAGS_RELEASE, 0x0f); + + /* send the toggle key states */ + input_send_synchronize_event(input, (toggleStates & 0x1F)); + + /* send another tab up like mstsc.exe */ + input_send_keyboard_event(input, KBD_FLAGS_RELEASE, 0x0f); + + /* finish with a mouse pointer position like mstsc.exe */ + input_send_extended_mouse_event(input, PTR_FLAGS_MOVE, x, y); +} + void input_send_fastpath_synchronize_event(rdpInput* input, UINT32 flags) { wStream* s; @@ -206,6 +221,35 @@ void input_send_fastpath_extended_mouse_event(rdpInput* input, UINT16 flags, UIN fastpath_send_input_pdu(rdp->fastpath, s); } +void input_send_fastpath_focus_in_event(rdpInput* input, UINT16 toggleStates, UINT16 x, UINT16 y) +{ + wStream* s; + rdpRdp* rdp = input->context->rdp; + BYTE eventFlags = 0; + + s = fastpath_input_pdu_init_header(rdp->fastpath); + /* send a tab up like mstsc.exe */ + eventFlags = FASTPATH_INPUT_KBDFLAGS_RELEASE | FASTPATH_INPUT_EVENT_SCANCODE << 5; + stream_write_BYTE(s, eventFlags); /* Key Release event (1 byte) */ + stream_write_BYTE(s, 0x0f); /* keyCode (1 byte) */ + + /* send the toggle key states */ + eventFlags = (toggleStates & 0x1F) | FASTPATH_INPUT_EVENT_SYNC << 5; + stream_write_BYTE(s, eventFlags); /* toggle state (1 byte) */ + + /* send another tab up like mstsc.exe */ + eventFlags = FASTPATH_INPUT_KBDFLAGS_RELEASE | FASTPATH_INPUT_EVENT_SCANCODE << 5; + stream_write_BYTE(s, eventFlags); /* Key Release event (1 byte) */ + stream_write_BYTE(s, 0x0f); /* keyCode (1 byte) */ + + /* finish with a mouse pointer position like mstsc.exe */ + eventFlags = 0 | FASTPATH_INPUT_EVENT_MOUSE << 5; + stream_write_BYTE(s, eventFlags); /* Mouse Pointer event (1 byte) */ + input_write_extended_mouse_event(s, PTR_FLAGS_MOVE, x, y); + + fastpath_send_multiple_input_pdu(rdp->fastpath, s, 4); +} + static BOOL input_recv_sync_event(rdpInput* input, wStream* s) { UINT32 toggleFlags; @@ -379,6 +423,7 @@ void input_register_client_callbacks(rdpInput* input) input->UnicodeKeyboardEvent = input_send_fastpath_unicode_keyboard_event; input->MouseEvent = input_send_fastpath_mouse_event; input->ExtendedMouseEvent = input_send_fastpath_extended_mouse_event; + input->FocusInEvent = input_send_fastpath_focus_in_event; } else { @@ -387,6 +432,7 @@ void input_register_client_callbacks(rdpInput* input) input->UnicodeKeyboardEvent = input_send_unicode_keyboard_event; input->MouseEvent = input_send_mouse_event; input->ExtendedMouseEvent = input_send_extended_mouse_event; + input->FocusInEvent = input_send_focus_in_event; } input->asynchronous = settings->AsyncInput; @@ -430,6 +476,11 @@ void freerdp_input_send_extended_mouse_event(rdpInput* input, UINT16 flags, UINT IFCALL(input->ExtendedMouseEvent, input, flags, x, y); } +void freerdp_input_send_focus_in_event(rdpInput* input, UINT16 toggleStates, UINT16 x, UINT16 y) +{ + IFCALL(input->FocusInEvent, input, toggleStates, x, y); +} + int input_process_events(rdpInput* input) { return input_message_queue_process_pending_messages(input); diff --git a/libfreerdp/core/rdp.h b/libfreerdp/core/rdp.h index a8128c2ee..5188facc5 100644 --- a/libfreerdp/core/rdp.h +++ b/libfreerdp/core/rdp.h @@ -156,6 +156,7 @@ struct rdp_rdp UINT32 errorInfo; UINT32 finalize_sc_pdus; BOOL disconnect; + BOOL resendFocus; }; BOOL rdp_read_security_header(wStream* s, UINT16* flags);