| // 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_ |