chromium/ash/webui/diagnostics_ui/backend/input/keyboard_input_data_event_watcher.cc

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/webui/diagnostics_ui/backend/input/keyboard_input_data_event_watcher.h"

#include <fcntl.h>
#include <linux/input.h>

#include <cstdint>
#include <memory>

#include "base/files/file_path.h"

namespace ash::diagnostics {

namespace {

const int kKeyReleaseValue = 0;

}  // namespace

KeyboardInputDataEventWatcher::KeyboardInputDataEventWatcher(
    uint32_t evdev_id,
    const base::FilePath& path,
    int fd,
    base::WeakPtr<KeyboardInputDataEventWatcher::Dispatcher> dispatcher)
    : InputDataEventWatcher(evdev_id, path, fd), dispatcher_(dispatcher) {}

KeyboardInputDataEventWatcher::KeyboardInputDataEventWatcher(
    uint32_t evdev_id,
    base::WeakPtr<KeyboardInputDataEventWatcher::Dispatcher> dispatcher)
    : InputDataEventWatcher(evdev_id), dispatcher_(dispatcher) {}

KeyboardInputDataEventWatcher::~KeyboardInputDataEventWatcher() = default;

// Once we have an entire keypress/release, dispatch it.
void KeyboardInputDataEventWatcher::ConvertKeyEvent(uint32_t key_code,
                                                    uint32_t key_state,
                                                    uint32_t scan_code) {
  bool down = key_state != kKeyReleaseValue;
  if (dispatcher_)
    dispatcher_->SendInputKeyEvent(this->evdev_id_, key_code, scan_code, down);
}

// Process evdev event structures directly from the kernel.
void KeyboardInputDataEventWatcher::ProcessEvent(const input_event& input) {
  // Accumulate relevant data about an event until a SYN_REPORT event releases
  // the full report. For more information, see kernel documentation for
  // input/event-codes.rst.
  switch (input.type) {
    case EV_MSC:
      if (input.code == MSC_SCAN)
        pending_scan_code_ = input.value;
      break;
    case EV_KEY:
      pending_key_code_ = input.code;
      pending_key_state_ = input.value;
      break;
    case EV_SYN:
      if (input.code == SYN_REPORT)
        ConvertKeyEvent(pending_key_code_, pending_key_state_,
                        pending_scan_code_);
      pending_key_code_ = 0;
      pending_key_state_ = 0;
      pending_scan_code_ = 0;
      break;
  }
}

}  // namespace ash::diagnostics