blob: aaccc89b58cf2001511666287d4cdef34364a7cb [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_HOST_LINUX_EI_KEYMAP_H_
#define REMOTING_HOST_LINUX_EI_KEYMAP_H_
#include <xkbcommon/xkbcommon.h>
#include <memory>
#include <set>
#include "base/functional/callback_forward.h"
#include "base/types/expected.h"
#include "remoting/host/base/pointer_utils.h"
#include "remoting/host/linux/fd_string_reader.h"
#include "remoting/proto/control.pb.h"
#include "third_party/libei/cipd/include/libei-1.0/libei.h"
#include "ui/events/keycodes/scoped_xkb.h"
namespace remoting {
// A keymap for a given keyboard ei_device. Per the documentation, this
// is constant for the lifetime of the device and can be cached.
class EiKeymap {
public:
using EiDevicePtr = CRefCounted<ei_device, ei_device_ref, ei_device_unref>;
explicit EiKeymap(EiDevicePtr keyboard);
EiKeymap(const EiKeymap&) = delete;
EiKeymap& operator=(const EiKeymap&) = delete;
~EiKeymap();
base::WeakPtr<EiKeymap> GetWeakPtr();
// Load the keymap from the specified device asynchronously. Errors are
// logged internally; the callback should check IsValid to see if the load
// succeeded.
void Load(base::OnceClosure callback);
bool IsValid() const;
xkb_keymap* Get();
const protocol::KeyboardLayout& GetLayoutProto() const;
struct Recipe {
explicit Recipe(uint32_t usb_code);
Recipe(const Recipe& other);
~Recipe();
// All values are USB keycodes.
uint32_t usb_code;
std::set<uint32_t> modifiers;
};
// Returns the USB keycode and modifiers for the specified codepoint. If
// the codepoint is not supported, sets usb_code to 0.
Recipe GetRecipeForCodepoint(uint32_t codepoint) const;
// Returns true if the specified USB keycode can safely be auto-repeated. This
// is a heuristic, as in principle an app could handle single vs. repeated
// keypresses any way it likes for any key, but it's a simple abstraction that
// allows us to suppress client-side auto-repeat for keys for which it is most
// likely to be unwanted without breaking the functionality of modifier keys.
bool CanAutoRepeatUsbCode(uint32_t usb_code) const;
private:
struct UsbCodeAndShiftLevel { uint32_t usb_code; int shift_level; };
void OnKeymapLoaded(base::OnceClosure callback,
base::expected<std::string, Loggable> result);
static void ProcessKey(xkb_keymap* keymap,
xkb_keycode_t keycode,
void* data);
EiDevicePtr keyboard_;
std::unique_ptr<FdStringReader> reader_;
std::unique_ptr<xkb_keymap, ui::XkbKeymapDeleter> keymap_;
std::unique_ptr<xkb_state, ui::XkbStateDeleter> xkb_state_;
protocol::KeyboardLayout layout_proto_;
std::map<int, int> shift_level_to_mask_;
uint32_t shift_key_usb_code_;
uint32_t altgr_key_usb_code_;
std::map<uint32_t, UsbCodeAndShiftLevel> codepoint_to_usb_code_and_shift_level_;
std::set<uint32_t> idempotent_usb_codes_;
base::WeakPtrFactory<EiKeymap> weak_factory_{this};
};
} // namespace remoting
#endif // REMOTING_HOST_LINUX_EI_KEYMAP_H_