mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-11-11 10:59:06 +08:00
[fix] keep stream menus open while suspending remote input
This commit is contained in:
@@ -48,6 +48,7 @@
|
|||||||
#include "features/gallery/gallery_workspace.h"
|
#include "features/gallery/gallery_workspace.h"
|
||||||
#include "features/gallery/preview_bandwidth.h"
|
#include "features/gallery/preview_bandwidth.h"
|
||||||
#include "features/gallery/preview_resolution.h"
|
#include "features/gallery/preview_resolution.h"
|
||||||
|
#include "features/input/stream_keyboard_focus.h"
|
||||||
#include "filesystem_utf8.h"
|
#include "filesystem_utf8.h"
|
||||||
#include "localization.h"
|
#include "localization.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
@@ -3803,19 +3804,10 @@ void GuiApplication::SyncXWaylandWindowActivation() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void GuiApplication::SetStreamKeyboardFocus(bool focused) {
|
void GuiApplication::SetStreamKeyboardFocus(bool focused) {
|
||||||
// Local dialogs own input even while the native window is active.
|
const bool local_input_active = ui_ && ui_->stream &&
|
||||||
if (focused && ui_ && ui_->stream &&
|
(*ui_->stream)->get_local_input_active();
|
||||||
(*ui_->stream)->get_modal_visible()) {
|
UpdateStreamKeyboardFocus(focused, local_input_active, focus_on_stream_window_,
|
||||||
focused = false;
|
[this](bool preserve_local_ui) { ReleaseControl(preserve_local_ui); });
|
||||||
}
|
|
||||||
if (focus_on_stream_window_ == focused) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
focus_on_stream_window_ = focused;
|
|
||||||
if (!focused) {
|
|
||||||
ReleaseControl();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiApplication::SyncStreamKeyboardFocus() {
|
void GuiApplication::SyncStreamKeyboardFocus() {
|
||||||
@@ -5665,7 +5657,7 @@ void GuiApplication::SyncAudioPlayback() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiApplication::ReleasePressedInput() {
|
void GuiApplication::ReleasePressedInput(bool preserve_local_ui) {
|
||||||
keyboard_.ForceReleasePressedKeys();
|
keyboard_.ForceReleasePressedKeys();
|
||||||
for (int button : ui_->pressed_mouse_buttons) {
|
for (int button : ui_->pressed_mouse_buttons) {
|
||||||
RemoteAction action{};
|
RemoteAction action{};
|
||||||
@@ -5678,13 +5670,16 @@ void GuiApplication::ReleasePressedInput() {
|
|||||||
SendRemoteInput(action);
|
SendRemoteInput(action);
|
||||||
}
|
}
|
||||||
ui_->pressed_mouse_buttons.clear();
|
ui_->pressed_mouse_buttons.clear();
|
||||||
if (ui_->stream) (*ui_->stream)->invoke_reset_input_state();
|
if (ui_->stream) {
|
||||||
|
if (preserve_local_ui) (*ui_->stream)->invoke_reset_pressed_input();
|
||||||
|
else (*ui_->stream)->invoke_reset_input_state();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiApplication::ReleaseControl() {
|
void GuiApplication::ReleaseControl(bool preserve_local_ui) {
|
||||||
const auto gallery_target = ui_->gallery_control_id;
|
const auto gallery_target = ui_->gallery_control_id;
|
||||||
devices_.StopKeyboardCapturer();
|
devices_.StopKeyboardCapturer();
|
||||||
ReleasePressedInput();
|
ReleasePressedInput(preserve_local_ui);
|
||||||
gallery_group_control_id_.clear();
|
gallery_group_control_id_.clear();
|
||||||
ui_->wall->set_gallery_group_controlling(false);
|
ui_->wall->set_gallery_group_controlling(false);
|
||||||
ui_->wall->set_gallery_remote_cursor_shape(
|
ui_->wall->set_gallery_remote_cursor_shape(
|
||||||
|
|||||||
@@ -84,8 +84,8 @@ private:
|
|||||||
void DeviceGroupAction(const std::string& action, const std::string& value,
|
void DeviceGroupAction(const std::string& action, const std::string& value,
|
||||||
bool gallery_window);
|
bool gallery_window);
|
||||||
bool SaveDeviceGroups(const std::string& new_group, bool gallery_window);
|
bool SaveDeviceGroups(const std::string& new_group, bool gallery_window);
|
||||||
void ReleasePressedInput();
|
void ReleasePressedInput(bool preserve_local_ui = false);
|
||||||
void ReleaseControl();
|
void ReleaseControl(bool preserve_local_ui = false);
|
||||||
void SyncAudioPlayback();
|
void SyncAudioPlayback();
|
||||||
void SaveGalleryWindowState();
|
void SaveGalleryWindowState();
|
||||||
void SyncAnnouncements();
|
void SyncAnnouncements();
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* @Author: DI JUNKUN
|
||||||
|
* @Date: 2026-11-11
|
||||||
|
* Copyright (c) 2026 by DI JUNKUN, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _STREAM_KEYBOARD_FOCUS_H_
|
||||||
|
#define _STREAM_KEYBOARD_FOCUS_H_
|
||||||
|
|
||||||
|
namespace crossdesk {
|
||||||
|
|
||||||
|
// Native window focus and ownership of keyboard input are different: a local
|
||||||
|
// menu keeps the window active while temporarily suspending remote input.
|
||||||
|
// Publish the new state before releasing input, since UI callbacks can reenter.
|
||||||
|
template <typename Release>
|
||||||
|
void UpdateStreamKeyboardFocus(bool focused, bool local_input_active,
|
||||||
|
bool& remote_focused, Release release) {
|
||||||
|
focused = focused && !local_input_active;
|
||||||
|
if (remote_focused == focused) return;
|
||||||
|
remote_focused = focused;
|
||||||
|
if (!focused) release(local_input_active);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace crossdesk
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -423,6 +423,10 @@ export component StreamWindow inherits Window {
|
|||||||
private property <length> disconnect-menu-y: root.control-panel-y(root.disconnect-menu-height);
|
private property <length> disconnect-menu-y: root.control-panel-y(root.disconnect-menu-height);
|
||||||
private property <bool> control-menu-open:
|
private property <bool> control-menu-open:
|
||||||
root.display-menu-open || root.shortcut-menu-open || root.video-menu-open || root.disconnect-menu-open;
|
root.display-menu-open || root.shortcut-menu-open || root.video-menu-open || root.disconnect-menu-open;
|
||||||
|
out property <bool> local-input-active: root.modal-visible || root.control-menu-open;
|
||||||
|
changed control-menu-open => {
|
||||||
|
root.keyboard-focus-changed(!root.control-menu-open && !root.modal-visible && input-focus.has-focus);
|
||||||
|
}
|
||||||
changed selected-tab => {
|
changed selected-tab => {
|
||||||
root.close-control-menus();
|
root.close-control-menus();
|
||||||
root.cancel-remote-pointer();
|
root.cancel-remote-pointer();
|
||||||
@@ -589,10 +593,14 @@ export component StreamWindow inherits Window {
|
|||||||
|
|
||||||
// Native focus/session changes release input in C++; clear the matching UI
|
// Native focus/session changes release input in C++; clear the matching UI
|
||||||
// ownership too, including when replacing the only tab (same tab index).
|
// ownership too, including when replacing the only tab (same tab index).
|
||||||
public function reset-input-state() {
|
public function reset-pressed-input() {
|
||||||
root.remote-left-down = false;
|
root.remote-left-down = false;
|
||||||
root.remote-right-down = false;
|
root.remote-right-down = false;
|
||||||
root.remote-middle-down = false;
|
root.remote-middle-down = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reset-input-state() {
|
||||||
|
root.reset-pressed-input();
|
||||||
root.close-control-menus();
|
root.close-control-menus();
|
||||||
root.control-drag-pending = false;
|
root.control-drag-pending = false;
|
||||||
root.end-control-drag();
|
root.end-control-drag();
|
||||||
@@ -1039,10 +1047,10 @@ export component StreamWindow inherits Window {
|
|||||||
|
|
||||||
input-focus := FocusScope {
|
input-focus := FocusScope {
|
||||||
focus-on-click: true;
|
focus-on-click: true;
|
||||||
focus-gained => { root.keyboard-focus-changed(true); }
|
focus-gained => { root.keyboard-focus-changed(!root.control-menu-open && !root.modal-visible); }
|
||||||
focus-lost => { root.keyboard-focus-changed(false); }
|
focus-lost => { root.keyboard-focus-changed(false); }
|
||||||
key-pressed(event) => {
|
key-pressed(event) => {
|
||||||
if !root.modal-visible {
|
if !root.modal-visible && !root.control-menu-open {
|
||||||
root.key-input(event.text, true, event.modifiers.control, event.modifiers.alt, event.modifiers.shift, event.modifiers.meta);
|
root.key-input(event.text, true, event.modifiers.control, event.modifiers.alt, event.modifiers.shift, event.modifiers.meta);
|
||||||
}
|
}
|
||||||
accept
|
accept
|
||||||
@@ -1053,7 +1061,7 @@ export component StreamWindow inherits Window {
|
|||||||
if event.text == Key.Escape || event.text == Key.Return {
|
if event.text == Key.Escape || event.text == Key.Return {
|
||||||
if root.privacy-unlock-visible { root.dismiss-privacy-unlock(); } else { root.dismiss-remote-update(); }
|
if root.privacy-unlock-visible { root.dismiss-privacy-unlock(); } else { root.dismiss-remote-update(); }
|
||||||
}
|
}
|
||||||
} else {
|
} else if !root.control-menu-open {
|
||||||
root.key-input(event.text, false, event.modifiers.control, event.modifiers.alt, event.modifiers.shift, event.modifiers.meta);
|
root.key-input(event.text, false, event.modifiers.control, event.modifiers.alt, event.modifiers.shift, event.modifiers.meta);
|
||||||
}
|
}
|
||||||
accept
|
accept
|
||||||
|
|||||||
Reference in New Issue
Block a user