8000 Global hotkeys by Nyjako · Pull Request #354 · uowuo/abaddon · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Global hotkeys #354

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

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open

Global hotkeys #354

wants to merge 9 commits into from

Conversation

Nyjako
Copy link
@Nyjako Nyjako commented Mar 17, 2025

Simple Hotkey Support

For now only support:

  • Mute: Alt+M
  • Deafen: Alt+D

This feature uses libUIOHook, which has been added as a submodule.

For now shortcuts are hardcoded in src/windows/voice/voicewindow.cpp

Addresses a request from this comment in issue #30
Closes #322

TODO

  • Make libuiohook an optional dependency.
  • Use Glib::Dispatcher to synchronize callbacks to the main thread.
  • Move hotkeys out of voicewindow.
  • Add configuration for shortcuts.
  • Convert human-readable shortcuts into libuihooks keycodes
  • Move GlobalHotkeyManager to Abaddon singleton.

Nyjako added 2 commits March 17, 2025 20:44
Added hotkey for mute ALT+M
Added hotkey for deafen ALT+D
@ouwou
Copy link
Member
ouwou commented Mar 17, 2025

interesting i havent seen that library before. i dont really like the low level keyboard hook on win32 (theres a reason msys disables it) but tbh if it works then i dont really mind.

id probably make GlobalHotkeyManager not a singleton and just move it to live in the Abaddon singleton. id also want libuiohook as an optional dependency (should be easy enough to just #ifdef out the public api and replace it with empty stubs)
also configuration is definitely necessary. ill have to look again at what gtk/glib might have for doing that

// Run hook in separate thread to not block gtk
std::thread([this]() {
if (hook_run() != UIOHOOK_SUCCESS) {
std::cerr << "Failed to start libuiohook" << std::endl;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should use spdlog. the "ui" logger is probably fine for this

Comment on lines 35 to 39
m_callbacks[id] = {
.keycode = keycode,
.modifiers = modifiers,
.callback = callback
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the .a = b syntax is c++20 but this is a c++17 project

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C++20 sneaked in while I wasn’t looking!

}

GlobalHotkeyManager::Hotkey* GlobalHotkeyManager::find_hotkey(uint16_t keycode, uint32_t modifiers) {
auto it = std::find_if(m_callbacks.begin(), m_callbacks.end(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldnt m_mutex be locked here too ?

Hotkey *hk = find_hotkey(event->data.keyboard.keycode, event->mask);
if (hk != nullptr) {
std::lock_guard<std::mutex> lock(m_mutex);
hk->callback();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i assume this will still execute the callback on the thread created above which does the hook stuff
since the callbacks are doing stuff to the ui from the wrong thread there will invariably be crashes. Glib::Dispatcher exists to synchronize back to the main thread. heres an example of using dispatcher+queue+mutex to synchronize from websocket thread back to main thread
https://github.com/uowuo/abaddon/blob/ba15622a751b8e67b8b62d512ad713bc408f090d/src/remoteauth/remoteauthclient.cpp

Comment on lines 60 to 69
// TODO: Load shortcuts from config file
m_mute_hotkey = GlobalHotkeyManager::instance().registerHotkey(VC_M, MASK_ALT, [this]() {
// This is probably stupid there is for sure some way to call event
// but I'm not really familiar with gtk and this works well.
m_mute.set_active( !m_mute.get_active() );
});
m_deafen_hotkey = GlobalHotkeyManager::instance().registerHotkey(VC_D, MASK_ALT, [this]() {
m_deafen.set_active( !m_deafen.get_active() );
});

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

im not entirely sure where the best place to do this would be (maybe just in the main Abaddon singleton, but theres gonna need to be some other changes to actually propagate that to the right places) but here definitely wont work. for example this window is intended to be able to be closed without disconnecting from vc in which case the hotkey is unregistered

Added `ENABLE_GLOBAL_HOTKEY` option in cmake (ON by default)
Removed designated initializer from struct
Replaced `std::cerr` with `spdlog::get("ui")->error`
Added missing mutex lock
Used `Glib::Dispatcher` for executing callbacks (Hope done correctly)

For now mute/deafen hotkey are still placed in voicewindow
@Nyjako
Copy link
Author
Nyjako commented Mar 18, 2025

My ideas for shortcuts configuration.

Human-Readable Parser

Parse shortcuts like ALT+M into their keycode/mask values.

Numerical values in config

Expose keycode and mask directly in settings.
This would require UI helper (e.g. Set Shortcuts dialog).

@ouwou
Copy link
Member
ouwou commented Mar 18, 2025

ideally both (config + ui helper) but for now just config is fine. GTK has gtk_accelerator_parse which can parse out <Alt>d for example. i assume well probably need a mapping somewhere from GDK keyvals to libuihooks virtual key codes

Nyjako added 2 commits March 19, 2025 07:15
I might have added a bit to much but it might be useful later with ui
helper
@Nyjako
Copy link
Author
Nyjako commented Mar 19, 2025

Would it be alright if I add public functions to VoiceWindow:

void SetMute( bool is_mute );
void SetDeaf( bool is_deaf );
bool GetMute();
bool GetDeaf();

Then register hotkey inside OnVoiceConnected function in abaddon.cpp

m_mute_hotkey_id = m_HotkeyManager.registerHotkey("<Alt>M", [this]() {
    if (m_voice_window != nullptr) {
        auto voice_window = dynamic_cast<VoiceWindow*>(m_voice_window);
        if (voice_window) {
            m_is_mute = !voice_window->GetMute();
            voice_window->SetMute( m_is_mute );
            return;
        }
    }
    m_is_mute = !m_is_mute;
    m_discord.SetVoiceMuted( m_is_mute );
    m_audio.SetCapture( !m_is_mute );
});

And in function OnVoiceDisconnected unregister voice hotkeys

@Nyjako Nyjako closed this Mar 19, 2025
@Nyjako Nyjako reopened this Mar 19, 2025
@ouwou
Copy link
Member
ouwou commented Mar 19, 2025

yeah thats fine. i should definitely rethink how i do muting and stuff but thats out of scope here so ill take care of it some other time.

Nyjako added 3 commits March 19, 2025 20:57
Moved hotkeys from `VoiceWindow` into `Abaddon` class
Added getters and setters in `VoiceWindow`
Hotkeys can now be assigned in `abaddon.ini` under `[hotkeys]`
Moved GDK keyval mapping to bottom of file
Added hotkeys to readme file
You can now use for example `<Control><Alt>M`
@Nyjako
Copy link
Author
Nyjako commented Mar 20, 2025

I think base hotkey support is done.
It would be great if someone could test on other platforms if everything works. (I'm using Linux with KDE Plasma)

The last commit was pushed by mistake it broke support for a single modifier.

@ouwou
Copy link
Member
ouwou commented Apr 8, 2025

sorry for the delay ill test this out and look over it again in a bit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
5EB2
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Keybind Support for deafen and mute on voice chat
2 participants
0