#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 {
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();
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();
uint32_t usb_code;
std::set<uint32_t> modifiers;
};
Recipe GetRecipeForCodepoint(uint32_t codepoint) const;
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};
};
}
#endif