blob: dc0ba9ab9f859cbf3424bcf1bf29496c4fb2063a [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MINIOS_KEY_READER_H_
#define MINIOS_KEY_READER_H_
#include <linux/input.h>
#include <memory>
#include <string>
#include <vector>
#include <base/files/file_descriptor_watcher_posix.h>
#include <base/files/file_util.h>
#include <base/files/scoped_file.h>
#include <xkbcommon/xkbcommon.h>
#include "minios/process_manager.h"
namespace minios {
constexpr int kMaxInputLength = 64;
// Increasing `kBackspaceSensitivity` will slow backspace speed.
constexpr int kBackspaceSensitivity = 2;
// Key values.
extern const int kKeyUp;
extern const int kKeyDown;
extern const int kKeyEnter;
// Key values for detachable.
extern const int kKeyVolUp;
extern const int kKeyVolDown;
extern const int kKeyPower;
// Key state parameters.
extern const int kFdsMax;
extern const int kKeyMax;
class KeyReader {
public:
// Default constructor can only access EvWaitForKeys.
explicit KeyReader(bool include_usb);
KeyReader(bool include_usb, std::string keyboard_layout);
~KeyReader();
class Delegate {
public:
// Keeps track of key states based on the file descriptor index and whether
// the key event is a key press or key release event as given by
// `key_released`. `key_changed` is the ev code for the key. Only records
// key state for valid keys.
virtual void OnKeyPress(int fd_index,
int key_changed,
bool key_released) = 0;
};
// Initializes the `epfd_` and sets the callback. Listens for input keys based
// on whether the device is detachable or not. Returns false on error.
bool Init(const std::vector<int>& valid_keys);
void SetDelegate(Delegate* delegate) { delegate_ = delegate; }
// Creates the correct keyboard layout for a given country code.
// Returns false for invalid keyboard layout, true otherwise.
bool SetKeyboardContext();
// Given a key code, does all the setup finding the available fds and events
// and creating the proper keyboard layout.
bool InputSetUp();
// In order to be able to display the string as users are typing,
// `GetUserInput` returns every time a char is added to the string buffer, but
// only returns with true once the enter key is pressed. Press tab to toggle
// between showing and hiding passwords. This is a blocking call, and any
// active watchers must be disabled for the duration of this function.
bool GetUserInput(bool* enter, bool* tab_toggle, std::string* user_input);
// Sets the watcher to the `epfd`, has a callback to `OnKeyEvent`.
bool StartWatcher();
// Stops the watcher.
void StopWatcher();
// Wrapper that does not take in tab toggle key. Used for testing.
bool GetCharForTest(const struct input_event& ev);
// Returns the current key input as a string. Used for testing.
std::string GetUserInputForTest();
private:
// Checks whether all the keys in `keys_` are supported by the fd. Returns
// false on failure.
bool SupportsAllKeys(const int fd);
// Checks all the valid files under `kDevInputEvent`, stores the valid
// keyboard devices to `fds_`. Will check if all keys are supported if input
// is true. Returns false if there are no available file descriptors.
virtual bool GetValidFds(bool check_supported_keys);
// Creates the epoll and gets event data. Sets epoll file descriptor and on
// returns true on success.
virtual bool EpollCreate(base::ScopedFD* epfd);
// Waits for a valid key event and reads it into the input event struct. Sets
// fd index and returns true on success.
virtual bool GetEpEvent(int epfd, struct input_event* ev, int* index);
// Get epoll event using `GetEpEvent`. If the event is a key event and is for
// a valid key, it and calls the Delegate `OnKeyPress` function to modify the
// screen and index.
virtual void OnKeyEvent();
// GetChar takes in an input event and adds to user input if the key press
// is a valid, printable ASCII. Pressing tab key toggles boolean. Returns
// false after enter key press, true otherwise.
bool GetChar(const struct input_event& ev, bool* tab_toggle);
std::string user_input_;
// Counts and aggregates repeated backspace key events.
int backspace_counter_;
// Checks that enter key down was recorded before returning on key up.
bool return_pressed_;
// Whether or not to include USB connections when scanning for events.
bool include_usb_;
// Keyboard layout for xkb common;
std::string keyboard_layout_;
// Stores open event connections.
std::vector<base::ScopedFD> fds_;
// Stores epoll file descriptor.
base::ScopedFD epfd_;
// Watches the epoll file descriptor and calls `OnKeyEvent`.
std::unique_ptr<base::FileDescriptorWatcher::Controller> watcher_;
// Allows class to only access the `EvWaitForKey` function. `GetInput` will
// return false.
bool use_only_evwaitkey_;
// A list of keys to listen for on the blocking call.
std::vector<int> keys_;
Delegate* delegate_;
// XKB common keyboard layout members.
struct xkb_context* ctx_{nullptr};
struct xkb_rule_names names_;
struct xkb_keymap* keymap_{nullptr};
struct xkb_state* state_{nullptr};
};
} // namespace minios
#endif // MINIOS_KEY_READER_H_