Revert "feat: hotkeys rework and MIDI support (#242)"
This reverts commit ad5fa403
This commit is contained in:
parent
e78f17fa6e
commit
085abaa50b
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -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
|
|
||||||
|
@ -39,7 +39,7 @@ if (WIN32)
|
|||||||
target_compile_options(soundux PRIVATE /W4)
|
target_compile_options(soundux PRIVATE /W4)
|
||||||
else()
|
else()
|
||||||
add_executable(soundux ${src})
|
add_executable(soundux ${src})
|
||||||
|
|
||||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
message(STATUS "Enabling warning and error flags for debug build")
|
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)
|
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/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
|
|
@ -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;
|
||||||
|
|
||||||
|
@ -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,117 +19,38 @@ 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);
|
||||||
{
|
pressedKeys.clear();
|
||||||
Globals::gGui->onHotKeyReceived(pressedKeys);
|
}
|
||||||
pressedKeys.clear();
|
else
|
||||||
}
|
{
|
||||||
else
|
pressedKeys.erase(std::remove_if(pressedKeys.begin(), pressedKeys.end(),
|
||||||
{
|
[key](const auto &item) { return key == item; }),
|
||||||
pressedKeys.erase(std::remove_if(pressedKeys.begin(), pressedKeys.end(),
|
pressedKeys.end());
|
||||||
[&](const auto &keyItem) { return key == keyItem; }),
|
|
||||||
pressedKeys.end());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool isCloseMatch(const std::vector<Key> &pressedKeys, const std::vector<Key> &keys)
|
bool isCloseMatch(const std::vector<int> &pressedKeys, const std::vector<int> &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,81 +97,78 @@ 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 ||
|
}
|
||||||
isCloseMatch(pressedKeys, Globals::gSettings.stopHotkey)))
|
|
||||||
{
|
|
||||||
Globals::gGui->stopSounds();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<Sound> 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<Sound> bestMatch;
|
||||||
|
|
||||||
|
if (Globals::gSettings.tabHotkeysOnly)
|
||||||
|
{
|
||||||
|
if (Globals::gData.isOnFavorites)
|
||||||
{
|
{
|
||||||
if (Globals::gData.isOnFavorites)
|
auto sounds = Globals::gData.getFavorites();
|
||||||
{
|
bestMatch = getBestMatch(sounds, pressedKeys);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto scopedSounds = Globals::gSounds.scoped();
|
auto tab = Globals::gData.getTab(Globals::gSettings.selectedTab);
|
||||||
bestMatch = getBestMatch(*scopedSounds, pressedKeys);
|
if (tab)
|
||||||
}
|
|
||||||
|
|
||||||
if (bestMatch)
|
|
||||||
{
|
|
||||||
auto pSound = Globals::gGui->playSound(bestMatch->id);
|
|
||||||
if (pSound)
|
|
||||||
{
|
{
|
||||||
Globals::gGui->onSoundPlayed(*pSound);
|
bestMatch = getBestMatch(tab->sounds, pressedKeys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
std::string Hotkeys::getKeyName(const Key &key)
|
|
||||||
{
|
|
||||||
if (key.type == Enums::KeyType::Midi)
|
|
||||||
{
|
{
|
||||||
return "MIDI_" + std::to_string(key.key);
|
auto scopedSounds = Globals::gSounds.scoped();
|
||||||
|
bestMatch = getBestMatch(*scopedSounds, pressedKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
if (bestMatch)
|
||||||
}
|
|
||||||
std::string Hotkeys::getKeySequence(const std::vector<Key> &keys)
|
|
||||||
{
|
|
||||||
std::string rtn;
|
|
||||||
|
|
||||||
for (auto it = keys.begin(); it != keys.end(); ++it)
|
|
||||||
{
|
{
|
||||||
rtn += getKeyName(*it);
|
auto pSound = Globals::gGui->playSound(bestMatch->id);
|
||||||
if (std::distance(it, keys.end()) > 1)
|
if (pSound)
|
||||||
{
|
{
|
||||||
rtn += " + ";
|
Globals::gGui->onSoundPlayed(*pSound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return rtn;
|
std::string Hotkeys::getKeySequence(const std::vector<int> &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 Objects
|
||||||
} // namespace Soundux
|
} // namespace Soundux
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -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 ||
|
||||||
|
cookie->evtype == XI_RawButtonPress || cookie->evtype == XI_RawButtonRelease))
|
||||||
{
|
{
|
||||||
if (cookie->evtype == XI_RawKeyPress || cookie->evtype == XI_RawKeyRelease)
|
auto *data = reinterpret_cast<XIRawEvent *>(cookie->data);
|
||||||
|
auto key = data->detail;
|
||||||
|
|
||||||
|
if (key == 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (cookie->evtype == XI_RawKeyPress || cookie->evtype == XI_RawButtonPress)
|
||||||
{
|
{
|
||||||
auto *data = reinterpret_cast<XIRawEvent *>(cookie->data);
|
onKeyDown(key);
|
||||||
auto key = data->detail;
|
|
||||||
|
|
||||||
Key pressedKey;
|
|
||||||
pressedKey.key = key;
|
|
||||||
pressedKey.type = Enums::KeyType::Keyboard;
|
|
||||||
|
|
||||||
if (cookie->evtype == XI_RawKeyPress)
|
|
||||||
{
|
|
||||||
onKeyDown(pressedKey);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
onKeyUp(pressedKey);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (cookie->evtype == XI_RawButtonPress || cookie->evtype == XI_RawButtonRelease)
|
else if (cookie->evtype == XI_RawKeyRelease || cookie->evtype == XI_RawButtonRelease)
|
||||||
{
|
{
|
||||||
auto *data = reinterpret_cast<XIRawEvent *>(cookie->data);
|
onKeyUp(key);
|
||||||
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)
|
|
||||||
|
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);
|
return "KEY_" + std::to_string(key);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key.type == Enums::KeyType::Mouse)
|
return str;
|
||||||
{
|
|
||||||
return "MOUSE_" + std::to_string(key.key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void X11::pressKeys(const std::vector<Key> &keys)
|
void Hotkeys::stop()
|
||||||
{
|
|
||||||
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
|
@ -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
|
|
@ -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);
|
|
||||||
|
|
||||||
Globals::gHotKeys->onKeyUp(key);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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)
|
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;
|
break;
|
||||||
key.type = Enums::KeyType::Mouse;
|
|
||||||
Soundux::Globals::gHotKeys->onKeyUp(key);
|
case WM_RBUTTONDOWN:
|
||||||
}
|
Globals::gHotKeys.onKeyDown(VK_RBUTTON);
|
||||||
break;
|
break;
|
||||||
case WM_RBUTTONDOWN: {
|
|
||||||
Key key;
|
case WM_MBUTTONDOWN:
|
||||||
key.key = VK_RBUTTON;
|
Globals::gHotKeys.onKeyDown(VK_MBUTTON);
|
||||||
key.type = Enums::KeyType::Mouse;
|
break;
|
||||||
Soundux::Globals::gHotKeys->onKeyDown(key);
|
|
||||||
}
|
case WM_MBUTTONUP:
|
||||||
break;
|
Globals::gHotKeys.onKeyUp(VK_MBUTTON);
|
||||||
case WM_MBUTTONUP: {
|
break;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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()
|
|
||||||
{
|
|
||||||
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)
|
void Hotkeys::stop()
|
||||||
{
|
|
||||||
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<Key> &keys)
|
|
||||||
{
|
|
||||||
std::unique_lock lock(keysToPressMutex);
|
|
||||||
keysToPress = keys;
|
|
||||||
}
|
|
||||||
void WindowsHotkeys::releaseKeys(const std::vector<Key> &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()
|
|
||||||
{
|
{
|
||||||
kill = true;
|
kill = true;
|
||||||
PostThreadMessage(GetThreadId(listener.native_handle()), WM_QUIT, 0, 0);
|
|
||||||
|
|
||||||
listener.join();
|
|
||||||
cv.notify_all();
|
|
||||||
keyPresser.join();
|
|
||||||
|
|
||||||
UnhookWindowsHookEx(oMouseProc);
|
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<int> &keys)
|
||||||
|
{
|
||||||
|
keysToPress = keys;
|
||||||
|
shouldPressKeys = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotkeys::releaseKeys([[maybe_unused]] const std::vector<int> &keys)
|
||||||
|
{
|
||||||
|
shouldPressKeys = false;
|
||||||
|
keysToPress.clear();
|
||||||
|
for (const auto &key : keys)
|
||||||
|
{
|
||||||
|
keybd_event(key, 0, 2, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // namespace Soundux::Objects
|
} // namespace Soundux::Objects
|
||||||
#endif
|
#endif
|
@ -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
|
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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},
|
||||||
@ -176,22 +131,9 @@ namespace nlohmann
|
|||||||
{
|
{
|
||||||
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(T{}).type_name())
|
||||||
{
|
{
|
||||||
if (j.at(key).type_name() == nlohmann::basic_json(typename T::value_type{}).type_name())
|
j.at(key).get_to(member);
|
||||||
{
|
|
||||||
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())
|
|
||||||
{
|
|
||||||
j.at(key).get_to(member);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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
|
@ -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>
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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
|
@ -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;
|
||||||
|
@ -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,33 +579,30 @@ namespace Soundux::Objects
|
|||||||
onError(Enums::ErrorCode::FailedToSetCustomVolume);
|
onError(Enums::ErrorCode::FailedToSetCustomVolume);
|
||||||
return std::nullopt;
|
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<float>(newVolume) / 100.f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Settings Window::changeSettings(Settings settings)
|
Settings Window::changeSettings(Settings settings)
|
||||||
{
|
{
|
||||||
auto oldSettings = Globals::gSettings;
|
auto oldSettings = Globals::gSettings;
|
||||||
Globals::gSettings = settings;
|
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<float>(newVolume) / 100.f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
@ -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)
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user