Revert "feat: hotkeys rework and MIDI support (#242)"

This reverts commit ad5fa403
This commit is contained in:
D3SOX 2022-05-27 18:48:25 +02:00
parent e78f17fa6e
commit 085abaa50b
No known key found for this signature in database
GPG Key ID: 39EC1673FC37B048
23 changed files with 368 additions and 715 deletions

3
.gitmodules vendored
View File

@ -41,6 +41,3 @@
[submodule "lib/guardpp"] [submodule "lib/guardpp"]
path = lib/guardpp path = lib/guardpp
url = https://github.com/Soundux/guardpp url = https://github.com/Soundux/guardpp
[submodule "lib/libremidi"]
path = lib/libremidi
url = https://github.com/Soundux/libremidi

View File

@ -78,7 +78,6 @@ add_subdirectory(lib/nativefiledialog-extended EXCLUDE_FROM_ALL)
add_subdirectory(lib/tiny-process-library EXCLUDE_FROM_ALL) add_subdirectory(lib/tiny-process-library EXCLUDE_FROM_ALL)
add_subdirectory(lib/backward-cpp EXCLUDE_FROM_ALL) add_subdirectory(lib/backward-cpp EXCLUDE_FROM_ALL)
add_subdirectory(lib/traypp EXCLUDE_FROM_ALL) add_subdirectory(lib/traypp EXCLUDE_FROM_ALL)
add_subdirectory(lib/libremidi)
add_subdirectory(lib/guardpp) add_subdirectory(lib/guardpp)
add_subdirectory(lib/lockpp) add_subdirectory(lib/lockpp)
@ -94,7 +93,7 @@ set(HTTPLIB_REQUIRE_OPENSSL ON)
add_subdirectory(lib/cpp-httplib EXCLUDE_FROM_ALL) add_subdirectory(lib/cpp-httplib EXCLUDE_FROM_ALL)
target_include_directories(soundux SYSTEM PRIVATE "lib/cpp-httplib") 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") if (${EMBED_PATH} STREQUAL "OFF")
message("Web-content will not be embedded") message("Web-content will not be embedded")

@ -1 +0,0 @@
Subproject commit e2213b724d8426366235f3de70db25fb231a0b07

View File

@ -33,9 +33,9 @@ namespace Soundux
inline Objects::Queue gQueue; inline Objects::Queue gQueue;
inline Objects::Config gConfig; inline Objects::Config gConfig;
inline Objects::YoutubeDl gYtdl; inline Objects::YoutubeDl gYtdl;
inline Objects::Hotkeys gHotKeys;
inline Objects::Settings gSettings; inline Objects::Settings gSettings;
inline std::unique_ptr<Objects::Window> gGui; inline std::unique_ptr<Objects::Window> gGui;
inline std::shared_ptr<Objects::Hotkeys> gHotKeys;
inline std::shared_ptr<guardpp::guard> gGuard; inline std::shared_ptr<guardpp::guard> gGuard;

View File

