// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/exo/wayland/zcr_keyboard_extension.h"
#include <keyboard-extension-unstable-v1-server-protocol.h>
#include <wayland-server-core.h>
#include <wayland-server-protocol-core.h>
#include "base/memory/raw_ptr.h"
#include "components/exo/keyboard.h"
#include "components/exo/keyboard_observer.h"
#include "components/exo/wayland/serial_tracker.h"
#include "components/exo/wayland/server_util.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
namespace exo {
namespace wayland {
namespace {
////////////////////////////////////////////////////////////////////////////////
// extended_keyboard interface:
class WaylandExtendedKeyboardImpl : public KeyboardObserver {
public:
WaylandExtendedKeyboardImpl(wl_resource* resource,
SerialTracker* serial_tracker,
Keyboard* keyboard)
: resource_(resource),
serial_tracker_(serial_tracker),
keyboard_(keyboard) {
keyboard_->AddObserver(this);
keyboard_->SetNeedKeyboardKeyAcks(true);
}
WaylandExtendedKeyboardImpl(const WaylandExtendedKeyboardImpl&) = delete;
WaylandExtendedKeyboardImpl& operator=(const WaylandExtendedKeyboardImpl&) =
delete;
~WaylandExtendedKeyboardImpl() override {
if (keyboard_) {
keyboard_->RemoveObserver(this);
keyboard_->SetNeedKeyboardKeyAcks(false);
}
}
// Overridden from KeyboardObserver:
void OnKeyboardDestroying(Keyboard* keyboard) override {
DCHECK(keyboard_ == keyboard);
keyboard_ = nullptr;
}
void OnKeyboardKey(base::TimeTicks time_stamp,
ui::DomCode code,
bool pressed) override {
if (wl_resource_get_version(resource_) <
ZCR_EXTENDED_KEYBOARD_V1_PEEK_KEY_SINCE_VERSION) {
return;
}
uint32_t serial = serial_tracker_->MaybeNextKeySerial();
zcr_extended_keyboard_v1_send_peek_key(
resource_, serial, TimeTicksToMilliseconds(time_stamp),
ui::KeycodeConverter::DomCodeToEvdevCode(code),
pressed ? WL_KEYBOARD_KEY_STATE_PRESSED
: WL_KEYBOARD_KEY_STATE_RELEASED);
wl_client_flush(client());
}
void AckKeyboardKey(uint32_t serial, bool handled) {
if (keyboard_)
keyboard_->AckKeyboardKey(serial, handled);
}
private:
wl_client* client() const { return wl_resource_get_client(resource_); }
const raw_ptr<wl_resource> resource_;
const raw_ptr<SerialTracker> serial_tracker_;
raw_ptr<Keyboard> keyboard_;
};
void extended_keyboard_destroy(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
void extended_keyboard_ack_key(wl_client* client,
wl_resource* resource,
uint32_t serial,
uint32_t handled_state) {
GetUserDataAs<WaylandExtendedKeyboardImpl>(resource)->AckKeyboardKey(
serial, handled_state == ZCR_EXTENDED_KEYBOARD_V1_HANDLED_STATE_HANDLED);
}
const struct zcr_extended_keyboard_v1_interface
extended_keyboard_implementation = {extended_keyboard_destroy,
extended_keyboard_ack_key};
////////////////////////////////////////////////////////////////////////////////
// keyboard_extension interface:
void keyboard_extension_get_extended_keyboard(wl_client* client,
wl_resource* resource,
uint32_t id,
wl_resource* keyboard_resource) {
WaylandKeyboardExtension* keyboard_extension =
GetUserDataAs<WaylandKeyboardExtension>(resource);
Keyboard* keyboard = GetUserDataAs<Keyboard>(keyboard_resource);
if (keyboard->AreKeyboardKeyAcksNeeded()) {
wl_resource_post_error(
resource, ZCR_KEYBOARD_EXTENSION_V1_ERROR_EXTENDED_KEYBOARD_EXISTS,
"keyboard has already been associated with a extended_keyboard object");
return;
}
wl_resource* extended_keyboard_resource =
wl_resource_create(client, &zcr_extended_keyboard_v1_interface,
wl_resource_get_version(resource), id);
SetImplementation(extended_keyboard_resource,
&extended_keyboard_implementation,
std::make_unique<WaylandExtendedKeyboardImpl>(
extended_keyboard_resource,
keyboard_extension->serial_tracker, keyboard));
}
const struct zcr_keyboard_extension_v1_interface
keyboard_extension_implementation = {
keyboard_extension_get_extended_keyboard};
} // namespace
void bind_keyboard_extension(wl_client* client,
void* data,
uint32_t version,
uint32_t id) {
wl_resource* resource = wl_resource_create(
client, &zcr_keyboard_extension_v1_interface, version, id);
wl_resource_set_implementation(resource, &keyboard_extension_implementation,
data, nullptr);
}
} // namespace wayland
} // namespace exo