Support LEDs in Xkb and libinput

Summary:
The Xkb implementation starts to track the state of the LEDs in the
keymap and emits a signal whenever the LEDs change. This signal is
connected to a method in LibInput::Connection which updates the led
state on all devices and uses it to init the state of the led when a new
device gets connected.

BUG: 369214
FIXED-IN: 5.8.2

Test Plan: Connected a keyboard with LEDs and enabled NumLock and ScrollLock.

Reviewers: #kwin, #plasma_on_wayland

Subscribers: plasma-devel, kwin

Tags: #plasma_on_wayland, #kwin

Differential Revision: https://phabricator.kde.org/D2943
icc-effect-5.14.5
Martin Gräßlin 2016-10-05 11:50:20 +02:00
parent 1c3cc6239e
commit 4c7752c965
5 changed files with 87 additions and 0 deletions

View File

@ -1233,7 +1233,9 @@ void InputRedirection::setupLibInput()
m_libInput = conn;
if (conn) {
conn->setInputConfig(m_inputConfig);
conn->updateLEDs(m_keyboard->xkb()->leds());
conn->setup();
connect(m_keyboard, &KeyboardInputRedirection::ledsChanged, conn, &LibInput::Connection::updateLEDs);
connect(conn, &LibInput::Connection::eventsRead, this,
[this] {
m_libInput->processEvents();

View File

@ -90,10 +90,15 @@ Xkb::Xkb(InputRedirection *input)
, m_controlModifier(0)
, m_altModifier(0)
, m_metaModifier(0)
, m_numLock(0)
, m_capsLock(0)
, m_scrollLock(0)
, m_modifiers(Qt::NoModifier)
, m_consumedModifiers(Qt::NoModifier)
, m_keysym(XKB_KEY_NoSymbol)
, m_leds()
{
qRegisterMetaType<KWin::Xkb::LEDs>();
if (!m_context) {
qCDebug(KWIN_XKB) << "Could not create xkb context";
} else {
@ -219,6 +224,11 @@ 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_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);
m_scrollLock = xkb_keymap_led_get_index(m_keymap, XKB_LED_NAME_SCROLL);
m_currentLayout = xkb_state_serialize_layout(m_state, XKB_STATE_LAYOUT_EFFECTIVE);
createKeymapFile();
@ -346,6 +356,23 @@ void Xkb::updateModifiers()
mods |= Qt::MetaModifier;
}
m_modifiers = mods;
// update LEDs
LEDs leds;
if (xkb_state_led_index_is_active(m_state, m_numLock) == 1) {
leds = leds | LED::NumLock;
}
if (xkb_state_led_index_is_active(m_state, m_capsLock) == 1) {
leds = leds | LED::CapsLock;
}
if (xkb_state_led_index_is_active(m_state, m_scrollLock) == 1) {
leds = leds | LED::ScrollLock;
}
if (m_leds != leds) {
m_leds = leds;
emit m_input->keyboard()->ledsChanged(m_leds);
}
const xkb_layout_index_t layout = xkb_state_serialize_layout(m_state, XKB_STATE_LAYOUT_EFFECTIVE);
if (layout != m_currentLayout) {
m_currentLayout = layout;

View File

@ -36,6 +36,7 @@ struct xkb_state;
struct xkb_compose_table;
struct xkb_compose_state;
typedef uint32_t xkb_mod_index_t;
typedef uint32_t xkb_led_index_t;
typedef uint32_t xkb_keysym_t;
namespace KWin
@ -71,6 +72,16 @@ public:
void switchToNextLayout();
enum class LED {
NumLock = 1 << 0,
CapsLock = 1 << 1,
ScrollLock = 1 << 2
};
Q_DECLARE_FLAGS(LEDs, LED)
LEDs leds() const {
return m_leds;
}
private:
xkb_keymap *loadKeymapFromConfig();
xkb_keymap *loadDefaultKeymap();
@ -87,6 +98,9 @@ private:
xkb_mod_index_t m_controlModifier;
xkb_mod_index_t m_altModifier;
xkb_mod_index_t m_metaModifier;
xkb_led_index_t m_numLock;
xkb_led_index_t m_capsLock;
xkb_led_index_t m_scrollLock;
Qt::KeyboardModifiers m_modifiers;
Qt::KeyboardModifiers m_consumedModifiers;
xkb_keysym_t m_keysym;
@ -100,6 +114,7 @@ private:
xkb_compose_table *table = nullptr;
xkb_compose_state *state = nullptr;
} m_compose;
LEDs m_leds;
};
class KeyboardInputRedirection : public QObject
@ -133,6 +148,9 @@ public:
return m_xkb->modifiers();
}
Q_SIGNALS:
void ledsChanged(KWin::Xkb::LEDs);
private Q_SLOTS:
void reconfigure();
@ -156,4 +174,7 @@ Qt::KeyboardModifiers Xkb::modifiers() const
}
Q_DECLARE_METATYPE(KWin::Xkb::LED)
Q_DECLARE_METATYPE(KWin::Xkb::LEDs)
#endif

