Move IKeyboard and subclasses to new library BlackInput

refs #256
This commit is contained in:
Roland Winklmeier
2014-06-04 14:23:14 +02:00
committed by Roland Winklmeier
parent 14e9e01b90
commit a131e8c91c
25 changed files with 105 additions and 65 deletions

View File

@@ -0,0 +1,185 @@
/* Copyright (C) 2013 VATSIM Community / contributors
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "keyboard_windows.h"
#include "keymapping_windows.h"
#include <QDebug>
using namespace BlackMisc::Hardware;
namespace BlackInput
{
CKeyboardWindows::CKeyboardWindows(QObject *parent) :
IKeyboard(parent),
m_keyboardHook(nullptr),
m_mode(Mode_Nominal)
{
}
CKeyboardWindows::~CKeyboardWindows()
{
if (m_keyboardHook)
UnhookWindowsHookEx(m_keyboardHook);
}
bool CKeyboardWindows::init()
{
m_keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, CKeyboardWindows::keyboardProc, GetModuleHandle(NULL), 0);
return true;
}
void CKeyboardWindows::startCapture(bool ignoreNextKey)
{
m_mode = Mode_Capture;
m_ignoreNextKey = ignoreNextKey;
m_pressedKey.setKeyObject(CKeyboardKey());
}
int CKeyboardWindows::sizeOfRegisteredFunctions() const
{
int size = 0;
foreach (QList<IKeyboard::RegistrationHandle> functions, m_registeredFunctions)
{
size += functions.size();
}
return size;
}
void CKeyboardWindows::triggerKey(const CKeyboardKey key, bool isPressed)
{
callFunctionsBy(key, isPressed);
}
void CKeyboardWindows::keyEvent(WPARAM vkcode, uint event)
{
BlackMisc::Hardware::CKeyboardKey lastPressedKey = m_pressedKey;
if (m_ignoreNextKey)
{
m_ignoreNextKey = false;
return;
}
bool isFinished = false;
if ((event == WM_KEYDOWN) || (event == WM_SYSKEYDOWN))
{
if (CKeyMappingWindows::isModifier(vkcode))
m_pressedKey.addModifier(CKeyMappingWindows::convertToModifier(vkcode));
else
{
m_pressedKey.setKey(CKeyMappingWindows::convertToKey(vkcode));
m_pressedKey.setNativeVirtualKey(vkcode);
}
}
else if ((event == WM_KEYUP) || (event == WM_SYSKEYUP) )
{
if (CKeyMappingWindows::isModifier(vkcode))
m_pressedKey.removeModifier(CKeyMappingWindows::convertToModifier(vkcode));
else
{
m_pressedKey.setKey(Qt::Key_unknown);
m_pressedKey.setNativeVirtualKey(0);
}
isFinished = true;
}
if (lastPressedKey == m_pressedKey)
return;
#ifdef DEBUG_KEYBOARD_WINDOWS
qDebug() << "Virtual key: " << vkcode;
#endif
if (m_mode == Mode_Capture)
{
if (isFinished)
{
sendCaptureNotification(lastPressedKey, true);
m_mode = Mode_Nominal;
}
else
{
sendCaptureNotification(m_pressedKey, false);
}
}
else
{
callFunctionsBy(lastPressedKey, false);
callFunctionsBy(m_pressedKey, true);
}
}
IKeyboard::RegistrationHandle CKeyboardWindows::registerHotkeyImpl(BlackMisc::Hardware::CKeyboardKey key, QObject *receiver, std::function<void(bool)> function)
{
IKeyboard::RegistrationHandle handle;
// Workaround: Remove key function. Otherwise operator== will not
// work when we create the key value object by pressed keys
key.setFunction(BlackMisc::Hardware::CKeyboardKey::HotkeyNone);
if (!key.hasModifier() && !key.hasKey())
{
return handle;
}
if (receiver == nullptr)
return handle;
handle.m_key = key;
handle.m_receiver = receiver;
handle.function = function;
QList<IKeyboard::RegistrationHandle> functions = m_registeredFunctions.value(key);
functions.append(handle);
m_registeredFunctions.insert(key, functions);
return handle;
}
void CKeyboardWindows::unregisterHotkeyImpl(const IKeyboard::RegistrationHandle &handle)
{
QList<IKeyboard::RegistrationHandle> functions = m_registeredFunctions.value(handle.m_key);
functions.removeAll(handle);
m_registeredFunctions.insert(handle.m_key, functions);
}
void CKeyboardWindows::unregisterAllHotkeysImpl()
{
m_registeredFunctions.clear();
}
void CKeyboardWindows::sendCaptureNotification(const CKeyboardKey &key, bool isFinished)
{
if (isFinished)
emit keySelectionFinished(key);
else
emit keySelectionChanged(key);
}
void CKeyboardWindows::callFunctionsBy(const CKeyboardKey &key, bool isPressed)
{
QList<IKeyboard::RegistrationHandle> functionHandles = m_registeredFunctions.value(key);
foreach (IKeyboard::RegistrationHandle functionHandle, functionHandles)
{
if (functionHandle.m_receiver.isNull())
{
continue;
}
functionHandle.function(isPressed);
}
}
LRESULT CALLBACK CKeyboardWindows::keyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CKeyboardWindows *keyboardWindows = qobject_cast<CKeyboardWindows*>(IKeyboard::getInstance());
if (nCode == HC_ACTION)
{
KBDLLHOOKSTRUCT *keyboardEvent =reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
WPARAM vkCode = keyboardEvent->vkCode;
keyboardWindows->keyEvent(vkCode, wParam);
}
return CallNextHookEx(keyboardWindows->keyboardHook(), nCode, wParam, lParam);
}
}

View File

@@ -0,0 +1,110 @@
/* Copyright (C) 2013 VATSIM Community / contributors
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*!
\file
*/
#ifndef BLACKINPUT_KEYBOARD_WINDOWS_H
#define BLACKINPUT_KEYBOARD_WINDOWS_H
#include "blackinput/keyboard.h"
#include "blackmisc/hwkeyboardkey.h"
#include <QHash>
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
namespace BlackInput
{
//! \brief Windows implemenation of IKeyboard using hook procedure
//! \todo Change QHash to a CCollection object
class CKeyboardWindows : public IKeyboard
{
Q_OBJECT
public:
//! \brief Destructor
virtual ~CKeyboardWindows();
//! \copydoc IKeyboard::selectKey()
virtual void startCapture(bool ignoreNextKey = false) override;
//! \copydoc IKeyboard::sizeOfRegisteredFunctions()
virtual int sizeOfRegisteredFunctions() const override;
//! \copydoc IKeyboard::triggerKey()
virtual void triggerKey(const BlackMisc::Hardware::CKeyboardKey key, bool isPressed) override;
//! \brief Keyboard hook handle
HHOOK keyboardHook() const { return m_keyboardHook; }
//! \private
void keyEvent(WPARAM vkCode, uint event);
protected:
friend class IKeyboard;
//! \brief Constructor
CKeyboardWindows(QObject *parent = nullptr);
//! \brief Copy Constructor
CKeyboardWindows(CKeyboardWindows const&);
//! \copydoc IKeyboard::init()
virtual bool init() override;
//! \brief Assignment operator
void operator=(CKeyboardWindows const&);
//! \copydoc IKeyboard::registerHotKeyImpl()
virtual IKeyboard::RegistrationHandle registerHotkeyImpl(BlackMisc::Hardware::CKeyboardKey key, QObject *receiver, std::function<void(bool)> function) override;
//! \copydoc IKeyboard::unregisterHotkeyImpl()
virtual void unregisterHotkeyImpl(const IKeyboard::RegistrationHandle &handle) override;
//! \copydoc IKeyboard::unregisterHotkeyImpl()
virtual void unregisterAllHotkeysImpl() override;
private:
/*!
* \brief Constructor
* \param keySet
* \param isFinished
*/
void sendCaptureNotification(const BlackMisc::Hardware::CKeyboardKey &key, bool isFinished);
/*!
* \brief Calls registered functions on keyboard event
* \param keySet
* \param isPressed
*/
void callFunctionsBy(const BlackMisc::Hardware::CKeyboardKey &keySet, bool isPressed);
void addKey(WPARAM vkcode);
void removeKey(WPARAM vkcode);
/*!
* \brief Keyboard hook procedure
* \param nCode
* \param wParam
* \param lParam
* \return
*/
static LRESULT CALLBACK keyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
QHash<BlackMisc::Hardware::CKeyboardKey, QList<IKeyboard::RegistrationHandle>> m_registeredFunctions; //!< Registered hotkey functions
BlackMisc::Hardware::CKeyboardKey m_pressedKey; //!< Set of virtual keys pressed in the last cycle
bool m_ignoreNextKey; //!< Is true if the next key needs to be ignored
HHOOK m_keyboardHook; //!< Keyboard hook handle
Mode m_mode; //!< Operation mode
};
}
#endif // BLACKINPUT_KEYBOARD_WINDOWS_H

View File

@@ -0,0 +1,94 @@
/* Copyright (C) 2013 VATSIM Community / contributors
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "keymapping_windows.h"
#include <QDebug>
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
using namespace BlackMisc::Hardware;
namespace BlackInput
{
Qt::Key CKeyMappingWindows::convertToKey(WPARAM virtualKey)
{
switch (virtualKey)
{
case '0': return Qt::Key_0; break;
case '1': return Qt::Key_1; break;
case '2': return Qt::Key_2; break;
case '3': return Qt::Key_3; break;
case '4': return Qt::Key_4; break;
case '5': return Qt::Key_5; break;
case '6': return Qt::Key_6; break;
case '7': return Qt::Key_7; break;
case '8': return Qt::Key_8; break;
case '9': return Qt::Key_9; break;
case 'A': return Qt::Key_A; break;
case 'B': return Qt::Key_B; break;
case 'C': return Qt::Key_C; break;
case 'D': return Qt::Key_D; break;
case 'E': return Qt::Key_E; break;
case 'F': return Qt::Key_F; break;
case 'G': return Qt::Key_G; break;
case 'H': return Qt::Key_H; break;
case 'I': return Qt::Key_I; break;
case 'J': return Qt::Key_J; break;
case 'K': return Qt::Key_K; break;
case 'L': return Qt::Key_L; break;
case 'M': return Qt::Key_M; break;
case 'N': return Qt::Key_N; break;
case 'O': return Qt::Key_O; break;
case 'P': return Qt::Key_P; break;
case 'Q': return Qt::Key_Q; break;
case 'R': return Qt::Key_R; break;
case 'S': return Qt::Key_S; break;
case 'T': return Qt::Key_T; break;
case 'U': return Qt::Key_U; break;
case 'V': return Qt::Key_V; break;
case 'W': return Qt::Key_W; break;
case 'X': return Qt::Key_X; break;
case 'Y': return Qt::Key_Y; break;
case 'Z': return Qt::Key_Z; break;
default: return Qt::Key_unknown; break;
}
}
CKeyboardKey::Modifier CKeyMappingWindows::convertToModifier(WPARAM virtualKey)
{
switch (virtualKey)
{
qDebug() << virtualKey;
case VK_LSHIFT: return CKeyboardKey::ModifierShiftLeft; break;
case VK_RSHIFT: return CKeyboardKey::ModifierShiftRight; break;
case VK_LCONTROL: return CKeyboardKey::ModifierCtrlLeft; break;
case VK_RCONTROL: return CKeyboardKey::ModifierCtrlRight; break;
case VK_LMENU: return CKeyboardKey::ModifierAltLeft; break;
case VK_RMENU: return CKeyboardKey::ModifierAltRight; break;
default: return CKeyboardKey::ModifierNone; break;
}
}
bool CKeyMappingWindows::isModifier(WPARAM vkcode)
{
switch (vkcode)
{
case VK_LSHIFT:
case VK_RSHIFT:
case VK_LCONTROL:
case VK_RCONTROL:
case VK_LMENU:
case VK_RMENU:
case VK_LWIN:
case VK_RWIN:
return true;
default: return false;
}
}
} // namespace BlackCore

View File

@@ -0,0 +1,45 @@
/* Copyright (C) 2013 VATSIM Community / contributors
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef BLACKINPUT_KEYMAPPING_WINDOWS_H
#define BLACKINPUT_KEYMAPPING_WINDOWS_H
#include "blackmisc/hwkeyboardkey.h"
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
namespace BlackInput
{
//! \brief This class provides methods to map between windows virtual keys and CKeyboardKey
class CKeyMappingWindows
{
public:
/*!
* \brief Converts a set of windows virtual keys to a CKeySet object
* \param virtualKey
* \return
*/
static BlackMisc::Hardware::CKeyboardKey::Modifier convertToModifier(WPARAM virtualKey);
/*!
* \brief Convert to Qt key
* \param virtualKey
* \return
*/
static Qt::Key convertToKey(WPARAM virtualKey);
/*!
* \brief Checks if its a modifier key
* \param vkcode
* \return
*/
static bool isModifier(WPARAM vkcode);
};
} // namespace BlackInput
#endif // guard