In case you use Raspberry Pi with RPi Display,Touch Interface and Direct Framebuffer, this evdev.py “patch” will permit use de Touch (XPT2046/ADS7846) in the same way that in ESP32 and Swap Axes.
import time
import sys
class mouse_touch:
def __init__(self, scr=None, cursor=None, device='/dev/input/event0',
format='llHHI',
EVDEV_HOR_MIN=None,
EVDEV_HOR_MAX=None,
EVDEV_VER_MIN=None,
EVDEV_VER_MAX=None,
SWAP_AXES=False):
# Open evdev and initialize members
self.evdev = open(device, 'rb')
self.poll = select.poll()
self.poll.register(self.evdev.fileno())
self.scr = scr if scr else lv.scr_act()
self.cursor = cursor if cursor else crosshair_cursor(self.scr)
self.hor_res = self.scr.get_width()
self.ver_res = self.scr.get_height()
self.format=format
self.EVDEV_HOR_MIN = EVDEV_HOR_MIN
self.EVDEV_HOR_MAX = EVDEV_HOR_MAX
self.EVDEV_VER_MIN = EVDEV_VER_MIN
self.EVDEV_VER_MAX = EVDEV_VER_MAX
self.SWAP_AXES = SWAP_AXES
# Register LVGL indev driver
self.indev_drv = lv.indev_drv_t()
self.indev_drv.init()
self.indev_drv.type = lv.INDEV_TYPE.POINTER
self.indev_drv.read_cb = self.mouse_read
self.indev = self.indev_drv.register()
def mapvalue(self,value_in, in_min, in_max, out_min, out_max):
mapping = int((value_in - in_min) * (out_max - out_min) / (in_max - in_min) + out_min)
return mapping
def mouse_read(self,
indev_drv,
data) -> int:
EVENT_SIZE = ustruct.calcsize(self.format)
EV_ABS = 0x03
EV_KEY = 0x01
ABS_X = 0x00
ABS_Y = 0x01
ABS_RX = 0x03
ABS_PRESSURE = 0x18
ABS_BRAKE = 0x0a
ABS_MT_POSITION_X = 0x35
ABS_MT_POSITION_Y = 0x36
ABS_MT_TRACKING_ID = 0x39
ABS_MAX = 0x3f
BTN_TOUCH = 0x14a
pressure = None
# Check if there is input to be read from evdev
while self.poll.poll()[0][1] & select.POLLIN:
if self.EVDEV_HOR_MIN is None:
self.EVDEV_HOR_MIN=0
if self.EVDEV_VER_MIN is None:
self.EVDEV_VER_MIN=0
if self.EVDEV_HOR_MAX is None:
self.EVDEV_HOR_MAX = self.hor_res
if self.EVDEV_VER_MAX is None:
self.EVDEV_VER_MAX = self.ver_res
# Read and parse evdev touch data
(tv_sec, tv_usec, typeval, code, value) = ustruct.unpack(self.format, self.evdev.read(EVENT_SIZE))
if typeval==EV_ABS:
if code == ABS_X:
if self.SWAP_AXES is True:
data.point.y = self.mapvalue(value, self.EVDEV_VER_MIN, self.EVDEV_VER_MAX, 0, self.scr.get_height())
else:
data.point.x = self.mapvalue(value, self.EVDEV_HOR_MIN, self.EVDEV_HOR_MAX, 0, self.scr.get_width())
elif code == ABS_Y:
if self.SWAP_AXES is True:
data.point.x = self.mapvalue(value, self.EVDEV_HOR_MIN, self.EVDEV_HOR_MAX, 0, self.scr.get_width())
else:
data.point.y = self.mapvalue(value, self.EVDEV_VER_MIN, self.EVDEV_VER_MAX, 0, self.scr.get_height())
elif code == ABS_MT_POSITION_X:
if self.SWAP_AXES is True:
data.point.y = self.mapvalue(value, self.EVDEV_VER_MIN, self.EVDEV_VER_MAX, 0, self.scr.get_height())
else:
data.point.x = self.mapvalue(value, self.EVDEV_HOR_MIN, self.EVDEV_HOR_MAX, 0, self.scr.get_width())
elif code == ABS_MT_POSITION_Y:
if self.SWAP_AXES is True:
data.point.x = self.mapvalue(value, self.EVDEV_HOR_MIN, self.EVDEV_HOR_MAX, 0, self.scr.get_width())
else:
data.point.y = self.mapvalue(value, self.EVDEV_VER_MIN, self.EVDEV_VER_MAX, 0, self.scr.get_height())
elif code == ABS_MT_TRACKING_ID:
if value == -1:
data.state = lv.INDEV_STATE.RELEASED
else:
data.state = lv.INDEV_STATE.PRESSED
elif typeval == EV_KEY:
if code == BTN_TOUCH:
if value == 0:
data.state = lv.INDEV_STATE.RELEASED
elif value == 1:
data.state = lv.INDEV_STATE.PRESSED
if self.cursor: self.cursor(data)
return 0
Example
import lvgl as lv
import fb
import evdev
class pointer_cursor:
def __init__(self, scr=None):
self.scr = scr if scr else lv.scr_act()
self.img = lv.img(self.scr)
self.img.set_src(lv.SYMBOL.GPS)
self.cursor_style = lv.style_t()
self.cursor_img = self.img
def __call__(self, data):
#print("State: %d - ValorX: %d ValorY:%d" % (data.state, data.point.x, data.point.y))
self.cursor_img.set_pos(data.point.x-15, data.point.y)
def delete(self):
self.cursor_hor.delete()
self.cursor_ver.delete()
lv.init()
fb.init()
# Register FB driver
disp_buf1 = lv.disp_draw_buf_t()
buf1_1 = bytes(480*10)
disp_buf1.init(buf1_1, None, len(buf1_1)//4)
disp_drv = lv.disp_drv_t()
disp_drv.init()
disp_drv.draw_buf = disp_buf1
disp_drv.flush_cb = fb.flush
disp_drv.hor_res = 480
disp_drv.ver_res = 320
disp_drv.register()
# Create a screen
#scr = lv.obj()
scr = lv.scr_act()
btn = lv.btn(scr)
btn.align(lv.ALIGN.CENTER, 0, 0)
label = lv.label(btn)
label.set_text("Hello World!")
cb = lv.checkbox(scr)
cb.set_text("Click Me")
cb.set_pos(10,160)
# Register Touch driver, pointer and calibration Or None if does not need it.
mouse = evdev.mouse_touch(scr=scr, cursor=pointer_cursor(scr=lv.scr_act()),
EVDEV_HOR_MIN=3930,
EVDEV_HOR_MAX=236,
EVDEV_VER_MIN=165,
EVDEV_VER_MAX=3929,
SWAP_AXES=True)
# Load the screen
lv.scr_load(scr)