Support enabling numlock on startup

Summary:
This change brings improved num lock support to KWin. The modifier state
is read and also mapped to Qt::KeyboardModifiers. Furthermore the input
config is read and the NumLock key is evaluated. If the requested state
does not match the current num lock state the state is swapped.

BUG: 375708
FIXED-IN: 5.15

Test Plan: New unit test added, no manual test due to lack of hardware

Subscribers: kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D16428
This commit is contained in:
Martin Flöser 2018-10-25 19:46:36 +02:00
parent 7e8facc3fd
commit 7c3a851b04
4 changed files with 83 additions and 0 deletions

View file

@ -60,6 +60,7 @@ private Q_SLOTS:
void testVirtualDesktopPolicy();
void testWindowPolicy();
void testApplicationPolicy();
void testNumLock();
private:
void reconfigureLayouts();
@ -83,6 +84,7 @@ void KeyboardLayoutTest::initTestCase()
kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
kwinApp()->setKxkbConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
kwinApp()->setInputConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
kwinApp()->start();
QVERIFY(workspaceCreatedSpy.wait());
@ -457,5 +459,46 @@ void KeyboardLayoutTest::testApplicationPolicy()
QTRY_COMPARE(xkb->layoutName(), QStringLiteral("German (Neo 2)"));
}
void KeyboardLayoutTest::testNumLock()
{
qputenv("KWIN_FORCE_NUM_LOCK_EVALUATION", "1");
auto xkb = input()->keyboard()->xkb();
// by default not set
QVERIFY(!xkb->modifiers().testFlag(Qt::KeypadModifier));
quint32 timestamp = 0;
kwinApp()->platform()->keyboardKeyPressed(KEY_NUMLOCK, timestamp++);
kwinApp()->platform()->keyboardKeyReleased(KEY_NUMLOCK, timestamp++);
// now it should be on
QVERIFY(xkb->modifiers().testFlag(Qt::KeypadModifier));
// and back to off
kwinApp()->platform()->keyboardKeyPressed(KEY_NUMLOCK, timestamp++);
kwinApp()->platform()->keyboardKeyReleased(KEY_NUMLOCK, timestamp++);
QVERIFY(!xkb->modifiers().testFlag(Qt::KeypadModifier));
// let's reconfigure to enable through config
auto group = kwinApp()->inputConfig()->group("Keyboard");
group.writeEntry("NumLock", 0);
group.sync();
xkb->reconfigure();
// now it should be on
QVERIFY(xkb->modifiers().testFlag(Qt::KeypadModifier));
// pressing should result in it being off
kwinApp()->platform()->keyboardKeyPressed(KEY_NUMLOCK, timestamp++);
kwinApp()->platform()->keyboardKeyReleased(KEY_NUMLOCK, timestamp++);
QVERIFY(!xkb->modifiers().testFlag(Qt::KeypadModifier));
// pressing again should enable it
kwinApp()->platform()->keyboardKeyPressed(KEY_NUMLOCK, timestamp++);
kwinApp()->platform()->keyboardKeyReleased(KEY_NUMLOCK, timestamp++);
QVERIFY(xkb->modifiers().testFlag(Qt::KeypadModifier));
// now reconfigure to disable on load
group.writeEntry("NumLock", 1);
group.sync();
xkb->reconfigure();
QVERIFY(!xkb->modifiers().testFlag(Qt::KeypadModifier));
}
WAYLANDTEST_MAIN(KeyboardLayoutTest)
#include "keyboard_layout_test.moc"

View file

@ -111,6 +111,7 @@ void KeyboardInputRedirection::init()
Q_ASSERT(!m_inited);
m_inited = true;
const auto config = kwinApp()->kxkbConfig();
m_xkb->setNumLockConfig(kwinApp()->inputConfig());
m_xkb->setConfig(config);
m_input->installInputEventSpy(new KeyStateChangedSpy(m_input));

28
xkb.cpp
View file

