mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-03-27 12:25:23 -05:00
Add macro action "hotkey" (#226)
This commit is contained in:
parent
d692444687
commit
ae4e861f7f
1
.github/workflows/build.yml
vendored
1
.github/workflows/build.yml
vendored
|
|
@ -160,6 +160,7 @@ jobs:
|
|||
libxcb-xinerama0-dev \
|
||||
libxcomposite-dev \
|
||||
libxinerama-dev \
|
||||
libxtst-dev \
|
||||
libmbedtls-dev \
|
||||
pkg-config \
|
||||
python3-dev \
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ set(advanced-scene-switcher_HEADERS
|
|||
src/headers/macro-action-edit.hpp
|
||||
src/headers/macro-action-audio.hpp
|
||||
src/headers/macro-action-filter.hpp
|
||||
src/headers/macro-action-hotkey.hpp
|
||||
src/headers/macro-action-macro.hpp
|
||||
src/headers/macro-action-media.hpp
|
||||
src/headers/macro-action-plugin-state.hpp
|
||||
|
|
@ -115,6 +116,7 @@ set(advanced-scene-switcher_HEADERS
|
|||
src/headers/macro.hpp
|
||||
src/headers/macro-selection.hpp
|
||||
src/headers/curl-helper.hpp
|
||||
src/headers/hotkey.hpp
|
||||
src/headers/screenshot-helper.hpp
|
||||
src/headers/name-dialog.hpp
|
||||
src/headers/duration-control.hpp
|
||||
|
|
@ -153,6 +155,7 @@ set(advanced-scene-switcher_SOURCES
|
|||
src/macro-action-edit.cpp
|
||||
src/macro-action-audio.cpp
|
||||
src/macro-action-filter.cpp
|
||||
src/macro-action-hotkey.cpp
|
||||
src/macro-action-macro.cpp
|
||||
src/macro-action-media.cpp
|
||||
src/macro-action-plugin-state.cpp
|
||||
|
|
|
|||
|
|
@ -229,6 +229,17 @@ AdvSceneSwitcher.action.virtualCamera="Virtual camera"
|
|||
AdvSceneSwitcher.action.virtualCamera.type.stop="Stop virtual camera"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.start="Start virtual camera"
|
||||
AdvSceneSwitcher.action.virtualCamera.entry="{{actions}}"
|
||||
AdvSceneSwitcher.action.hotkey="Hotkey"
|
||||
AdvSceneSwitcher.action.hotkey.leftShift="Left Shift"
|
||||
AdvSceneSwitcher.action.hotkey.rightShift="Right Shift"
|
||||
AdvSceneSwitcher.action.hotkey.leftCtrl="Left Ctrl"
|
||||
AdvSceneSwitcher.action.hotkey.rightCtrl="Right Ctrl"
|
||||
AdvSceneSwitcher.action.hotkey.leftAlt="Left Alt"
|
||||
AdvSceneSwitcher.action.hotkey.rightAlt="Right Alt"
|
||||
AdvSceneSwitcher.action.hotkey.leftMeta="Left Meta"
|
||||
AdvSceneSwitcher.action.hotkey.rightMeta="Right Meta"
|
||||
AdvSceneSwitcher.action.hotkey.disabled="Cannot simulate key presses - functionality disabled!"
|
||||
AdvSceneSwitcher.action.hotkey.entry="Press {{keys}}"
|
||||
|
||||
; Transition Tab
|
||||
AdvSceneSwitcher.transitionTab.title="Transition"
|
||||
|
|
|
|||
|
|
@ -433,6 +433,8 @@ extern "C" void FreeSceneSwitcher()
|
|||
loaded_curl_lib = nullptr;
|
||||
}
|
||||
|
||||
PlatformCleanup();
|
||||
|
||||
delete switcher;
|
||||
switcher = nullptr;
|
||||
}
|
||||
|
|
@ -546,6 +548,8 @@ extern "C" void InitSceneSwitcher()
|
|||
switcher->curl = f_curl_init();
|
||||
}
|
||||
|
||||
PlatformInit();
|
||||
|
||||
auto cb = []() {
|
||||
QMainWindow *window =
|
||||
(QMainWindow *)obs_frontend_get_main_window();
|
||||
|
|
|
|||
125
src/headers/hotkey.hpp
Normal file
125
src/headers/hotkey.hpp
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
#pragma once
|
||||
|
||||
extern bool canSimulateKeyPresses;
|
||||
|
||||
enum class HotkeyType {
|
||||
Key_NoKey = 0,
|
||||
|
||||
Key_A,
|
||||
Key_B,
|
||||
Key_C,
|
||||
Key_D,
|
||||
Key_E,
|
||||
Key_F,
|
||||
Key_G,
|
||||
Key_H,
|
||||
Key_I,
|
||||
Key_J,
|
||||
Key_K,
|
||||
Key_L,
|
||||
Key_M,
|
||||
Key_N,
|
||||
Key_O,
|
||||
Key_P,
|
||||
Key_Q,
|
||||
Key_R,
|
||||
Key_S,
|
||||
Key_T,
|
||||
Key_U,
|
||||
Key_V,
|
||||
Key_W,
|
||||
Key_X,
|
||||
Key_Y,
|
||||
Key_Z,
|
||||
|
||||
Key_0,
|
||||
Key_1,
|
||||
Key_2,
|
||||
Key_3,
|
||||
Key_4,
|
||||
Key_5,
|
||||
Key_6,
|
||||
Key_7,
|
||||
Key_8,
|
||||
Key_9,
|
||||
|
||||
Key_F1,
|
||||
Key_F2,
|
||||
Key_F3,
|
||||
Key_F4,
|
||||
Key_F5,
|
||||
Key_F6,
|
||||
Key_F7,
|
||||
Key_F8,
|
||||
Key_F9,
|
||||
Key_F10,
|
||||
Key_F11,
|
||||
Key_F12,
|
||||
Key_F13,
|
||||
Key_F14,
|
||||
Key_F15,
|
||||
Key_F16,
|
||||
Key_F17,
|
||||
Key_F18,
|
||||
Key_F19,
|
||||
Key_F20,
|
||||
Key_F21,
|
||||
Key_F22,
|
||||
Key_F23,
|
||||
Key_F24,
|
||||
|
||||
Key_Escape,
|
||||
Key_Space,
|
||||
Key_Return,
|
||||
Key_Backspace,
|
||||
Key_Tab,
|
||||
|
||||
Key_Shift_L,
|
||||
Key_Shift_R,
|
||||
Key_Control_L,
|
||||
Key_Control_R,
|
||||
Key_Alt_L,
|
||||
Key_Alt_R,
|
||||
Key_Win_L,
|
||||
Key_Win_R,
|
||||
Key_Apps,
|
||||
|
||||
Key_CapsLock,
|
||||
Key_NumLock,
|
||||
Key_ScrollLock,
|
||||
|
||||
Key_PrintScreen,
|
||||
Key_Pause,
|
||||
|
||||
Key_Insert,
|
||||
Key_Delete,
|
||||
Key_PageUP,
|
||||
Key_PageDown,
|
||||
Key_Home,
|
||||
Key_End,
|
||||
|
||||
Key_Left,
|
||||
Key_Right,
|
||||
Key_Up,
|
||||
Key_Down,
|
||||
|
||||
Key_Numpad0,
|
||||
Key_Numpad1,
|
||||
Key_Numpad2,
|
||||
Key_Numpad3,
|
||||
Key_Numpad4,
|
||||
Key_Numpad5,
|
||||
Key_Numpad6,
|
||||
Key_Numpad7,
|
||||
Key_Numpad8,
|
||||
Key_Numpad9,
|
||||
|
||||
Key_NumpadAdd,
|
||||
Key_NumpadSubtract,
|
||||
Key_NumpadMultiply,
|
||||
Key_NumpadDivide,
|
||||
Key_NumpadDecimal,
|
||||
Key_NumpadEnter
|
||||
};
|
||||
|
||||
void registerHotkeys();
|
||||
78
src/headers/macro-action-hotkey.hpp
Normal file
78
src/headers/macro-action-hotkey.hpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
#pragma once
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "hotkey.hpp"
|
||||
|
||||
#include <QCheckBox>
|
||||
|
||||
class MacroActionHotkey : public MacroAction {
|
||||
public:
|
||||
bool PerformAction();
|
||||
void LogAction();
|
||||
bool Save(obs_data_t *obj);
|
||||
bool Load(obs_data_t *obj);
|
||||
std::string GetId() { return id; };
|
||||
static std::shared_ptr<MacroAction> Create()
|
||||
{
|
||||
return std::make_shared<MacroActionHotkey>();
|
||||
}
|
||||
|
||||
OBSWeakSource _HotkeySource;
|
||||
HotkeyType _key = HotkeyType::Key_NoKey;
|
||||
bool _leftShift = false;
|
||||
bool _rightShift = false;
|
||||
bool _leftCtrl = false;
|
||||
bool _rightCtrl = false;
|
||||
bool _leftAlt = false;
|
||||
bool _rightAlt = false;
|
||||
bool _leftMeta = false;
|
||||
bool _rightMeta = false;
|
||||
|
||||
private:
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroActionHotkeyEdit : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MacroActionHotkeyEdit(
|
||||
QWidget *parent,
|
||||
std::shared_ptr<MacroActionHotkey> entryData = nullptr);
|
||||
void UpdateEntryData();
|
||||
static QWidget *Create(QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action)
|
||||
{
|
||||
return new MacroActionHotkeyEdit(
|
||||
parent,
|
||||
std::dynamic_pointer_cast<MacroActionHotkey>(action));
|
||||
}
|
||||
|
||||
private slots:
|
||||
void KeyChanged(int key);
|
||||
void LShiftChanged(int state);
|
||||
void RShiftChanged(int state);
|
||||
void LCtrlChanged(int state);
|
||||
void RCtrlChanged(int state);
|
||||
void LAltChanged(int state);
|
||||
void RAltChanged(int state);
|
||||
void LMetaChanged(int state);
|
||||
void RMetaChanged(int state);
|
||||
|
||||
protected:
|
||||
QComboBox *_keys;
|
||||
QCheckBox *_leftShift;
|
||||
QCheckBox *_rightShift;
|
||||
QCheckBox *_leftCtrl;
|
||||
QCheckBox *_rightCtrl;
|
||||
QCheckBox *_leftAlt;
|
||||
QCheckBox *_rightAlt;
|
||||
QCheckBox *_leftMeta;
|
||||
QCheckBox *_rightMeta;
|
||||
|
||||
std::shared_ptr<MacroActionHotkey> _entryData;
|
||||
|
||||
private:
|
||||
QHBoxLayout *_mainLayout;
|
||||
bool _loading = true;
|
||||
};
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
#include "hotkey.hpp"
|
||||
|
||||
void GetWindowList(std::vector<std::string> &windows);
|
||||
void GetWindowList(QStringList &windows);
|
||||
|
|
@ -9,3 +10,6 @@ std::pair<int, int> getCursorPos();
|
|||
int secondsSinceLastInput();
|
||||
void GetProcessList(QStringList &processes);
|
||||
bool isInFocus(const QString &executable);
|
||||
void PressKeys(const std::vector<HotkeyType> keys);
|
||||
void PlatformInit();
|
||||
void PlatformCleanup();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
#include "headers/hotkey.hpp"
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include <obs-module.h>
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
void startHotkeyFunc(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
|
||||
bool pressed)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
#include "../headers/hotkey.hpp"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/extensions/scrnsaver.h>
|
||||
#include <X11/extensions/XTest.h>
|
||||
#undef Bool
|
||||
#undef CursorShape
|
||||
#undef Expose
|
||||
|
|
@ -15,11 +19,18 @@
|
|||
#undef Unsorted
|
||||
#include <util/platform.h>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <QStringList>
|
||||
#include <QRegularExpression>
|
||||
#include <QLibrary>
|
||||
|
||||
static Display *xdisplay = 0;
|
||||
|
||||
static QLibrary *libXtstHandle = nullptr;
|
||||
typedef int (*keyPressFunc)(Display *, unsigned int, bool, unsigned long);
|
||||
static keyPressFunc pressFunc = nullptr;
|
||||
bool canSimulateKeyPresses = false;
|
||||
|
||||
Display *disp()
|
||||
{
|
||||
if (!xdisplay)
|
||||
|
|
@ -242,14 +253,13 @@ std::pair<int, int> getCursorPos()
|
|||
int win_y;
|
||||
unsigned int mask;
|
||||
|
||||
dpy = XOpenDisplay(NULL);
|
||||
dpy = disp();
|
||||
root = XDefaultRootWindow(dpy);
|
||||
|
||||
if (XQueryPointer(dpy, root, &ret_root, &ret_child, &root_x, &root_y,
|
||||
&win_x, &win_y, &mask)) {
|
||||
pos = std::pair<int, int>(root_x, root_y);
|
||||
}
|
||||
XCloseDisplay(dpy);
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
|
@ -382,14 +392,186 @@ int secondsSinceLastInput()
|
|||
|
||||
mit_info = XScreenSaverAllocInfo();
|
||||
|
||||
if ((display = XOpenDisplay(NULL)) == NULL) {
|
||||
return (-1);
|
||||
if ((display = disp()) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
screen = DefaultScreen(display);
|
||||
XScreenSaverQueryInfo(display, RootWindow(display, screen), mit_info);
|
||||
idle_time = (mit_info->idle) / 1000;
|
||||
XFree(mit_info);
|
||||
XCloseDisplay(display);
|
||||
|
||||
return idle_time;
|
||||
}
|
||||
|
||||
static std::unordered_map<HotkeyType, long> keyTable = {
|
||||
// Chars
|
||||
{HotkeyType::Key_A, XK_A},
|
||||
{HotkeyType::Key_B, XK_B},
|
||||
{HotkeyType::Key_C, XK_C},
|
||||
{HotkeyType::Key_D, XK_D},
|
||||
{HotkeyType::Key_E, XK_E},
|
||||
{HotkeyType::Key_F, XK_F},
|
||||
{HotkeyType::Key_G, XK_G},
|
||||
{HotkeyType::Key_H, XK_H},
|
||||
{HotkeyType::Key_I, XK_I},
|
||||
{HotkeyType::Key_J, XK_J},
|
||||
{HotkeyType::Key_K, XK_K},
|
||||
{HotkeyType::Key_L, XK_L},
|
||||
{HotkeyType::Key_M, XK_M},
|
||||
{HotkeyType::Key_N, XK_N},
|
||||
{HotkeyType::Key_O, XK_O},
|
||||
{HotkeyType::Key_P, XK_P},
|
||||
{HotkeyType::Key_Q, XK_Q},
|
||||
{HotkeyType::Key_R, XK_R},
|
||||
{HotkeyType::Key_S, XK_S},
|
||||
{HotkeyType::Key_T, XK_T},
|
||||
{HotkeyType::Key_U, XK_U},
|
||||
{HotkeyType::Key_V, XK_V},
|
||||
{HotkeyType::Key_W, XK_W},
|
||||
{HotkeyType::Key_X, XK_X},
|
||||
{HotkeyType::Key_Y, XK_Y},
|
||||
{HotkeyType::Key_Z, XK_Z},
|
||||
|
||||
// Numbers
|
||||
{HotkeyType::Key_0, XK_0},
|
||||
{HotkeyType::Key_1, XK_1},
|
||||
{HotkeyType::Key_2, XK_2},
|
||||
{HotkeyType::Key_3, XK_3},
|
||||
{HotkeyType::Key_4, XK_4},
|
||||
{HotkeyType::Key_5, XK_5},
|
||||
{HotkeyType::Key_6, XK_6},
|
||||
{HotkeyType::Key_7, XK_7},
|
||||
{HotkeyType::Key_8, XK_8},
|
||||
{HotkeyType::Key_9, XK_9},
|
||||
|
||||
{HotkeyType::Key_F1, XK_F1},
|
||||
{HotkeyType::Key_F2, XK_F2},
|
||||
{HotkeyType::Key_F3, XK_F3},
|
||||
{HotkeyType::Key_F4, XK_F4},
|
||||
{HotkeyType::Key_F5, XK_F5},
|
||||
{HotkeyType::Key_F6, XK_F6},
|
||||
{HotkeyType::Key_F7, XK_F7},
|
||||
{HotkeyType::Key_F8, XK_F8},
|
||||
{HotkeyType::Key_F9, XK_F9},
|
||||
{HotkeyType::Key_F10, XK_F10},
|
||||
{HotkeyType::Key_F11, XK_F11},
|
||||
{HotkeyType::Key_F12, XK_F12},
|
||||
{HotkeyType::Key_F13, XK_F13},
|
||||
{HotkeyType::Key_F14, XK_F14},
|
||||
{HotkeyType::Key_F15, XK_F15},
|
||||
{HotkeyType::Key_F16, XK_F16},
|
||||
{HotkeyType::Key_F17, XK_F17},
|
||||
{HotkeyType::Key_F18, XK_F18},
|
||||
{HotkeyType::Key_F19, XK_F19},
|
||||
{HotkeyType::Key_F20, XK_F20},
|
||||
{HotkeyType::Key_F21, XK_F21},
|
||||
{HotkeyType::Key_F22, XK_F22},
|
||||
{HotkeyType::Key_F23, XK_F23},
|
||||
{HotkeyType::Key_F24, XK_F24},
|
||||
|
||||
{HotkeyType::Key_Escape, XK_Escape},
|
||||
{HotkeyType::Key_Space, XK_space},
|
||||
{HotkeyType::Key_Return, XK_Return},
|
||||
{HotkeyType::Key_Backspace, XK_BackSpace},
|
||||
{HotkeyType::Key_Tab, XK_Tab},
|
||||
|
||||
{HotkeyType::Key_Shift_L, XK_Shift_L},
|
||||
{HotkeyType::Key_Shift_R, XK_Shift_R},
|
||||
{HotkeyType::Key_Control_L, XK_Control_L},
|
||||
{HotkeyType::Key_Control_R, XK_Control_R},
|
||||
{HotkeyType::Key_Alt_L, XK_Alt_L},
|
||||
{HotkeyType::Key_Alt_R, XK_Alt_R},
|
||||
{HotkeyType::Key_Win_L, XK_Super_L},
|
||||
{HotkeyType::Key_Win_R, XK_Super_R},
|
||||
{HotkeyType::Key_Apps, XK_Hyper_L},
|
||||
|
||||
{HotkeyType::Key_CapsLock, XK_Caps_Lock},
|
||||
{HotkeyType::Key_NumLock, XK_Num_Lock},
|
||||
{HotkeyType::Key_ScrollLock, XK_Scroll_Lock},
|
||||
|
||||
{HotkeyType::Key_PrintScreen, XK_Print},
|
||||
{HotkeyType::Key_Pause, XK_Pause},
|
||||
|
||||
{HotkeyType::Key_Insert, XK_Insert},
|
||||
{HotkeyType::Key_Delete, XK_Delete},
|
||||
{HotkeyType::Key_PageUP, XK_Page_Up},
|
||||
{HotkeyType::Key_PageDown, XK_Page_Down},
|
||||
{HotkeyType::Key_Home, XK_Home},
|
||||
{HotkeyType::Key_End, XK_End},
|
||||
|
||||
{HotkeyType::Key_Left, XK_Left},
|
||||
{HotkeyType::Key_Up, XK_Up},
|
||||
{HotkeyType::Key_Right, XK_Right},
|
||||
{HotkeyType::Key_Down, XK_Down},
|
||||
|
||||
{HotkeyType::Key_Numpad0, XK_KP_0},
|
||||
{HotkeyType::Key_Numpad1, XK_KP_1},
|
||||
{HotkeyType::Key_Numpad2, XK_KP_2},
|
||||
{HotkeyType::Key_Numpad3, XK_KP_3},
|
||||
{HotkeyType::Key_Numpad4, XK_KP_4},
|
||||
{HotkeyType::Key_Numpad5, XK_KP_5},
|
||||
{HotkeyType::Key_Numpad6, XK_KP_6},
|
||||
{HotkeyType::Key_Numpad7, XK_KP_7},
|
||||
{HotkeyType::Key_Numpad8, XK_KP_8},
|
||||
{HotkeyType::Key_Numpad9, XK_KP_9},
|
||||
|
||||
{HotkeyType::Key_NumpadAdd, XK_KP_Add},
|
||||
{HotkeyType::Key_NumpadSubtract, XK_KP_Subtract},
|
||||
{HotkeyType::Key_NumpadMultiply, XK_KP_Multiply},
|
||||
{HotkeyType::Key_NumpadDivide, XK_KP_Divide},
|
||||
{HotkeyType::Key_NumpadDecimal, XK_KP_Decimal},
|
||||
{HotkeyType::Key_NumpadEnter, XK_KP_Enter},
|
||||
};
|
||||
|
||||
void PressKeys(const std::vector<HotkeyType> keys)
|
||||
{
|
||||
if (!canSimulateKeyPresses) {
|
||||
return;
|
||||
}
|
||||
|
||||
Display *display = disp();
|
||||
if (display == NULL)
|
||||
return;
|
||||
|
||||
// Press keys
|
||||
for (auto &key : keys) {
|
||||
auto it = keyTable.find(key);
|
||||
if (it == keyTable.end()) {
|
||||
continue;
|
||||
}
|
||||
pressFunc(display, XKeysymToKeycode(display, it->second), true,
|
||||
CurrentTime);
|
||||
}
|
||||
XFlush(display);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(300));
|
||||
|
||||
// Release keys
|
||||
for (auto &key : keys) {
|
||||
auto it = keyTable.find(key);
|
||||
if (it == keyTable.end()) {
|
||||
continue;
|
||||
}
|
||||
pressFunc(display, XKeysymToKeycode(display, it->second), false,
|
||||
CurrentTime);
|
||||
}
|
||||
|
||||
XFlush(display);
|
||||
}
|
||||
|
||||
void PlatformInit()
|
||||
{
|
||||
libXtstHandle = new QLibrary("libXtst.so", nullptr);
|
||||
pressFunc = (keyPressFunc)libXtstHandle->resolve("XTestFakeKeyEvent");
|
||||
int _;
|
||||
canSimulateKeyPresses = pressFunc &&
|
||||
!XQueryExtension(disp(), "XTEST", &_, &_, &_);
|
||||
}
|
||||
|
||||
void PlatformCleanup()
|
||||
{
|
||||
delete libXtstHandle;
|
||||
libXtstHandle = nullptr;
|
||||
|
||||
cleanupDisplay();
|
||||
}
|
||||
|
|
|
|||
377
src/macro-action-hotkey.cpp
Normal file
377
src/macro-action-hotkey.cpp
Normal file
|
|
@ -0,0 +1,377 @@
|
|||
#include "headers/macro-action-hotkey.hpp"
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
|
||||
const std::string MacroActionHotkey::id = "hotkey";
|
||||
|
||||
// TODO:
|
||||
// I can't seem to get this to work so drop support for this functionality
|
||||
// on MacOS
|
||||
#if !__APPLE__
|
||||
bool MacroActionHotkey::_registered = MacroActionFactory::Register(
|
||||
MacroActionHotkey::id,
|
||||
{MacroActionHotkey::Create, MacroActionHotkeyEdit::Create,
|
||||
"AdvSceneSwitcher.action.hotkey"});
|
||||
#endif
|
||||
|
||||
bool MacroActionHotkey::PerformAction()
|
||||
{
|
||||
std::vector<HotkeyType> keys;
|
||||
if (_leftShift) {
|
||||
keys.push_back(HotkeyType::Key_Shift_L);
|
||||
}
|
||||
if (_rightShift) {
|
||||
keys.push_back(HotkeyType::Key_Shift_R);
|
||||
}
|
||||
if (_leftCtrl) {
|
||||
keys.push_back(HotkeyType::Key_Control_L);
|
||||
}
|
||||
if (_rightCtrl) {
|
||||
keys.push_back(HotkeyType::Key_Control_R);
|
||||
}
|
||||
if (_leftAlt) {
|
||||
keys.push_back(HotkeyType::Key_Alt_L);
|
||||
}
|
||||
if (_rightAlt) {
|
||||
keys.push_back(HotkeyType::Key_Alt_R);
|
||||
}
|
||||
if (_key != HotkeyType::Key_NoKey) {
|
||||
keys.push_back(_key);
|
||||
}
|
||||
|
||||
if (!keys.empty()) {
|
||||
std::thread t([keys]() { PressKeys(keys); });
|
||||
t.detach();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacroActionHotkey::LogAction()
|
||||
{
|
||||
vblog(LOG_INFO, "sent hotkey");
|
||||
}
|
||||
|
||||
bool MacroActionHotkey::Save(obs_data_t *obj)
|
||||
{
|
||||
MacroAction::Save(obj);
|
||||
obs_data_set_int(obj, "key", static_cast<int>(_key));
|
||||
obs_data_set_bool(obj, "left_shift", _leftShift);
|
||||
obs_data_set_bool(obj, "right_shift", _rightShift);
|
||||
obs_data_set_bool(obj, "left_ctrl", _leftCtrl);
|
||||
obs_data_set_bool(obj, "right_ctrl", _rightCtrl);
|
||||
obs_data_set_bool(obj, "left_alt", _leftAlt);
|
||||
obs_data_set_bool(obj, "right_alt", _rightAlt);
|
||||
obs_data_set_bool(obj, "left_meta", _leftMeta);
|
||||
obs_data_set_bool(obj, "right_meta", _rightMeta);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroActionHotkey::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroAction::Load(obj);
|
||||
_key = static_cast<HotkeyType>(obs_data_get_int(obj, "key"));
|
||||
_leftShift = obs_data_get_bool(obj, "left_shift");
|
||||
_rightShift = obs_data_get_bool(obj, "right_shift");
|
||||
_leftCtrl = obs_data_get_bool(obj, "left_ctrl");
|
||||
_rightCtrl = obs_data_get_bool(obj, "right_ctrl");
|
||||
_leftAlt = obs_data_get_bool(obj, "left_alt");
|
||||
_rightAlt = obs_data_get_bool(obj, "right_alt");
|
||||
_leftMeta = obs_data_get_bool(obj, "left_meta");
|
||||
_rightMeta = obs_data_get_bool(obj, "right_meta");
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void populateKeySelection(QComboBox *list)
|
||||
{
|
||||
list->addItem("No key");
|
||||
list->addItem("A");
|
||||
list->addItem("B");
|
||||
list->addItem("C");
|
||||
list->addItem("D");
|
||||
list->addItem("E");
|
||||
list->addItem("F");
|
||||
list->addItem("G");
|
||||
list->addItem("H");
|
||||
list->addItem("I");
|
||||
list->addItem("J");
|
||||
list->addItem("K");
|
||||
list->addItem("L");
|
||||
list->addItem("M");
|
||||
list->addItem("N");
|
||||
list->addItem("O");
|
||||
list->addItem("P");
|
||||
list->addItem("Q");
|
||||
list->addItem("R");
|
||||
list->addItem("S");
|
||||
list->addItem("T");
|
||||
list->addItem("U");
|
||||
list->addItem("V");
|
||||
list->addItem("W");
|
||||
list->addItem("X");
|
||||
list->addItem("Y");
|
||||
list->addItem("Z");
|
||||
list->addItem("0");
|
||||
list->addItem("1");
|
||||
list->addItem("2");
|
||||
list->addItem("3");
|
||||
list->addItem("4");
|
||||
list->addItem("5");
|
||||
list->addItem("6");
|
||||
list->addItem("7");
|
||||
list->addItem("8");
|
||||
list->addItem("9");
|
||||
list->addItem("F1");
|
||||
list->addItem("F2");
|
||||
list->addItem("F3");
|
||||
list->addItem("F4");
|
||||
list->addItem("F5");
|
||||
list->addItem("F6");
|
||||
list->addItem("F7");
|
||||
list->addItem("F8");
|
||||
list->addItem("F9");
|
||||
list->addItem("F10");
|
||||
list->addItem("F11");
|
||||
list->addItem("F12");
|
||||
list->addItem("F13");
|
||||
list->addItem("F14");
|
||||
list->addItem("F15");
|
||||
list->addItem("F16");
|
||||
list->addItem("F17");
|
||||
list->addItem("F18");
|
||||
list->addItem("F19");
|
||||
list->addItem("F20");
|
||||
list->addItem("F21");
|
||||
list->addItem("F22");
|
||||
list->addItem("F23");
|
||||
list->addItem("F24");
|
||||
list->addItem("Escape");
|
||||
list->addItem("Space");
|
||||
list->addItem("Return");
|
||||
list->addItem("Backspace");
|
||||
list->addItem("Tab");
|
||||
list->addItem("Shift_L");
|
||||
list->addItem("Shift_R");
|
||||
list->addItem("Control_L");
|
||||
list->addItem("Control_R");
|
||||
list->addItem("Alt_L");
|
||||
list->addItem("Alt_R");
|
||||
list->addItem("Win_L");
|
||||
list->addItem("Win_R");
|
||||
list->addItem("Apps");
|
||||
list->addItem("CapsLock");
|
||||
list->addItem("NumLock");
|
||||
list->addItem("ScrollLock");
|
||||
list->addItem("PrintScreen");
|
||||
list->addItem("Pause");
|
||||
list->addItem("Insert");
|
||||
list->addItem("Delete");
|
||||
list->addItem("PageUP");
|
||||
list->addItem("PageDown");
|
||||
list->addItem("Home");
|
||||
list->addItem("End");
|
||||
list->addItem("Left");
|
||||
list->addItem("Right");
|
||||
list->addItem("Up");
|
||||
list->addItem("Down");
|
||||
list->addItem("Numpad0");
|
||||
list->addItem("Numpad1");
|
||||
list->addItem("Numpad2");
|
||||
list->addItem("Numpad3");
|
||||
list->addItem("Numpad4");
|
||||
list->addItem("Numpad5");
|
||||
list->addItem("Numpad6");
|
||||
list->addItem("Numpad7");
|
||||
list->addItem("Numpad8");
|
||||
list->addItem("Numpad9");
|
||||
list->addItem("NumpadAdd");
|
||||
list->addItem("NumpadSubtract");
|
||||
list->addItem("NumpadMultiply");
|
||||
list->addItem("NumpadDivide");
|
||||
list->addItem("NumpadDecimal");
|
||||
list->addItem("NumpadEnter");
|
||||
}
|
||||
|
||||
MacroActionHotkeyEdit::MacroActionHotkeyEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionHotkey> entryData)
|
||||
: QWidget(parent)
|
||||
{
|
||||
_keys = new QComboBox();
|
||||
_leftShift = new QCheckBox(
|
||||
obs_module_text("AdvSceneSwitcher.action.hotkey.leftShift"));
|
||||
_rightShift = new QCheckBox(
|
||||
obs_module_text("AdvSceneSwitcher.action.hotkey.rightShift"));
|
||||
_leftCtrl = new QCheckBox(
|
||||
obs_module_text("AdvSceneSwitcher.action.hotkey.leftCtrl"));
|
||||
_rightCtrl = new QCheckBox(
|
||||
obs_module_text("AdvSceneSwitcher.action.hotkey.rightCtrl"));
|
||||
_leftAlt = new QCheckBox(
|
||||
obs_module_text("AdvSceneSwitcher.action.hotkey.leftAlt"));
|
||||
_rightAlt = new QCheckBox(
|
||||
obs_module_text("AdvSceneSwitcher.action.hotkey.rightAlt"));
|
||||
_leftMeta = new QCheckBox(
|
||||
obs_module_text("AdvSceneSwitcher.action.hotkey.leftMeta"));
|
||||
_rightMeta = new QCheckBox(
|
||||
obs_module_text("AdvSceneSwitcher.action.hotkey.rightMeta"));
|
||||
|
||||
populateKeySelection(_keys);
|
||||
|
||||
QWidget::connect(_keys, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(KeyChanged(int)));
|
||||
QWidget::connect(_leftShift, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(LShiftChanged(int)));
|
||||
QWidget::connect(_rightShift, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(RShiftChanged(int)));
|
||||
QWidget::connect(_leftCtrl, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(LCtrlChanged(int)));
|
||||
QWidget::connect(_rightCtrl, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(RCtrlChanged(int)));
|
||||
QWidget::connect(_leftAlt, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(LAltChanged(int)));
|
||||
QWidget::connect(_rightAlt, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(RAltChanged(int)));
|
||||
QWidget::connect(_leftMeta, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(LMetaChanged(int)));
|
||||
QWidget::connect(_rightMeta, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(RMetaChanged(int)));
|
||||
|
||||
QHBoxLayout *line1Layout = new QHBoxLayout;
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{keys}}", _keys},
|
||||
};
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.action.hotkey.entry"),
|
||||
line1Layout, widgetPlaceholders);
|
||||
|
||||
QHBoxLayout *line2Layout = new QHBoxLayout;
|
||||
line2Layout->addWidget(_leftShift);
|
||||
line2Layout->addWidget(_rightShift);
|
||||
line2Layout->addWidget(_leftCtrl);
|
||||
line2Layout->addWidget(_rightCtrl);
|
||||
line2Layout->addWidget(_leftAlt);
|
||||
line2Layout->addWidget(_rightAlt);
|
||||
line2Layout->addWidget(_leftMeta);
|
||||
line2Layout->addWidget(_rightMeta);
|
||||
line2Layout->addStretch();
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(line1Layout);
|
||||
mainLayout->addLayout(line2Layout);
|
||||
|
||||
if (!canSimulateKeyPresses) {
|
||||
mainLayout->addWidget(new QLabel(obs_module_text(
|
||||
"AdvSceneSwitcher.action.hotkey.disabled")));
|
||||
}
|
||||
|
||||
setLayout(mainLayout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
void MacroActionHotkeyEdit::UpdateEntryData()
|
||||
{
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
_keys->setCurrentIndex(static_cast<int>(_entryData->_key));
|
||||
_leftShift->setChecked(_entryData->_leftShift);
|
||||
_rightShift->setChecked(_entryData->_rightShift);
|
||||
_leftCtrl->setChecked(_entryData->_leftCtrl);
|
||||
_rightCtrl->setChecked(_entryData->_rightCtrl);
|
||||
_leftAlt->setChecked(_entryData->_leftAlt);
|
||||
_rightAlt->setChecked(_entryData->_rightAlt);
|
||||
_leftMeta->setChecked(_entryData->_leftMeta);
|
||||
_rightMeta->setChecked(_entryData->_rightMeta);
|
||||
}
|
||||
|
||||
void MacroActionHotkeyEdit::LShiftChanged(int state)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_leftShift = state;
|
||||
}
|
||||
|
||||
void MacroActionHotkeyEdit::RShiftChanged(int state)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_rightShift = state;
|
||||
}
|
||||
|
||||
void MacroActionHotkeyEdit::LCtrlChanged(int state)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_leftCtrl = state;
|
||||
}
|
||||
|
||||
void MacroActionHotkeyEdit::RCtrlChanged(int state)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_rightCtrl = state;
|
||||
}
|
||||
|
||||
void MacroActionHotkeyEdit::LAltChanged(int state)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_leftAlt = state;
|
||||
}
|
||||
|
||||
void MacroActionHotkeyEdit::RAltChanged(int state)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_rightAlt = state;
|
||||
}
|
||||
|
||||
void MacroActionHotkeyEdit::LMetaChanged(int state)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_leftMeta = state;
|
||||
}
|
||||
|
||||
void MacroActionHotkeyEdit::RMetaChanged(int state)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_rightMeta = state;
|
||||
}
|
||||
|
||||
void MacroActionHotkeyEdit::KeyChanged(int key)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_key = static_cast<HotkeyType>(key);
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
#include "../headers/hotkey.hpp"
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
#import <CoreGraphics/CGEvent.h>
|
||||
|
|
@ -7,6 +9,10 @@
|
|||
#include <vector>
|
||||
#include <QStringList>
|
||||
#include <QRegularExpression>
|
||||
#include <map>
|
||||
#include <thread>
|
||||
|
||||
bool canSimulateKeyPresses = true;
|
||||
|
||||
void GetWindowList(std::vector<std::string> &windows)
|
||||
{
|
||||
|
|
@ -281,3 +287,216 @@ bool isInFocus(const QString &executable)
|
|||
|
||||
return (equals || matches);
|
||||
}
|
||||
|
||||
static std::map<HotkeyType, CGKeyCode> keyTable = {
|
||||
// Chars
|
||||
{HotkeyType::Key_A, kVK_ANSI_A},
|
||||
{HotkeyType::Key_B, kVK_ANSI_B},
|
||||
{HotkeyType::Key_C, kVK_ANSI_C},
|
||||
{HotkeyType::Key_D, kVK_ANSI_D},
|
||||
{HotkeyType::Key_E, kVK_ANSI_E},
|
||||
{HotkeyType::Key_F, kVK_ANSI_F},
|
||||
{HotkeyType::Key_G, kVK_ANSI_G},
|
||||
{HotkeyType::Key_H, kVK_ANSI_H},
|
||||
{HotkeyType::Key_I, kVK_ANSI_I},
|
||||
{HotkeyType::Key_J, kVK_ANSI_J},
|
||||
{HotkeyType::Key_K, kVK_ANSI_K},
|
||||
{HotkeyType::Key_L, kVK_ANSI_L},
|
||||
{HotkeyType::Key_M, kVK_ANSI_M},
|
||||
{HotkeyType::Key_N, kVK_ANSI_N},
|
||||
{HotkeyType::Key_O, kVK_ANSI_O},
|
||||
{HotkeyType::Key_P, kVK_ANSI_P},
|
||||
{HotkeyType::Key_Q, kVK_ANSI_Q},
|
||||
{HotkeyType::Key_R, kVK_ANSI_R},
|
||||
{HotkeyType::Key_S, kVK_ANSI_S},
|
||||
{HotkeyType::Key_T, kVK_ANSI_T},
|
||||
{HotkeyType::Key_U, kVK_ANSI_U},
|
||||
{HotkeyType::Key_V, kVK_ANSI_V},
|
||||
{HotkeyType::Key_W, kVK_ANSI_W},
|
||||
{HotkeyType::Key_X, kVK_ANSI_X},
|
||||
{HotkeyType::Key_Y, kVK_ANSI_Y},
|
||||
{HotkeyType::Key_Z, kVK_ANSI_Z},
|
||||
|
||||
// Numbers
|
||||
{HotkeyType::Key_0, kVK_ANSI_0},
|
||||
{HotkeyType::Key_1, kVK_ANSI_1},
|
||||
{HotkeyType::Key_2, kVK_ANSI_2},
|
||||
{HotkeyType::Key_3, kVK_ANSI_3},
|
||||
{HotkeyType::Key_4, kVK_ANSI_4},
|
||||
{HotkeyType::Key_5, kVK_ANSI_5},
|
||||
{HotkeyType::Key_6, kVK_ANSI_6},
|
||||
{HotkeyType::Key_7, kVK_ANSI_7},
|
||||
{HotkeyType::Key_8, kVK_ANSI_8},
|
||||
{HotkeyType::Key_9, kVK_ANSI_9},
|
||||
|
||||
{HotkeyType::Key_F1, kVK_F1},
|
||||
{HotkeyType::Key_F2, kVK_F2},
|
||||
{HotkeyType::Key_F3, kVK_F3},
|
||||
{HotkeyType::Key_F4, kVK_F4},
|
||||
{HotkeyType::Key_F5, kVK_F5},
|
||||
{HotkeyType::Key_F6, kVK_F6},
|
||||
{HotkeyType::Key_F7, kVK_F7},
|
||||
{HotkeyType::Key_F8, kVK_F8},
|
||||
{HotkeyType::Key_F9, kVK_F9},
|
||||
{HotkeyType::Key_F10, kVK_F10},
|
||||
{HotkeyType::Key_F11, kVK_F11},
|
||||
{HotkeyType::Key_F12, kVK_F12},
|
||||
{HotkeyType::Key_F13, kVK_F13},
|
||||
{HotkeyType::Key_F14, kVK_F14},
|
||||
{HotkeyType::Key_F15, kVK_F15},
|
||||
{HotkeyType::Key_F16, kVK_F16},
|
||||
{HotkeyType::Key_F17, kVK_F17},
|
||||
{HotkeyType::Key_F18, kVK_F18},
|
||||
{HotkeyType::Key_F19, kVK_F19},
|
||||
{HotkeyType::Key_F20, kVK_F20},
|
||||
// F21-F24 does not exist on MacOS
|
||||
|
||||
{HotkeyType::Key_Escape, kVK_Escape},
|
||||
{HotkeyType::Key_Space, kVK_Space},
|
||||
{HotkeyType::Key_Return, kVK_Return},
|
||||
{HotkeyType::Key_Backspace, kVK_Delete},
|
||||
{HotkeyType::Key_Tab, kVK_Tab},
|
||||
|
||||
{HotkeyType::Key_Shift_L, kVK_Shift},
|
||||
{HotkeyType::Key_Shift_R, kVK_RightShift},
|
||||
{HotkeyType::Key_Control_L, kVK_Control},
|
||||
{HotkeyType::Key_Control_R, kVK_RightControl},
|
||||
{HotkeyType::Key_Alt_L, kVK_Option},
|
||||
{HotkeyType::Key_Alt_R, kVK_RightOption},
|
||||
{HotkeyType::Key_Win_L, kVK_Command},
|
||||
{HotkeyType::Key_Win_R, kVK_RightCommand},
|
||||
// Not sure what Key_Apps would correspond to
|
||||
|
||||
{HotkeyType::Key_CapsLock, kVK_CapsLock},
|
||||
{HotkeyType::Key_NumLock, kVK_ANSI_KeypadClear},
|
||||
{HotkeyType::Key_ScrollLock, kVK_F14},
|
||||
|
||||
{HotkeyType::Key_PrintScreen, kVK_F13},
|
||||
{HotkeyType::Key_Pause, kVK_F15},
|
||||
|
||||
{HotkeyType::Key_Insert, kVK_Help},
|
||||
{HotkeyType::Key_Delete, kVK_ForwardDelete},
|
||||
{HotkeyType::Key_PageUP, kVK_PageUp},
|
||||
{HotkeyType::Key_PageDown, kVK_PageDown},
|
||||
{HotkeyType::Key_Home, kVK_Home},
|
||||
{HotkeyType::Key_End, kVK_End},
|
||||
|
||||
{HotkeyType::Key_Left, kVK_LeftArrow},
|
||||
{HotkeyType::Key_Up, kVK_UpArrow},
|
||||
{HotkeyType::Key_Right, kVK_RightArrow},
|
||||
{HotkeyType::Key_Down, kVK_DownArrow},
|
||||
|
||||
{HotkeyType::Key_Numpad0, kVK_ANSI_Keypad0},
|
||||
{HotkeyType::Key_Numpad1, kVK_ANSI_Keypad1},
|
||||
{HotkeyType::Key_Numpad2, kVK_ANSI_Keypad2},
|
||||
{HotkeyType::Key_Numpad3, kVK_ANSI_Keypad3},
|
||||
{HotkeyType::Key_Numpad4, kVK_ANSI_Keypad4},
|
||||
{HotkeyType::Key_Numpad5, kVK_ANSI_Keypad5},
|
||||
{HotkeyType::Key_Numpad6, kVK_ANSI_Keypad6},
|
||||
{HotkeyType::Key_Numpad7, kVK_ANSI_Keypad7},
|
||||
{HotkeyType::Key_Numpad8, kVK_ANSI_Keypad8},
|
||||
{HotkeyType::Key_Numpad9, kVK_ANSI_Keypad9},
|
||||
|
||||
{HotkeyType::Key_NumpadAdd, kVK_ANSI_KeypadPlus},
|
||||
{HotkeyType::Key_NumpadSubtract, kVK_ANSI_KeypadMinus},
|
||||
{HotkeyType::Key_NumpadMultiply, kVK_ANSI_KeypadMultiply},
|
||||
{HotkeyType::Key_NumpadDivide, kVK_ANSI_KeypadDivide},
|
||||
{HotkeyType::Key_NumpadDecimal, kVK_ANSI_KeypadDecimal},
|
||||
{HotkeyType::Key_NumpadEnter, kVK_ANSI_KeypadEnter},
|
||||
};
|
||||
|
||||
void PressKeys(const std::vector<HotkeyType> keys)
|
||||
{
|
||||
// TODO:
|
||||
// I can't seem to get this to work so drop support for this functionality
|
||||
// on MacOS
|
||||
canSimulateKeyPresses = false;
|
||||
return;
|
||||
|
||||
// Check premissions
|
||||
NSDictionary *options =
|
||||
@{(__bridge id)kAXTrustedCheckOptionPrompt: @NO};
|
||||
if (!AXIsProcessTrustedWithOptions((CFDictionaryRef)options)) {
|
||||
NSString *urlString =
|
||||
@"x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility";
|
||||
[[NSWorkspace sharedWorkspace]
|
||||
openURL:[NSURL URLWithString:urlString]];
|
||||
canSimulateKeyPresses = false;
|
||||
return;
|
||||
}
|
||||
|
||||
long modifierFlags = 0;
|
||||
auto source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||
if (!source) {
|
||||
canSimulateKeyPresses = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Press keys
|
||||
for (auto &key : keys) {
|
||||
auto it = keyTable.find(key);
|
||||
if (it == keyTable.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CGKeyCode inputKeyCode = it->second;
|
||||
CGEventRef keyPress =
|
||||
CGEventCreateKeyboardEvent(source, inputKeyCode, true);
|
||||
if (!keyPress) {
|
||||
canSimulateKeyPresses = false;
|
||||
CFRelease(source);
|
||||
return;
|
||||
}
|
||||
CGEventSetFlags(keyPress, modifierFlags);
|
||||
CGEventPost(kCGAnnotatedSessionEventTap, keyPress);
|
||||
CFRelease(keyPress);
|
||||
|
||||
switch (it->first) {
|
||||
case HotkeyType::Key_Shift_L:
|
||||
case HotkeyType::Key_Shift_R:
|
||||
modifierFlags |= NX_SHIFTMASK;
|
||||
break;
|
||||
case HotkeyType::Key_Control_L:
|
||||
case HotkeyType::Key_Control_R:
|
||||
modifierFlags |= NX_CONTROLMASK;
|
||||
break;
|
||||
case HotkeyType::Key_Alt_L:
|
||||
case HotkeyType::Key_Alt_R:
|
||||
modifierFlags |= NX_ALTERNATEMASK;
|
||||
break;
|
||||
case HotkeyType::Key_Win_L:
|
||||
case HotkeyType::Key_Win_R:
|
||||
modifierFlags |= NX_COMMANDMASK;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// When instantly releasing the key presses OBS might miss them
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(300));
|
||||
|
||||
// Release keys
|
||||
for (auto &key : keys) {
|
||||
auto it = keyTable.find(key);
|
||||
if (it == keyTable.end()) {
|
||||
continue;
|
||||
}
|
||||
CGKeyCode inputKeyCode = it->second;
|
||||
CGEventRef keyRelease =
|
||||
CGEventCreateKeyboardEvent(source, inputKeyCode, false);
|
||||
if (!keyRelease) {
|
||||
canSimulateKeyPresses = false;
|
||||
CFRelease(source);
|
||||
return;
|
||||
}
|
||||
CGEventPost(kCGAnnotatedSessionEventTap, keyRelease);
|
||||
CFRelease(keyRelease);
|
||||
}
|
||||
|
||||
CFRelease(source);
|
||||
}
|
||||
|
||||
void PlatformCleanup() {}
|
||||
|
||||
void PlatformInit() {}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#include "../headers/hotkey.hpp"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <util/platform.h>
|
||||
|
|
@ -9,9 +11,12 @@
|
|||
#include <vector>
|
||||
#include <QStringList>
|
||||
#include <QRegularExpression>
|
||||
#include "..\headers\platform-funcs.hpp"
|
||||
|
||||
#define MAX_SEARCH 1000
|
||||
|
||||
bool canSimulateKeyPresses = true;
|
||||
|
||||
static bool GetWindowTitle(HWND window, std::string &title)
|
||||
{
|
||||
size_t len = (size_t)GetWindowTextLengthW(window);
|
||||
|
|
@ -266,6 +271,160 @@ bool isInFocus(const QString &executable)
|
|||
return (equals || matches);
|
||||
}
|
||||
|
||||
static std::unordered_map<HotkeyType, long> keyTable = {
|
||||
// Chars
|
||||
{HotkeyType::Key_A, 0x41},
|
||||
{HotkeyType::Key_B, 0x42},
|
||||
{HotkeyType::Key_C, 0x43},
|
||||
{HotkeyType::Key_D, 0x44},
|
||||
{HotkeyType::Key_E, 0x45},
|
||||
{HotkeyType::Key_F, 0x46},
|
||||
{HotkeyType::Key_G, 0x47},
|
||||
{HotkeyType::Key_H, 0x48},
|
||||
{HotkeyType::Key_I, 0x49},
|
||||
{HotkeyType::Key_J, 0x4A},
|
||||
{HotkeyType::Key_K, 0x4B},
|
||||
{HotkeyType::Key_L, 0x4C},
|
||||
{HotkeyType::Key_M, 0x4D},
|
||||
{HotkeyType::Key_N, 0x4E},
|
||||
{HotkeyType::Key_O, 0x4F},
|
||||
{HotkeyType::Key_P, 0x50},
|
||||
{HotkeyType::Key_Q, 0x51},
|
||||
{HotkeyType::Key_R, 0x52},
|
||||
{HotkeyType::Key_S, 0x53},
|
||||
{HotkeyType::Key_T, 0x54},
|
||||
{HotkeyType::Key_U, 0x55},
|
||||
{HotkeyType::Key_V, 0x56},
|
||||
{HotkeyType::Key_W, 0x57},
|
||||
{HotkeyType::Key_X, 0x58},
|
||||
{HotkeyType::Key_Y, 0x59},
|
||||
{HotkeyType::Key_Z, 0x5A},
|
||||
|
||||
// Numbers
|
||||
{HotkeyType::Key_0, 0x30},
|
||||
{HotkeyType::Key_1, 0x31},
|
||||
{HotkeyType::Key_2, 0x32},
|
||||
{HotkeyType::Key_3, 0x33},
|
||||
{HotkeyType::Key_4, 0x34},
|
||||
{HotkeyType::Key_5, 0x35},
|
||||
{HotkeyType::Key_6, 0x36},
|
||||
{HotkeyType::Key_7, 0x37},
|
||||
{HotkeyType::Key_8, 0x38},
|
||||
{HotkeyType::Key_9, 0x39},
|
||||
|
||||
{HotkeyType::Key_F1, VK_F1},
|
||||
{HotkeyType::Key_F2, VK_F2},
|
||||
{HotkeyType::Key_F3, VK_F3},
|
||||
{HotkeyType::Key_F4, VK_F4},
|
||||
{HotkeyType::Key_F5, VK_F5},
|
||||
{HotkeyType::Key_F6, VK_F6},
|
||||
{HotkeyType::Key_F7, VK_F7},
|
||||
{HotkeyType::Key_F8, VK_F8},
|
||||
{HotkeyType::Key_F9, VK_F9},
|
||||
{HotkeyType::Key_F10, VK_F10},
|
||||
{HotkeyType::Key_F11, VK_F11},
|
||||
{HotkeyType::Key_F12, VK_F12},
|
||||
{HotkeyType::Key_F13, VK_F13},
|
||||
{HotkeyType::Key_F14, VK_F14},
|
||||
{HotkeyType::Key_F15, VK_F15},
|
||||
{HotkeyType::Key_F16, VK_F16},
|
||||
{HotkeyType::Key_F17, VK_F17},
|
||||
{HotkeyType::Key_F18, VK_F18},
|
||||
{HotkeyType::Key_F19, VK_F19},
|
||||
{HotkeyType::Key_F20, VK_F20},
|
||||
{HotkeyType::Key_F21, VK_F21},
|
||||
{HotkeyType::Key_F22, VK_F22},
|
||||
{HotkeyType::Key_F23, VK_F23},
|
||||
{HotkeyType::Key_F24, VK_F24},
|
||||
|
||||
{HotkeyType::Key_Escape, VK_ESCAPE},
|
||||
{HotkeyType::Key_Space, VK_SPACE},
|
||||
{HotkeyType::Key_Return, VK_RETURN},
|
||||
{HotkeyType::Key_Backspace, VK_BACK},
|
||||
{HotkeyType::Key_Tab, VK_TAB},
|
||||
|
||||
{HotkeyType::Key_Shift_L, VK_LSHIFT},
|
||||
{HotkeyType::Key_Shift_R, VK_RSHIFT},
|
||||
{HotkeyType::Key_Control_L, VK_LCONTROL},
|
||||
{HotkeyType::Key_Control_R, VK_RCONTROL},
|
||||
{HotkeyType::Key_Alt_L, VK_LMENU},
|
||||
{HotkeyType::Key_Alt_R, VK_RMENU},
|
||||
{HotkeyType::Key_Win_L, VK_LWIN},
|
||||
{HotkeyType::Key_Win_R, VK_RWIN},
|
||||
{HotkeyType::Key_Apps, VK_APPS},
|
||||
|
||||
{HotkeyType::Key_CapsLock, VK_CAPITAL},
|
||||
{HotkeyType::Key_NumLock, VK_NUMLOCK},
|
||||
{HotkeyType::Key_ScrollLock, VK_SCROLL},
|
||||
|
||||
{HotkeyType::Key_PrintScreen, VK_SNAPSHOT},
|
||||
{HotkeyType::Key_Pause, VK_PAUSE},
|
||||
|
||||
{HotkeyType::Key_Insert, VK_INSERT},
|
||||
{HotkeyType::Key_Delete, VK_DELETE},
|
||||
{HotkeyType::Key_PageUP, VK_PRIOR},
|
||||
{HotkeyType::Key_PageDown, VK_NEXT},
|
||||
{HotkeyType::Key_Home, VK_HOME},
|
||||
{HotkeyType::Key_End, VK_END},
|
||||
|
||||
{HotkeyType::Key_Left, VK_LEFT},
|
||||
{HotkeyType::Key_Up, VK_UP},
|
||||
{HotkeyType::Key_Right, VK_RIGHT},
|
||||
{HotkeyType::Key_Down, VK_DOWN},
|
||||
|
||||
{HotkeyType::Key_Numpad0, VK_NUMPAD0},
|
||||
{HotkeyType::Key_Numpad1, VK_NUMPAD1},
|
||||
{HotkeyType::Key_Numpad2, VK_NUMPAD2},
|
||||
{HotkeyType::Key_Numpad3, VK_NUMPAD3},
|
||||
{HotkeyType::Key_Numpad4, VK_NUMPAD4},
|
||||
{HotkeyType::Key_Numpad5, VK_NUMPAD5},
|
||||
{HotkeyType::Key_Numpad6, VK_NUMPAD6},
|
||||
{HotkeyType::Key_Numpad7, VK_NUMPAD7},
|
||||
{HotkeyType::Key_Numpad8, VK_NUMPAD8},
|
||||
{HotkeyType::Key_Numpad9, VK_NUMPAD9},
|
||||
|
||||
{HotkeyType::Key_NumpadAdd, VK_ADD},
|
||||
{HotkeyType::Key_NumpadSubtract, VK_SUBTRACT},
|
||||
{HotkeyType::Key_NumpadMultiply, VK_MULTIPLY},
|
||||
{HotkeyType::Key_NumpadDivide, VK_DIVIDE},
|
||||
{HotkeyType::Key_NumpadDecimal, VK_DECIMAL},
|
||||
{HotkeyType::Key_NumpadEnter, VK_RETURN},
|
||||
};
|
||||
|
||||
void PressKeys(const std::vector<HotkeyType> keys)
|
||||
{
|
||||
INPUT ip;
|
||||
ip.type = INPUT_KEYBOARD;
|
||||
ip.ki.wScan = 0;
|
||||
ip.ki.time = 0;
|
||||
ip.ki.dwExtraInfo = 0;
|
||||
|
||||
// Press keys
|
||||
ip.ki.dwFlags = 0;
|
||||
for (auto &key : keys) {
|
||||
auto it = keyTable.find(key);
|
||||
if (it == keyTable.end()) {
|
||||
continue;
|
||||
}
|
||||
ip.ki.wVk = it->second;
|
||||
SendInput(1, &ip, sizeof(INPUT));
|
||||
}
|
||||
|
||||
// When instantly releasing the key presses OBS might miss them
|
||||
Sleep(300);
|
||||
|
||||
// Release keys
|
||||
ip.ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
for (auto &key : keys) {
|
||||
auto it = keyTable.find(key);
|
||||
if (it == keyTable.end()) {
|
||||
continue;
|
||||
}
|
||||
ip.ki.wVk = it->second;
|
||||
SendInput(1, &ip, sizeof(INPUT));
|
||||
}
|
||||
}
|
||||
|
||||
int getLastInputTime()
|
||||
{
|
||||
LASTINPUTINFO lastInputInfo;
|
||||
|
|
@ -285,3 +444,7 @@ int secondsSinceLastInput()
|
|||
{
|
||||
return (getTime() - getLastInputTime()) / 1000;
|
||||
}
|
||||
|
||||
void PlatformInit() {}
|
||||
|
||||
void PlatformCleanup() {}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user