deskflow/src/unittests/platform/EiKeyStateTests.cpp

138 lines
3.7 KiB
C++
Raw Normal View History

/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2026 Deskflow Developers
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "EiKeyStateTests.h"
#include "base/EventQueue.h"
#include "deskflow/AppUtil.h"
#include "deskflow/KeyTypes.h"
#include "platform/EiKeyState.h"
#include <QByteArray>
#include <QTemporaryFile>
#include <cstdint>
namespace {
class TestAppUtil : public AppUtil
{
public:
int run() override
{
return 0;
}
std::vector<std::string> getKeyboardLayoutList() override
{
return {"en"};
}
std::string getCurrentLanguageCode() override
{
return "en";
}
};
const char TestKeymap[] = R"XKB(xkb_keymap {
xkb_keycodes "test" {
minimum = 8;
maximum = 255;
<LFSH> = 50;
<NMLK> = 77;
};
xkb_types "test" {
type "ONE_LEVEL" {
modifiers = none;
level_name[Level1] = "Any";
};
};
xkb_compat "test" {
interpret Shift_L+AnyOfOrNone(all) {
action = SetMods(modifiers=Shift);
};
interpret Num_Lock+AnyOfOrNone(all) {
action = LockMods(modifiers=Mod2);
};
};
xkb_symbols "test" {
key <LFSH> { [ Shift_L ] };
key <NMLK> { [ Num_Lock ] };
modifier_map Shift { <LFSH> };
modifier_map Mod2 { <NMLK> };
};
};)XKB";
// XKB keycodes for TestKeymap.
constexpr std::uint32_t LeftShiftKeycode = 50;
constexpr std::uint32_t NumLockKeycode = 77;
} // namespace
void EiKeyStateTests::initTestCase()
{
m_arch.init();
m_log.setFilter(LogLevel::Level::Verbose);
}
void EiKeyStateTests::clearStaleModifiers_shiftDownAndNumLockOn_shiftClearedAndNumLockPreserved()
{
TestAppUtil appUtil;
EventQueue eventQueue;
deskflow::EiKeyState keyState(nullptr, &eventQueue);
QTemporaryFile keymapFile;
QVERIFY(keymapFile.open());
const QByteArray keymapData = QByteArray::fromRawData(TestKeymap, sizeof(TestKeymap) - 1);
QCOMPARE(keymapFile.write(keymapData), keymapData.size());
QVERIFY(keymapFile.flush());
keyState.init(keymapFile.handle(), keymapFile.size());
keyState.updateXkbState(LeftShiftKeycode, true);
keyState.updateXkbState(NumLockKeycode, true);
keyState.updateXkbState(NumLockKeycode, false);
QVERIFY((keyState.pollActiveModifiers() & KeyModifierShift) != 0);
QVERIFY((keyState.pollActiveModifiers() & KeyModifierNumLock) != 0);
keyState.clearStaleModifiers();
QVERIFY((keyState.pollActiveModifiers() & KeyModifierShift) == 0);
QVERIFY((keyState.pollActiveModifiers() & KeyModifierNumLock) != 0);
}
void EiKeyStateTests::updateLockedModifiers_compositorLockState_numLockFollowsCompositor()
{
// Real modifier Mod2 is index 4 (Shift, Lock, Control, Mod1, Mod2, ...).
constexpr std::uint32_t xkbMod2Mask = 1 << 4;
TestAppUtil appUtil;
EventQueue eventQueue;
deskflow::EiKeyState keyState(nullptr, &eventQueue);
QTemporaryFile keymapFile;
QVERIFY(keymapFile.open());
const QByteArray keymapData = QByteArray::fromRawData(TestKeymap, sizeof(TestKeymap) - 1);
QCOMPARE(keymapFile.write(keymapData), keymapData.size());
QVERIFY(keymapFile.flush());
keyState.init(keymapFile.handle(), keymapFile.size());
keyState.updateXkbState(LeftShiftKeycode, true);
QVERIFY((keyState.pollActiveModifiers() & KeyModifierNumLock) == 0);
// NumLock toggled on locally, reported by the compositor
keyState.updateLockedModifiers(xkbMod2Mask);
QVERIFY((keyState.pollActiveModifiers() & KeyModifierNumLock) != 0);
QVERIFY((keyState.pollActiveModifiers() & KeyModifierShift) != 0);
keyState.clearStaleModifiers();
QVERIFY((keyState.pollActiveModifiers() & KeyModifierNumLock) != 0);
// NumLock toggled off locally
keyState.updateLockedModifiers(0);
QVERIFY((keyState.pollActiveModifiers() & KeyModifierNumLock) == 0);
}
QTEST_MAIN(EiKeyStateTests)