chromium/ui/events/ozone/evdev/libinput_event_converter.h

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

#ifndef UI_EVENTS_OZONE_EVDEV_LIBINPUT_EVENT_CONVERTER_H_
#define UI_EVENTS_OZONE_EVDEV_LIBINPUT_EVENT_CONVERTER_H_

#include <libinput.h>

#include <optional>
#include <ostream>

#include "ui/events/ozone/evdev/event_converter_evdev.h"

namespace ui {

class CursorDelegateEvdev;
class DeviceEventDispatcherEvdev;
class EventDeviceInfo;

// Use libinput (freedesktop.org/wiki/Software/libinput) to read events from
// old touchpads that are not supported by libgestures.
//
// Note that although libinput can read inputs from any number of devices, this
// implementation only attaches one device per libinput context.
class LibInputEventConverter : public EventConverterEvdev {
 public:
  // This class wraps the libinput_event struct from libinput library.
  class LibInputEvent {
   public:
    LibInputEvent(LibInputEvent&& other);
    explicit LibInputEvent(libinput_event* const event);
    LibInputEvent(const LibInputEvent& other) = delete;
    LibInputEvent& operator=(const LibInputEvent& other) = delete;
    ~LibInputEvent();

    libinput_event_pointer* PointerEvent() const;
    libinput_event_type Type() const;

   private:
    libinput_event* event_;
  };

  // This class wraps the libinput_device struct from libinput library.
  class LibInputDevice {
   public:
    LibInputDevice(int id, libinput_device* const device);
    LibInputDevice(LibInputDevice&& other);
    LibInputDevice(const LibInputDevice& other) = delete;
    LibInputDevice& operator=(const LibInputDevice& other) = delete;
    ~LibInputDevice();

    void ApplySettings(const InputDeviceSettingsEvdev& settings) const;

   private:
    std::string GetCapabilitiesString();

    void SetNaturalScrollEnabled(const bool enabled) const;
    void SetSensitivity(const int sensitivity) const;
    void SetTapToClickEnabled(const bool enabled) const;

    const int device_id_;
    libinput_device* device_;
  };

  // This class wraps the libinput struct from libinput library. Any operations
  // that uses libinput struct are implemented here.
  class LibInputContext {
   public:
    static std::optional<LibInputContext> Create();
    LibInputContext(LibInputContext&& other);
    LibInputContext(const LibInputContext& other) = delete;
    LibInputContext& operator=(const LibInputContext& other) = delete;
    ~LibInputContext();

    std::optional<LibInputEventConverter::LibInputDevice> AddDevice(
        int id,
        const base::FilePath& path) const;
    bool Dispatch() const;
    int Fd();
    std::optional<LibInputEventConverter::LibInputEvent> NextEvent() const;

   private:
    explicit LibInputContext(libinput* const li);

    static int OpenRestricted(const char* path, int flags, void* user_data);
    static void CloseRestricted(int fd, void* user_data);
    static void LogHandler(libinput* libinput,
                           enum libinput_log_priority priority,
                           const char* format,
                           va_list args);

    static constexpr libinput_interface interface_ = {OpenRestricted,
                                                      CloseRestricted};

    libinput* li_;
  };

  static std::unique_ptr<LibInputEventConverter> Create(
      const base::FilePath& path,
      int id,
      const EventDeviceInfo& devinfo,
      CursorDelegateEvdev* cursor,
      DeviceEventDispatcherEvdev* dispatcher);

  LibInputEventConverter(LibInputEventConverter::LibInputContext&& ctx,
                         const base::FilePath& path,
                         int id,
                         const EventDeviceInfo& devinfo,
                         CursorDelegateEvdev* cursor,
                         DeviceEventDispatcherEvdev* dispatcher);
  LibInputEventConverter(const LibInputEventConverter& other) = delete;
  LibInputEventConverter& operator=(const LibInputEventConverter& other) =
      delete;
  ~LibInputEventConverter() override;

  void ApplyDeviceSettings(const InputDeviceSettingsEvdev& settings) final;

  bool HasKeyboard() const final;

  bool HasMouse() const final;

  bool HasTouchpad() const final;

  bool HasTouchscreen() const final;

  std::ostream& DescribeForLog(std::ostream& os) const override;

 private:
  void OnFileCanReadWithoutBlocking(int fd) final;
  void HandleEvent(const LibInputEvent& event);
  void HandlePointerMotion(const LibInputEvent& evt);
  void HandlePointerButton(const LibInputEvent& evt);
  void HandlePointerAxis(const LibInputEvent& evt);
  base::TimeTicks Timestamp(const LibInputEvent& evt);

  DeviceEventDispatcherEvdev* const dispatcher_;
  CursorDelegateEvdev* const cursor_;

  const bool has_keyboard_;
  const bool has_mouse_;
  const bool has_touchpad_;
  const bool has_touchscreen_;

  const LibInputContext context_;
  const std::optional<LibInputDevice> device_;
};

}  // namespace ui

#endif  // UI_EVENTS_OZONE_EVDEV_LIBINPUT_EVENT_CONVERTER_H_