View File

@ -47,6 +47,21 @@ QThread *Connection::s_thread = nullptr;
static Context *s_context = nullptr;
static quint32 toLibinputLEDS(Xkb::LEDs leds)
{
quint32 libinputLeds = 0;
if (leds.testFlag(Xkb::LED::NumLock)) {
libinputLeds = libinputLeds | LIBINPUT_LED_NUM_LOCK;
}
if (leds.testFlag(Xkb::LED::CapsLock)) {
libinputLeds = libinputLeds | LIBINPUT_LED_CAPS_LOCK;
}
if (leds.testFlag(Xkb::LED::ScrollLock)) {
libinputLeds = libinputLeds | LIBINPUT_LED_SCROLL_LOCK;
}
return libinputLeds;
}
Connection::Connection(QObject *parent)
: Connection(nullptr, parent)
{
@ -95,6 +110,7 @@ Connection::Connection(Context *input, QObject *parent)
, m_input(input)
, m_notifier(nullptr)
, m_mutex(QMutex::Recursive)
, m_leds()
{
Q_ASSERT(m_input);
@ -246,6 +262,10 @@ void Connection::processEvents()
}
}
applyDeviceConfig(device);
// enable possible leds
libinput_device_led_update(device->device(), static_cast<libinput_led>(toLibinputLEDS(m_leds)));
emit deviceAdded(device);
break;
}
@ -513,5 +533,18 @@ void Connection::toggleTouchpads()
}
}
void Connection::updateLEDs(Xkb::LEDs leds)
{
if (m_leds == leds) {
return;
}
m_leds = leds;
// update on devices
const libinput_led l = static_cast<libinput_led>(toLibinputLEDS(leds));
for (auto it = m_devices.constBegin(), end = m_devices.constEnd(); it != end; ++it) {
libinput_device_led_update((*it)->device(), l);
}
}
}
}

View File

@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define KWIN_LIBINPUT_CONNECTION_H
#include "../input.h"
#include "../keyboard_input.h"
#include <kwinglobals.h>
#include <QObject>
@ -82,6 +83,8 @@ public:
return m_devices;
}
void updateLEDs(KWin::Xkb::LEDs leds);
Q_SIGNALS:
void keyChanged(quint32 key, KWin::InputRedirection::KeyboardKeyState, quint32 time, KWin::LibInput::Device *device);
void pointerButtonChanged(quint32 button, KWin::InputRedirection::PointerButtonState state, quint32 time, KWin::LibInput::Device *device);
@ -135,6 +138,7 @@ private:
QVector<Device*> m_devices;
KSharedConfigPtr m_config;
bool m_touchpadsEnabled = true;
Xkb::LEDs m_leds;
KWIN_SINGLETON(Connection)
static QThread *s_thread;