I have a TSTP MTouch device and experienced the same problem but none of the solutions worked. I kept having accurate touch coordinates in X11, but the range of coordinates was much smaller if I used framebuffer outside X11. As it turned out, this was not a calibration issue but seems to be a pygame or SDL problem.
I ended up directly polling the device and decoding the data in python.
My touchscreen showed up as follows in dmesg:
[ 6.008767] input: TSTP MTouch as /devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.4/1-1.4:1.0/0003:0416:C168.0001/input/input2
[ 6.009580] hid-multitouch 0003:0416:C168.0001: input,hidraw0: USB HID v1.11 Device [TSTP MTouch] on usb-0000:01:00.0-1.4/input0
I checked /dev/hidraw0 and found that it sends packets with 56 bytes of data for each touch interaction. I dumped the data using the command "xxd -c 56 /dev/hidraw0" and got the following structure:
Touch press:
000000e0: 0101 a903 5902 02ee 02b4 0200 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 000a
0000 0002
Touch release:
00000118: 0100 a903 5902 02ee 02b4 0200 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 000a
0000 0002
As you can see, first byte is a header, second byte is a boolean, followed by two integers with the X/Y coordinates in little-endian, followed by a separator and then several X/Y multitouch points. Note that the touch coordinates were perfectly correct, there was no rotation or calibration needed.
I handle the data in python with the following function:
def handleTouchscreen():
global lastCustomEvent
previousClickedState = False
device_file = "/dev/hidraw0"
while True:
try:
with open(device_file, 'rb') as f:
while True:
packet = f.read(packet_length)
if (touchDebug == True):
print("Received: %s" %(packet.hex()))
(tag, clicked, x, y) = struct.unpack_from('<c?HH', packet)
if (clicked == True and previousClickedState == False):
previousClickedState = True
if (touchDebug == True):
print("Pressed X=%d Y=%d" % (x, y))
lastCustomEvent = pygame.event.Event(pygame.JOYBUTTONDOWN, {'pos': (x, y), 'button': 1})
elif (clicked == False and previousClickedState == True):
previousClickedState = False
if (touchDebug == True):
print("Released X=%d Y=%d" % (x, y))
lastCustomEvent = pygame.event.Event(pygame.JOYBUTTONUP, {'pos': (x, y), 'button': 1})
time.sleep(0.01)
except Exception as err:
print(f'Error occured: {err}')
I used JOYBUTTONDOWN so I could handle them separate from the (still present) mouse events that had wrong coordinates.
In my actual pygame application I integrated it as follows:
event_list = pygame.event.get()
for event in event_list:
if event.type == pygame.QUIT:
run = False
if (useCustomTouchscreenHandling == True and lastCustomEvent != False):
event_list.append(lastCustomEvent)
lastCustomEvent = False
mySpriteGroup.update(event_list)
This way I can enable/disable this as needed, and the incorrect mouse coordinates don't interfere with my program. I can now finally stop running this in X11 and save quite a lot of resources and processing power on my raspberry.