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.**
```c
/*Register at least one display before you register any input devices*/
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.
- 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)`
- 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.
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.
- 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.
To use an *Encoder* (similarly to the *Keypads*) the objects should be added to groups.
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*/
data->state = LV_INDEV_STATE_PRESSED; /*Set the pressed state*/
} else {
data->state = LV_INDEV_STATE_RELEASED; /*Set the released state*/
}
data->btn = last_btn; /*Save the last button*/
}
```
## Other features
### Parameters
The default value of the following parameters can be changed in `lv_indev_drv_t`:
-`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_repeat_time` Interval of sending `LV_EVENT_LONG_PRESSED_REPEAT` (in milliseconds)
-`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.
### Feedback
Besides `read_cb` a `feedback_cb` callback can be also specified in `lv_indev_drv_t`.
`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`.
### Associating with a display
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()`).
The associated display is stored and can be changed in `disp` field of the driver.
### Buffered reading
By default, LVGL calls `read_cb` periodically. Because of this intermittent polling there is a chance that some user gestures are missed.
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.
Setting the `data->continue_reading` flag will tell LVGL there is more data to read and it should call `read_cb` again.
## 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.