Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[global-shortcut][v2] How to register a shortcut using tauri_plugin_global_shortcut #965

Closed
MystiPanda opened this issue Feb 18, 2024 · 19 comments

Comments

@MystiPanda
Copy link

During the migration process, I found that the register function in the tauri_plugin_global_shortcut plug-in does not accept the handler parameter. How can I register a shortcut key?

Thanks and looking forward to your reply:)

@amrbashir
Copy link
Member

I have updated the example, check it out here https://github.com/tauri-apps/plugins-workspace/tree/v2/plugins/global-shortcut#usage

@MystiPanda
Copy link
Author

emm, with all due respect, this design seems a bit counter-intuitive. Is this part of the api likely to change in the future?

@jasonterando
Copy link

jasonterando commented Feb 19, 2024

Hi, I'm on v2.0, beta 0 for@tauri-apps/plugin-global-shortcut. When running an application with the below main(), I do see the "Setting up global shortcut" message printed, but I do not see the "Shortcut" println coming up on every hotkey-ish type of key press, and I do not (nor do I see the Ctrl-N println for that matter).

I'm running a NextJS/React app, if that is relevant. JavaScript registrations using register still work, so I could fall back to that if necessary.

What am I missing? Is there an additional init() like there is for other plugins?

Thanks!

 fn main() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![open_workbook, save_workbook, run_request, cancel_request, clear_cached_authorization])
        .plugin(tauri_plugin_fs::init())
        .plugin(tauri_plugin_dialog::init())
        .setup(|app| {
            #[cfg(desktop)]
            {
              println!("Setting up global shortcut");
              use tauri_plugin_global_shortcut::{Shortcut, Code, Modifiers};
              let ctrl_n_shortcut = Shortcut::new(Some(Modifiers::CONTROL), Code::KeyN);
              app.handle().plugin(
                tauri_plugin_global_shortcut::Builder::with_handler(move |app, shortcut| {
                    println!("{:?}", shortcut);
                    if shortcut == &ctrl_n_shortcut {
                        println!("Ctrl-N Detected!");
                        app.emit_to(EventTarget::any(), "NEW",  "").unwrap()
                    }
                })
                .build()
              )?;
            }
            Ok(())            
        })
        .run(tauri::generate_context!())
        .expect("error running app");
}

@FabianLars
Copy link
Member

emm, with all due respect, this design seems a bit counter-intuitive. Is this part of the api likely to change in the future?

Anything specific that triggers you? Or even better, any ideas how to improve it? Afaik we don't really have any changes planned, but we still can do it while it's still in beta.

@amrbashir
Copy link
Member

amrbashir commented Feb 19, 2024

@jasonterando I have updated the example, I forgot to add the registering code

 fn main() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![open_workbook, save_workbook, run_request, cancel_request, clear_cached_authorization])
        .plugin(tauri_plugin_fs::init())
        .plugin(tauri_plugin_dialog::init())
        .setup(|app| {
            #[cfg(desktop)]
            {
              println!("Setting up global shortcut");
-             use tauri_plugin_global_shortcut::{Shortcut, Code, Modifiers};
+             use tauri_plugin_global_shortcut::{Shortcut, Code, Modifiers, GlobalShortcutExt};
              let ctrl_n_shortcut = Shortcut::new(Some(Modifiers::CONTROL), Code::KeyN);
              app.handle().plugin(
                tauri_plugin_global_shortcut::Builder::with_handler(move |app, shortcut| {
                    println!("{:?}", shortcut);
                    if shortcut == &ctrl_n_shortcut {
                        println!("Ctrl-N Detected!");
                        app.emit_to(EventTarget::any(), "NEW",  "").unwrap()
                    }
                })
                .build()
              )?;
+             app.global_shorcut().register(ctrl_n_shortcut )?;
            }
            Ok(())            
        })
        .run(tauri::generate_context!())
        .expect("error running app");
}

@amrbashir
Copy link
Member

emm, with all due respect, this design seems a bit counter-intuitive. Is this part of the api likely to change in the future?

As fabian said, we are open to suggestions and nothing is set to stone just yet

@MystiPanda
Copy link
Author

@FabianLars @amrbashir Sorry, I just saw your reply, Thank you for your replies. What I am building now is an application that can run in the background, that is, it will still run in the background after closing the last window. This application allows users to customize a series of global shortcut keys that need to be bound. A rust function to perform some system-level operations, such as opening/closing the system proxy, so I cannot complete the shortcut key binding operation in the js code. However, based on the current interface design, I want to implement this in rust It seems to be very difficult to customize the shortcut key function. In my opinion, it would be great if the rust api of the shortcut key plug-in can be as concise and easy to use as the js api, just like the v1 version, at least js and rust can look at the code logic. It is a unified way of use.

The use cases I am talking about should be more common usage in desktop software, not special cases of individual software, so I hope you can take its application scenarios into consideration when designing the API.

@amrbashir
Copy link
Member

I think we can do something like this (while keeping the current API as well)

app.global_shortcut().register_with_handler(shortcut, |app| {
  // shortcut triggered
});

@MystiPanda
Copy link
Author

I noticed that there is still an exposed register function, but it does not accept the handler parameter. I am confused about what this function is used for now.

@MystiPanda
Copy link
Author

I think we can do something like this (while keeping the current API as well)

app.global_shortcut().register_with_handler(shortcut, |app| {
  // shortcut triggered
});