@ -1,10 +1,6 @@
#include "hotkeys.hpp" #include "hotkeys.hpp"
#include "keys.hpp"
#include "linux/x11.hpp"
#include "windows/windows.hpp"
#include <core/global/globals.hpp> #include <core/global/globals.hpp>
#include <cstdint> #include <cstdint>
#include <fancy.hpp>
namespace Soundux namespace Soundux
{ {
@ -23,97 +19,19 @@ namespace Soundux
} // namespace traits } // namespace traits
namespace Objects namespace Objects
{ {
std::shared_ptr<Hotkeys> Hotkeys::createInstance() void Hotkeys::init()
{ {
std::shared_ptr<Hotkeys> rtn; listener = std::thread([this] { listen(); });
#if defined(__linux__)
rtn = std::shared_ptr<X11>(new X11()); // NOLINT
#elif defined(_WIN32)
rtn = std::shared_ptr<WindowsHotkeys>(new WindowsHotkeys()); // NOLINT
#endif
rtn->setup();
return rtn;
} }
void Hotkeys::shouldNotify(bool status)
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<int>((static_cast<float>(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)
{ {
pressedKeys.clear(); pressedKeys.clear();
shouldNotify = state; notify = status;
} }
void Hotkeys::requestKnob(bool state) void Hotkeys::onKeyUp(int key)
{ {
shouldNotifyKnob = state; if (notify && !pressedKeys.empty() &&
} std::find(pressedKeys.begin(), pressedKeys.end(), key) != pressedKeys.end())
void Hotkeys::onKeyUp(const Key &key)
{
if (std::find(pressedKeys.begin(), pressedKeys.end(), key) != pressedKeys.end())
{
if (shouldNotify)
{ {
Globals::gGui->onHotKeyReceived(pressedKeys); Globals::gGui->onHotKeyReceived(pressedKeys);
pressedKeys.clear(); pressedKeys.clear();
@ -121,19 +39,18 @@ namespace Soundux
else else
{ {
pressedKeys.erase(std::remove_if(pressedKeys.begin(), pressedKeys.end(), pressedKeys.erase(std::remove_if(pressedKeys.begin(), pressedKeys.end(),
[&](const auto &keyItem) { return key == keyItem; }), [key](const auto &item) { return key == item; }),
pressedKeys.end()); pressedKeys.end());
} }
} }
} bool isCloseMatch(const std::vector<int> &pressedKeys, const std::vector<int> &keys)
bool isCloseMatch(const std::vector<Key> &pressedKeys, const std::vector<Key> &keys)
{ {
if (pressedKeys.size() >= keys.size()) if (pressedKeys.size() >= keys.size())
{ {
bool allMatched = true; bool allMatched = true;
for (const auto &key : keys) 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; allMatched = false;
} }
@ -142,14 +59,13 @@ namespace Soundux
} }
return false; return false;
} }
template <typename T> std::optional<Sound> getBestMatch(const T &list, const std::vector<Key> &pressedKeys) template <typename T> std::optional<Sound> getBestMatch(const T &list, const std::vector<int> &pressedKeys)
{ {
std::optional<Sound> rtn; std::optional<Sound> rtn;
for (const auto &_sound : list) for (const auto &_sound : list)
{ {
const auto &sound = [&]() constexpr const auto &sound = [&] {
{
if constexpr (traits::is_pair<std::decay_t<decltype(_sound)>>::value) if constexpr (traits::is_pair<std::decay_t<decltype(_sound)>>::value)
{ {
return _sound.second.get(); return _sound.second.get();
@ -158,13 +74,12 @@ namespace Soundux
{ {
return _sound; return _sound;
} }
} }();
();
if (sound.hotkeys.empty()) if (sound.hotkeys.empty())
continue; continue;
if (pressedKeys == sound.hotkeys) if (sound.hotkeys == pressedKeys)
{ {
rtn = sound; rtn = sound;
break; break;
@ -182,18 +97,27 @@ namespace Soundux
} }
return rtn; 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; return;
} }
pressedKeys.emplace_back(key); if (notify)
if (!shouldNotify)
{ {
if (!Globals::gSettings.stopHotkey.empty() && return;
(Globals::gSettings.stopHotkey == pressedKeys || }
if (!Globals::gSettings.stopHotkey.empty() && (pressedKeys == Globals::gSettings.stopHotkey ||
isCloseMatch(pressedKeys, Globals::gSettings.stopHotkey))) isCloseMatch(pressedKeys, Globals::gSettings.stopHotkey)))
{ {
Globals::gGui->stopSounds(); Globals::gGui->stopSounds();
@ -233,30 +157,18 @@ namespace Soundux
} }
} }
} }
} std::string Hotkeys::getKeySequence(const std::vector<int> &keys)
std::string Hotkeys::getKeyName(const Key &key)
{
if (key.type == Enums::KeyType::Midi)
{
return "MIDI_" + std::to_string(key.key);
}
return "";
}
std::string Hotkeys::getKeySequence(const std::vector<Key> &keys)
{ {
std::string rtn; std::string rtn;
for (const auto &key : keys)
for (auto it = keys.begin(); it != keys.end(); ++it)
{ {
rtn += getKeyName(*it); rtn += getKeyName(key) + " + ";
if (std::distance(it, keys.end()) > 1) }
if (!rtn.empty())
{ {
rtn += " + "; return rtn.substr(0, rtn.length() - 3);
} }
} return "";
return rtn;
} }
} // namespace Objects } // namespace Objects
} // namespace Soundux } // namespace Soundux

View File

@ -1,15 +1,7 @@
#pragma once #pragma once
#pragma push_macro("max")
#pragma push_macro("min")
#undef min
#undef max
#include <libremidi/libremidi.hpp>
#pragma pop_macro("min")
#pragma pop_macro("max")
#include "keys.hpp"
#include <atomic> #include <atomic>
#include <string> #include <string>
#include <thread>
#include <vector> #include <vector>
namespace Soundux namespace Soundux
@ -18,32 +10,33 @@ namespace Soundux
{ {
class Hotkeys class Hotkeys
{ {
libremidi::midi_in midi; std::thread listener;
std::atomic<bool> kill = false;
std::atomic<bool> notify = false;
protected: std::vector<int> pressedKeys;
Hotkeys() = default; std::vector<int> keysToPress;
virtual void setup(); #if defined(_WIN32)
std::thread keyPressThread;
std::atomic<bool> shouldPressKeys = false;
#endif
protected: private:
std::vector<Key> pressedKeys; void listen();
std::atomic<bool> shouldNotify = false;
std::atomic<bool> shouldNotifyKnob = false;
public: public:
static std::shared_ptr<Hotkeys> createInstance(); void init();
void stop();
void shouldNotify(bool);
public: void onKeyUp(int);
virtual void notify(bool); void onKeyDown(int);
virtual void requestKnob(bool);
virtual void onKeyUp(const Key &); void pressKeys(const std::vector<int> &);
virtual void onKeyDown(const Key &); void releaseKeys(const std::vector<int> &);
virtual void pressKeys(const std::vector<Key> &) = 0; std::string getKeyName(const int &);
virtual void releaseKeys(const std::vector<Key> &) = 0; std::string getKeySequence(const std::vector<int> &);
virtual std::string getKeyName(const Key &);
virtual std::string getKeySequence(const std::vector<Key> &);
}; };
} // namespace Objects } // namespace Objects
} // namespace Soundux } // namespace Soundux

View File

@ -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

View File

@ -1,33 +0,0 @@
#pragma once
#include <cstdint>
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

View File

@ -1,26 +1,25 @@
#if defined(__linux__) #if defined(__linux__) && __has_include(<X11/Xlib.h>)
#include "x11.hpp" #include "../hotkeys.hpp"
#include <X11/X.h>
#include <X11/XKBlib.h> #include <X11/XKBlib.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/extensions/XI2.h>
#include <X11/extensions/XInput2.h> #include <X11/extensions/XInput2.h>
#include <X11/extensions/XTest.h> #include <X11/extensions/XTest.h>
#include <chrono> #include <chrono>
#include <core/hotkeys/keys.hpp> #include <cstdlib>
#include <fancy.hpp> #include <fancy.hpp>
#include <thread> #include <thread>
using namespace std::chrono_literals;
namespace Soundux::Objects namespace Soundux::Objects
{ {
void X11::setup() Display *display;
void Hotkeys::listen()
{ {
Hotkeys::setup(); auto *displayenv = std::getenv("DISPLAY"); // NOLINT
listener = std::thread([this] { listen(); }); auto *x11Display = XOpenDisplay(displayenv);
}
void X11::listen()
{
auto *displayEnv = std::getenv("DISPLAY"); // NOLINT
auto *x11Display = XOpenDisplay(displayEnv);
if (!x11Display) if (!x11Display)
{ {
@ -28,18 +27,20 @@ namespace Soundux::Objects
if (!(x11Display = XOpenDisplay(":0"))) if (!(x11Display = XOpenDisplay(":0")))
{ {
Fancy::fancy.logTime().failure() << "Could not open X11 Display" << std::endl; Fancy::fancy.logTime().failure() << "Could not open X11 Display" << std::endl;
return;
} }
} }
else else
{ {
Fancy::fancy.logTime().message() << "Using DISPLAY " << displayEnv << std::endl; Fancy::fancy.logTime().message() << "Using DISPLAY " << displayenv << std::endl;
} }
display = x11Display; 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)) if (!XQueryExtension(display, "XInputExtension", &major_op, &event_rtn, &ext_rtn))
{ {
Fancy::fancy.logTime().failure() << "Failed to find XInputExtension" << std::endl; Fancy::fancy.logTime().failure() << "Failed to find XInputExtension" << std::endl;
return;
} }
Window root = DefaultRootWindow(display); // NOLINT Window root = DefaultRootWindow(display); // NOLINT
@ -66,106 +67,78 @@ namespace Soundux::Objects
XNextEvent(display, &event); XNextEvent(display, &event);
auto *cookie = reinterpret_cast<XGenericEventCookie *>(&event.xcookie); auto *cookie = reinterpret_cast<XGenericEventCookie *>(&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 ||
if (cookie->evtype == XI_RawKeyPress || cookie->evtype == XI_RawKeyRelease) cookie->evtype == XI_RawButtonPress || cookie->evtype == XI_RawButtonRelease))
{ {
auto *data = reinterpret_cast<XIRawEvent *>(cookie->data); auto *data = reinterpret_cast<XIRawEvent *>(cookie->data);
auto key = data->detail; auto key = data->detail;
Key pressedKey; if (key == 1)
pressedKey.key = key; continue;
pressedKey.type = Enums::KeyType::Keyboard;
if (cookie->evtype == XI_RawKeyPress) if (cookie->evtype == XI_RawKeyPress || cookie->evtype == XI_RawButtonPress)
{ {
onKeyDown(pressedKey); onKeyDown(key);
} }
else else if (cookie->evtype == XI_RawKeyRelease || cookie->evtype == XI_RawButtonRelease)
{ {
onKeyUp(pressedKey); onKeyUp(key);
}
}
else if (cookie->evtype == XI_RawButtonPress || cookie->evtype == XI_RawButtonRelease)
{
auto *data = reinterpret_cast<XIRawEvent *>(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);
}
}
} }
} }
} }
else else
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(100ms);
} }
} }
} }
std::string X11::getKeyName(const Key &key)
{
if (!Hotkeys::getKeyName(key).empty())
{
return Hotkeys::getKeyName(key);
}
if (key.type == Enums::KeyType::Keyboard) std::string Hotkeys::getKeyName(const int &key)
{ {
KeySym keySym = XkbKeycodeToKeysym(display, key.key, 0, 0); // 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
if (keySym == NoSymbol) KeySym s = XkbKeycodeToKeysym(display, key, 0, 0);
if (s == NoSymbol)
{ {
return "KEY_" + std::to_string(key.key); return "KEY_" + std::to_string(key);
} }
auto *str = XKeysymToString(keySym); auto *str = XKeysymToString(s);
if (!str) if (str == nullptr)
{ {
return "KEY_" + std::to_string(key.key); return "KEY_" + std::to_string(key);
} }
return str; return str;
} }
if (key.type == Enums::KeyType::Mouse) void Hotkeys::stop()
{
return "MOUSE_" + std::to_string(key.key);
}
return "";
}
void X11::pressKeys(const std::vector<Key> &keys)
{
for (const auto &key : keys)
{
XTestFakeKeyEvent(display, key.key, True, 0);
}
}
void X11::releaseKeys(const std::vector<Key> &keys)
{
for (const auto &key : keys)
{
XTestFakeKeyEvent(display, key.key, False, 0);
}
}
X11::~X11()
{ {
kill = true; kill = true;
listener.join(); listener.join();
} }
void Hotkeys::pressKeys(const std::vector<int> &keys)
{
keysToPress = keys;
for (const auto &key : keys)
{
XTestFakeKeyEvent(display, key, True, 0);
}
}
void Hotkeys::releaseKeys(const std::vector<int> &keys)
{
keysToPress.clear();
for (const auto &key : keys)
{
XTestFakeKeyEvent(display, key, False, 0);
}
}
} // namespace Soundux::Objects } // namespace Soundux::Objects
#endif #endif

