2021-04-12 18:19:04 +02:00
# Input device interface
## Types of input devices
2021-11-28 20:41:18 -05:00
To 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.**
2021-04-12 18:19:04 +02:00
```c
2021-11-28 20:41:18 -05:00
lv_disp_drv_register(&disp_drv);
2021-09-29 10:31:35 +02:00
static lv_indev_drv_t indev_drv;
2021-04-12 18:19:04 +02:00
lv_indev_drv_init(&indev_drv); /*Basic initialization*/
indev_drv.type =... /*See below.*/
indev_drv.read_cb =... /*See below.*/
/*Register the driver in LVGL and save the created input device object*/
lv_indev_t * my_indev = lv_indev_drv_register(&indev_drv);
```
2021-09-06 04:55:37 -04:00
The `type` member can be:
2021-05-13 21:23:11 +02:00
- `LV_INDEV_TYPE_POINTER` touchpad or mouse
- `LV_INDEV_TYPE_KEYPAD` keyboard or keypad
- `LV_INDEV_TYPE_ENCODER` encoder with left/right turn and push options
- `LV_INDEV_TYPE_BUTTON` external buttons virtually pressing the screen
2021-04-12 18:19:04 +02:00
2021-05-13 21:23:11 +02:00
`read_cb` is a function pointer which will be called periodically to report the current state of an input device.
2021-04-12 18:19:04 +02:00
Visit [Input devices ](/overview/indev ) to learn more about input devices in general.
### Touchpad, mouse or any pointer
2021-06-09 15:10:35 +02:00
Input devices that can click points on the screen belong to this category.
2021-04-12 18:19:04 +02:00
```c
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = my_input_read;
...
2021-05-13 21:23:11 +02:00
void my_input_read(lv_indev_drv_t * drv, lv_indev_data_t*data)
2021-04-12 18:19:04 +02:00
{
2021-05-13 21:23:11 +02:00
if(touchpad_pressed) {
2021-04-12 18:19:04 +02:00
data->point.x = touchpad_x;
data->point.y = touchpad_y;
2021-05-13 21:23:11 +02:00
data->state = LV_INDEV_STATE_PRESSED;
} else {
2022-03-21 18:25:51 +08:00
data->state = LV_INDEV_STATE_RELEASED;
2021-05-13 21:23:11 +02:00
}
2021-04-12 18:19:04 +02:00
}
```
To set a mouse cursor use `lv_indev_set_cursor(my_indev, &img_cursor)` . (`my_indev` is the return value of `lv_indev_drv_register` )
### Keypad or keyboard
Full keyboards with all the letters or simple keypads with a few navigation buttons belong here.
To use a keyboard/keypad:
- Register a `read_cb` function with `LV_INDEV_TYPE_KEYPAD` type.
2021-06-09 15:10:35 +02:00
- 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)`
2021-04-12 18:19:04 +02:00
- 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` )
- Use `LV_KEY_...` to navigate among the objects in the group. See `lv_core/lv_group.h` for the available keys.
```c
indev_drv.type = LV_INDEV_TYPE_KEYPAD;
indev_drv.read_cb = keyboard_read;
...
2021-05-13 21:23:11 +02:00
void keyboard_read(lv_indev_drv_t * drv, lv_indev_data_t*data){
2021-04-12 18:19:04 +02:00
data->key = last_key(); /*Get the last pressed or released key*/
2021-05-13 21:23:11 +02:00
if(key_pressed()) data->state = LV_INDEV_STATE_PRESSED;
else data->state = LV_INDEV_STATE_RELEASED;
2021-04-12 18:19:04 +02:00
}
```
### Encoder
2021-09-06 04:55:37 -04:00
With an encoder you can do the following:
2021-04-12 18:19:04 +02:00
1. Press its button
2. Long-press its button
3. Turn left
4. Turn right
In short, the Encoder input devices work like this:
- By turning the encoder you can focus on the next/previous object.
- When you press the encoder on a simple object (like a button), it will be clicked.
2021-09-06 04:55:37 -04:00
- 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.
- To leave edit mode, long press the button.
2021-04-12 18:19:04 +02:00
To use an *Encoder* (similarly to the *Keypads* ) the objects should be added to groups.
```c
indev_drv.type = LV_INDEV_TYPE_ENCODER;
indev_drv.read_cb = encoder_read;
...
2021-05-13 21:23:11 +02:00
void encoder_read(lv_indev_drv_t * drv, lv_indev_data_t*data){
2021-04-12 18:19:04 +02:00
data->enc_diff = enc_get_new_moves();
2021-05-13 21:23:11 +02:00
if(enc_pressed()) data->state = LV_INDEV_STATE_PRESSED;
else data->state = LV_INDEV_STATE_RELEASED;
2021-04-12 18:19:04 +02:00
}
```
2021-05-13 21:23:11 +02:00
2021-04-12 18:19:04 +02:00
#### Using buttons with Encoder logic
2022-03-21 18:25:51 +08:00
In addition to standard encoder behavior, you can also utilize its logic to navigate(focus) and edit widgets using buttons.
2021-05-13 21:23:11 +02:00
This is especially handy if you have only few buttons available, or you want to use other buttons in addition to encoder wheel.
2021-04-12 18:19:04 +02:00
2021-05-13 21:23:11 +02:00
You need to have 3 buttons available:
- `LV_KEY_ENTER` will simulate press or pushing of the encoder button
- `LV_KEY_LEFT` will simulate turning encoder left
- `LV_KEY_RIGHT` will simulate turning encoder right
2021-04-12 18:19:04 +02:00
- other keys will be passed to the focused widget
2021-09-06 04:55:37 -04:00
If you hold the keys it will simulate an encoder advance with period specified in `indev_drv.long_press_rep_time` .
2021-04-12 18:19:04 +02:00
```c
indev_drv.type = LV_INDEV_TYPE_ENCODER;
indev_drv.read_cb = encoder_with_keys_read;
...
2021-07-18 05:54:33 -07:00
void encoder_with_keys_read(lv_indev_drv_t * drv, lv_indev_data_t*data){
2021-04-12 18:19:04 +02:00
data->key = last_key(); /*Get the last pressed or released key*/
/* use LV_KEY_ENTER for encoder press */
2021-05-13 21:23:11 +02:00
if(key_pressed()) data->state = LV_INDEV_STATE_PRESSED;
2021-04-12 18:19:04 +02:00
else {
2021-05-13 21:23:11 +02:00
data->state = LV_INDEV_STATE_RELEASED;
2021-04-12 18:19:04 +02:00
/* Optionally you can also use enc_diff, if you have encoder*/
data->enc_diff = enc_get_new_moves();
}
}
```
### Button
*Buttons* mean external "hardware" buttons next to the screen which are assigned to specific coordinates of the screen.
If a button is pressed it will simulate the pressing on the assigned coordinate. (Similarly to a touchpad)
2022-03-21 18:25:51 +08:00
To assign buttons to coordinates use `lv_indev_set_button_points(my_indev, points_array)` .
2022-01-17 14:10:23 +01:00
`points_array` should look like `const lv_point_t points_array[] = { {12,30},{60,90}, ...}`
2021-04-12 18:19:04 +02:00
``` 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.
```
```c
indev_drv.type = LV_INDEV_TYPE_BUTTON;
indev_drv.read_cb = button_read;
...
2021-05-13 21:23:11 +02:00
void button_read(lv_indev_drv_t * drv, lv_indev_data_t*data){
2021-04-12 18:19:04 +02:00
static uint32_t last_btn = 0; /*Store the last pressed button*/
int btn_pr = my_btn_read(); /*Get the ID (0,1,2...) of the pressed button*/
if(btn_pr >= 0) { /*Is there a button press? (E.g. -1 indicated no button was pressed)*/
last_btn = btn_pr; /*Save the ID of the pressed button*/
2021-05-13 21:23:11 +02:00
data->state = LV_INDEV_STATE_PRESSED; /*Set the pressed state*/
2021-04-12 18:19:04 +02:00
} else {
2021-05-13 21:23:11 +02:00
data->state = LV_INDEV_STATE_RELEASED; /*Set the released state*/
2021-04-12 18:19:04 +02:00
}
data->btn = last_btn; /*Save the last button*/
}
```
## Other features
2021-05-13 21:23:11 +02:00
### Parameters
2021-04-12 18:19:04 +02:00
2021-08-26 10:52:39 +02:00
The default value of the following parameters can be changed in `lv_indev_drv_t` :
2021-05-13 21:23:11 +02:00
- `scroll_limit` Number of pixels to slide before actually scrolling the object.
- `scroll_throw` Scroll throw (momentum) slow-down in [%]. Greater value means faster slow-down.
- `long_press_time` Press time to send `LV_EVENT_LONG_PRESSED` (in milliseconds)
- `long_press_rep_time` Interval of sending `LV_EVENT_LONG_PRESSED_REPEAT` (in milliseconds)
2021-06-09 15:10:35 +02:00
- `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.
2021-04-12 18:19:04 +02:00
2021-05-13 21:23:11 +02:00
### Feedback
2021-04-12 18:19:04 +02:00
2021-05-13 21:23:11 +02:00
Besides `read_cb` a `feedback_cb` callback can be also specified in `lv_indev_drv_t` .
2021-08-26 10:52:39 +02:00
`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` .
2021-05-13 21:23:11 +02:00
### Associating with a display
2021-11-23 10:50:18 +01:00
Every 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()` ).
2021-04-12 18:19:04 +02:00
The associated display is stored and can be changed in `disp` field of the driver.
2021-05-20 22:25:47 +02:00
### Buffered reading
2022-03-21 18:25:51 +08:00
By default, LVGL calls `read_cb` periodically. Because of this intermittent polling there is a chance that some user gestures are missed.
2021-05-13 21:23:11 +02:00
2022-03-21 18:25:51 +08:00
To 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.
2021-09-06 04:55:37 -04:00
Setting the `data->continue_reading` flag will tell LVGL there is more data to read and it should call `read_cb` again.
2021-05-20 22:25:47 +02:00
## Further reading
- [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.
- [INdev features ](/overview/display ) to learn more about higher level input device features.
2021-04-12 18:19:04 +02:00
## API
```eval_rst
.. doxygenfile:: lv_hal_indev.h
:project: lvgl
```