/* SPDX-FileCopyrightText: 2014 Martin Gräßlin SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "display.h" #include "keyboard_p.h" #include "seat.h" #include "seat_p.h" #include "surface.h" #include "utils/common.h" // Qt #include #include namespace KWin { KeyboardInterfacePrivate::KeyboardInterfacePrivate(SeatInterface *s) : seat(s) { } void KeyboardInterfacePrivate::keyboard_release(Resource *resource) { wl_resource_destroy(resource->handle); } void KeyboardInterfacePrivate::keyboard_bind_resource(Resource *resource) { const ClientConnection *focusedClient = focusedSurface ? focusedSurface->client() : nullptr; if (resource->version() >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) { send_repeat_info(resource->handle, keyRepeat.charactersPerSecond, keyRepeat.delay); } if (!keymap.isNull()) { sendKeymap(resource); } if (focusedClient && focusedClient->client() == resource->client()) { const QList keys = pressedKeys(); const QByteArray keysData = QByteArray::fromRawData(reinterpret_cast(keys.data()), sizeof(quint32) * keys.count()); const quint32 serial = seat->display()->nextSerial(); send_enter(resource->handle, serial, focusedSurface->resource(), keysData); send_modifiers(resource->handle, serial, modifiers.depressed, modifiers.latched, modifiers.locked, modifiers.group); } } QList KeyboardInterfacePrivate::keyboardsForClient(ClientConnection *client) const { return resourceMap().values(client->client()); } void KeyboardInterfacePrivate::sendLeave(SurfaceInterface *surface, quint32 serial) { const QList keyboards = keyboardsForClient(surface->client()); for (Resource *keyboardResource : keyboards) { send_leave(keyboardResource->handle, serial, surface->resource()); } } void KeyboardInterfacePrivate::sendEnter(SurfaceInterface *surface, quint32 serial) { const auto states = pressedKeys(); QByteArray data = QByteArray::fromRawData(reinterpret_cast(states.constData()), sizeof(quint32) * states.size()); const QList keyboards = keyboardsForClient(surface->client()); for (Resource *keyboardResource : keyboards) { send_enter(keyboardResource->handle, serial, surface->resource(), data); } } void KeyboardInterfacePrivate::sendKeymap(Resource *resource) { // From version 7 on, keymaps must be mapped privately, so that // we can seal the fd and reuse it between clients. if (resource->version() >= 7 && sharedKeymapFile.effectiveFlags().testFlag(RamFile::Flag::SealWrite)) { send_keymap(resource->handle, keymap_format::keymap_format_xkb_v1, sharedKeymapFile.fd(), sharedKeymapFile.size()); // otherwise give each client its own unsealed copy. } else { RamFile keymapFile("kwin-xkb-keymap", keymap.constData(), keymap.size() + 1); // Include QByteArray null-terminator. send_keymap(resource->handle, keymap_format::keymap_format_xkb_v1, keymapFile.fd(), keymapFile.size()); } } void KeyboardInterface::setKeymap(const QByteArray &content) { if (content.isNull()) { return; } d->keymap = content; // +1 to include QByteArray null terminator. d->sharedKeymapFile = RamFile("kwin-xkb-keymap-shared", content.constData(), content.size() + 1, RamFile::Flag::SealWrite); const auto keyboardResources = d->resourceMap(); for (KeyboardInterfacePrivate::Resource *resource : keyboardResources) { d->sendKeymap(resource); } } void KeyboardInterfacePrivate::sendModifiers(SurfaceInterface *surface, quint32 depressed, quint32 latched, quint32 locked, quint32 group, quint32 serial) { const QList keyboards = keyboardsForClient(surface->client()); for (Resource *keyboardResource : keyboards) { send_modifiers(keyboardResource->handle, serial, depressed, latched, locked, group); } } bool KeyboardInterfacePrivate::updateKey(quint32 key, KeyboardKeyState state) { auto it = states.find(key); if (it == states.end()) { states.insert(key, state); return true; } if (it.value() == state) { return false; } it.value() = state; return true; } KeyboardInterface::KeyboardInterface(SeatInterface *seat) : d(new KeyboardInterfacePrivate(seat)) { } KeyboardInterface::~KeyboardInterface() = default; void KeyboardInterfacePrivate::sendModifiers(SurfaceInterface *surface) { sendModifiers(surface, modifiers.depressed, modifiers.latched, modifiers.locked, modifiers.group, modifiers.serial); } void KeyboardInterface::setFocusedSurface(SurfaceInterface *surface, quint32 serial) { if (d->focusedSurface == surface) { return; } if (d->focusedSurface) { d->sendLeave(d->focusedSurface, serial); disconnect(d->destroyConnection); } d->focusedSurface = surface; if (!d->focusedSurface) { return; } d->destroyConnection = connect(d->focusedSurface, &SurfaceInterface::aboutToBeDestroyed, this, [this] { d->sendLeave(d->focusedSurface, d->seat->display()->nextSerial()); d->focusedSurface = nullptr; }); d->sendEnter(d->focusedSurface, serial); d->sendModifiers(d->focusedSurface); } void KeyboardInterface::setModifierFocusSurface(SurfaceInterface *surface) { if (d->modifierFocusSurface == surface) { return; } d->modifierFocusSurface = surface; if (d->modifierFocusSurface && d->focusedSurface != d->modifierFocusSurface) { d->modifiers.serial = d->seat->display()->nextSerial(); d->sendModifiers(d->modifierFocusSurface); } } QList KeyboardInterfacePrivate::pressedKeys() const { QList keys; for (auto it = states.constBegin(); it != states.constEnd(); ++it) { if (it.value() == KeyboardKeyState::Pressed) { keys << it.key(); } } return keys; } void KeyboardInterface::sendKey(quint32 key, KeyboardKeyState state, ClientConnection *client) { const QList keyboards = d->keyboardsForClient(client); const quint32 serial = d->seat->display()->nextSerial(); for (KeyboardInterfacePrivate::Resource *keyboardResource : keyboards) { d->send_key(keyboardResource->handle, serial, d->seat->timestamp().count(), key, quint32(state)); } } void KeyboardInterface::sendKey(quint32 key, KeyboardKeyState state) { if (!d->updateKey(key, state)) { return; } if (!d->focusedSurface) { return; } sendKey(key, state, d->focusedSurface->client()); } void KeyboardInterface::sendModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group) { bool changed = false; if (d->modifiers.depressed != depressed) { d->modifiers.depressed = depressed; changed = true; } if (d->modifiers.latched != latched) { d->modifiers.latched = latched; changed = true; } if (d->modifiers.locked != locked) { d->modifiers.locked = locked; changed = true; } if (d->modifiers.group != group) { d->modifiers.group = group; changed = true; } if (!changed) { return; } if (d->focusedSurface) { d->modifiers.serial = d->seat->display()->nextSerial(); d->sendModifiers(d->focusedSurface, depressed, latched, locked, group, d->modifiers.serial); } if (d->modifierFocusSurface && d->focusedSurface != d->modifierFocusSurface) { d->modifiers.serial = d->seat->display()->nextSerial(); d->sendModifiers(d->modifierFocusSurface, depressed, latched, locked, group, d->modifiers.serial); } } void KeyboardInterface::setRepeatInfo(qint32 charactersPerSecond, qint32 delay) { d->keyRepeat.charactersPerSecond = std::max(charactersPerSecond, 0); d->keyRepeat.delay = std::max(delay, 0); const auto keyboards = d->resourceMap(); for (KeyboardInterfacePrivate::Resource *keyboardResource : keyboards) { if (keyboardResource->version() >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) { d->send_repeat_info(keyboardResource->handle, d->keyRepeat.charactersPerSecond, d->keyRepeat.delay); } } } SurfaceInterface *KeyboardInterface::focusedSurface() const { return d->focusedSurface; } qint32 KeyboardInterface::keyRepeatDelay() const { return d->keyRepeat.delay; } qint32 KeyboardInterface::keyRepeatRate() const { return d->keyRepeat.charactersPerSecond; } } #include "moc_keyboard.cpp"