File: EvdevInjector.h

package info (click to toggle)
android-platform-tools 34.0.5-12
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 150,900 kB
  • sloc: cpp: 805,786; java: 293,500; ansic: 128,288; xml: 127,491; python: 41,481; sh: 14,245; javascript: 9,665; cs: 3,846; asm: 2,049; makefile: 1,917; yacc: 440; awk: 368; ruby: 183; sql: 140; perl: 88; lex: 67
file content (148 lines) | stat: -rw-r--r-- 5,031 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#ifndef ANDROID_DVR_EVDEV_INJECTOR_H
#define ANDROID_DVR_EVDEV_INJECTOR_H

#include <android-base/unique_fd.h>
#include <linux/uinput.h>
#include <utils/String8.h>

#include <cstdint>
#include <memory>
#include <unordered_set>

namespace android {
namespace dvr {

// Simulated evdev input device.
//
class EvdevInjector {
 public:
  // EvdevInjector-specific error codes are negative integers; other non-zero
  // values returned from public routines are |errno| codes from underlying I/O.
  // EvdevInjector maintains a 'sticky' error state, similar to |errno|, so that
  // a caller can perform a sequence of operations and check for errors at the
  // end using |GetError()|. In general, the first such error will be recorded
  // and will suppress effects of further device operations until |ResetError()|
  // is called.
  //
  enum : int {
    ERROR_DEVICE_NAME = -1,     // Invalid device name.
    ERROR_PROPERTY_RANGE = -2,  // |INPUT_PROP_*| code out of range.
    ERROR_KEY_RANGE = -3,       // |KEY_*|/|BTN_*| code out of range.
    ERROR_ABS_RANGE = -4,       // |ABS_*| code out of range.
    ERROR_SEQUENCING = -5,      // Configure/Send out of order.
    ERROR_REL_RANGE = -6,       // |REL_*| code out of range.
  };

  // Key event |value| is not defined in <linux/input.h>.
  enum : int32_t { KEY_RELEASE = 0, KEY_PRESS = 1, KEY_REPEAT = 2 };

  // UInput provides a shim to intercept /dev/uinput operations
  // just above the system call level, for testing.
  //
  class UInput {
   public:
    UInput() {}
    virtual ~UInput() {}
    virtual int Open();
    virtual int Close();
    virtual int Write(const void* buf, size_t count);
    virtual int IoctlVoid(int request);
    virtual int IoctlSetInt(int request, int value);

   private:
    base::unique_fd fd_;
  };

  EvdevInjector() {}
  ~EvdevInjector() { Close(); }
  void Close();

  int GetError() const { return error_; }
  void ResetError() { error_ = 0; }

  // Configuration must be performed before sending any events.
  // |ConfigureBegin()| must be called first, and |ConfigureEnd()| last,
  // with zero or more other |Configure...()| calls in between in any order.

  // Configure the basic evdev device properties; must be called first.
  int ConfigureBegin(const char* device_name, int16_t bustype, int16_t vendor,
                     int16_t product, int16_t version);

  // Configure an optional input device property.
  // @param property  One of the |INPUT_PROP_*| constants from <linux/input.h>.
  int ConfigureInputProperty(int property);

  // Configure an input key.
  // @param key One of the |KEY_*| or |BTN_*| constants from <linux/input.h>.
  int ConfigureKey(uint16_t key);

  // Configure an absolute axis.
  // @param abs_type One of the |KEY_*| or |BTN_*| constants from
  // <linux/input.h>.
  int ConfigureAbs(uint16_t abs_type, int32_t min, int32_t max, int32_t fuzz,
                   int32_t flat);

  // Configure the number of multitouch slots.
  int ConfigureAbsSlots(int slots);

  // Configure multitouch coordinate range.
  int ConfigureMultiTouchXY(int32_t x0, int32_t y0, int32_t x1, int32_t y1);

  // Configure a relative axis.
  // @param rel_type One of the |REL_*| constants from <linux/input.h>.
  int ConfigureRel(uint16_t rel_type);

  // Complete configuration and create the input device.
  int ConfigureEnd();

  // Send various events.
  //
  int Send(uint16_t type, uint16_t code, int32_t value);
  int SendSynReport();
  int SendKey(uint16_t code, int32_t value);
  int SendAbs(uint16_t code, int32_t value);
  int SendRel(uint16_t code, int32_t value);
  int SendMultiTouchSlot(int32_t slot);
  int SendMultiTouchXY(int32_t slot, int32_t id, int32_t x, int32_t y);
  int SendMultiTouchLift(int32_t slot);

  void dumpInternal(String8& result);

 protected:
  // Must be called only between construction and ConfigureBegin().
  inline void SetUInputForTesting(UInput* uinput) { uinput_ = uinput; }
  // Caller must not retain pointer longer than EvdevInjector.
  inline const uinput_user_dev* GetUiDevForTesting() const { return &uidev_; }

 private:
  // Phase to enforce that configuration is complete before events are sent.
  enum class State { NEW, CONFIGURING, READY, CLOSED };

  // Sets |error_| if it is not already set; returns |code|.
  int Error(int code);

  // Returns a nonzero error if the injector is not in the required |state|.
  int RequireState(State state);

  // Configures an event type if necessary.
  // @param type One of the |EV_*| constants from <linux/input.h>.
  int EnableEventType(uint16_t type);

  // Active pointer to owned or testing UInput.
  UInput* uinput_ = nullptr;
  std::unique_ptr<UInput> owned_uinput_;

  State state_ = State::NEW;
  int error_ = 0;
  uinput_user_dev uidev_;
  std::unordered_set<uint16_t> enabled_event_types_;
  int32_t latest_slot_ = -1;

  EvdevInjector(const EvdevInjector&) = delete;
  void operator=(const EvdevInjector&) = delete;
};

}  // namespace dvr
}  // namespace android

#endif  // ANDROID_DVR_EVDEV_INJECTOR_H