This looks good for me.

@amrbashir
Copy link
Member

I noticed that there is still an exposed register function, but it does not accept the handler parameter. I am confused about what this function is used for now.

The function is used to register a shortcut that will be catched by the handler passed to tauri_plugin_global_shortcut::Builder::with_handler

@MystiPanda
Copy link
Author

I noticed that there is still an exposed register function, but it does not accept the handler parameter. I am confused about what this function is used for now.

The function is used to register a shortcut that will be catched by the handler passed to tauri_plugin_global_shortcut::Builder::with_handler

So did you forget to call the register function in your example?

@amrbashir
Copy link
Member

yeah, I updated the example.

@MystiPanda
Copy link
Author

Oh, I just saw your reply above. I have no other questions. The regiater_with_handler proposal you mentioned is great.

Thank you for your patience, and thank you for your hard work:)

@jasonterando
Copy link

Thanks @amrbashir - getting closer :) If I try doing a doing an app.emit or app.emit_to from within the "with_handler", I get the following error, which is hitting the boundary of my meager (but growing) Rust knowledge. Can you give me an idea of what I'm doing wrong? Thanks!

        .setup(|app| {
            #[cfg(desktop)]
            {
                use tauri_plugin_global_shortcut::{Code, GlobalShortcutExt, Modifiers, Shortcut};

                let ctrl_n_shortcut = Shortcut::new(Some(Modifiers::CONTROL), Code::KeyN);
                app.handle().plugin(
                    tauri_plugin_global_shortcut::Builder::with_handler(move |_app, shortcut| {
                        println!("{:?}", shortcut);
                        if shortcut == &ctrl_n_shortcut {
                            println!("Ctrl-N Detected!");
                            app.emit("new", "").unwrap()
                            // app.emit_to(EventTarget::any(), "new",  "").unwrap()
                        }
                    })
                    .build(),
                )?;

                app.global_shortcut().register(ctrl_n_shortcut)?;
            }
`(dyn for<'a> FnOnce(&'a mut tauri::App) -> Result<(), Box<(dyn std::error::Error + 'static)>> + Send + 'static)` cannot be shared between threads safely
the trait `Sync` is not implemented for `(dyn for<'a> FnOnce(&'a mut tauri::App) -> Result<(), Box<(dyn std::error::Error + 'static)>> + Send + 'static)`
required for `Unique<(dyn for<'a> FnOnce(&'a mut tauri::App) -> Result<(), Box<(dyn std::error::Error + 'static)>> + Send + 'static)>` to implement `Sync`
required because it appears within the type `&mut App`

@amrbashir
Copy link
Member

App is not Send or Sync and you need to get a handle to it instead

   .setup(|app| {
            #[cfg(desktop)]
            {
                use tauri_plugin_global_shortcut::{Code, GlobalShortcutExt, Modifiers, Shortcut};

                let ctrl_n_shortcut = Shortcut::new(Some(Modifiers::CONTROL), Code::KeyN);
+               let handle = app.handle().clone();
                app.handle().plugin(
                    tauri_plugin_global_shortcut::Builder::with_handler(move |_app, shortcut| {
                        println!("{:?}", shortcut);
                        if shortcut == &ctrl_n_shortcut {
                            println!("Ctrl-N Detected!");
-                           app.emit("new", "").unwrap()
+                           handle.emit("new", "").unwrap()
                            // app.emit_to(EventTarget::any(), "new",  "").unwrap()
                        }
                    })
                    .build(),
                )?;

                app.global_shortcut().register(ctrl_n_shortcut)?;
            }

@amrbashir
Copy link
Member

PR for the new API #969

@jasonterando
Copy link

@amrbashir - My Hero, thanks! I imagine doing an "emit" from the handler would be a pretty common use case, it may be worthwhile including that in the updated example, if you haven't already.

@amrbashir
Copy link
Member

will do

ppbl pushed a commit to ppbl/plugins-workspace that referenced this issue Feb 20, 2024
lucasfernog added a commit that referenced this issue Mar 7, 2024
* feat(global-shortcut): add `GlobalShortcutExt::register_with_handler`

ref: #965

* clippy

* refactor apis to take closure by default

* change file

* Update .changes/global-shortcut-refactor.md

Co-authored-by: Simon Hyll <[email protected]>

* Update global-shortcut-refactor.md

* use option instead

* clippy

* update readme

* on_shortcut and with_shortcut

* map handler

* simplify events

* lint

---------

Co-authored-by: Simon Hyll <[email protected]>
Co-authored-by: Lucas Nogueira <[email protected]>
tauri-bot pushed a commit to tauri-apps/tauri-plugin-global-shortcut that referenced this issue Mar 7, 2024
* feat(global-shortcut): add `GlobalShortcutExt::register_with_handler`

ref: tauri-apps/plugins-workspace#965

* clippy

* refactor apis to take closure by default

* change file

* Update .changes/global-shortcut-refactor.md

Co-authored-by: Simon Hyll <[email protected]>

* Update global-shortcut-refactor.md

* use option instead

* clippy

* update readme

* on_shortcut and with_shortcut

* map handler

* simplify events

* lint

---------

Co-authored-by: Simon Hyll <[email protected]>
Co-authored-by: Lucas Nogueira <[email protected]>

Committed via a GitHub action: https://github.com/tauri-apps/plugins-workspace/actions/runs/8191604626

Co-authored-by: lucasfernog <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants