Files
pilotclient/src/blackcore/win/keyboard_windows.cpp
Roland Winklmeier a7465fa6a3 Windows implementation of IKeyboard interface
Located in a win subfolder. It uses keyboard hooks to get
key up and down events. Keymapping is done in a separate
windows specific class.

refs #83
2014-03-11 21:50:25 +01:00

186 lines
5.6 KiB
C++

/* 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 BlackCore
{
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);
}
}