diff --git a/.gitmodules b/.gitmodules index b1dda15..9c7cf0c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -41,6 +41,3 @@ [submodule "lib/guardpp"] path = lib/guardpp url = https://github.com/Soundux/guardpp -[submodule "lib/libremidi"] - path = lib/libremidi - url = https://github.com/Soundux/libremidi diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ba7843..242b17b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ if (WIN32) target_compile_options(soundux PRIVATE /W4) else() add_executable(soundux ${src}) - + if (CMAKE_BUILD_TYPE STREQUAL "Debug") message(STATUS "Enabling warning and error flags for debug build") target_compile_options(soundux PRIVATE -Wall -Werror -Wextra -pedantic -Wno-unused-lambda-capture -Wno-gnu) @@ -78,7 +78,6 @@ add_subdirectory(lib/nativefiledialog-extended EXCLUDE_FROM_ALL) add_subdirectory(lib/tiny-process-library EXCLUDE_FROM_ALL) add_subdirectory(lib/backward-cpp EXCLUDE_FROM_ALL) add_subdirectory(lib/traypp EXCLUDE_FROM_ALL) -add_subdirectory(lib/libremidi) add_subdirectory(lib/guardpp) add_subdirectory(lib/lockpp) @@ -94,7 +93,7 @@ set(HTTPLIB_REQUIRE_OPENSSL ON) add_subdirectory(lib/cpp-httplib EXCLUDE_FROM_ALL) target_include_directories(soundux SYSTEM PRIVATE "lib/cpp-httplib") -target_link_libraries(soundux PRIVATE webview nfd tiny-process-library tray guardpp httplib lockpp libremidi) +target_link_libraries(soundux PRIVATE webview nfd tiny-process-library tray guard httplib lockpp) if (${EMBED_PATH} STREQUAL "OFF") message("Web-content will not be embedded") diff --git a/lib/libremidi b/lib/libremidi deleted file mode 160000 index e2213b7..0000000 --- a/lib/libremidi +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e2213b724d8426366235f3de70db25fb231a0b07 diff --git a/src/core/global/globals.hpp b/src/core/global/globals.hpp index 7450bd2..1c5eee1 100644 --- a/src/core/global/globals.hpp +++ b/src/core/global/globals.hpp @@ -33,9 +33,9 @@ namespace Soundux inline Objects::Queue gQueue; inline Objects::Config gConfig; inline Objects::YoutubeDl gYtdl; + inline Objects::Hotkeys gHotKeys; inline Objects::Settings gSettings; inline std::unique_ptr gGui; - inline std::shared_ptr gHotKeys; inline std::shared_ptr gGuard; diff --git a/src/core/hotkeys/hotkeys.cpp b/src/core/hotkeys/hotkeys.cpp index b135f97..6a07f70 100644 --- a/src/core/hotkeys/hotkeys.cpp +++ b/src/core/hotkeys/hotkeys.cpp @@ -1,10 +1,6 @@ #include "hotkeys.hpp" -#include "keys.hpp" -#include "linux/x11.hpp" -#include "windows/windows.hpp" #include #include -#include namespace Soundux { @@ -23,117 +19,38 @@ namespace Soundux } // namespace traits namespace Objects { - std::shared_ptr Hotkeys::createInstance() + void Hotkeys::init() { - std::shared_ptr rtn; -#if defined(__linux__) - rtn = std::shared_ptr(new X11()); // NOLINT -#elif defined(_WIN32) - rtn = std::shared_ptr(new WindowsHotkeys()); // NOLINT -#endif - rtn->setup(); - return rtn; + listener = std::thread([this] { listen(); }); } - - void Hotkeys::setup() - { - try - { - midi.open_port(); - midi.set_callback([this](const libremidi::message &message) { - if (message.size() < 3) - { - Fancy::fancy.logTime().failure() - << "Midi Message contains less than 3 bytes, can't parse information"; - return; - } - - auto byte0 = message[0]; - auto byte1 = message[1]; - auto byte2 = message[2]; - - MidiKey key; - key.byte0 = byte0; - key.key = byte1; - key.byte2 = byte2; - key.type = Enums::KeyType::Midi; - - if (byte0 == 144) - { - onKeyDown(key); - } - else if (byte0 == 128) - { - onKeyUp(key); - } - else if (byte0 == 176) - { - if (shouldNotifyKnob) - { - Globals::gGui->onHotKeyReceived({key}); // NOLINT - } - else - { - auto newVolume = static_cast((static_cast(byte2) / 127.f) * 100); - - if (Globals::gSettings.localVolumeKnob && key == Globals::gSettings.localVolumeKnob) - { - Globals::gSettings.localVolume = newVolume; - Globals::gGui->onVolumeChanged(); - - Globals::gQueue.push([=]() { Globals::gGui->onLocalVolumeChanged(newVolume); }); - } - else if (Globals::gSettings.remoteVolumeKnob && key == Globals::gSettings.remoteVolumeKnob) - { - Globals::gSettings.remoteVolume = newVolume; - Globals::gGui->onVolumeChanged(); - - Globals::gQueue.push([=]() { Globals::gGui->onRemoteVolumeChanged(newVolume); }); - } - } - } - }); - midi.ignore_types(false, false, false); - } - catch (const libremidi::midi_exception &e) - { - Fancy::fancy.logTime().failure() << "Failed to initialize libremidi: " << e.what() << std::endl; - } - } - void Hotkeys::notify(bool state) + void Hotkeys::shouldNotify(bool status) { pressedKeys.clear(); - shouldNotify = state; + notify = status; } - void Hotkeys::requestKnob(bool state) + void Hotkeys::onKeyUp(int key) { - shouldNotifyKnob = state; - } - void Hotkeys::onKeyUp(const Key &key) - { - if (std::find(pressedKeys.begin(), pressedKeys.end(), key) != pressedKeys.end()) + if (notify && !pressedKeys.empty() && + std::find(pressedKeys.begin(), pressedKeys.end(), key) != pressedKeys.end()) { - if (shouldNotify) - { - Globals::gGui->onHotKeyReceived(pressedKeys); - pressedKeys.clear(); - } - else - { - pressedKeys.erase(std::remove_if(pressedKeys.begin(), pressedKeys.end(), - [&](const auto &keyItem) { return key == keyItem; }), - pressedKeys.end()); - } + Globals::gGui->onHotKeyReceived(pressedKeys); + pressedKeys.clear(); + } + else + { + pressedKeys.erase(std::remove_if(pressedKeys.begin(), pressedKeys.end(), + [key](const auto &item) { return key == item; }), + pressedKeys.end()); } } - bool isCloseMatch(const std::vector &pressedKeys, const std::vector &keys) + bool isCloseMatch(const std::vector &pressedKeys, const std::vector &keys) { if (pressedKeys.size() >= keys.size()) { bool allMatched = true; for (const auto &key : keys) { - if (std::find(pressedKeys.begin(), pressedKeys.end(), key) == pressedKeys.end()) // NOLINT + if (std::find(pressedKeys.begin(), pressedKeys.end(), key) == pressedKeys.end()) { allMatched = false; } @@ -142,14 +59,13 @@ namespace Soundux } return false; } - template std::optional getBestMatch(const T &list, const std::vector &pressedKeys) + template std::optional getBestMatch(const T &list, const std::vector &pressedKeys) { std::optional rtn; for (const auto &_sound : list) { - const auto &sound = [&]() constexpr - { + const auto &sound = [&] { if constexpr (traits::is_pair>::value) { return _sound.second.get(); @@ -158,13 +74,12 @@ namespace Soundux { return _sound; } - } - (); + }(); if (sound.hotkeys.empty()) continue; - if (pressedKeys == sound.hotkeys) + if (sound.hotkeys == pressedKeys) { rtn = sound; break; @@ -182,81 +97,78 @@ namespace Soundux } return rtn; } - void Hotkeys::onKeyDown(const Key &key) + void Hotkeys::onKeyDown(int key) { - if (std::find(pressedKeys.begin(), pressedKeys.end(), key) != pressedKeys.end()) + if (std::find(keysToPress.begin(), keysToPress.end(), key) != keysToPress.end()) + { + return; + } + if (std::find(pressedKeys.begin(), pressedKeys.end(), key) == pressedKeys.end()) + { + pressedKeys.emplace_back(key); + } + else { return; } - pressedKeys.emplace_back(key); - if (!shouldNotify) + if (notify) { - if (!Globals::gSettings.stopHotkey.empty() && - (Globals::gSettings.stopHotkey == pressedKeys || - isCloseMatch(pressedKeys, Globals::gSettings.stopHotkey))) - { - Globals::gGui->stopSounds(); - return; - } + return; + } - std::optional bestMatch; + if (!Globals::gSettings.stopHotkey.empty() && (pressedKeys == Globals::gSettings.stopHotkey || + isCloseMatch(pressedKeys, Globals::gSettings.stopHotkey))) + { + Globals::gGui->stopSounds(); + return; + } - if (Globals::gSettings.tabHotkeysOnly) + std::optional bestMatch; + + if (Globals::gSettings.tabHotkeysOnly) + { + if (Globals::gData.isOnFavorites) { - if (Globals::gData.isOnFavorites) - { - auto sounds = Globals::gData.getFavorites(); - bestMatch = getBestMatch(sounds, pressedKeys); - } - else - { - auto tab = Globals::gData.getTab(Globals::gSettings.selectedTab); - if (tab) - { - bestMatch = getBestMatch(tab->sounds, pressedKeys); - } - } + auto sounds = Globals::gData.getFavorites(); + bestMatch = getBestMatch(sounds, pressedKeys); } else { - auto scopedSounds = Globals::gSounds.scoped(); - bestMatch = getBestMatch(*scopedSounds, pressedKeys); - } - - if (bestMatch) - { - auto pSound = Globals::gGui->playSound(bestMatch->id); - if (pSound) + auto tab = Globals::gData.getTab(Globals::gSettings.selectedTab); + if (tab) { - Globals::gGui->onSoundPlayed(*pSound); + bestMatch = getBestMatch(tab->sounds, pressedKeys); } } } - } - std::string Hotkeys::getKeyName(const Key &key) - { - if (key.type == Enums::KeyType::Midi) + else { - return "MIDI_" + std::to_string(key.key); + auto scopedSounds = Globals::gSounds.scoped(); + bestMatch = getBestMatch(*scopedSounds, pressedKeys); } - return ""; - } - std::string Hotkeys::getKeySequence(const std::vector &keys) - { - std::string rtn; - - for (auto it = keys.begin(); it != keys.end(); ++it) + if (bestMatch) { - rtn += getKeyName(*it); - if (std::distance(it, keys.end()) > 1) + auto pSound = Globals::gGui->playSound(bestMatch->id); + if (pSound) { - rtn += " + "; + Globals::gGui->onSoundPlayed(*pSound); } } - - return rtn; + } + std::string Hotkeys::getKeySequence(const std::vector &keys) + { + std::string rtn; + for (const auto &key : keys) + { + rtn += getKeyName(key) + " + "; + } + if (!rtn.empty()) + { + return rtn.substr(0, rtn.length() - 3); + } + return ""; } } // namespace Objects } // namespace Soundux \ No newline at end of file diff --git a/src/core/hotkeys/hotkeys.hpp b/src/core/hotkeys/hotkeys.hpp index d891898..6bafa1d 100644 --- a/src/core/hotkeys/hotkeys.hpp +++ b/src/core/hotkeys/hotkeys.hpp @@ -1,15 +1,7 @@ #pragma once -#pragma push_macro("max") -#pragma push_macro("min") -#undef min -#undef max -#include -#pragma pop_macro("min") -#pragma pop_macro("max") - -#include "keys.hpp" #include #include +#include #include namespace Soundux @@ -18,32 +10,33 @@ namespace Soundux { class Hotkeys { - libremidi::midi_in midi; + std::thread listener; + std::atomic kill = false; + std::atomic notify = false; - protected: - Hotkeys() = default; - virtual void setup(); + std::vector pressedKeys; + std::vector keysToPress; +#if defined(_WIN32) + std::thread keyPressThread; + std::atomic shouldPressKeys = false; +#endif - protected: - std::vector pressedKeys; - std::atomic shouldNotify = false; - std::atomic shouldNotifyKnob = false; + private: + void listen(); public: - static std::shared_ptr createInstance(); + void init(); + void stop(); + void shouldNotify(bool); - public: - virtual void notify(bool); - virtual void requestKnob(bool); + void onKeyUp(int); + void onKeyDown(int); - virtual void onKeyUp(const Key &); - virtual void onKeyDown(const Key &); + void pressKeys(const std::vector &); + void releaseKeys(const std::vector &); - virtual void pressKeys(const std::vector &) = 0; - virtual void releaseKeys(const std::vector &) = 0; - - virtual std::string getKeyName(const Key &); - virtual std::string getKeySequence(const std::vector &); + std::string getKeyName(const int &); + std::string getKeySequence(const std::vector &); }; } // namespace Objects } // namespace Soundux \ No newline at end of file diff --git a/src/core/hotkeys/keys.cpp b/src/core/hotkeys/keys.cpp deleted file mode 100644 index 2fddcab..0000000 --- a/src/core/hotkeys/keys.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "keys.hpp" - -namespace Soundux::Objects -{ - bool Key::operator==(const Key &other) const - { - return other.key == key && other.type == type; - } -} // namespace Soundux::Objects \ No newline at end of file diff --git a/src/core/hotkeys/keys.hpp b/src/core/hotkeys/keys.hpp deleted file mode 100644 index edf15ed..0000000 --- a/src/core/hotkeys/keys.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once -#include - -namespace Soundux -{ - namespace Enums - { - enum class KeyType : std::uint8_t - { - Keyboard, - Mouse, - Midi - }; - } // namespace Enums - - namespace Objects - { - struct Key - { - int key; - Enums::KeyType type; - - virtual ~Key() = default; - bool operator==(const Key &) const; - }; - struct MidiKey : public Key - { - int byte0; // Action - int byte2; // Knob value / Press strength - ~MidiKey() override = default; - }; - } // namespace Objects -} // namespace Soundux \ No newline at end of file diff --git a/src/core/hotkeys/linux/x11.cpp b/src/core/hotkeys/linux/x11.cpp index d0f6071..700811f 100644 --- a/src/core/hotkeys/linux/x11.cpp +++ b/src/core/hotkeys/linux/x11.cpp @@ -1,26 +1,25 @@ -#if defined(__linux__) -#include "x11.hpp" +#if defined(__linux__) && __has_include() +#include "../hotkeys.hpp" +#include #include #include +#include #include #include #include -#include +#include #include #include +using namespace std::chrono_literals; + namespace Soundux::Objects { - void X11::setup() + Display *display; + void Hotkeys::listen() { - Hotkeys::setup(); - listener = std::thread([this] { listen(); }); - } - - void X11::listen() - { - auto *displayEnv = std::getenv("DISPLAY"); // NOLINT - auto *x11Display = XOpenDisplay(displayEnv); + auto *displayenv = std::getenv("DISPLAY"); // NOLINT + auto *x11Display = XOpenDisplay(displayenv); if (!x11Display) { @@ -28,18 +27,20 @@ namespace Soundux::Objects if (!(x11Display = XOpenDisplay(":0"))) { Fancy::fancy.logTime().failure() << "Could not open X11 Display" << std::endl; + return; } } else { - Fancy::fancy.logTime().message() << "Using DISPLAY " << displayEnv << std::endl; + Fancy::fancy.logTime().message() << "Using DISPLAY " << displayenv << std::endl; } - display = x11Display; - int event_rtn = 0, ext_rtn = 0; + + int major_op = 0, event_rtn = 0, ext_rtn = 0; if (!XQueryExtension(display, "XInputExtension", &major_op, &event_rtn, &ext_rtn)) { Fancy::fancy.logTime().failure() << "Failed to find XInputExtension" << std::endl; + return; } Window root = DefaultRootWindow(display); // NOLINT @@ -66,106 +67,78 @@ namespace Soundux::Objects XNextEvent(display, &event); auto *cookie = reinterpret_cast(&event.xcookie); - if (XGetEventData(display, cookie) && cookie->type == GenericEvent && cookie->extension == major_op) + if (XGetEventData(display, cookie) && cookie->type == GenericEvent && cookie->extension == major_op && + (cookie->evtype == XI_RawKeyPress || cookie->evtype == XI_RawKeyRelease || + cookie->evtype == XI_RawButtonPress || cookie->evtype == XI_RawButtonRelease)) { - if (cookie->evtype == XI_RawKeyPress || cookie->evtype == XI_RawKeyRelease) + auto *data = reinterpret_cast(cookie->data); + auto key = data->detail; + + if (key == 1) + continue; + + if (cookie->evtype == XI_RawKeyPress || cookie->evtype == XI_RawButtonPress) { - auto *data = reinterpret_cast(cookie->data); - auto key = data->detail; - - Key pressedKey; - pressedKey.key = key; - pressedKey.type = Enums::KeyType::Keyboard; - - if (cookie->evtype == XI_RawKeyPress) - { - onKeyDown(pressedKey); - } - else - { - onKeyUp(pressedKey); - } + onKeyDown(key); } - else if (cookie->evtype == XI_RawButtonPress || cookie->evtype == XI_RawButtonRelease) + else if (cookie->evtype == XI_RawKeyRelease || cookie->evtype == XI_RawButtonRelease) { - auto *data = reinterpret_cast(cookie->data); - auto button = data->detail; - - if (button != 1) - { - Key pressedButton; - pressedButton.key = button; - pressedButton.type = Enums::KeyType::Mouse; - - if (cookie->evtype == XI_RawButtonPress) - { - onKeyDown(pressedButton); - } - else - { - onKeyUp(pressedButton); - } - } + onKeyUp(key); } } } else { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + std::this_thread::sleep_for(100ms); } } } - std::string X11::getKeyName(const Key &key) + + std::string Hotkeys::getKeyName(const int &key) { - if (!Hotkeys::getKeyName(key).empty()) + // TODO(curve): There is no Keysym for the mouse buttons and I couldn't find any way to get the name for the + // mouse buttons so they'll just be named KEY_1 (1 is the Keycode). Maybe someone will be able to help me but I + // just can't figure it out + + KeySym s = XkbKeycodeToKeysym(display, key, 0, 0); + + if (s == NoSymbol) { - return Hotkeys::getKeyName(key); + return "KEY_" + std::to_string(key); } - if (key.type == Enums::KeyType::Keyboard) + auto *str = XKeysymToString(s); + if (str == nullptr) { - KeySym keySym = XkbKeycodeToKeysym(display, key.key, 0, 0); - - if (keySym == NoSymbol) - { - return "KEY_" + std::to_string(key.key); - } - - auto *str = XKeysymToString(keySym); - if (!str) - { - return "KEY_" + std::to_string(key.key); - } - - return str; + return "KEY_" + std::to_string(key); } - if (key.type == Enums::KeyType::Mouse) - { - return "MOUSE_" + std::to_string(key.key); - } - - return ""; + return str; } - void X11::pressKeys(const std::vector &keys) - { - for (const auto &key : keys) - { - XTestFakeKeyEvent(display, key.key, True, 0); - } - } - void X11::releaseKeys(const std::vector &keys) - { - for (const auto &key : keys) - { - XTestFakeKeyEvent(display, key.key, False, 0); - } - } - X11::~X11() + void Hotkeys::stop() { kill = true; listener.join(); } + + void Hotkeys::pressKeys(const std::vector &keys) + { + keysToPress = keys; + for (const auto &key : keys) + { + XTestFakeKeyEvent(display, key, True, 0); + } + } + + void Hotkeys::releaseKeys(const std::vector &keys) + { + keysToPress.clear(); + for (const auto &key : keys) + { + XTestFakeKeyEvent(display, key, False, 0); + } + } } // namespace Soundux::Objects + #endif \ No newline at end of file diff --git a/src/core/hotkeys/linux/x11.hpp b/src/core/hotkeys/linux/x11.hpp deleted file mode 100644 index d663262..0000000 --- a/src/core/hotkeys/linux/x11.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once -#if defined(__linux__) -#include -#include - -struct _XDisplay; // NOLINT -using Display = _XDisplay; - -namespace Soundux -{ - namespace Objects - { - class X11 : public Hotkeys - { - int major_op; - Display *display; - std::thread listener; - std::atomic kill = false; - - private: - void listen(); - void setup() override; - - public: - ~X11(); - std::string getKeyName(const Key &key) override; - void pressKeys(const std::vector &keys) override; - void releaseKeys(const std::vector &keys) override; - }; - } // namespace Objects -} // namespace Soundux - -#endif \ No newline at end of file diff --git a/src/core/hotkeys/windows/windows.cpp b/src/core/hotkeys/windows/windows.cpp index 8ee5fad..f211c8a 100644 --- a/src/core/hotkeys/windows/windows.cpp +++ b/src/core/hotkeys/windows/windows.cpp @@ -1,90 +1,88 @@ #if defined(_WIN32) -#include "windows.hpp" +#include "../hotkeys.hpp" +#include +#include #include -#include + +using namespace std::chrono_literals; namespace Soundux::Objects { - HHOOK WindowsHotkeys::oMouseProc; - HHOOK WindowsHotkeys::oKeyboardProc; + HHOOK oKeyBoardProc; + HHOOK oMouseProc; - void WindowsHotkeys::setup() - { - Hotkeys::setup(); - - oMouseProc = SetWindowsHookEx(WH_MOUSE_LL, mouseProc, nullptr, NULL); - oKeyboardProc = SetWindowsHookEx(WH_KEYBOARD_LL, keyBoardProc, nullptr, NULL); - - listener = std::thread([this] { listen(); }); - keyPresser = std::thread([this] { presser(); }); - } - LRESULT CALLBACK WindowsHotkeys::keyBoardProc(int nCode, WPARAM wParam, LPARAM lParam) + LRESULT CALLBACK keyBoardProc(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode == HC_ACTION) { - auto *info = reinterpret_cast(lParam); // NOLINT - if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) { - Key key; - key.type = Enums::KeyType::Keyboard; - key.key = static_cast(info->vkCode); - - Globals::gHotKeys->onKeyDown(key); + auto *info = reinterpret_cast(lParam); + Globals::gHotKeys.onKeyDown(info->vkCode); } else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP) { - Key key; - key.type = Enums::KeyType::Keyboard; - key.key = static_cast(info->vkCode); - - Globals::gHotKeys->onKeyUp(key); + auto *info = reinterpret_cast(lParam); + Globals::gHotKeys.onKeyUp(info->vkCode); } } - return CallNextHookEx(oKeyboardProc, nCode, wParam, lParam); + return CallNextHookEx(oKeyBoardProc, nCode, wParam, lParam); } - LRESULT CALLBACK WindowsHotkeys::mouseProc(int nCode, WPARAM wParam, LPARAM lParam) + + LRESULT CALLBACK mouseProc(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode == HC_ACTION) { + // TODO(curve): How would I tell if XButton1 or XButton2 is pressed? Is there a nicer way to do this? + switch (wParam) { - case WM_RBUTTONUP: { - Key key; - key.key = VK_RBUTTON; - key.type = Enums::KeyType::Mouse; - Soundux::Globals::gHotKeys->onKeyUp(key); - } - break; - case WM_RBUTTONDOWN: { - Key key; - key.key = VK_RBUTTON; - key.type = Enums::KeyType::Mouse; - Soundux::Globals::gHotKeys->onKeyDown(key); - } - break; - case WM_MBUTTONUP: { - Key key; - key.key = VK_MBUTTON; - key.type = Enums::KeyType::Mouse; - Soundux::Globals::gHotKeys->onKeyUp(key); - } - break; - case WM_MBUTTONDOWN: { - Key key; - key.key = VK_RBUTTON; - key.type = Enums::KeyType::Mouse; - Soundux::Globals::gHotKeys->onKeyDown(key); - } - break; + case WM_RBUTTONUP: + Globals::gHotKeys.onKeyUp(VK_RBUTTON); + break; + + case WM_RBUTTONDOWN: + Globals::gHotKeys.onKeyDown(VK_RBUTTON); + break; + + case WM_MBUTTONDOWN: + Globals::gHotKeys.onKeyDown(VK_MBUTTON); + break; + + case WM_MBUTTONUP: + Globals::gHotKeys.onKeyUp(VK_MBUTTON); + break; } } return CallNextHookEx(oMouseProc, nCode, wParam, lParam); } - void WindowsHotkeys::listen() + + void Hotkeys::listen() { + oKeyBoardProc = SetWindowsHookEx(WH_KEYBOARD_LL, keyBoardProc, GetModuleHandle(nullptr), NULL); + oMouseProc = SetWindowsHookEx(WH_MOUSE_LL, mouseProc, GetModuleHandle(nullptr), NULL); + keyPressThread = std::thread([this] { + while (!kill) + { + //* Yes, this is absolutely cursed. I tried to implement this by just sending the keydown event once but + //* it does not work like that on windows, so I have to do this, thank you Microsoft, I hate you. + if (shouldPressKeys) + { + for (const auto &key : keysToPress) + { + keybd_event(key, 0, 1, 0); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + } + else + { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + } + }); + MSG message; - while (!GetMessage(&message, nullptr, 0, 0)) + while (!GetMessage(&message, nullptr, NULL, NULL)) { if (kill) { @@ -94,82 +92,68 @@ namespace Soundux::Objects DispatchMessage(&message); } } - void WindowsHotkeys::presser() - { - std::unique_lock lock(keysToPressMutex); - while (!kill) - { - cv.wait(lock, [&]() { return !keysToPress.empty() || kill; }); - //* Yes, this is absolutely cursed. I tried to implement this by just sending the keydown event once but - //* it does not work like that on windows, so I have to do this, thank you Microsoft, I hate you. - for (const auto &key : keysToPress) - { - keybd_event(key.key, 0, 1, 0); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - } - } - std::string WindowsHotkeys::getKeyName(const Key &key) - { - if (!Hotkeys::getKeyName(key).empty()) - { - return Hotkeys::getKeyName(key); - } - if (key.type == Enums::KeyType::Keyboard) - { - char name[128]; - auto result = GetKeyNameTextA(MapVirtualKey(key.key, MAPVK_VK_TO_VSC) << 16, name, 128); - - if (result == 0) - { - return "KEY_" + std::to_string(key.key); - } - - return name; - } - - if (key.type == Enums::KeyType::Mouse) - { - return "MOUSE_" + std::to_string(key.key); - } - - return ""; - } - void WindowsHotkeys::pressKeys(const std::vector &keys) - { - std::unique_lock lock(keysToPressMutex); - keysToPress = keys; - } - void WindowsHotkeys::releaseKeys(const std::vector &keys) - { - std::unique_lock lock(keysToPressMutex); - for (const auto &key : keys) - { - for (auto it = keysToPress.begin(); it != keysToPress.end();) - { - if (*it == key) - { - it = keysToPress.erase(it); - } - else - { - ++it; - } - } - } - } - WindowsHotkeys::~WindowsHotkeys() + void Hotkeys::stop() { kill = true; - PostThreadMessage(GetThreadId(listener.native_handle()), WM_QUIT, 0, 0); - - listener.join(); - cv.notify_all(); - keyPresser.join(); - UnhookWindowsHookEx(oMouseProc); - UnhookWindowsHookEx(oKeyboardProc); + UnhookWindowsHookEx(oKeyBoardProc); + PostThreadMessage(GetThreadId(listener.native_handle()), WM_QUIT, 0, 0); + listener.join(); + keyPressThread.join(); + } + + std::string Hotkeys::getKeyName(const int &key) + { + auto scanCode = MapVirtualKey(key, MAPVK_VK_TO_VSC); + + CHAR name[128]; + int result = 0; + switch (key) + { + case VK_LEFT: + case VK_UP: + case VK_RIGHT: + case VK_DOWN: + case VK_RCONTROL: + case VK_RMENU: + case VK_LWIN: + case VK_RWIN: + case VK_APPS: + case VK_PRIOR: + case VK_NEXT: + case VK_END: + case VK_HOME: + case VK_INSERT: + case VK_DELETE: + case VK_DIVIDE: + case VK_NUMLOCK: + scanCode |= KF_EXTENDED; + default: + result = GetKeyNameTextA(scanCode << 16, name, 128); + } + if (result == 0) + { + return "KEY_" + std::to_string(key); + } + + return name; + } + + void Hotkeys::pressKeys(const std::vector &keys) + { + keysToPress = keys; + shouldPressKeys = true; + } + + void Hotkeys::releaseKeys([[maybe_unused]] const std::vector &keys) + { + shouldPressKeys = false; + keysToPress.clear(); + for (const auto &key : keys) + { + keybd_event(key, 0, 2, 0); + } } } // namespace Soundux::Objects #endif \ No newline at end of file diff --git a/src/core/hotkeys/windows/windows.hpp b/src/core/hotkeys/windows/windows.hpp deleted file mode 100644 index 5b61530..0000000 --- a/src/core/hotkeys/windows/windows.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once -#if defined(_WIN32) -#include -#include -#include -#include - -namespace Soundux -{ - namespace Objects - { - class WindowsHotkeys : public Hotkeys - { - std::thread listener; - std::thread keyPresser; - std::atomic kill = false; - - std::condition_variable cv; - std::mutex keysToPressMutex; - std::vector keysToPress; - - private: - void listen(); - void presser(); - void setup() override; - - private: - static HHOOK oMouseProc; - static HHOOK oKeyboardProc; - - static LRESULT CALLBACK mouseProc(int, WPARAM, LPARAM); - static LRESULT CALLBACK keyBoardProc(int, WPARAM, LPARAM); - - public: - ~WindowsHotkeys(); - std::string getKeyName(const Key &key) override; - void pressKeys(const std::vector &keys) override; - void releaseKeys(const std::vector &keys) override; - }; - } // namespace Objects -} // namespace Soundux - -#endif \ No newline at end of file diff --git a/src/core/objects/objects.hpp b/src/core/objects/objects.hpp index ef2b5a7..909ee7a 100644 --- a/src/core/objects/objects.hpp +++ b/src/core/objects/objects.hpp @@ -8,7 +8,7 @@ namespace Soundux { namespace Objects { - struct Key; + struct AudioDevice; struct Sound { @@ -17,7 +17,7 @@ namespace Soundux std::string path; bool isFavorite = false; - std::vector hotkeys; + std::vector hotkeys; std::uint64_t modifiedDate; std::optional localVolume; diff --git a/src/core/objects/settings.hpp b/src/core/objects/settings.hpp index d3ccc43..15ceb48 100644 --- a/src/core/objects/settings.hpp +++ b/src/core/objects/settings.hpp @@ -1,7 +1,5 @@ #pragma once #include -#include -#include #include #include @@ -16,18 +14,15 @@ namespace Soundux Enums::Theme theme = Enums::Theme::System; std::optional language; - std::vector pushToTalkKeys; - std::vector stopHotkey; - - std::optional remoteVolumeKnob; - std::optional localVolumeKnob; + std::vector pushToTalkKeys; + std::vector stopHotkey; std::vector outputs; std::uint32_t selectedTab = 0; - bool syncVolumes = false; int remoteVolume = 100; int localVolume = 50; + bool syncVolumes = false; bool allowMultipleOutputs = false; bool useAsDefaultDevice = false; diff --git a/src/helper/json/bindings.hpp b/src/helper/json/bindings.hpp index 87365e2..bda3f00 100644 --- a/src/helper/json/bindings.hpp +++ b/src/helper/json/bindings.hpp @@ -1,69 +1,11 @@ #pragma once #include -#include #include #include #include -namespace Soundux -{ - namespace traits - { - template struct is_optional - { - private: - static std::uint8_t test(...); - template static auto test(std::optional *) -> std::uint16_t; - - public: - static const bool value = sizeof(test(reinterpret_cast *>(0))) == sizeof(std::uint16_t); - }; - } // namespace traits -} // namespace Soundux - namespace nlohmann { - template struct adl_serializer> - { - static void to_json(json &j, const std::optional &obj) - { - if (obj) - { - j = *obj; - } - else - { - j = nullptr; - } - } - static void from_json(const json &j, const std::optional &obj) - { - if (!j.is_null()) - { - obj = j.get(); - } - } - }; // namespace nlohmann - template <> struct adl_serializer - { - static void to_json(json &j, const Soundux::Objects::Key &obj) - { - j = {{"key", obj.key}, {"type", obj.type}}; - } - static void from_json(const json &j, Soundux::Objects::Key &obj) - { - if (j.find("type") != j.end()) - { - j.at("key").get_to(obj.key); - j.at("type").get_to(obj.type); - } - else - { - j.get_to(obj.key); - obj.type = Soundux::Enums::KeyType::Keyboard; - } - } - }; // namespace nlohmann template <> struct adl_serializer { static void to_json(json &j, const Soundux::Objects::Sound &obj) @@ -72,14 +14,29 @@ namespace nlohmann {"name", obj.name}, {"hotkeys", obj.hotkeys}, {"hotkeySequence", - Soundux::Globals::gHotKeys->getKeySequence(obj.hotkeys)}, //* For frontend and config readability + Soundux::Globals::gHotKeys.getKeySequence(obj.hotkeys)}, //* For frontend and config readability {"id", obj.id}, {"path", obj.path}, {"isFavorite", obj.isFavorite}, - {"localVolume", obj.localVolume}, - {"remoteVolume", obj.remoteVolume}, {"modifiedDate", obj.modifiedDate}, }; + + if (obj.localVolume) + { + j["localVolume"] = *obj.localVolume; + } + else + { + j["localVolume"] = nullptr; + } + if (obj.remoteVolume) + { + j["remoteVolume"] = *obj.remoteVolume; + } + else + { + j["remoteVolume"] = nullptr; + } } static void from_json(const json &j, Soundux::Objects::Sound &obj) { @@ -163,8 +120,6 @@ namespace nlohmann {"pushToTalkKeys", obj.pushToTalkKeys}, {"tabHotkeysOnly", obj.tabHotkeysOnly}, {"minimizeToTray", obj.minimizeToTray}, - {"localVolumeKnob", obj.localVolumeKnob}, - {"remoteVolumeKnob", obj.remoteVolumeKnob}, {"allowOverlapping", obj.allowOverlapping}, {"muteDuringPlayback", obj.muteDuringPlayback}, {"useAsDefaultDevice", obj.useAsDefaultDevice}, @@ -176,22 +131,9 @@ namespace nlohmann { if (j.find(key) != j.end()) { - if constexpr (Soundux::traits::is_optional::value) + if (j.at(key).type_name() == nlohmann::basic_json(T{}).type_name()) { - if (j.at(key).type_name() == nlohmann::basic_json(typename T::value_type{}).type_name()) - { - if (!j.at(key).is_null()) - { - member = j.at(key).get(); - } - } - } - else - { - if (j.at(key).type_name() == nlohmann::basic_json(T{}).type_name()) - { - j.at(key).get_to(member); - } + j.at(key).get_to(member); } } } @@ -212,8 +154,6 @@ namespace nlohmann get_to_safe(j, "pushToTalkKeys", obj.pushToTalkKeys); get_to_safe(j, "minimizeToTray", obj.minimizeToTray); get_to_safe(j, "tabHotkeysOnly", obj.tabHotkeysOnly); - get_to_safe(j, "localVolumeKnob", obj.localVolumeKnob); - get_to_safe(j, "remoteVolumeKnob", obj.remoteVolumeKnob); get_to_safe(j, "allowOverlapping", obj.allowOverlapping); get_to_safe(j, "useAsDefaultDevice", obj.useAsDefaultDevice); get_to_safe(j, "muteDuringPlayback", obj.muteDuringPlayback); @@ -337,5 +277,22 @@ namespace nlohmann }; } }; + template <> struct adl_serializer> + { + static void to_json(json &j, const std::optional &obj) + { + if (obj) + { + j = { + {"name", obj->getName()}, + {"guid", obj->getGUID()}, + }; + } + else + { + j = "null"; + } + } + }; #endif } // namespace nlohmann \ No newline at end of file diff --git a/src/helper/misc/misc.cpp b/src/helper/misc/misc.cpp index 399bc8e..11ed51e 100644 --- a/src/helper/misc/misc.cpp +++ b/src/helper/misc/misc.cpp @@ -5,12 +5,7 @@ #include #include #include - -#pragma push_macro("UNICOCDE") -#undef UNICODE #include -#pragma pop_macro("UNICOCDE") - #include #include diff --git a/src/helper/queue/queue.cpp b/src/helper/queue/queue.cpp index 257b482..b56e938 100644 --- a/src/helper/queue/queue.cpp +++ b/src/helper/queue/queue.cpp @@ -10,33 +10,29 @@ namespace Soundux::Objects cv.wait(lock, [&]() { return !queue.empty() || stop; }); while (!queue.empty()) { - auto front = queue.begin(); - front->function(); - queue.erase(front); + auto front = std::move(*queue.begin()); + + lock.unlock(); + front.second(); + lock.lock(); + + queue.erase(front.first); } } } + void Queue::push_unique(std::uint64_t id, std::function function) { { std::lock_guard lock(queueMutex); - if (std::find_if(queue.begin(), queue.end(), - [&id](const auto &entry) { return entry.id && *entry.id == id; }) != queue.end()) + if (queue.find(id) != queue.end()) { return; } } std::unique_lock lock(queueMutex); - queue.emplace_back(Call{std::move(function), id}); - lock.unlock(); - - cv.notify_one(); - } - void Queue::push(std::function function) - { - std::unique_lock lock(queueMutex); - queue.emplace_back(Call{std::move(function), std::nullopt}); + queue.emplace(id, std::move(function)); lock.unlock(); cv.notify_one(); diff --git a/src/helper/queue/queue.hpp b/src/helper/queue/queue.hpp index 33ca651..203c475 100644 --- a/src/helper/queue/queue.hpp +++ b/src/helper/queue/queue.hpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include @@ -13,14 +12,8 @@ namespace Soundux { class Queue { - struct Call - { - std::function function; - std::optional id; - }; - + std::map> queue; std::mutex queueMutex; - std::vector queue; std::condition_variable cv; std::atomic stop; @@ -33,7 +26,6 @@ namespace Soundux Queue(); ~Queue(); - void push(std::function); void push_unique(std::uint64_t, std::function); }; } // namespace Objects diff --git a/src/helper/ytdl/youtube-dl.hpp b/src/helper/ytdl/youtube-dl.hpp index 836ffd6..12b05c1 100644 --- a/src/helper/ytdl/youtube-dl.hpp +++ b/src/helper/ytdl/youtube-dl.hpp @@ -1,12 +1,7 @@ #pragma once #include #include - -#pragma push_macro("UNICOCDE") -#undef UNICODE #include -#pragma pop_macro("UNICOCDE") - #include #include diff --git a/src/ui/impl/webview/webview.cpp b/src/ui/impl/webview/webview.cpp index 645e803..575bcd6 100644 --- a/src/ui/impl/webview/webview.cpp +++ b/src/ui/impl/webview/webview.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #ifdef _WIN32 #include "../../assets/icon.h" @@ -123,14 +122,12 @@ namespace Soundux::Objects webview->expose(Webview::Function("stopSounds", [this]() { stopSounds(); })); webview->expose(Webview::Function("changeSettings", [this](const Settings &newSettings) { return changeSettings(newSettings); })); - webview->expose(Webview::Function("requestHotkey", [](bool state) { Globals::gHotKeys->notify(state); })); + webview->expose(Webview::Function("requestHotkey", [](bool state) { Globals::gHotKeys.shouldNotify(state); })); webview->expose(Webview::Function( - "setHotkey", [this](std::uint32_t id, const std::vector &keys) { return setHotkey(id, keys); })); - webview->expose(Webview::Function("getHotkeySequence", [this](const std::vector &keys) { - return Globals::gHotKeys->getKeySequence(keys); + "setHotkey", [this](std::uint32_t id, const std::vector &keys) { return setHotkey(id, keys); })); + webview->expose(Webview::Function("getHotkeySequence", [this](const std::vector &keys) { + return Globals::gHotKeys.getKeySequence(keys); })); - webview->expose( - Webview::Function("getKeyName", [this](const Key &key) { return Globals::gHotKeys->getKeyName(key); })); webview->expose(Webview::Function("removeTab", [this](std::uint32_t id) { return removeTab(id); })); webview->expose(Webview::Function("refreshTab", [this](std::uint32_t id) { return refreshTab(id); })); webview->expose(Webview::Function( @@ -172,8 +169,6 @@ namespace Soundux::Objects return setCustomRemoteVolume(id, volume); })); webview->expose(Webview::Function("toggleSoundPlayback", [this]() { return toggleSoundPlayback(); })); - webview->expose( - Webview::Function("requestKnob", [this](bool state) { Globals::gHotKeys->requestKnob(state); })); #if !defined(__linux__) webview->expose(Webview::Function("getOutputs", [this]() { return getOutputs(); })); @@ -392,10 +387,15 @@ namespace Soundux::Objects } Fancy::fancy.logTime().message() << "UI exited" << std::endl; } - void WebView::onHotKeyReceived(const std::vector &keys) + void WebView::onHotKeyReceived(const std::vector &keys) { - webview->callFunction( - Webview::JavaScriptFunction("window.hotkeyReceived", Globals::gHotKeys->getKeySequence(keys), keys)); + std::string hotkeySequence; + for (const auto &key : keys) + { + hotkeySequence += Globals::gHotKeys.getKeyName(key) + " + "; + } + webview->callFunction(Webview::JavaScriptFunction( + "window.hotkeyReceived", hotkeySequence.substr(0, hotkeySequence.length() - 3), keys)); } void WebView::onSoundFinished(const PlayingSound &sound) { @@ -448,12 +448,4 @@ namespace Soundux::Objects webview->callFunction( Webview::JavaScriptFunction("window.getStore().commit", "setAdministrativeModal", true)); } - void WebView::onLocalVolumeChanged(int volume) - { - webview->callFunction(Webview::JavaScriptFunction("window.getStore().commit", "setLocalVolume", volume)); - } - void WebView::onRemoteVolumeChanged(int volume) - { - webview->callFunction(Webview::JavaScriptFunction("window.getStore().commit", "setRemoteVolume", volume)); - } } // namespace Soundux::Objects \ No newline at end of file diff --git a/src/ui/impl/webview/webview.hpp b/src/ui/impl/webview/webview.hpp index 6f74f5c..95a2f73 100644 --- a/src/ui/impl/webview/webview.hpp +++ b/src/ui/impl/webview/webview.hpp @@ -28,12 +28,10 @@ namespace Soundux void setup() override; void mainLoop() override; void onSoundFinished(const PlayingSound &sound) override; - void onHotKeyReceived(const std::vector &keys) override; + void onHotKeyReceived(const std::vector &keys) override; void onAdminRequired() override; void onSettingsChanged() override; - void onLocalVolumeChanged(int volume) override; - void onRemoteVolumeChanged(int volume) override; void onSwitchOnConnectDetected(bool state) override; void onError(const Enums::ErrorCode &error) override; void onSoundPlayed(const PlayingSound &sound) override; diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp index f908949..1e60b8a 100644 --- a/src/ui/ui.cpp +++ b/src/ui/ui.cpp @@ -15,8 +15,7 @@ namespace Soundux::Objects void Window::setup() { NFD::Init(); - Globals::gHotKeys = Hotkeys::createInstance(); - + Globals::gHotKeys.init(); for (auto &tab : Globals::gData.getTabs()) { tab.sounds = getTabContent(tab); @@ -26,6 +25,7 @@ namespace Soundux::Objects Window::~Window() { NFD::Quit(); + Globals::gHotKeys.stop(); } std::vector Window::getTabContent(const Tab &tab) const { @@ -225,7 +225,7 @@ namespace Soundux::Objects } if (!Globals::gSettings.pushToTalkKeys.empty()) { - Globals::gHotKeys->pressKeys(Globals::gSettings.pushToTalkKeys); + Globals::gHotKeys.pressKeys(Globals::gSettings.pushToTalkKeys); } auto playingSound = Globals::gAudio.play(*sound); @@ -297,7 +297,7 @@ namespace Soundux::Objects } if (!Globals::gSettings.pushToTalkKeys.empty()) { - Globals::gHotKeys->pressKeys(Globals::gSettings.pushToTalkKeys); + Globals::gHotKeys.pressKeys(Globals::gSettings.pushToTalkKeys); } if (Globals::gSettings.outputs.empty() && !Globals::gSettings.useAsDefaultDevice) @@ -579,33 +579,30 @@ namespace Soundux::Objects onError(Enums::ErrorCode::FailedToSetCustomVolume); return std::nullopt; } - void Window::onVolumeChanged() - { - for (const auto &playingSound : Globals::gAudio.getPlayingSounds()) - { - int newVolume = 0; - const auto &sound = playingSound.sound; - - if (playingSound.playbackDevice.isDefault) - { - newVolume = sound.localVolume ? *sound.localVolume : Globals::gSettings.localVolume; - } - else - { - newVolume = sound.remoteVolume ? *sound.remoteVolume : Globals::gSettings.remoteVolume; - } - - playingSound.raw.device.load()->masterVolumeFactor = static_cast(newVolume) / 100.f; - } - } Settings Window::changeSettings(Settings settings) { auto oldSettings = Globals::gSettings; Globals::gSettings = settings; - if ((settings.localVolume != oldSettings.localVolume || settings.remoteVolume != oldSettings.remoteVolume)) + if ((settings.localVolume != oldSettings.localVolume || settings.remoteVolume != oldSettings.remoteVolume) && + !Globals::gAudio.getPlayingSounds().empty()) { - onVolumeChanged(); + for (const auto &playingSound : Globals::gAudio.getPlayingSounds()) + { + int newVolume = 0; + const auto &sound = playingSound.sound; + + if (playingSound.playbackDevice.isDefault) + { + newVolume = sound.localVolume ? *sound.localVolume : Globals::gSettings.localVolume; + } + else + { + newVolume = sound.remoteVolume ? *sound.remoteVolume : Globals::gSettings.remoteVolume; + } + + playingSound.raw.device.load()->masterVolumeFactor = static_cast(newVolume) / 100.f; + } } #if defined(__linux__) @@ -717,9 +714,9 @@ namespace Soundux::Objects #endif return Globals::gSettings; } - void Window::onHotKeyReceived([[maybe_unused]] const std::vector &keys) + void Window::onHotKeyReceived([[maybe_unused]] const std::vector &keys) { - Globals::gHotKeys->notify(false); + Globals::gHotKeys.shouldNotify(false); } std::optional Window::refreshTab(const std::uint32_t &id) { @@ -756,7 +753,7 @@ namespace Soundux::Objects onError(Enums::ErrorCode::TabDoesNotExist); return std::nullopt; } - std::optional Window::setHotkey(const std::uint32_t &id, const std::vector &hotkeys) + std::optional Window::setHotkey(const std::uint32_t &id, const std::vector &hotkeys) { auto sound = Globals::gData.getSound(id); if (sound) @@ -954,7 +951,7 @@ namespace Soundux::Objects { if (!Globals::gSettings.pushToTalkKeys.empty()) { - Globals::gHotKeys->releaseKeys(Globals::gSettings.pushToTalkKeys); + Globals::gHotKeys.releaseKeys(Globals::gSettings.pushToTalkKeys); } #if defined(__linux__) @@ -992,7 +989,7 @@ namespace Soundux::Objects { if (!Globals::gSettings.pushToTalkKeys.empty()) { - Globals::gHotKeys->pressKeys(Globals::gSettings.pushToTalkKeys); + Globals::gHotKeys.pressKeys(Globals::gSettings.pushToTalkKeys); } } void Window::setIsOnFavorites(bool state) diff --git a/src/ui/ui.hpp b/src/ui/ui.hpp index 91ba32c..a917b31 100644 --- a/src/ui/ui.hpp +++ b/src/ui/ui.hpp @@ -77,7 +77,6 @@ namespace Soundux virtual std::optional setSortMode(const std::uint32_t &, Enums::SortMode); protected: - virtual void onVolumeChanged(); virtual bool toggleSoundPlayback(); virtual void stopSounds(bool = false); virtual bool stopSound(const std::uint32_t &); @@ -89,7 +88,7 @@ namespace Soundux virtual std::optional repeatSound(const std::uint32_t &, bool); virtual std::optional seekSound(const std::uint32_t &, std::uint64_t); - virtual std::optional setHotkey(const std::uint32_t &, const std::vector &); + virtual std::optional setHotkey(const std::uint32_t &, const std::vector &); virtual std::optional setCustomLocalVolume(const std::uint32_t &, const std::optional &); virtual std::optional setCustomRemoteVolume(const std::uint32_t &, const std::optional &); @@ -101,13 +100,11 @@ namespace Soundux virtual void onAdminRequired() = 0; virtual void onSettingsChanged() = 0; - virtual void onLocalVolumeChanged(int) = 0; - virtual void onRemoteVolumeChanged(int) = 0; virtual void onSwitchOnConnectDetected(bool) = 0; virtual void onSoundPlayed(const PlayingSound &); virtual void onError(const Enums::ErrorCode &) = 0; virtual void onSoundFinished(const PlayingSound &); - virtual void onHotKeyReceived(const std::vector &); + virtual void onHotKeyReceived(const std::vector &); virtual void onSoundProgressed(const PlayingSound &) = 0; virtual void onDownloadProgressed(float, const std::string &) = 0; };