1# Input device interface
2
3## Types of input devices
4
5To register an input device an `lv_indev_drv_t` variable has to be initialized. **Be sure to register at least one display before you register any input devices.**
6
7```c
8/*Register at least one display before you register any input devices*/
9lv_disp_drv_register(&disp_drv);
10
11static lv_indev_drv_t indev_drv;
12lv_indev_drv_init(&indev_drv);      /*Basic initialization*/
13indev_drv.type =...                 /*See below.*/
14indev_drv.read_cb =...              /*See below.*/
15/*Register the driver in LVGL and save the created input device object*/
16lv_indev_t * my_indev = lv_indev_drv_register(&indev_drv);
17```
18
19The `type` member can be:
20- `LV_INDEV_TYPE_POINTER` touchpad or mouse
21- `LV_INDEV_TYPE_KEYPAD` keyboard or keypad
22- `LV_INDEV_TYPE_ENCODER` encoder with left/right turn and push options
23- `LV_INDEV_TYPE_BUTTON` external buttons virtually pressing the screen
24
25`read_cb` is a function pointer which will be called periodically to report the current state of an input device.
26
27Visit [Input devices](/overview/indev) to learn more about input devices in general.
28
29###  Touchpad, mouse or any pointer
30Input devices that can click points on the screen belong to this category.
31
32```c
33indev_drv.type = LV_INDEV_TYPE_POINTER;
34indev_drv.read_cb = my_input_read;
35
36...
37
38void my_input_read(lv_indev_drv_t * drv, lv_indev_data_t*data)
39{
40  if(touchpad_pressed) {
41    data->point.x = touchpad_x;
42    data->point.y = touchpad_y;
43    data->state = LV_INDEV_STATE_PRESSED;
44  } else {
45    data->state = LV_INDEV_STATE_RELEASED;
46  }
47}
48```
49
50To set a mouse cursor use `lv_indev_set_cursor(my_indev, &img_cursor)`. (`my_indev` is the return value of `lv_indev_drv_register`)
51
52### Keypad or keyboard
53
54Full keyboards with all the letters or simple keypads with a few navigation buttons belong here.
55
56To use a keyboard/keypad:
57- Register a `read_cb` function with `LV_INDEV_TYPE_KEYPAD` type.
58- An object group has to be created: `lv_group_t * g = lv_group_create()` and objects have to be added to it with `lv_group_add_obj(g, obj)`
59- The created group has to be assigned to an input device: `lv_indev_set_group(my_indev, g)` (`my_indev` is the return value of `lv_indev_drv_register`)
60- Use `LV_KEY_...` to navigate among the objects in the group. See `lv_core/lv_group.h` for the available keys.
61
62```c
63indev_drv.type = LV_INDEV_TYPE_KEYPAD;
64indev_drv.read_cb = keyboard_read;
65
66...
67
68void keyboard_read(lv_indev_drv_t * drv, lv_indev_data_t*data){
69  data->key = last_key();            /*Get the last pressed or released key*/
70
71  if(key_pressed()) data->state = LV_INDEV_STATE_PRESSED;
72  else data->state = LV_INDEV_STATE_RELEASED;
73}
74```
75
76### Encoder
77With an encoder you can do the following:
781. Press its button
792. Long-press its button
803. Turn left
814. Turn right
82
83In short, the Encoder input devices work like this:
84- By turning the encoder you can focus on the next/previous object.
85- When you press the encoder on a simple object (like a button), it will be clicked.
86- If you press the encoder on a complex object (like a list, message box, etc.) the object will go to edit mode whereby you can navigate inside the object by turning the encoder.
87- To leave edit mode, long press the button.
88
89
90To use an *Encoder* (similarly to the *Keypads*) the objects should be added to groups.
91
92
93```c
94indev_drv.type = LV_INDEV_TYPE_ENCODER;
95indev_drv.read_cb = encoder_read;
96
97...
98
99void encoder_read(lv_indev_drv_t * drv, lv_indev_data_t*data){
100  data->enc_diff = enc_get_new_moves();
101
102  if(enc_pressed()) data->state = LV_INDEV_STATE_PRESSED;
103  else data->state = LV_INDEV_STATE_RELEASED;
104}
105```
106
107#### Using buttons with Encoder logic
108In addition to standard encoder behavior, you can also utilize its logic to navigate(focus) and edit widgets using buttons.
109This is especially handy if you have only few buttons available, or you want to use other buttons in addition to encoder wheel.
110
111You need to have 3 buttons available:
112- `LV_KEY_ENTER` will simulate press or pushing of the encoder button
113- `LV_KEY_LEFT` will simulate turning encoder left
114- `LV_KEY_RIGHT` will simulate turning encoder right
115- other keys will be passed to the focused widget
116
117If you hold the keys it will simulate an encoder advance with period specified in `indev_drv.long_press_repeat_time`.
118
119```c
120indev_drv.type = LV_INDEV_TYPE_ENCODER;
121indev_drv.read_cb = encoder_with_keys_read;
122
123...
124
125void encoder_with_keys_read(lv_indev_drv_t * drv, lv_indev_data_t*data){
126  data->key = last_key();            /*Get the last pressed or released key*/
127                                     /* use LV_KEY_ENTER for encoder press */
128  if(key_pressed()) data->state = LV_INDEV_STATE_PRESSED;
129  else {
130      data->state = LV_INDEV_STATE_RELEASED;
131      /* Optionally you can also use enc_diff, if you have encoder*/
132      data->enc_diff = enc_get_new_moves();
133  }
134}
135```
136
137### Button
138*Buttons* mean external "hardware" buttons next to the screen which are assigned to specific coordinates of the screen.
139If a button is pressed it will simulate the pressing on the assigned coordinate. (Similarly to a touchpad)
140
141To assign buttons to coordinates use `lv_indev_set_button_points(my_indev, points_array)`.
142`points_array` should look like `const lv_point_t points_array[] = { {12,30},{60,90}, ...}`
143
144``` important::  The points_array can't go out of scope. Either declare it as a global variable or as a static variable inside a function.
145```
146
147```c
148indev_drv.type = LV_INDEV_TYPE_BUTTON;
149indev_drv.read_cb = button_read;
150
151...
152
153void button_read(lv_indev_drv_t * drv, lv_indev_data_t*data){
154    static uint32_t last_btn = 0;   /*Store the last pressed button*/
155    int btn_pr = my_btn_read();     /*Get the ID (0,1,2...) of the pressed button*/
156    if(btn_pr >= 0) {               /*Is there a button press? (E.g. -1 indicated no button was pressed)*/
157       last_btn = btn_pr;           /*Save the ID of the pressed button*/
158       data->state = LV_INDEV_STATE_PRESSED;  /*Set the pressed state*/
159    } else {
160       data->state = LV_INDEV_STATE_RELEASED; /*Set the released state*/
161    }
162
163    data->btn = last_btn;            /*Save the last button*/
164}
165```
166
167## Other features
168
169### Parameters
170
171The default value of the following parameters can be changed in `lv_indev_drv_t`:
172- `scroll_limit` Number of pixels to slide before actually scrolling the object.
173- `scroll_throw`  Scroll throw (momentum) slow-down in [%]. Greater value means faster slow-down.
174- `long_press_time` Press time to send `LV_EVENT_LONG_PRESSED` (in milliseconds)
175- `long_press_repeat_time` Interval of sending `LV_EVENT_LONG_PRESSED_REPEAT` (in milliseconds)
176- `read_timer` pointer to the `lv_timer` which reads the input device. Its parameters can be changed by `lv_timer_...()` functions. `LV_INDEV_DEF_READ_PERIOD` in `lv_conf.h` sets the default read period.
177
178### Feedback
179
180Besides `read_cb` a `feedback_cb` callback can be also specified in `lv_indev_drv_t`.
181`feedback_cb` is called when any type of event is sent by the input devices (independently of its type). This allows generating feedback for the user, e.g. to play a sound on `LV_EVENT_CLICKED`.
182
183
184### Associating with a display
185Every input device is associated with a display. By default, a new input device is added to the last display created or explicitly selected (using `lv_disp_set_default()`).
186The associated display is stored and can be changed in `disp` field of the driver.
187
188### Buffered reading
189By default, LVGL calls `read_cb` periodically. Because of this intermittent polling there is a chance that some user gestures are missed.
190
191To solve this you can write an event driven driver for your input device that buffers measured data. In `read_cb` you can report the buffered data instead of directly reading the input device.
192Setting the `data->continue_reading` flag will tell LVGL there is more data to read and it should call `read_cb` again.
193
194## Further reading
195
196- [lv_port_indev_template.c](https://github.com/lvgl/lvgl/blob/master/examples/porting/lv_port_indev_template.c) for a template for your own driver.
197- [INdev features](/overview/display) to learn more about higher level input device features.
198
199## API
200
201```eval_rst
202
203.. doxygenfile:: lv_hal_indev.h
204  :project: lvgl
205
206```
207