View File

@ -1,33 +0,0 @@
#pragma once
#if defined(__linux__)
#include <core/hotkeys/hotkeys.hpp>
#include <thread>
struct _XDisplay; // NOLINT
using Display = _XDisplay;
namespace Soundux
{
namespace Objects
{
class X11 : public Hotkeys
{
int major_op;
Display *display;
std::thread listener;
std::atomic<bool> kill = false;
private:
void listen();
void setup() override;
public:
~X11();
std::string getKeyName(const Key &key) override;
void pressKeys(const std::vector<Key> &keys) override;
void releaseKeys(const std::vector<Key> &keys) override;
};
} // namespace Objects
} // namespace Soundux
#endif

View File

@ -1,90 +1,88 @@
#if defined(_WIN32) #if defined(_WIN32)
#include "windows.hpp" #include "../hotkeys.hpp"
#include <Windows.h>
#include <chrono>
#include <core/global/globals.hpp> #include <core/global/globals.hpp>
#include <winuser.h>
using namespace std::chrono_literals;
namespace Soundux::Objects namespace Soundux::Objects
{ {
HHOOK WindowsHotkeys::oMouseProc; HHOOK oKeyBoardProc;
HHOOK WindowsHotkeys::oKeyboardProc; HHOOK oMouseProc;
void WindowsHotkeys::setup() LRESULT CALLBACK keyBoardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
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)
{ {
if (nCode == HC_ACTION) if (nCode == HC_ACTION)
{ {
auto *info = reinterpret_cast<PKBDLLHOOKSTRUCT>(lParam); // NOLINT
if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)
{ {
Key key; auto *info = reinterpret_cast<PKBDLLHOOKSTRUCT>(lParam);
key.type = Enums::KeyType::Keyboard; Globals::gHotKeys.onKeyDown(info->vkCode);
key.key = static_cast<int>(info->vkCode);
Globals::gHotKeys->onKeyDown(key);
} }
else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP) else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP)
{ {
Key key; auto *info = reinterpret_cast<PKBDLLHOOKSTRUCT>(lParam);
key.type = Enums::KeyType::Keyboard; Globals::gHotKeys.onKeyUp(info->vkCode);
key.key = static_cast<int>(info->vkCode); }
}
return CallNextHookEx(oKeyBoardProc, nCode, wParam, lParam);
}
Globals::gHotKeys->onKeyUp(key); LRESULT CALLBACK mouseProc(int nCode, WPARAM wParam, LPARAM lParam)
}
}
return CallNextHookEx(oKeyboardProc, nCode, wParam, lParam);
}
LRESULT CALLBACK WindowsHotkeys::mouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{ {
if (nCode == HC_ACTION) 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) switch (wParam)
{ {
case WM_RBUTTONUP: { case WM_RBUTTONUP:
Key key; Globals::gHotKeys.onKeyUp(VK_RBUTTON);
key.key = VK_RBUTTON;
key.type = Enums::KeyType::Mouse;
Soundux::Globals::gHotKeys->onKeyUp(key);
}
break; break;
case WM_RBUTTONDOWN: {
Key key; case WM_RBUTTONDOWN:
key.key = VK_RBUTTON; Globals::gHotKeys.onKeyDown(VK_RBUTTON);
key.type = Enums::KeyType::Mouse;
Soundux::Globals::gHotKeys->onKeyDown(key);
}
break; break;
case WM_MBUTTONUP: {
Key key; case WM_MBUTTONDOWN:
key.key = VK_MBUTTON; Globals::gHotKeys.onKeyDown(VK_MBUTTON);
key.type = Enums::KeyType::Mouse;
Soundux::Globals::gHotKeys->onKeyUp(key);
}
break; break;
case WM_MBUTTONDOWN: {
Key key; case WM_MBUTTONUP:
key.key = VK_RBUTTON; Globals::gHotKeys.onKeyUp(VK_MBUTTON);
key.type = Enums::KeyType::Mouse;
Soundux::Globals::gHotKeys->onKeyDown(key);
}
break; break;
} }
} }
return CallNextHookEx(oMouseProc, nCode, wParam, lParam); 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; MSG message;
while (!GetMessage(&message, nullptr, 0, 0)) while (!GetMessage(&message, nullptr, NULL, NULL))
{ {
if (kill) if (kill)
{ {
@ -94,82 +92,68 @@ namespace Soundux::Objects
DispatchMessage(&message); DispatchMessage(&message);
} }
} }
void WindowsHotkeys::presser()
void Hotkeys::stop()
{ {
std::unique_lock lock(keysToPressMutex); kill = true;
while (!kill) UnhookWindowsHookEx(oMouseProc);
{ UnhookWindowsHookEx(oKeyBoardProc);
cv.wait(lock, [&]() { return !keysToPress.empty() || kill; }); PostThreadMessage(GetThreadId(listener.native_handle()), WM_QUIT, 0, 0);
//* Yes, this is absolutely cursed. I tried to implement this by just sending the keydown event once but listener.join();
//* it does not work like that on windows, so I have to do this, thank you Microsoft, I hate you. keyPressThread.join();
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) std::string Hotkeys::getKeyName(const int &key)
{ {
char name[128]; auto scanCode = MapVirtualKey(key, MAPVK_VK_TO_VSC);
auto result = GetKeyNameTextA(MapVirtualKey(key.key, MAPVK_VK_TO_VSC) << 16, name, 128);
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) if (result == 0)
{ {
return "KEY_" + std::to_string(key.key); return "KEY_" + std::to_string(key);
} }
return name; return name;
} }
if (key.type == Enums::KeyType::Mouse) void Hotkeys::pressKeys(const std::vector<int> &keys)
{ {
return "MOUSE_" + std::to_string(key.key); keysToPress = keys;
shouldPressKeys = true;
} }
return ""; void Hotkeys::releaseKeys([[maybe_unused]] const std::vector<int> &keys)
}
void WindowsHotkeys::pressKeys(const std::vector<Key> &keys)
{ {
std::unique_lock lock(keysToPressMutex); shouldPressKeys = false;
keysToPress = keys; keysToPress.clear();
}
void WindowsHotkeys::releaseKeys(const std::vector<Key> &keys)
{
std::unique_lock lock(keysToPressMutex);
for (const auto &key : keys) for (const auto &key : keys)
{ {
for (auto it = keysToPress.begin(); it != keysToPress.end();) keybd_event(key, 0, 2, 0);
{
if (*it == key)
{
it = keysToPress.erase(it);
} }
else
{
++it;
}
}
}
}
WindowsHotkeys::~WindowsHotkeys()
{
kill = true;
PostThreadMessage(GetThreadId(listener.native_handle()), WM_QUIT, 0, 0);
listener.join();
cv.notify_all();
keyPresser.join();
UnhookWindowsHookEx(oMouseProc);
UnhookWindowsHookEx(oKeyboardProc);
} }
} // namespace Soundux::Objects } // namespace Soundux::Objects
#endif #endif

