blob: 03c81126dd17c363869811173a40fff80761b334 [file] [log] [blame]
Jeff Browne839a582010-04-22 18:58:52 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef _UI_INPUT_READER_H
18#define _UI_INPUT_READER_H
19
20#include <ui/EventHub.h>
21#include <ui/Input.h>
Jeff Browne839a582010-04-22 18:58:52 -070022#include <ui/InputDispatcher.h>
23#include <utils/KeyedVector.h>
24#include <utils/threads.h>
25#include <utils/Timers.h>
26#include <utils/RefBase.h>
27#include <utils/String8.h>
28#include <utils/BitSet.h>
29
30#include <stddef.h>
31#include <unistd.h>
32
33/* Maximum pointer id value supported.
34 * (This is limited by our use of BitSet32 to track pointer assignments.) */
35#define MAX_POINTER_ID 32
36
Jeff Browne839a582010-04-22 18:58:52 -070037/* Maximum number of historical samples to average. */
38#define AVERAGING_HISTORY_SIZE 5
39
40
41namespace android {
42
43extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState);
44extern int32_t rotateKeyCode(int32_t keyCode, int32_t orientation);
45
46/*
47 * An input device structure tracks the state of a single input device.
48 *
49 * This structure is only used by ReaderThread and is not intended to be shared with
50 * DispatcherThread (because that would require locking). This works out fine because
51 * DispatcherThread is only interested in cooked event data anyways and does not need
52 * any of the low-level data from InputDevice.
53 */
54struct InputDevice {
55 struct AbsoluteAxisInfo {
Jeff Brown4036f7f2010-06-29 16:52:21 -070056 bool valid; // set to true if axis parameters are known, false otherwise
57
Jeff Browne839a582010-04-22 18:58:52 -070058 int32_t minValue; // minimum value
59 int32_t maxValue; // maximum value
60 int32_t range; // range of values, equal to maxValue - minValue
61 int32_t flat; // center flat position, eg. flat == 8 means center is between -8 and 8
62 int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise
63 };
64
65 struct VirtualKey {
66 int32_t keyCode;
67 int32_t scanCode;
68 uint32_t flags;
69
70 // computed hit box, specified in touch screen coords based on known display size
71 int32_t hitLeft;
72 int32_t hitTop;
73 int32_t hitRight;
74 int32_t hitBottom;
75
76 inline bool isHit(int32_t x, int32_t y) const {
77 return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom;
78 }
79 };
80
81 struct KeyboardState {
82 struct Current {
83 int32_t metaState;
84 nsecs_t downTime; // time of most recent key down
85 } current;
86
87 void reset();
88 };
89
90 struct TrackballState {
91 struct Accumulator {
92 enum {
93 FIELD_BTN_MOUSE = 1,
94 FIELD_REL_X = 2,
95 FIELD_REL_Y = 4
96 };
97
98 uint32_t fields;
99
100 bool btnMouse;
101 int32_t relX;
102 int32_t relY;
103
104 inline void clear() {
105 fields = 0;
106 }
107
108 inline bool isDirty() {
109 return fields != 0;
110 }
111 } accumulator;
112
113 struct Current {
114 bool down;
115 nsecs_t downTime;
116 } current;
117
118 struct Precalculated {
119 float xScale;
120 float yScale;
121 float xPrecision;
122 float yPrecision;
123 } precalculated;
124
125 void reset();
126 };
127
128 struct SingleTouchScreenState {
129 struct Accumulator {
130 enum {
131 FIELD_BTN_TOUCH = 1,
132 FIELD_ABS_X = 2,
133 FIELD_ABS_Y = 4,
134 FIELD_ABS_PRESSURE = 8,
135 FIELD_ABS_TOOL_WIDTH = 16
136 };
137
138 uint32_t fields;
139
140 bool btnTouch;
141 int32_t absX;
142 int32_t absY;
143 int32_t absPressure;
144 int32_t absToolWidth;
145
146 inline void clear() {
147 fields = 0;
148 }
149
150 inline bool isDirty() {
151 return fields != 0;
152 }
153 } accumulator;
154
155 struct Current {
156 bool down;
157 int32_t x;
158 int32_t y;
159 int32_t pressure;
160 int32_t size;
161 } current;
162
163 void reset();
164 };
165
166 struct MultiTouchScreenState {
167 struct Accumulator {
168 enum {
169 FIELD_ABS_MT_POSITION_X = 1,
170 FIELD_ABS_MT_POSITION_Y = 2,
171 FIELD_ABS_MT_TOUCH_MAJOR = 4,
172 FIELD_ABS_MT_WIDTH_MAJOR = 8,
173 FIELD_ABS_MT_TRACKING_ID = 16
174 };
175
176 uint32_t pointerCount;
177 struct Pointer {
178 uint32_t fields;
179
180 int32_t absMTPositionX;
181 int32_t absMTPositionY;
182 int32_t absMTTouchMajor;
183 int32_t absMTWidthMajor;
184 int32_t absMTTrackingId;
185
186 inline void clear() {
187 fields = 0;
188 }
189 } pointers[MAX_POINTERS + 1]; // + 1 to remove the need for extra range checks
190
191 inline void clear() {
192 pointerCount = 0;
193 pointers[0].clear();
194 }
195
196 inline bool isDirty() {
197 return pointerCount != 0;
198 }
199 } accumulator;
200
201 void reset();
202 };
203
204 struct PointerData {
205 uint32_t id;
206 int32_t x;
207 int32_t y;
208 int32_t pressure;
209 int32_t size;
210 };
211
212 struct TouchData {
213 uint32_t pointerCount;
214 PointerData pointers[MAX_POINTERS];
215 BitSet32 idBits;
216 uint32_t idToIndex[MAX_POINTER_ID];
217
218 void copyFrom(const TouchData& other);
219
220 inline void clear() {
221 pointerCount = 0;
222 idBits.clear();
223 }
224 };
225
226 // common state used for both single-touch and multi-touch screens after the initial
227 // touch decoding has been performed
228 struct TouchScreenState {
229 Vector<VirtualKey> virtualKeys;
230
231 struct Parameters {
232 bool useBadTouchFilter;
233 bool useJumpyTouchFilter;
234 bool useAveragingTouchFilter;
235
236 AbsoluteAxisInfo xAxis;
237 AbsoluteAxisInfo yAxis;
238 AbsoluteAxisInfo pressureAxis;
239 AbsoluteAxisInfo sizeAxis;
240 } parameters;
241
242 // The touch data of the current sample being processed.
243 TouchData currentTouch;
244
245 // The touch data of the previous sample that was processed. This is updated
246 // incrementally while the current sample is being processed.
247 TouchData lastTouch;
248
249 // The time the primary pointer last went down.
250 nsecs_t downTime;
251
252 struct CurrentVirtualKeyState {
Jeff Brownf16c26d2010-07-02 15:37:36 -0700253 enum Status {
254 STATUS_UP,
255 STATUS_DOWN,
256 STATUS_CANCELED
257 };
258
259 Status status;
Jeff Browne839a582010-04-22 18:58:52 -0700260 nsecs_t downTime;
261 int32_t keyCode;
262 int32_t scanCode;
263 } currentVirtualKey;
264
265 struct AveragingTouchFilterState {
266 // Individual history tracks are stored by pointer id
267 uint32_t historyStart[MAX_POINTERS];
268 uint32_t historyEnd[MAX_POINTERS];
269 struct {
270 struct {
271 int32_t x;
272 int32_t y;
273 int32_t pressure;
274 } pointers[MAX_POINTERS];
275 } historyData[AVERAGING_HISTORY_SIZE];
276 } averagingTouchFilter;
277
278 struct JumpTouchFilterState {
279 int32_t jumpyPointsDropped;
280 } jumpyTouchFilter;
281
282 struct Precalculated {
Jeff Brown4036f7f2010-06-29 16:52:21 -0700283 int32_t xOrigin;
Jeff Browne839a582010-04-22 18:58:52 -0700284 float xScale;
Jeff Brown4036f7f2010-06-29 16:52:21 -0700285
286 int32_t yOrigin;
Jeff Browne839a582010-04-22 18:58:52 -0700287 float yScale;
Jeff Brown4036f7f2010-06-29 16:52:21 -0700288
289 int32_t pressureOrigin;
Jeff Browne839a582010-04-22 18:58:52 -0700290 float pressureScale;
Jeff Brown4036f7f2010-06-29 16:52:21 -0700291
292 int32_t sizeOrigin;
Jeff Browne839a582010-04-22 18:58:52 -0700293 float sizeScale;
294 } precalculated;
295
296 void reset();
297
298 bool applyBadTouchFilter();
299 bool applyJumpyTouchFilter();
300 void applyAveragingTouchFilter();
301 void calculatePointerIds();
302
303 bool isPointInsideDisplay(int32_t x, int32_t y) const;
Jeff Brownf16c26d2010-07-02 15:37:36 -0700304 const InputDevice::VirtualKey* findVirtualKeyHit() const;
Jeff Browne839a582010-04-22 18:58:52 -0700305 };
306
307 InputDevice(int32_t id, uint32_t classes, String8 name);
308
309 int32_t id;
310 uint32_t classes;
311 String8 name;
312 bool ignored;
313
314 KeyboardState keyboard;
315 TrackballState trackball;
316 TouchScreenState touchScreen;
317 union {
318 SingleTouchScreenState singleTouchScreen;
319 MultiTouchScreenState multiTouchScreen;
320 };
321
322 void reset();
323
324 inline bool isKeyboard() const { return classes & INPUT_DEVICE_CLASS_KEYBOARD; }
325 inline bool isAlphaKey() const { return classes & INPUT_DEVICE_CLASS_ALPHAKEY; }
326 inline bool isTrackball() const { return classes & INPUT_DEVICE_CLASS_TRACKBALL; }
327 inline bool isDPad() const { return classes & INPUT_DEVICE_CLASS_DPAD; }
328 inline bool isSingleTouchScreen() const { return (classes
329 & (INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT))
330 == INPUT_DEVICE_CLASS_TOUCHSCREEN; }
331 inline bool isMultiTouchScreen() const { return classes
332 & INPUT_DEVICE_CLASS_TOUCHSCREEN_MT; }
333 inline bool isTouchScreen() const { return classes
334 & (INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT); }
335};
336
337
Jeff Brown54bc2812010-06-15 01:31:58 -0700338/*
339 * Input reader policy interface.
340 *
341 * The input reader policy is used by the input reader to interact with the Window Manager
342 * and other system components.
343 *
344 * The actual implementation is partially supported by callbacks into the DVM
345 * via JNI. This interface is also mocked in the unit tests.
346 */
347class InputReaderPolicyInterface : public virtual RefBase {
348protected:
349 InputReaderPolicyInterface() { }
350 virtual ~InputReaderPolicyInterface() { }
351
352public:
353 /* Display orientations. */
354 enum {
355 ROTATION_0 = 0,
356 ROTATION_90 = 1,
357 ROTATION_180 = 2,
358 ROTATION_270 = 3
359 };
360
361 /* Actions returned by interceptXXX methods. */
362 enum {
363 // The input dispatcher should do nothing and discard the input unless other
364 // flags are set.
365 ACTION_NONE = 0,
366
367 // The input dispatcher should dispatch the input to the application.
368 ACTION_DISPATCH = 0x00000001,
369
370 // The input dispatcher should perform special filtering in preparation for
371 // a pending app switch.
372 ACTION_APP_SWITCH_COMING = 0x00000002,
373
374 // The input dispatcher should add POLICY_FLAG_WOKE_HERE to the policy flags it
375 // passes through the dispatch pipeline.
376 ACTION_WOKE_HERE = 0x00000004,
377
378 // The input dispatcher should add POLICY_FLAG_BRIGHT_HERE to the policy flags it
379 // passes through the dispatch pipeline.
Jeff Brown50de30a2010-06-22 01:27:15 -0700380 ACTION_BRIGHT_HERE = 0x00000008,
Jeff Brown54bc2812010-06-15 01:31:58 -0700381 };
382
383 /* Describes a virtual key. */
384 struct VirtualKeyDefinition {
385 int32_t scanCode;
386
387 // configured position data, specified in display coords
388 int32_t centerX;
389 int32_t centerY;
390 int32_t width;
391 int32_t height;
392 };
393
394 /* Gets information about the display with the specified id.
395 * Returns true if the display info is available, false otherwise.
396 */
397 virtual bool getDisplayInfo(int32_t displayId,
398 int32_t* width, int32_t* height, int32_t* orientation) = 0;
399
Jeff Brownf16c26d2010-07-02 15:37:36 -0700400 /* Provides feedback for a virtual key down.
Jeff Brown54bc2812010-06-15 01:31:58 -0700401 */
Jeff Brownf16c26d2010-07-02 15:37:36 -0700402 virtual void virtualKeyDownFeedback() = 0;
Jeff Brown54bc2812010-06-15 01:31:58 -0700403
404 /* Intercepts a key event.
405 * The policy can use this method as an opportunity to perform power management functions
406 * and early event preprocessing.
407 *
408 * Returns a policy action constant such as ACTION_DISPATCH.
409 */
410 virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
411 bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) = 0;
412
413 /* Intercepts a trackball event.
414 * The policy can use this method as an opportunity to perform power management functions
415 * and early event preprocessing.
416 *
417 * Returns a policy action constant such as ACTION_DISPATCH.
418 */
419 virtual int32_t interceptTrackball(nsecs_t when, bool buttonChanged, bool buttonDown,
420 bool rolled) = 0;
421
422 /* Intercepts a touch event.
423 * The policy can use this method as an opportunity to perform power management functions
424 * and early event preprocessing.
425 *
426 * Returns a policy action constant such as ACTION_DISPATCH.
427 */
428 virtual int32_t interceptTouch(nsecs_t when) = 0;
429
430 /* Intercepts a switch event.
431 * The policy can use this method as an opportunity to perform power management functions
432 * and early event preprocessing.
433 *
434 * Switches are not dispatched to applications so this method should
435 * usually return ACTION_NONE.
436 */
437 virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue) = 0;
438
439 /* Determines whether to turn on some hacks we have to improve the touch interaction with a
440 * certain device whose screen currently is not all that good.
441 */
442 virtual bool filterTouchEvents() = 0;
443
444 /* Determines whether to turn on some hacks to improve touch interaction with another device
445 * where touch coordinate data can get corrupted.
446 */
447 virtual bool filterJumpyTouchEvents() = 0;
448
449 /* Gets the configured virtual key definitions for an input device. */
450 virtual void getVirtualKeyDefinitions(const String8& deviceName,
451 Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) = 0;
452
453 /* Gets the excluded device names for the platform. */
454 virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0;
455};
456
457
458/* Processes raw input events and sends cooked event data to an input dispatcher. */
Jeff Browne839a582010-04-22 18:58:52 -0700459class InputReaderInterface : public virtual RefBase {
460protected:
461 InputReaderInterface() { }
462 virtual ~InputReaderInterface() { }
463
464public:
465 /* Runs a single iteration of the processing loop.
466 * Nominally reads and processes one incoming message from the EventHub.
467 *
468 * This method should be called on the input reader thread.
469 */
470 virtual void loopOnce() = 0;
471
472 /* Gets the current virtual key. Returns false if not down.
473 *
474 * This method may be called on any thread (usually by the input manager).
475 */
476 virtual bool getCurrentVirtualKey(int32_t* outKeyCode, int32_t* outScanCode) const = 0;
Jeff Brown54bc2812010-06-15 01:31:58 -0700477
478 /* Gets the current input device configuration.
479 *
480 * This method may be called on any thread (usually by the input manager).
481 */
482 virtual void getCurrentInputConfiguration(InputConfiguration* outConfiguration) const = 0;
483
484 /*
485 * Query current input state.
486 * deviceId may be -1 to search for the device automatically, filtered by class.
487 * deviceClasses may be -1 to ignore device class while searching.
488 */
489 virtual int32_t getCurrentScanCodeState(int32_t deviceId, int32_t deviceClasses,
490 int32_t scanCode) const = 0;
491 virtual int32_t getCurrentKeyCodeState(int32_t deviceId, int32_t deviceClasses,
492 int32_t keyCode) const = 0;
493 virtual int32_t getCurrentSwitchState(int32_t deviceId, int32_t deviceClasses,
494 int32_t sw) const = 0;
495
496 /* Determine whether physical keys exist for the given framework-domain key codes. */
497 virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const = 0;
Jeff Browne839a582010-04-22 18:58:52 -0700498};
499
Jeff Brown54bc2812010-06-15 01:31:58 -0700500
Jeff Browne839a582010-04-22 18:58:52 -0700501/* The input reader reads raw event data from the event hub and processes it into input events
Jeff Brown54bc2812010-06-15 01:31:58 -0700502 * that it sends to the input dispatcher. Some functions of the input reader, such as early
503 * event filtering in low power states, are controlled by a separate policy object.
504 *
505 * IMPORTANT INVARIANT:
506 * Because the policy can potentially block or cause re-entrance into the input reader,
507 * the input reader never calls into the policy while holding its internal locks.
Jeff Browne839a582010-04-22 18:58:52 -0700508 */
509class InputReader : public InputReaderInterface {
510public:
511 InputReader(const sp<EventHubInterface>& eventHub,
Jeff Brown54bc2812010-06-15 01:31:58 -0700512 const sp<InputReaderPolicyInterface>& policy,
Jeff Browne839a582010-04-22 18:58:52 -0700513 const sp<InputDispatcherInterface>& dispatcher);
514 virtual ~InputReader();
515
516 virtual void loopOnce();
517
518 virtual bool getCurrentVirtualKey(int32_t* outKeyCode, int32_t* outScanCode) const;
519
Jeff Brown54bc2812010-06-15 01:31:58 -0700520 virtual void getCurrentInputConfiguration(InputConfiguration* outConfiguration) const;
521
522 virtual int32_t getCurrentScanCodeState(int32_t deviceId, int32_t deviceClasses,
523 int32_t scanCode) const;
524 virtual int32_t getCurrentKeyCodeState(int32_t deviceId, int32_t deviceClasses,
525 int32_t keyCode) const;
526 virtual int32_t getCurrentSwitchState(int32_t deviceId, int32_t deviceClasses,
527 int32_t sw) const;
528
529 virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const;
530
Jeff Browne839a582010-04-22 18:58:52 -0700531private:
532 // Lock that must be acquired while manipulating state that may be concurrently accessed
533 // from other threads by input state query methods. It should be held for as short a
534 // time as possible.
535 //
536 // Exported state:
537 // - global virtual key code and scan code
538 // - device list and immutable properties of devices such as id, name, and class
539 // (but not other internal device state)
540 mutable Mutex mExportedStateLock;
541
Jeff Brown54bc2812010-06-15 01:31:58 -0700542 // current virtual key information (lock mExportedStateLock)
543 int32_t mExportedVirtualKeyCode;
544 int32_t mExportedVirtualScanCode;
545
546 // current input configuration (lock mExportedStateLock)
547 InputConfiguration mExportedInputConfiguration;
Jeff Browne839a582010-04-22 18:58:52 -0700548
549 // combined key meta state
550 int32_t mGlobalMetaState;
551
552 sp<EventHubInterface> mEventHub;
Jeff Brown54bc2812010-06-15 01:31:58 -0700553 sp<InputReaderPolicyInterface> mPolicy;
Jeff Browne839a582010-04-22 18:58:52 -0700554 sp<InputDispatcherInterface> mDispatcher;
555
556 KeyedVector<int32_t, InputDevice*> mDevices;
557
558 // display properties needed to translate touch screen coordinates into display coordinates
559 int32_t mDisplayOrientation;
560 int32_t mDisplayWidth;
561 int32_t mDisplayHeight;
562
563 // low-level input event decoding
564 void process(const RawEvent* rawEvent);
565 void handleDeviceAdded(const RawEvent* rawEvent);
566 void handleDeviceRemoved(const RawEvent* rawEvent);
567 void handleSync(const RawEvent* rawEvent);
568 void handleKey(const RawEvent* rawEvent);
569 void handleRelativeMotion(const RawEvent* rawEvent);
570 void handleAbsoluteMotion(const RawEvent* rawEvent);
571 void handleSwitch(const RawEvent* rawEvent);
572
573 // input policy processing and dispatch
574 void onKey(nsecs_t when, InputDevice* device, bool down,
575 int32_t keyCode, int32_t scanCode, uint32_t policyFlags);
Jeff Brown54bc2812010-06-15 01:31:58 -0700576 void onSwitch(nsecs_t when, InputDevice* device, int32_t switchCode, int32_t switchValue);
Jeff Browne839a582010-04-22 18:58:52 -0700577 void onSingleTouchScreenStateChanged(nsecs_t when, InputDevice* device);
578 void onMultiTouchScreenStateChanged(nsecs_t when, InputDevice* device);
579 void onTouchScreenChanged(nsecs_t when, InputDevice* device, bool havePointerIds);
580 void onTrackballStateChanged(nsecs_t when, InputDevice* device);
581 void onConfigurationChanged(nsecs_t when);
582
583 bool applyStandardInputDispatchPolicyActions(nsecs_t when,
584 int32_t policyActions, uint32_t* policyFlags);
585
586 bool consumeVirtualKeyTouches(nsecs_t when, InputDevice* device, uint32_t policyFlags);
587 void dispatchVirtualKey(nsecs_t when, InputDevice* device, uint32_t policyFlags,
588 int32_t keyEventAction, int32_t keyEventFlags);
589 void dispatchTouches(nsecs_t when, InputDevice* device, uint32_t policyFlags);
590 void dispatchTouch(nsecs_t when, InputDevice* device, uint32_t policyFlags,
591 InputDevice::TouchData* touch, BitSet32 idBits, int32_t motionEventAction);
592
593 // display
594 void resetDisplayProperties();
595 bool refreshDisplayProperties();
596
597 // device management
598 InputDevice* getDevice(int32_t deviceId);
599 InputDevice* getNonIgnoredDevice(int32_t deviceId);
600 void addDevice(nsecs_t when, int32_t deviceId);
601 void removeDevice(nsecs_t when, InputDevice* device);
602 void configureDevice(InputDevice* device);
603 void configureDeviceForCurrentDisplaySize(InputDevice* device);
604 void configureVirtualKeys(InputDevice* device);
605 void configureAbsoluteAxisInfo(InputDevice* device, int axis, const char* name,
606 InputDevice::AbsoluteAxisInfo* out);
Jeff Brown54bc2812010-06-15 01:31:58 -0700607 void configureExcludedDevices();
Jeff Browne839a582010-04-22 18:58:52 -0700608
609 // global meta state management for all devices
610 void resetGlobalMetaState();
611 int32_t globalMetaState();
612
613 // virtual key management
Jeff Brown54bc2812010-06-15 01:31:58 -0700614 void updateExportedVirtualKeyState();
615
616 // input configuration management
617 void updateExportedInputConfiguration();
Jeff Browne839a582010-04-22 18:58:52 -0700618};
619
620
621/* Reads raw events from the event hub and processes them, endlessly. */
622class InputReaderThread : public Thread {
623public:
624 InputReaderThread(const sp<InputReaderInterface>& reader);
625 virtual ~InputReaderThread();
626
627private:
628 sp<InputReaderInterface> mReader;
629
630 virtual bool threadLoop();
631};
632
633} // namespace android
634
635#endif // _UI_INPUT_READER_H