diff --git a/libweston/backend-rdp/rdp.c b/libweston/backend-rdp/rdp.c index 09debbae9..5c18cf516 100644 --- a/libweston/backend-rdp/rdp.c +++ b/libweston/backend-rdp/rdp.c @@ -1736,8 +1736,10 @@ xf_input_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code) enum wl_keyboard_key_state keyState; freerdp_peer *client = input->context->peer; RdpPeerContext *peerContext = (RdpPeerContext *)input->context; - struct rdp_backend *b = peerContext->rdpBackend; - bool need_release = false; + struct weston_keyboard *keyboard = weston_seat_get_keyboard(peerContext->item.seat); + /*struct rdp_backend *b = peerContext->rdpBackend;*/ + bool send_key = false; + bool send_release_key = false; int notify = 0; struct timespec time; @@ -1753,7 +1755,7 @@ xf_input_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code) notify = 1; } - if (notify) { + if (keyboard && notify) { full_code = code; if (flags & KBD_FLAGS_EXTENDED) full_code |= KBD_FLAGS_EXTENDED; @@ -1776,22 +1778,10 @@ xf_input_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code) /* RDP works same, there is no release for those 2 Korean keys, * thus generate release right after press. */ assert(keyState == WL_KEYBOARD_KEY_STATE_PRESSED); - need_release = true; + send_release_key = true; } else { vk_code = GetVirtualKeyCodeFromVirtualScanCode(full_code, client->settings->KeyboardType); } - assert(vk_code <= 0xFF); - if (keyState == WL_KEYBOARD_KEY_STATE_RELEASED) { - /* Ignore release if key is not previously pressed. */ - if ((peerContext->key_state[vk_code>>3] & (1<<(vk_code&0x7))) == 0) { - rdp_debug_verbose(b, "%s: inconsistent key state vk_code:%x\n", - __func__, vk_code); - goto exit; - } - peerContext->key_state[vk_code>>3] &= ~(1<<(vk_code&0x7)); - } else if (!need_release /* when release is issued right after, no need to save state */) { - peerContext->key_state[vk_code>>3] |= (1<<(vk_code&0x7)); - } /* Korean keyboard support */ /* WinPR's GetKeycodeFromVirtualKeyCode() expects no extended bit for VK_HANGUL and VK_HANJA */ if (vk_code != VK_HANGUL && vk_code != VK_HANJA) @@ -1799,30 +1789,42 @@ xf_input_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code) vk_code |= KBDEXT; scan_code = GetKeycodeFromVirtualKeyCode(vk_code, KEYCODE_TYPE_EVDEV); - /*weston_log("code=%x ext=%d vk_code=%x scan_code=%x\n", code, (flags & KBD_FLAGS_EXTENDED) ? 1 : 0, vk_code, scan_code);*/ - weston_compositor_get_time(&time); - notify_key(peerContext->item.seat, &time, - scan_code - 8, keyState, STATE_UPDATE_AUTOMATIC); - /*rdp_debug_verbose(b, "RDP backend: %s code=%x ext=%d vk_code=%x scan_code=%x pressed=%d, idle_inhibit=%d\n", - __func__, code, (flags & KBD_FLAGS_EXTENDED) ? 1 : 0, - vk_code, scan_code, keyState, b->compositor->idle_inhibit);*/ + /* Ignore release if key is not previously pressed. */ + if (keyState == WL_KEYBOARD_KEY_STATE_RELEASED) { + uint32_t *k, *end; + end = keyboard->keys.data + keyboard->keys.size; + for (k = keyboard->keys.data; k < end; k++) { + if (*k == (scan_code - 8)) { + send_key = true; + break; + } + } + } else { + send_key = true; + } - if (need_release) { - /* send release of same key */ + if (send_key) { +send_release_key: weston_compositor_get_time(&time); notify_key(peerContext->item.seat, &time, - scan_code - 8, WL_KEYBOARD_KEY_STATE_RELEASED, STATE_UPDATE_AUTOMATIC); + scan_code - 8, keyState, STATE_UPDATE_AUTOMATIC); - /*rdp_debug_verbose(b, "RDP backend: %s code=%x ext=%d vk_code=%x scan_code=%x pressed=%d, idle_inhibit=%d\n", + /*rdp_debug(b, "RDP backend: %s code=%x ext=%d vk_code=%x scan_code=%x pressed=%d, idle_inhibit=%d\n", __func__, code, (flags & KBD_FLAGS_EXTENDED) ? 1 : 0, vk_code, scan_code, keyState, b->compositor->idle_inhibit);*/ + + if (send_release_key) { + send_release_key = false; + assert(keyState == WL_KEYBOARD_KEY_STATE_PRESSED); + keyState = WL_KEYBOARD_KEY_STATE_RELEASED; + goto send_release_key; + } } } -exit: FREERDP_CB_RETURN(TRUE); } diff --git a/libweston/backend-rdp/rdp.h b/libweston/backend-rdp/rdp.h index 021ebe166..7689210d9 100644 --- a/libweston/backend-rdp/rdp.h +++ b/libweston/backend-rdp/rdp.h @@ -276,7 +276,6 @@ struct rdp_peer_context { bool button_state[5]; bool mouseButtonSwap; - char key_state[0xff/8]; // one bit per key. int verticalAccumWheelRotationPrecise; int verticalAccumWheelRotationDiscrete; int horizontalAccumWheelRotationPrecise; diff --git a/rdprail-shell/shell.c b/rdprail-shell/shell.c index 884516f0c..3bb5fb7cc 100644 --- a/rdprail-shell/shell.c +++ b/rdprail-shell/shell.c @@ -199,6 +199,7 @@ struct rotate_grab { struct shell_seat { struct weston_seat *seat; + struct desktop_shell *shell; struct wl_listener seat_destroy_listener; struct weston_surface *focused_surface; @@ -230,6 +231,9 @@ find_shell_output_from_weston_output(struct desktop_shell *shell, static void shell_surface_update_child_surface_layers(struct shell_surface *shsurf); +static void +shell_backend_request_window_activate(void *shell_context, struct weston_seat *seat, struct weston_surface *surface); + #define ICON_STRIDE( W, BPP ) ((((W) * (BPP) + 31) / 32) * 4) static int cached_tm_mday = -1; @@ -1459,20 +1463,59 @@ handle_keyboard_focus(struct wl_listener *listener, void *data) { struct weston_keyboard *keyboard = data; struct shell_seat *seat = get_shell_seat(keyboard->seat); + struct desktop_shell *shell = seat->shell; + struct weston_surface* new_focused_surface = weston_surface_get_main_surface(keyboard->focus); + struct weston_surface* old_focused_surface = seat->focused_surface; + + if (shell->debugLevel >= RDPRAIL_SHELL_DEBUG_LEVEL_VERBOSE) { + struct weston_desktop_surface *old_desktop_surface = NULL; + struct weston_desktop_surface *new_desktop_surface = NULL; + const char *old_title = NULL; + const char *new_title = NULL; + + if (old_focused_surface) + old_desktop_surface = weston_surface_get_desktop_surface(old_focused_surface); + if (new_focused_surface) + new_desktop_surface = weston_surface_get_desktop_surface(new_focused_surface); + if (old_desktop_surface) + old_title = weston_desktop_surface_get_title(old_desktop_surface); + if (new_desktop_surface) + new_title = weston_desktop_surface_get_title(new_desktop_surface); + + shell_rdp_debug_verbose(shell, "%s: moving focus from %p:%s to %p:%s\n", __func__, + old_focused_surface, old_title, new_focused_surface, new_title); + } - if (seat->focused_surface) { - struct shell_surface *shsurf = get_shell_surface(seat->focused_surface); + if (old_focused_surface) { + struct shell_surface *shsurf = get_shell_surface(old_focused_surface); if (shsurf) shell_surface_lose_keyboard_focus(shsurf); } - seat->focused_surface = weston_surface_get_main_surface(keyboard->focus); + seat->focused_surface = new_focused_surface; - if (seat->focused_surface) { - struct shell_surface *shsurf = get_shell_surface(seat->focused_surface); + if (new_focused_surface) { + struct shell_surface *shsurf = get_shell_surface(new_focused_surface); if (shsurf) shell_surface_gain_keyboard_focus(shsurf); } + + if (new_focused_surface == shell->focus_proxy_surface) { + /* When new focused window is focus proxy window, client side window is + taking focus and server side window is losing focus, thus let keyboard + to clear out currently pressed keys. This is because once server side + window is gone from client desktop, the client no longer sends keyboard + inputs including key release, thus if any keys are currently at pressed + state, it doesn't recieve release for those keys from RDP client. */ + while (keyboard->keys.size) { + struct timespec time; + uint32_t *k = keyboard->keys.data; + weston_compositor_get_time(&time); + notify_key(seat->seat, &time, *k, + WL_KEYBOARD_KEY_STATE_RELEASED, STATE_UPDATE_AUTOMATIC); + /* shell_rdp_debug_verbose(shell, "%s: released key:0x%x\n", __func__, *k); */ + } + } } /* The surface will be inserted into the list immediately after the link @@ -1935,7 +1978,7 @@ shell_seat_caps_changed(struct wl_listener *listener, void *data) } static struct shell_seat * -create_shell_seat(struct weston_seat *seat) +create_shell_seat(struct desktop_shell *shell, struct weston_seat *seat) { struct shell_seat *shseat; @@ -1946,6 +1989,7 @@ create_shell_seat(struct weston_seat *seat) } shseat->seat = seat; + shseat->shell = shell; shseat->seat_destroy_listener.notify = destroy_shell_seat; wl_signal_add(&seat->destroy_signal, @@ -3740,7 +3784,26 @@ desktop_shell_set_focus_proxy(struct wl_client *client, struct wl_resource *surface_resource) { struct desktop_shell *shell = wl_resource_get_user_data(resource); - shell->focus_proxy_surface = wl_resource_get_user_data(surface_resource); + struct weston_surface *surface; + struct shell_surface *shsurf; + + surface = wl_resource_get_user_data(surface_resource); + if (!surface) { + shell_rdp_debug(shell, "%s: surface is NULL\n", __func__); + return; + } + + shsurf = get_shell_surface(surface); + if (!shsurf) { + shell_rdp_debug(shell, "%s: surface:%p is not shell surface\n", __func__, surface); + return; + } + + shell->focus_proxy_surface = surface; + + /* Update the surface’s layer. This brings it to the top of the stacking + * order as appropriate. */ + shell_surface_update_layer(shsurf); } static const struct weston_rdprail_shell_interface rdprail_shell_implementation = { @@ -4074,8 +4137,12 @@ static void handle_seat_created(struct wl_listener *listener, void *data) { struct weston_seat *seat = data; + struct desktop_shell *shell; + + shell = container_of(listener, struct desktop_shell, + seat_create_listener); - create_shell_seat(seat); + create_shell_seat(shell, seat); } struct shell_workarea_change { @@ -4114,7 +4181,8 @@ shell_reposition_view_on_workarea_change(struct weston_view *view, void *data) but if it does, the server has no way to tell where it goes, thus here forcing backend to resend window state to client, this force window state, especially window position keeps in sync between server and client. */ - rail_state->forceUpdateWindowState = true; + if (rail_state) + rail_state->forceUpdateWindowState = true; /* If view's upper-left is within 10% of bottom-right of workarea boundary, adjust the position. */ int new_workarea_width = (int)workarea_change->new_workarea.width;