@ -34,6 +34,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// system
#include <sys/mman.h>
#include <unistd.h>
#include <bitset>
Q_LOGGING_CATEGORY(KWIN_XKB, "kwin_xkbcommon", QtCriticalMsg)
@ -75,6 +76,7 @@ Xkb::Xkb(QObject *parent)
, m_controlModifier(0)
, m_altModifier(0)
, m_metaModifier(0)
, m_numModifier(0)
, m_numLock(0)
, m_capsLock(0)
, m_scrollLock(0)
@ -214,6 +216,7 @@ void Xkb::installKeymap(int fd, uint32_t size)
qCDebug(KWIN_XKB) << "Could not map keymap from file";
return;
}
m_ownership = Ownership::Client;
updateKeymap(keymap);
}
@ -238,6 +241,7 @@ void Xkb::updateKeymap(xkb_keymap *keymap)
m_controlModifier = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_CTRL);
m_altModifier = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_ALT);
m_metaModifier = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_LOGO);
m_numModifier = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_NUM);
m_numLock = xkb_keymap_led_get_index(m_keymap, XKB_LED_NAME_NUM);
m_capsLock = xkb_keymap_led_get_index(m_keymap, XKB_LED_NAME_CAPS);
@ -249,8 +253,29 @@ void Xkb::updateKeymap(xkb_keymap *keymap)
m_modifierState.latched = xkb_state_serialize_mods(m_state, xkb_state_component(XKB_STATE_MODS_LATCHED));
m_modifierState.locked = xkb_state_serialize_mods(m_state, xkb_state_component(XKB_STATE_MODS_LOCKED));
static bool s_startup = true;
if (s_startup || qEnvironmentVariableIsSet("KWIN_FORCE_NUM_LOCK_EVALUATION")) {
s_startup = false;
if (m_ownership == Ownership::Server && m_numModifier != XKB_MOD_INVALID && m_numLockConfig) {
const KConfigGroup config = m_numLockConfig->group("Keyboard");
// STATE_ON = 0, STATE_OFF = 1, STATE_UNCHANGED = 2, see plasma-desktop/kcms/keyboard/kcmmisc.h
const auto setting = config.readEntry("NumLock", 2);
const bool numLockIsOn = xkb_state_mod_index_is_active(m_state, m_numModifier, XKB_STATE_MODS_LOCKED);
if ((setting == 0 && !numLockIsOn) || (setting == 1 && numLockIsOn)) {
std::bitset<sizeof(xkb_mod_mask_t)*8> mask{m_modifierState.locked};
if (mask.size() > m_numModifier) {
mask[m_numModifier] = (setting == 0);
m_modifierState.locked = mask.to_ulong();
xkb_state_update_mask(m_state, m_modifierState.depressed, m_modifierState.latched, m_modifierState.locked, 0, 0, m_currentLayout);
m_modifierState.locked = xkb_state_serialize_mods(m_state, xkb_state_component(XKB_STATE_MODS_LOCKED));
}
}
}
}
createKeymapFile();
forwardModifiers();
updateModifiers();
}
void Xkb::createKeymapFile()
@ -344,6 +369,9 @@ void Xkb::updateModifiers()
if (xkb_state_mod_index_is_active(m_state, m_metaModifier, XKB_STATE_MODS_EFFECTIVE) == 1) {
mods |= Qt::MetaModifier;
}
if (xkb_state_mod_index_is_active(m_state, m_numModifier, XKB_STATE_MODS_EFFECTIVE) == 1) {
mods |= Qt::KeypadModifier;
}
m_modifiers = mods;
// update LEDs

11
xkb.h
View file

@ -58,6 +58,9 @@ public:
void setConfig(KSharedConfigPtr config) {
m_config = config;
}
void setNumLockConfig(KSharedConfigPtr config) {
m_numLockConfig = config;
}
void reconfigure();
void installKeymap(int fd, uint32_t size);
@ -130,6 +133,7 @@ private:
xkb_mod_index_t m_controlModifier;
xkb_mod_index_t m_altModifier;
xkb_mod_index_t m_metaModifier;
xkb_mod_index_t m_numModifier;
xkb_led_index_t m_numLock;
xkb_led_index_t m_capsLock;
xkb_led_index_t m_scrollLock;
@ -144,6 +148,7 @@ private:
} m_compose;
LEDs m_leds;
KSharedConfigPtr m_config;
KSharedConfigPtr m_numLockConfig;
struct {
xkb_mod_index_t depressed = 0;
@ -151,6 +156,12 @@ private:
xkb_mod_index_t locked = 0;
} m_modifierState;
enum class Ownership {
Server,
Client
};
Ownership m_ownership = Ownership::Server;
QPointer<KWayland::Server::SeatInterface> m_seat;
};