View File

@ -1,43 +0,0 @@
#pragma once
#if defined(_WIN32)
#include <core/hotkeys/hotkeys.hpp>
#include <mutex>
#include <thread>
#include <windows.h>
namespace Soundux
{
namespace Objects
{
class WindowsHotkeys : public Hotkeys
{
std::thread listener;
std::thread keyPresser;
std::atomic<bool> kill = false;
std::condition_variable cv;
std::mutex keysToPressMutex;
std::vector<Key> 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<Key> &keys) override;
void releaseKeys(const std::vector<Key> &keys) override;
};
} // namespace Objects
} // namespace Soundux
#endif

View File

@ -8,7 +8,7 @@ namespace Soundux
{ {
namespace Objects namespace Objects
{ {
struct Key; struct AudioDevice;
struct Sound struct Sound
{ {
@ -17,7 +17,7 @@ namespace Soundux
std::string path; std::string path;
bool isFavorite = false; bool isFavorite = false;
std::vector<Key> hotkeys; std::vector<int> hotkeys;
std::uint64_t modifiedDate; std::uint64_t modifiedDate;
std::optional<int> localVolume; std::optional<int> localVolume;

View File

@ -1,7 +1,5 @@
#pragma once #pragma once
#include <core/enums/enums.hpp> #include <core/enums/enums.hpp>
#include <core/hotkeys/keys.hpp>
#include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
@ -16,18 +14,15 @@ namespace Soundux
Enums::Theme theme = Enums::Theme::System; Enums::Theme theme = Enums::Theme::System;
std::optional<std::string> language; std::optional<std::string> language;
std::vector<Key> pushToTalkKeys; std::vector<int> pushToTalkKeys;
std::vector<Key> stopHotkey; std::vector<int> stopHotkey;
std::optional<Key> remoteVolumeKnob;
std::optional<Key> localVolumeKnob;
std::vector<std::string> outputs; std::vector<std::string> outputs;
std::uint32_t selectedTab = 0; std::uint32_t selectedTab = 0;
bool syncVolumes = false;
int remoteVolume = 100; int remoteVolume = 100;
int localVolume = 50; int localVolume = 50;
bool syncVolumes = false;
bool allowMultipleOutputs = false; bool allowMultipleOutputs = false;
bool useAsDefaultDevice = false; bool useAsDefaultDevice = false;

View File

@ -1,69 +1,11 @@
#pragma once #pragma once
#include <core/global/globals.hpp> #include <core/global/globals.hpp>
#include <core/hotkeys/keys.hpp>
#include <helper/audio/windows/winsound.hpp> #include <helper/audio/windows/winsound.hpp>
#include <helper/version/check.hpp> #include <helper/version/check.hpp>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
namespace Soundux
{
namespace traits
{
template <typename T> struct is_optional
{
private:
static std::uint8_t test(...);
template <typename O> static auto test(std::optional<O> *) -> std::uint16_t;
public:
static const bool value = sizeof(test(reinterpret_cast<std::decay_t<T> *>(0))) == sizeof(std::uint16_t);
};
} // namespace traits
} // namespace Soundux
namespace nlohmann namespace nlohmann
{ {
template <typename T> struct adl_serializer<std::optional<T>>
{
static void to_json(json &j, const std::optional<T> &obj)
{
if (obj)
{
j = *obj;
}
else
{
j = nullptr;
}
}
static void from_json(const json &j, const std::optional<T> &obj)
{
if (!j.is_null())
{
obj = j.get<T>();
}
}
}; // namespace nlohmann
template <> struct adl_serializer<Soundux::Objects::Key>
{
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<Soundux::Objects::Sound> template <> struct adl_serializer<Soundux::Objects::Sound>
{ {
static void to_json(json &j, const Soundux::Objects::Sound &obj) static void to_json(json &j, const Soundux::Objects::Sound &obj)
@ -72,14 +14,29 @@ namespace nlohmann
{"name", obj.name}, {"name", obj.name},
{"hotkeys", obj.hotkeys}, {"hotkeys", obj.hotkeys},
{"hotkeySequence", {"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}, {"id", obj.id},
{"path", obj.path}, {"path", obj.path},
{"isFavorite", obj.isFavorite}, {"isFavorite", obj.isFavorite},
{"localVolume", obj.localVolume},
{"remoteVolume", obj.remoteVolume},
{"modifiedDate", obj.modifiedDate}, {"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) static void from_json(const json &j, Soundux::Objects::Sound &obj)
{ {
@ -163,8 +120,6 @@ namespace nlohmann
{"pushToTalkKeys", obj.pushToTalkKeys}, {"pushToTalkKeys", obj.pushToTalkKeys},
{"tabHotkeysOnly", obj.tabHotkeysOnly}, {"tabHotkeysOnly", obj.tabHotkeysOnly},
{"minimizeToTray", obj.minimizeToTray}, {"minimizeToTray", obj.minimizeToTray},
{"localVolumeKnob", obj.localVolumeKnob},
{"remoteVolumeKnob", obj.remoteVolumeKnob},
{"allowOverlapping", obj.allowOverlapping}, {"allowOverlapping", obj.allowOverlapping},
{"muteDuringPlayback", obj.muteDuringPlayback}, {"muteDuringPlayback", obj.muteDuringPlayback},
{"useAsDefaultDevice", obj.useAsDefaultDevice}, {"useAsDefaultDevice", obj.useAsDefaultDevice},
@ -175,18 +130,6 @@ namespace nlohmann
template <typename T> static void get_to_safe(const json &j, const std::string &key, T &member) noexcept template <typename T> static void get_to_safe(const json &j, const std::string &key, T &member) noexcept
{ {
if (j.find(key) != j.end()) if (j.find(key) != j.end())
{
if constexpr (Soundux::traits::is_optional<T>::value)
{
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<typename T::value_type>();
}
}
}
else
{ {
if (j.at(key).type_name() == nlohmann::basic_json(T{}).type_name()) if (j.at(key).type_name() == nlohmann::basic_json(T{}).type_name())
{ {
@ -194,7 +137,6 @@ namespace nlohmann
} }
} }
} }
}
static void from_json(const json &j, Soundux::Objects::Settings &obj) static void from_json(const json &j, Soundux::Objects::Settings &obj)
{ {
@ -212,8 +154,6 @@ namespace nlohmann
get_to_safe(j, "pushToTalkKeys", obj.pushToTalkKeys); get_to_safe(j, "pushToTalkKeys", obj.pushToTalkKeys);
get_to_safe(j, "minimizeToTray", obj.minimizeToTray); get_to_safe(j, "minimizeToTray", obj.minimizeToTray);
get_to_safe(j, "tabHotkeysOnly", obj.tabHotkeysOnly); 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, "allowOverlapping", obj.allowOverlapping);
get_to_safe(j, "useAsDefaultDevice", obj.useAsDefaultDevice); get_to_safe(j, "useAsDefaultDevice", obj.useAsDefaultDevice);
get_to_safe(j, "muteDuringPlayback", obj.muteDuringPlayback); get_to_safe(j, "muteDuringPlayback", obj.muteDuringPlayback);
@ -337,5 +277,22 @@ namespace nlohmann
}; };
} }
}; };
template <> struct adl_serializer<std::optional<Soundux::Objects::RecordingDevice>>
{
static void to_json(json &j, const std::optional<Soundux::Objects::RecordingDevice> &obj)
{
if (obj)
{
j = {
{"name", obj->getName()},
{"guid", obj->getGUID()},
};
}
else
{
j = "null";
}
}
};
#endif #endif
} // namespace nlohmann } // namespace nlohmann

View File

@ -5,12 +5,7 @@
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <optional> #include <optional>
#pragma push_macro("UNICOCDE")
#undef UNICODE
#include <process.hpp> #include <process.hpp>
#pragma pop_macro("UNICOCDE")
#include <regex> #include <regex>
#include <system_error> #include <system_error>

View File

@ -10,33 +10,29 @@ namespace Soundux::Objects
cv.wait(lock, [&]() { return !queue.empty() || stop; }); cv.wait(lock, [&]() { return !queue.empty() || stop; });
while (!queue.empty()) while (!queue.empty())
{ {
auto front = queue.begin(); auto front = std::move(*queue.begin());
front->function();
queue.erase(front); lock.unlock();
front.second();
lock.lock();
queue.erase(front.first);
} }
} }
} }
void Queue::push_unique(std::uint64_t id, std::function<void()> function) void Queue::push_unique(std::uint64_t id, std::function<void()> function)
{ {
{ {
std::lock_guard lock(queueMutex); std::lock_guard lock(queueMutex);
if (std::find_if(queue.begin(), queue.end(), if (queue.find(id) != queue.end())
[&id](const auto &entry) { return entry.id && *entry.id == id; }) != queue.end())
{ {
return; return;
} }
} }
std::unique_lock lock(queueMutex); std::unique_lock lock(queueMutex);
queue.emplace_back(Call{std::move(function), id}); queue.emplace(id, std::move(function));
lock.unlock();
cv.notify_one();
}
void Queue::push(std::function<void()> function)
{
std::unique_lock lock(queueMutex);
queue.emplace_back(Call{std::move(function), std::nullopt});
lock.unlock(); lock.unlock();
cv.notify_one(); cv.notify_one();

View File

@ -3,7 +3,6 @@
#include <condition_variable> #include <condition_variable>
#include <functional> #include <functional>
#include <map> #include <map>
#include <optional>
#include <queue> #include <queue>
#include <thread> #include <thread>
@ -13,14 +12,8 @@ namespace Soundux
{ {
class Queue class Queue
{ {
struct Call std::map<std::uint64_t, std::function<void()>> queue;
{
std::function<void()> function;
std::optional<std::uint64_t> id;
};
std::mutex queueMutex; std::mutex queueMutex;
std::vector<Call> queue;
std::condition_variable cv; std::condition_variable cv;
std::atomic<bool> stop; std::atomic<bool> stop;
@ -33,7 +26,6 @@ namespace Soundux
Queue(); Queue();
~Queue(); ~Queue();
void push(std::function<void()>);
void push_unique(std::uint64_t, std::function<void()>); void push_unique(std::uint64_t, std::function<void()>);
}; };
} // namespace Objects } // namespace Objects

View File

@ -1,12 +1,7 @@
#pragma once #pragma once
#include <json.hpp> #include <json.hpp>
#include <optional> #include <optional>
#pragma push_macro("UNICOCDE")
#undef UNICODE
#include <process.hpp> #include <process.hpp>
#pragma pop_macro("UNICOCDE")
#include <regex> #include <regex>
#include <string> #include <string>

View File

@ -9,7 +9,6 @@
#include <helper/systeminfo/systeminfo.hpp> #include <helper/systeminfo/systeminfo.hpp>
#include <helper/version/check.hpp> #include <helper/version/check.hpp>
#include <helper/ytdl/youtube-dl.hpp> #include <helper/ytdl/youtube-dl.hpp>
#include <javascript/function.hpp>
#ifdef _WIN32 #ifdef _WIN32
#include "../../assets/icon.h" #include "../../assets/icon.h"
@ -123,14 +122,12 @@ namespace Soundux::Objects
webview->expose(Webview::Function("stopSounds", [this]() { stopSounds(); })); webview->expose(Webview::Function("stopSounds", [this]() { stopSounds(); }));
webview->expose(Webview::Function("changeSettings", webview->expose(Webview::Function("changeSettings",
[this](const Settings &newSettings) { return changeSettings(newSettings); })); [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( webview->expose(Webview::Function(
"setHotkey", [this](std::uint32_t id, const std::vector<Key> &keys) { return setHotkey(id, keys); })); "setHotkey", [this](std::uint32_t id, const std::vector<int> &keys) { return setHotkey(id, keys); }));
webview->expose(Webview::Function("getHotkeySequence", [this](const std::vector<Key> &keys) { webview->expose(Webview::Function("getHotkeySequence", [this](const std::vector<int> &keys) {
return Globals::gHotKeys->getKeySequence(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("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("refreshTab", [this](std::uint32_t id) { return refreshTab(id); }));
webview->expose(Webview::Function( webview->expose(Webview::Function(
@ -172,8 +169,6 @@ namespace Soundux::Objects
return setCustomRemoteVolume(id, volume); return setCustomRemoteVolume(id, volume);
})); }));
webview->expose(Webview::Function("toggleSoundPlayback", [this]() { return toggleSoundPlayback(); })); webview->expose(Webview::Function("toggleSoundPlayback", [this]() { return toggleSoundPlayback(); }));
webview->expose(
Webview::Function("requestKnob", [this](bool state) { Globals::gHotKeys->requestKnob(state); }));
#if !defined(__linux__) #if !defined(__linux__)
webview->expose(Webview::Function("getOutputs", [this]() { return getOutputs(); })); webview->expose(Webview::Function("getOutputs", [this]() { return getOutputs(); }));
@ -392,10 +387,15 @@ namespace Soundux::Objects
} }
Fancy::fancy.logTime().message() << "UI exited" << std::endl; Fancy::fancy.logTime().message() << "UI exited" << std::endl;
} }
void WebView::onHotKeyReceived(const std::vector<Key> &keys) void WebView::onHotKeyReceived(const std::vector<int> &keys)
{ {
webview->callFunction<void>( std::string hotkeySequence;
Webview::JavaScriptFunction("window.hotkeyReceived", Globals::gHotKeys->getKeySequence(keys), keys)); for (const auto &key : keys)
{
hotkeySequence += Globals::gHotKeys.getKeyName(key) + " + ";
}
webview->callFunction<void>(Webview::JavaScriptFunction(
"window.hotkeyReceived", hotkeySequence.substr(0, hotkeySequence.length() - 3), keys));
} }
void WebView::onSoundFinished(const PlayingSound &sound) void WebView::onSoundFinished(const PlayingSound &sound)
{ {
@ -448,12 +448,4 @@ namespace Soundux::Objects
webview->callFunction<void>( webview->callFunction<void>(
Webview::JavaScriptFunction("window.getStore().commit", "setAdministrativeModal", true)); Webview::JavaScriptFunction("window.getStore().commit", "setAdministrativeModal", true));
} }
void WebView::onLocalVolumeChanged(int volume)
{
webview->callFunction<void>(Webview::JavaScriptFunction("window.getStore().commit", "setLocalVolume", volume));
}
void WebView::onRemoteVolumeChanged(int volume)
{
webview->callFunction<void>(Webview::JavaScriptFunction("window.getStore().commit", "setRemoteVolume", volume));
}
} // namespace Soundux::Objects } // namespace Soundux::Objects

View File

@ -28,12 +28,10 @@ namespace Soundux
void setup() override; void setup() override;
void mainLoop() override; void mainLoop() override;
void onSoundFinished(const PlayingSound &sound) override; void onSoundFinished(const PlayingSound &sound) override;
void onHotKeyReceived(const std::vector<Key> &keys) override; void onHotKeyReceived(const std::vector<int> &keys) override;
void onAdminRequired() override; void onAdminRequired() override;
void onSettingsChanged() override; void onSettingsChanged() override;
void onLocalVolumeChanged(int volume) override;
void onRemoteVolumeChanged(int volume) override;
void onSwitchOnConnectDetected(bool state) override; void onSwitchOnConnectDetected(bool state) override;
void onError(const Enums::ErrorCode &error) override; void onError(const Enums::ErrorCode &error) override;
void onSoundPlayed(const PlayingSound &sound) override; void onSoundPlayed(const PlayingSound &sound) override;

View File

@ -15,8 +15,7 @@ namespace Soundux::Objects
void Window::setup() void Window::setup()
{ {
NFD::Init(); NFD::Init();
Globals::gHotKeys = Hotkeys::createInstance(); Globals::gHotKeys.init();
for (auto &tab : Globals::gData.getTabs()) for (auto &tab : Globals::gData.getTabs())
{ {
tab.sounds = getTabContent(tab); tab.sounds = getTabContent(tab);
@ -26,6 +25,7 @@ namespace Soundux::Objects
Window::~Window() Window::~Window()
{ {
NFD::Quit(); NFD::Quit();
Globals::gHotKeys.stop();
} }
std::vector<Sound> Window::getTabContent(const Tab &tab) const std::vector<Sound> Window::getTabContent(const Tab &tab) const
{ {
@ -225,7 +225,7 @@ namespace Soundux::Objects
} }
if (!Globals::gSettings.pushToTalkKeys.empty()) if (!Globals::gSettings.pushToTalkKeys.empty())
{ {
Globals::gHotKeys->pressKeys(Globals::gSettings.pushToTalkKeys); Globals::gHotKeys.pressKeys(Globals::gSettings.pushToTalkKeys);
} }
auto playingSound = Globals::gAudio.play(*sound); auto playingSound = Globals::gAudio.play(*sound);
@ -297,7 +297,7 @@ namespace Soundux::Objects
} }
if (!Globals::gSettings.pushToTalkKeys.empty()) 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) if (Globals::gSettings.outputs.empty() && !Globals::gSettings.useAsDefaultDevice)
@ -579,7 +579,13 @@ namespace Soundux::Objects
onError(Enums::ErrorCode::FailedToSetCustomVolume); onError(Enums::ErrorCode::FailedToSetCustomVolume);
return std::nullopt; return std::nullopt;
} }
void Window::onVolumeChanged() Settings Window::changeSettings(Settings settings)
{
auto oldSettings = Globals::gSettings;
Globals::gSettings = settings;
if ((settings.localVolume != oldSettings.localVolume || settings.remoteVolume != oldSettings.remoteVolume) &&
!Globals::gAudio.getPlayingSounds().empty())
{ {
for (const auto &playingSound : Globals::gAudio.getPlayingSounds()) for (const auto &playingSound : Globals::gAudio.getPlayingSounds())
{ {
@ -598,15 +604,6 @@ namespace Soundux::Objects
playingSound.raw.device.load()->masterVolumeFactor = static_cast<float>(newVolume) / 100.f; playingSound.raw.device.load()->masterVolumeFactor = static_cast<float>(newVolume) / 100.f;
} }
} }
Settings Window::changeSettings(Settings settings)
{
auto oldSettings = Globals::gSettings;
Globals::gSettings = settings;
if ((settings.localVolume != oldSettings.localVolume || settings.remoteVolume != oldSettings.remoteVolume))
{
onVolumeChanged();
}
#if defined(__linux__) #if defined(__linux__)
if (settings.audioBackend != oldSettings.audioBackend) if (settings.audioBackend != oldSettings.audioBackend)
@ -717,9 +714,9 @@ namespace Soundux::Objects
#endif #endif
return Globals::gSettings; return Globals::gSettings;
} }
void Window::onHotKeyReceived([[maybe_unused]] const std::vector<Key> &keys) void Window::onHotKeyReceived([[maybe_unused]] const std::vector<int> &keys)
{ {
Globals::gHotKeys->notify(false); Globals::gHotKeys.shouldNotify(false);
} }
std::optional<Tab> Window::refreshTab(const std::uint32_t &id) std::optional<Tab> Window::refreshTab(const std::uint32_t &id)
{ {
@ -756,7 +753,7 @@ namespace Soundux::Objects
onError(Enums::ErrorCode::TabDoesNotExist); onError(Enums::ErrorCode::TabDoesNotExist);
return std::nullopt; return std::nullopt;
} }
std::optional<Sound> Window::setHotkey(const std::uint32_t &id, const std::vector<Key> &hotkeys) std::optional<Sound> Window::setHotkey(const std::uint32_t &id, const std::vector<int> &hotkeys)
{ {
auto sound = Globals::gData.getSound(id); auto sound = Globals::gData.getSound(id);
if (sound) if (sound)
@ -954,7 +951,7 @@ namespace Soundux::Objects
{ {
if (!Globals::gSettings.pushToTalkKeys.empty()) if (!Globals::gSettings.pushToTalkKeys.empty())
{ {
Globals::gHotKeys->releaseKeys(Globals::gSettings.pushToTalkKeys); Globals::gHotKeys.releaseKeys(Globals::gSettings.pushToTalkKeys);
} }
#if defined(__linux__) #if defined(__linux__)
@ -992,7 +989,7 @@ namespace Soundux::Objects
{ {
if (!Globals::gSettings.pushToTalkKeys.empty()) if (!Globals::gSettings.pushToTalkKeys.empty())
{ {
Globals::gHotKeys->pressKeys(Globals::gSettings.pushToTalkKeys); Globals::gHotKeys.pressKeys(Globals::gSettings.pushToTalkKeys);
} }
} }
void Window::setIsOnFavorites(bool state) void Window::setIsOnFavorites(bool state)

View File

@ -77,7 +77,6 @@ namespace Soundux
virtual std::optional<Tab> setSortMode(const std::uint32_t &, Enums::SortMode); virtual std::optional<Tab> setSortMode(const std::uint32_t &, Enums::SortMode);
protected: protected:
virtual void onVolumeChanged();
virtual bool toggleSoundPlayback(); virtual bool toggleSoundPlayback();
virtual void stopSounds(bool = false); virtual void stopSounds(bool = false);
virtual bool stopSound(const std::uint32_t &); virtual bool stopSound(const std::uint32_t &);
@ -89,7 +88,7 @@ namespace Soundux
virtual std::optional<PlayingSound> repeatSound(const std::uint32_t &, bool); virtual std::optional<PlayingSound> repeatSound(const std::uint32_t &, bool);
virtual std::optional<PlayingSound> seekSound(const std::uint32_t &, std::uint64_t); virtual std::optional<PlayingSound> seekSound(const std::uint32_t &, std::uint64_t);
virtual std::optional<Sound> setHotkey(const std::uint32_t &, const std::vector<Key> &); virtual std::optional<Sound> setHotkey(const std::uint32_t &, const std::vector<int> &);
virtual std::optional<Sound> setCustomLocalVolume(const std::uint32_t &, const std::optional<int> &); virtual std::optional<Sound> setCustomLocalVolume(const std::uint32_t &, const std::optional<int> &);
virtual std::optional<Sound> setCustomRemoteVolume(const std::uint32_t &, const std::optional<int> &); virtual std::optional<Sound> setCustomRemoteVolume(const std::uint32_t &, const std::optional<int> &);
@ -101,13 +100,11 @@ namespace Soundux
virtual void onAdminRequired() = 0; virtual void onAdminRequired() = 0;
virtual void onSettingsChanged() = 0; virtual void onSettingsChanged() = 0;
virtual void onLocalVolumeChanged(int) = 0;
virtual void onRemoteVolumeChanged(int) = 0;
virtual void onSwitchOnConnectDetected(bool) = 0; virtual void onSwitchOnConnectDetected(bool) = 0;
virtual void onSoundPlayed(const PlayingSound &); virtual void onSoundPlayed(const PlayingSound &);
virtual void onError(const Enums::ErrorCode &) = 0; virtual void onError(const Enums::ErrorCode &) = 0;
virtual void onSoundFinished(const PlayingSound &); virtual void onSoundFinished(const PlayingSound &);
virtual void onHotKeyReceived(const std::vector<Key> &); virtual void onHotKeyReceived(const std::vector<int> &);
virtual void onSoundProgressed(const PlayingSound &) = 0; virtual void onSoundProgressed(const PlayingSound &) = 0;
virtual void onDownloadProgressed(float, const std::string &) = 0; virtual void onDownloadProgressed(float, const std::string &) = 0;
}; };