blob: 8cacd5e8c53f4daec48cba6fa7796d4f1a21291c [file] [log] [blame]
// 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.
#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)
// 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 {
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);
// 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>
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 {
zx_status_t Setup(async_dispatcher_t* dispatcher, keypress_handler_t handler, bool repeat_keys);
// 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; }
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};