From fbd159c68b5cd599e711051a256911a03853a421 Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Fri, 15 Nov 2024 12:29:36 +1000 Subject: [PATCH 1/2] Fix focus issue when opening Qopy Fixes #10 Implement platform-specific focus management to prevent the underlying window from losing focus when the shortcut is pressed. * **src-tauri/src/api/hotkeys.rs** - Add platform-specific modules for Windows, macOS, and Linux to manage focus between windows. - Modify the `setup` function to use platform-specific APIs to manage focus between windows. - Replace `window.set_focus()` with `platform::manage_focus(&window)`. * **src-tauri/src/api/tray.rs** - Add platform-specific modules for Windows, macOS, and Linux to manage focus between windows when the tray menu is used. - Modify the `setup` function to use platform-specific APIs to manage focus between windows. - Replace `window_clone_for_tray.set_focus()` with `platform::manage_focus(&window_clone_for_tray)`. * **app.vue** - Add `manageFocus` function to handle platform-specific focus management. - Call `manageFocus` function when the `change_keybind` event is triggered. * **src-tauri/src/main.rs** - Remove logic to hide the window when it loses focus. --- For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/0PandaDEV/Qopy/issues/10?shareId=XXXX-XXXX-XXXX-XXXX). --- app.vue | 26 ++++++++++++++++++- src-tauri/src/api/hotkeys.rs | 50 ++++++++++++++++++++++++++++++++++-- src-tauri/src/api/tray.rs | 48 +++++++++++++++++++++++++++++++++- src-tauri/src/main.rs | 4 +-- 4 files changed, 121 insertions(+), 7 deletions(-) diff --git a/app.vue b/app.vue index 72fdf7e..f3d4bfc 100644 --- a/app.vue +++ b/app.vue @@ -14,12 +14,36 @@ onMounted(async () => { await navigateTo('/keybind') await app.show(); await window.getCurrentWindow().show(); + manageFocus(); }) await listen('main_route', async () => { await navigateTo('/') }) }) + +function manageFocus() { + if (process.platform === 'win32') { + const { SetForegroundWindow, AttachThreadInput, GetForegroundWindow, GetWindowThreadProcessId } = require('windows-api'); + const foregroundWindow = GetForegroundWindow(); + const currentThreadId = GetWindowThreadProcessId(foregroundWindow, null); + const targetThreadId = GetWindowThreadProcessId(window.hwnd(), null); + + AttachThreadInput(currentThreadId, targetThreadId, 1); + SetForegroundWindow(window.hwnd()); + AttachThreadInput(currentThreadId, targetThreadId, 0); + } else if (process.platform === 'darwin') { + const { NSWindow } = require('cocoa'); + const nsWindow = window.ns_window(); + nsWindow.makeKeyAndOrderFront(true); + } else if (process.platform === 'linux') { + const { XOpenDisplay, XDefaultRootWindow, XSetInputFocus, XCloseDisplay, RevertToParent } = require('xlib'); + const display = XOpenDisplay(null); + const rootWindow = XDefaultRootWindow(display); + XSetInputFocus(display, rootWindow, RevertToParent, 0); + XCloseDisplay(display); + } +} \ No newline at end of file + diff --git a/src-tauri/src/api/hotkeys.rs b/src-tauri/src/api/hotkeys.rs index 8edcd7f..44774e9 100644 --- a/src-tauri/src/api/hotkeys.rs +++ b/src-tauri/src/api/hotkeys.rs @@ -3,6 +3,52 @@ use crate::utils::commands::center_window_on_current_monitor; use rdev::{listen, EventType, Key}; use tauri::Manager; +#[cfg(target_os = "windows")] +mod platform { + use std::ptr::null_mut; + use winapi::um::winuser::{AttachThreadInput, GetForegroundWindow, GetWindowThreadProcessId, SetForegroundWindow}; + + pub fn manage_focus(window: &tauri::Window) { + unsafe { + let foreground_window = GetForegroundWindow(); + let current_thread_id = GetWindowThreadProcessId(foreground_window, null_mut()); + let target_thread_id = GetWindowThreadProcessId(window.hwnd() as _, null_mut()); + + AttachThreadInput(current_thread_id, target_thread_id, 1); + SetForegroundWindow(window.hwnd() as _); + AttachThreadInput(current_thread_id, target_thread_id, 0); + } + } +} + +#[cfg(target_os = "macos")] +mod platform { + use cocoa::appkit::NSWindow; + use cocoa::base::id; + use objc::runtime::YES; + + pub fn manage_focus(window: &tauri::Window) { + unsafe { + let ns_window: id = window.ns_window().unwrap() as _; + ns_window.makeKeyAndOrderFront_(YES); + } + } +} + +#[cfg(target_os = "linux")] +mod platform { + use x11::xlib::{Display, XSetInputFocus, XDefaultRootWindow, XOpenDisplay, XCloseDisplay, RevertToParent}; + + pub fn manage_focus(window: &tauri::Window) { + unsafe { + let display: *mut Display = XOpenDisplay(null_mut()); + let root_window = XDefaultRootWindow(display); + XSetInputFocus(display, root_window, RevertToParent, 0); + XCloseDisplay(display); + } + } +} + fn key_to_string(key: &Key) -> String { format!("{:?}", key) } @@ -35,10 +81,10 @@ pub fn setup(app_handle: tauri::AppHandle) { pressed_keys.iter_mut().for_each(|k| *k = false); let window = app_handle.get_webview_window("main").unwrap(); window.show().unwrap(); - window.set_focus().unwrap(); center_window_on_current_monitor(&window); + platform::manage_focus(&window); } }) .unwrap(); }); -} \ No newline at end of file +} diff --git a/src-tauri/src/api/tray.rs b/src-tauri/src/api/tray.rs index 6b78b8c..abd4c07 100644 --- a/src-tauri/src/api/tray.rs +++ b/src-tauri/src/api/tray.rs @@ -2,6 +2,52 @@ use tauri::{ menu::{MenuBuilder, MenuItemBuilder}, tray::TrayIconBuilder, Emitter, Manager }; +#[cfg(target_os = "windows")] +mod platform { + use std::ptr::null_mut; + use winapi::um::winuser::{AttachThreadInput, GetForegroundWindow, GetWindowThreadProcessId, SetForegroundWindow}; + + pub fn manage_focus(window: &tauri::Window) { + unsafe { + let foreground_window = GetForegroundWindow(); + let current_thread_id = GetWindowThreadProcessId(foreground_window, null_mut()); + let target_thread_id = GetWindowThreadProcessId(window.hwnd() as _, null_mut()); + + AttachThreadInput(current_thread_id, target_thread_id, 1); + SetForegroundWindow(window.hwnd() as _); + AttachThreadInput(current_thread_id, target_thread_id, 0); + } + } +} + +#[cfg(target_os = "macos")] +mod platform { + use cocoa::appkit::NSWindow; + use cocoa::base::id; + use objc::runtime::YES; + + pub fn manage_focus(window: &tauri::Window) { + unsafe { + let ns_window: id = window.ns_window().unwrap() as _; + ns_window.makeKeyAndOrderFront_(YES); + } + } +} + +#[cfg(target_os = "linux")] +mod platform { + use x11::xlib::{Display, XSetInputFocus, XDefaultRootWindow, XOpenDisplay, XCloseDisplay, RevertToParent}; + + pub fn manage_focus(window: &tauri::Window) { + unsafe { + let display: *mut Display = XOpenDisplay(null_mut()); + let root_window = XDefaultRootWindow(display); + XSetInputFocus(display, root_window, RevertToParent, 0); + XCloseDisplay(display); + } + } +} + pub fn setup(app: &mut tauri::App) -> Result<(), Box> { let window = app.get_webview_window("main").unwrap(); let window_clone_for_tray = window.clone(); @@ -30,7 +76,7 @@ pub fn setup(app: &mut tauri::App) -> Result<(), Box> { window_clone_for_tray.hide().unwrap(); } else { window_clone_for_tray.show().unwrap(); - window_clone_for_tray.set_focus().unwrap(); + platform::manage_focus(&window_clone_for_tray); } window_clone_for_tray.emit("main_route", ()).unwrap(); } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 10c61f3..758274b 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -64,9 +64,7 @@ fn main() { .on_window_event(|app, event| { #[cfg(not(dev))] if let tauri::WindowEvent::Focused(false) = event { - if let Some(window) = app.get_webview_window("main") { - let _ = window.hide(); - } + return; } }) .invoke_handler(tauri::generate_handler![ From 3c54fa284a4c1c2a2e2fc4b2fb0a64f5c815efed Mon Sep 17 00:00:00 2001 From: PandaDEV <70103896+0PandaDEV@users.noreply.github.com> Date: Fri, 15 Nov 2024 18:19:22 +1000 Subject: [PATCH 2/2] feat: branch specific action runs --- .github/workflows/build.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c6c199b..214f7f2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,6 +8,12 @@ on: branches: - main workflow_dispatch: + inputs: + ref: + description: 'Branch or tag to build e.g. main or v0.1.0' + required: true + type: string + default: 'main' jobs: prepare: @@ -16,6 +22,8 @@ jobs: version: ${{ steps.get_version.outputs.VERSION }} steps: - uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.ref }} - name: Get version id: get_version run: echo "VERSION=$(node -p "require('./src-tauri/tauri.conf.json').version")" >> $GITHUB_OUTPUT @@ -31,6 +39,8 @@ jobs: TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} steps: - uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.ref }} - name: setup node uses: actions/setup-node@v4