| // Copyright 2017 The Fuchsia 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 SRC_BRINGUP_BIN_VIRTCON_KEYBOARD_H_ |
| #define SRC_BRINGUP_BIN_VIRTCON_KEYBOARD_H_ |
| |
| #include <fuchsia/input/report/llcpp/fidl.h> |
| #include <fuchsia/io/llcpp/fidl.h> |
| #include <lib/async/cpp/task.h> |
| #include <lib/async/cpp/wait.h> |
| #include <lib/fdio/cpp/caller.h> |
| #include <lib/zx/timer.h> |
| #include <stdint.h> |
| #include <zircon/types.h> |
| |
| #include <array> |
| #include <optional> |
| |
| #include "vc.h" |
| |
| #define MOD_LSHIFT (1 << 0) |
| #define MOD_RSHIFT (1 << 1) |
| #define MOD_LALT (1 << 2) |
| #define MOD_RALT (1 << 3) |
| #define MOD_LCTRL (1 << 4) |
| #define MOD_RCTRL (1 << 5) |
| #define MOD_CAPSLOCK (1 << 6) |
| |
| #define MOD_SHIFT (MOD_LSHIFT | MOD_RSHIFT) |
| #define MOD_ALT (MOD_LALT | MOD_RALT) |
| #define MOD_CTRL (MOD_LCTRL | MOD_RCTRL) |
| |
| // Global function which sets up the global keyboard watcher. |
| zx_status_t setup_keyboard_watcher(async_dispatcher_t* dispatcher, keypress_handler_t handler, |
| bool repeat_keys); |
| |
| // A |Keyboard| is created with a callback to handle keypresses. |
| // The Keyboard is responsible for watching the keyboard device, parsing |
| // events, handling key-repeats/modifiers, and sending keypresses to |
| // the |keypress_handler_t|. |
| class Keyboard { |
| public: |
| Keyboard(async_dispatcher_t* dispatcher, keypress_handler_t handler, bool repeat_keys) |
| : dispatcher_(dispatcher), handler_(handler), repeat_enabled_(repeat_keys) {} |
| |
| // Have the keyboard start watching a given device. |
| // |caller| represents the keyboard device. |
| zx_status_t Setup(fidl::WireSyncClient<fuchsia_input_report::InputDevice> keyboard_client); |
| |
| // Process a given set of keys and send them to the handler. |
| void ProcessInput(const fuchsia_input_report::wire::InputReport& report); |
| |
| private: |
| // The callback for when key-repeat is triggered. |
| void TimerCallback(async_dispatcher_t* dispatcher, async::TaskBase* task, zx_status_t status); |
| void InputCallback(fuchsia_input_report::wire::InputReportsReaderReadInputReportsResult result); |
| |
| // This is the callback if reader_client_ is unbound. This tries to reconnect and |
| // will delete Keyboard if reconnecting fails. |
| void InputReaderUnbound(fidl::UnbindInfo info); |
| |
| // Attempt to connect to an InputReportsReader and start a ReadInputReports call. |
| zx_status_t StartReading(); |
| |
| // Send a report to the device that enables/disables the capslock LED. |
| void SetCapsLockLed(bool caps_lock); |
| |
| async_dispatcher_t* dispatcher_; |
| async::TaskMethod<Keyboard, &Keyboard::TimerCallback> timer_task_{this}; |
| |
| keypress_handler_t handler_ = {}; |
| |
| zx::duration repeat_interval_ = zx::duration::infinite(); |
| std::optional<fidl::WireSyncClient<fuchsia_input_report::InputDevice>> keyboard_client_; |
| fidl::Client<fuchsia_input_report::InputReportsReader> reader_client_; |
| |
| int modifiers_ = 0; |
| bool repeat_enabled_ = true; |
| bool is_repeating_ = false; |
| uint8_t repeating_keycode_; |
| std::array<fuchsia_input::wire::Key, fuchsia_input_report::wire::kKeyboardMaxPressedKeys> |
| last_pressed_keys_; |
| size_t last_pressed_keys_size_ = 0; |
| }; |
| |
| // A |KeyboardWatcher| opens a directory and will watch for new input devices. |
| // It will create a |Keyboard| for each input device that is a keyboard. |
| class KeyboardWatcher { |
| public: |
| zx_status_t Setup(async_dispatcher_t* dispatcher, keypress_handler_t handler, bool repeat_keys); |
| |
| private: |
| // Callback when a new file is created in the directory. |
| void DirCallback(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status, |
| const zx_packet_signal_t* signal); |
| |
| // Attempts to open the file and create a new Keyboard. |
| zx_status_t OpenFile(uint8_t evt, char* name); |
| |
| // The channel representing the directory this is watching. |
| fidl::UnownedClientEnd<fuchsia_io::Directory> Directory() { return dir_caller_.directory(); } |
| |
| bool repeat_keys_ = true; |
| keypress_handler_t handler_ = {}; |
| |
| fdio_cpp::FdioCaller dir_caller_; |
| async_dispatcher_t* dispatcher_ = nullptr; |
| async::WaitMethod<KeyboardWatcher, &KeyboardWatcher::DirCallback> dir_wait_{this}; |
| }; |
| |
| #endif // SRC_BRINGUP_BIN_VIRTCON_KEYBOARD_H_ |