summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2015-11-22 15:06:30 +0100
committerStanislaw Halik <sthalik@misaki.pl>2015-11-22 15:55:39 +0100
commita9860e951757bf454b83b13ce7eff865f0b6644e (patch)
tree88d13f20a8066e0a2aaf0f94944a03733279db66
parent763da906a83b80eadb736008dbb558b809552505 (diff)
api/keyboard: implement a central worker
DirectInput dies when two LPDIRECTINPUT8 handles are obtained. Implement a singleton worker providing keypress events.
-rw-r--r--opentrack/keybinding-worker.cpp153
-rw-r--r--opentrack/keybinding-worker.hpp48
2 files changed, 137 insertions, 64 deletions
diff --git a/opentrack/keybinding-worker.cpp b/opentrack/keybinding-worker.cpp
index 31eb9e80..d876d5a1 100644
--- a/opentrack/keybinding-worker.cpp
+++ b/opentrack/keybinding-worker.cpp
@@ -9,11 +9,14 @@
#include "keybinding-worker.hpp"
#if defined(_WIN32)
-# include <functional>
-# include <windows.h>
-# include <QDebug>
+
+#include <functional>
+#include <windows.h>
+#include <QDebug>
+#include <QMutexLocker>
KeybindingWorker::~KeybindingWorker() {
+ qDebug() << "keybinding worker stop";
should_quit = true;
wait();
if (dinkeyboard) {
@@ -24,11 +27,8 @@ KeybindingWorker::~KeybindingWorker() {
din->Release();
}
-KeybindingWorker::KeybindingWorker(std::function<void(Key&)> receiver, WId h) :
- should_quit(true), receiver(receiver)
+KeybindingWorker::KeybindingWorker() : should_quit(true)
{
- HWND handle = reinterpret_cast<HWND>(h);
-
if (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&din, NULL) != DI_OK) {
qDebug() << "setup DirectInput8 Creation failed!" << GetLastError();
return;
@@ -47,7 +47,7 @@ KeybindingWorker::KeybindingWorker(std::function<void(Key&)> receiver, WId h) :
din = 0;
return;
}
- if (dinkeyboard->SetCooperativeLevel((HWND) handle, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND) != DI_OK) {
+ if (dinkeyboard->SetCooperativeLevel(GetDesktopWindow(), DISCL_NONEXCLUSIVE | DISCL_BACKGROUND) != DI_OK) {
dinkeyboard->Release();
din->Release();
din = 0;
@@ -65,6 +65,13 @@ KeybindingWorker::KeybindingWorker(std::function<void(Key&)> receiver, WId h) :
return;
}
should_quit = false;
+ start();
+}
+
+KeybindingWorker& KeybindingWorker::make()
+{
+ static KeybindingWorker k;
+ return k;
}
void KeybindingWorker::run() {
@@ -73,59 +80,99 @@ void KeybindingWorker::run() {
while (!should_quit)
{
{
- const HRESULT hr = dinkeyboard->GetDeviceState(256, (LPVOID)keystate);
-
- if (hr != DI_OK) {
- qDebug() << "Tracker::run GetDeviceState function failed!" << GetLastError();
- Sleep(25);
- continue;
- }
- }
-
- {
- using joy_fn = std::function<void(const QString& guid, int idx, bool held)>;
-
- joy_fn f = [&](const QString& guid, int idx, bool held) -> void {
- Key k;
- k.keycode = idx;
- k.shift = !!(keystate[DIK_LSHIFT] & 0x80 || keystate[DIK_RSHIFT] & 0x80);
- k.alt = !!(keystate[DIK_LALT] & 0x80 || keystate[DIK_RALT] & 0x80);
- k.ctrl = !!(keystate[DIK_LCONTROL] & 0x80 || keystate[DIK_RCONTROL] & 0x80);
- k.guid = guid;
- k.held = held;
- receiver(k);
- };
+ QMutexLocker l(&mtx);
- joy_ctx.poll(f);
- }
-
- for (int i = 0; i < 256; i++)
- {
- Key k;
- if (keystate[i] & 0x80)
+ if (receivers.size())
{
- switch (i)
{
- case DIK_LCONTROL:
- case DIK_LSHIFT:
- case DIK_LALT:
- case DIK_RCONTROL:
- case DIK_RSHIFT:
- case DIK_RALT:
- break;
- default:
- k.shift = !!(keystate[DIK_LSHIFT] & 0x80) || !!(keystate[DIK_RSHIFT] & 0x80);
- k.alt = !!(keystate[DIK_LALT] & 0x80) || !!(keystate[DIK_RALT] & 0x80);
- k.ctrl = !!(keystate[DIK_LCONTROL] & 0x80) || !!(keystate[DIK_RCONTROL] & 0x80);
- k.keycode = i;
- receiver(k);
- break;
+ const HRESULT hr = dinkeyboard->GetDeviceState(256, (LPVOID)keystate);
+
+ if (hr != DI_OK) {
+ qDebug() << "Tracker::run GetDeviceState function failed!" << GetLastError();
+ Sleep(25);
+ continue;
+ }
+ }
+
+ {
+ using joy_fn = std::function<void(const QString& guid, int idx, bool held)>;
+
+ joy_fn f = [&](const QString& guid, int idx, bool held) -> void {
+ Key k;
+ k.keycode = idx;
+ k.shift = !!(keystate[DIK_LSHIFT] & 0x80 || keystate[DIK_RSHIFT] & 0x80);
+ k.alt = !!(keystate[DIK_LALT] & 0x80 || keystate[DIK_RALT] & 0x80);
+ k.ctrl = !!(keystate[DIK_LCONTROL] & 0x80 || keystate[DIK_RCONTROL] & 0x80);
+ k.guid = guid;
+ k.held = held;
+
+ for (auto& r : receivers)
+ r(k);
+ };
+
+ joy_ctx.poll(f);
+ }
+
+ for (int i = 0; i < 256; i++)
+ {
+ Key k;
+ if (keystate[i] & 0x80)
+ {
+ switch (i)
+ {
+ case DIK_LCONTROL:
+ case DIK_LSHIFT:
+ case DIK_LALT:
+ case DIK_RCONTROL:
+ case DIK_RSHIFT:
+ case DIK_RALT:
+ break;
+ default:
+ k.shift = !!(keystate[DIK_LSHIFT] & 0x80) || !!(keystate[DIK_RSHIFT] & 0x80);
+ k.alt = !!(keystate[DIK_LALT] & 0x80) || !!(keystate[DIK_RALT] & 0x80);
+ k.ctrl = !!(keystate[DIK_LCONTROL] & 0x80) || !!(keystate[DIK_RCONTROL] & 0x80);
+ k.keycode = i;
+
+ for (auto& r : receivers)
+ r(k);
+ break;
+ }
+ }
}
}
}
-
+
// keypresses get dropped with high values
Sleep(4);
}
}
+
+KeybindingWorker::fun* KeybindingWorker::_add_receiver(KeybindingWorker::fun receiver)
+{
+ QMutexLocker l(&mtx);
+ receivers.push_back(receiver);
+ qDebug() << "add receiver" << (long) &receivers[receivers.size()-1];
+ return &receivers[receivers.size()-1];
+}
+
+void KeybindingWorker::remove_receiver(KeybindingWorker::fun* pos)
+{
+ QMutexLocker l(&mtx);
+ bool ok = false;
+
+ for (int i = receivers.size() - 1; i >= 0; i--)
+ {
+ if (&receivers[i] == pos)
+ {
+ ok = true;
+ qDebug() << "remove receiver" << (long) pos;
+ receivers.erase(receivers.begin() + i);
+ }
+ }
+ if (!ok)
+ {
+ qDebug() << "bad remove receiver" << (long) pos;
+ }
+}
+
#endif \ No newline at end of file
diff --git a/opentrack/keybinding-worker.hpp b/opentrack/keybinding-worker.hpp
index b5d63fac..5a73b1b1 100644
--- a/opentrack/keybinding-worker.hpp
+++ b/opentrack/keybinding-worker.hpp
@@ -20,6 +20,7 @@
#include <QMutex>
#include <QWidget>
#include <functional>
+#include <vector>
#ifdef _WIN32
# undef DIRECTINPUT_VERSION
@@ -53,21 +54,46 @@ typedef unsigned char BYTE;
struct Key { int foo; };
#endif
-struct OPENTRACK_EXPORT KeybindingWorker : public QThread {
-#ifdef _WIN32
+struct OPENTRACK_EXPORT KeybindingWorker : private QThread
+{
private:
LPDIRECTINPUT8 din;
LPDIRECTINPUTDEVICE8 dinkeyboard;
win32_joy_ctx joy_ctx;
-public:
volatile bool should_quit;
- std::function<void(Key&)> receiver;
+ using fun = std::function<void(Key&)>;
+ std::vector<fun> receivers;
+ QMutex mtx;
+
+ void run() override;
+ KeybindingWorker();
+
+ KeybindingWorker(const KeybindingWorker&) = delete;
+ KeybindingWorker& operator=(KeybindingWorker&) = delete;
+ static KeybindingWorker& make();
+ fun* _add_receiver(fun receiver);
+ void remove_receiver(fun* pos);
~KeybindingWorker();
- KeybindingWorker(std::function<void(Key&)> receiver, WId h);
- void run();
-#else
public:
- KeybindingWorker(Key, Key, Key, WId) {}
- void run() {}
-#endif
-}; \ No newline at end of file
+ class Token
+ {
+ friend class KeybindingWorker;
+ fun* pos;
+ //Token(const Token&) = delete;
+ Token& operator=(Token&) = delete;
+ public:
+ Token(fun receiver)
+ {
+ pos = make()._add_receiver(receiver);
+ }
+ ~Token()
+ {
+ make().remove_receiver(pos);
+ }
+ };
+ friend class Token;
+ static Token add_receiver(fun receiver)
+ {
+ return Token(receiver);
+ }
+};