n4archive / pigame

A pygame wrapper for the libary pitft_touchscreen.
GNU Lesser General Public License v3.0
6 stars 1 forks source link

Some touch events not occuring at proper coordinates #1

Closed BroMarduk closed 5 years ago

BroMarduk commented 5 years ago

I have an app that uses a grid of buttons and I noticed when using your code, at times when repeatedly pressing a button, the click would jump to a different button. Using the evtest tool, I tracked these events down to cases when either the X or Y or both the X and Y coordinates would not change and the events in the pitft_touchscreen tool were coming in with a None value for X or Y (evdev is stateful, so this behavior makes sense).

In your current code, when this occurs you seem to be grabbing the replacement value from pygame, but is seems that the coordinates are sometimes not the same as the press location if the last event is a button_up event. I re-wrote the code and got it working by storing historical values so the events missing the X and Y (or in some cases when the tap is in the exact same place, both comeback as None) are replaced with stateful equivalents.

Please let me know if this is something you want to possibly change in your library or have a better way to keep the coordinates stateful. (I didn't test this completely as I have the code running in a separate class using class variables as well as in Python 2.7, but the concepts should be the same).

I can say that now my touch locations are always consistent.

import pygame,pitft_touchscreen
from pygame.locals import *
pitft=pitft_touchscreen.pitft_touchscreen()
pitft.pigameevs=[]
pitft.es = 0
pitft.pl = {'x': False, 'y': False}

def init(rotation:int=90):
    pitft.pigamerotr=rotation
    pitft.start()

def run():
    while not pitft.queue_empty():
        for r in pitft.get_event():
            # Set the pygame event coordinates to the last settings.  This
            # allows us to handle the case where a click occurred in the
            # same spot on one or both of the axes.
            e = {'y': pitft.pl['y'], 'x': pitft.pl['x']}
            if r['x'] is not None:
                e['y'] = r['x']
            if r['y'] is not None:
                e['x'] = r['y']
            # If there is still no X & Y coordinates and nothing 
            # historical, throw away the event....
            if e['x'] is None or e['y'] is None:
                break
            if pitft.pigamerotr==90:
                e={"x":e["x"],"y":240-e["y"]}
            elif pitft.pigamerotr==270:
                e={"x":320-e["x"],"y":e["y"]}
            else:
                raise(Exception("PiTft rotation is unsupported"))
            d={}
            t=MOUSEBUTTONUP if r['touch'] == 0 else (
                    MOUSEBUTTONDOWN if pitft.es == 0 else MOUSEMOTION)
            if t==MOUSEBUTTONDOWN:
                pitft.es=1
                d["button"]=1
                d["pos"]=(e["x"],e["y"])
                pygame.mouse.set_pos(e["x"],e["y"])
            elif t==MOUSEBUTTONUP:
                pitft.es = 0
                d["button"]=1
                d["pos"]=(e["x"],e["y"])
            else:
                d["buttons"]=(True,False,False)
                d["rel"]=(0,0)
                d["pos"]=(e["x"],e["y"])
                pygame.mouse.set_pos(e["x"],e["y"])
            pe=pygame.event.Event(t,d)
            pygame.event.post(pe)
def quit():
    pitft.stop()
nift4 commented 5 years ago

Hi, I don't have issues. As a sidenote: The code is designed for python3 :) EDIT: See down

nift4 commented 5 years ago

Oops wrong button :)

nift4 commented 5 years ago

Wait: there is a issue (i don't know why!!) if SDL_MOUSEDEV is not /dev/null or if SDL_MOUSEDRV is not dummy. You need both variables to set! And you fix the issue by not using the cached SDL value that are corrupted if the env is not set. Please try it out to set the envoriment!

BroMarduk commented 5 years ago

No issues with making the code Python3 only as I am moving there eventually but wanted/needed backwards support at this time so my example reflects that. I was just trying to help you fix the case where the mouse coordinates were wrong on occasion as the EVDEV driver is stateful (https://www.kernel.org/doc/html/latest/input/event-codes.html) and the received messages reflect that, but the current code was trying to get the missing position from the pygame driver instead of storing state, which resulted in clicks/touches in inaccurate areas.

Perhaps I misunderstand the last issue, but based on my interpretation of how the code would be used (as a replacement for TSLIB - which fixes the issues with the fact that Adafruit no longer releases a compatible PiTFT capacitive touch driver, I didn't imagine the use case where SDL_MOUSEDEV would not be "/dev/null" or SDL_MOUSEDRV would NOT be "Dummy" as if you were using TSLIB you would be using the Resistive PiTFT (and could use the normal pygame method).

If you could describe the use case for having SDL_MOUSEDEV set (to what I am assuming would be "/dev/input/touchscreen") and SDL_MOUSEDRV set (to what I am assuming would be "TSLIB" - let me know if these assumptions are wrong), I'd be happy to help you figure this out...Also does the issue happen in the current code release or just the code I changed?

On a complete side note, I did extend the pitft_touchscreen code to work with the Adafruit 3.5in Resistive screen (and most likely the 2.8 as well, but I have not fully tested it yet. The Resistive screens use a different EVDEV set of messages and includes Pressure. In addition I added support for dropped events (SYN_DROPPED) messages from EVDEV, which occasionally happen. If you are interested in this code or it helps solve the issue above, I can send it over - I'm really trying to remove any dependencies on the reverted libsdl1.2debian package.

nift4 commented 5 years ago

EDIT

Better help in the next comment!

Original Post

I must make docs.With my driver you dont need any special libsdl1.2debian. That was from the resistive touch screen because for it TSLIB worked and the Adafruit guys haven't removed it from the capacitive help page (For it TSLIB don't work). Because TSLIB isn't working I have created the driver. But EvDev has also a backend to SDL but that is crazy(If I move my finger up, the cursor is jumping randomly). My driver is also a communication of EVDEV to the PyGame event system. The mousedriver(SDL_MOUSEDRV) should be set to "dummy" because EvDev is buggy, TSLIB is not working and so I add my own emulated events to the queue (in pigame.run()). But somewhat is buggy if the mousedevice(SDL_MOUSEDEV) is not "/dev/null".

nift4 commented 5 years ago

PRESIDENOTE: I moved all pigame related projects except Raspberry-Pi-Testing to a organisation named pigamedrv :) EDIT: This documentation page (yes, I started to write documentation) can be helpful

What who where???

Touch detection

libsdl1.2debian

If reverted TSLIB interface works properly.

TSLIB

The default interface for the resestive, a SDL_MOUSEDRV. Don't accepting the device file of the capacitive touchscreen 2.8".

evdev

It's a dependecy of pitft_touchscreen but it's also bugging around with SDL/PyGame. To stop it use BOTH variables: SDL_MOUSEDRV=dummy SDL_MOUSEDEV=/dev/null

pigame

Why this works with SDL_MOUSEDRV=dummy?

Because its using PyGame's event system (not SDL/PyGame's driver system, SDL is the framework behind PyGame) to add custom mouse events(MOUSEBUTTONUP etc.).

What's doing this? pitft_touchscreen is doing touch detection!

It adds events from pitft_touchscreen after convertion to PyGame.

Python2.7 support

I accept pull requests that add support for Python 2.7 (if it's not supported already) if they keep Python 3 support.

The pitft_touchscreen updates from you

Hmm, this driver/connector is orginally designed for ONLY the 2.8" capacitive. For the 2.8" Resistive is full support if you revert libsdl1.2debian. But I read you don't want old versions of SDL. If you maintain the code for supporting that models and the other specific hardware related things it's okay. You must maintain the 2.8" Resistive support and 3.5" support because i don't have them! For more discussion I refer to: #4

Some thing

In your PTMenu README I read "all touchdisplays need kernel changes"! The 2.8" both capacitive and resistive have a userland driver: pigame (for capacitive touch) TSLIB(for resistive touch) something from the Adafruit site(Graphics and whatever). :)

What questions I have?

Can you push the code with extended support over there? EDIT: Found: https://github.com/BroMarduk/pitft_touchscreen/tree/add-resistive-screen-support Can you simply run your code (without why?) with the enviorment variables SDL_MOUSEDEV=/dev/null SDL_MOUSEDRV=dummy python mycode.py

BroMarduk commented 5 years ago

Yes, you found it. I made a few changes to https://github.com/BroMarduk/pitft_touchscreen/tree/add-resistive-screen-support today, with latest updates, as I am still testing the new features.

I currently set SDL_MOUSEDEV=/dev/null and SDL_MOUSEDRV=dummy in my code. I plan do to smart detection in the future, but for now this works for me. Screen.EvDisplays simply contains a list of supported devices at this point and Defaults.tft_type is the current display.

        import os

        # TFT TYPE CONSTANTS
        DISP22NT   = AF_2315 = NONE22 = 1  # GPIOs 17,22,23,27,(18)
        DISP24R    = AF_2455 = RES24  = 2  # GPIOs 16,13,12,6,5,(18)
        DISP28R    = AF_1601 = RES28  = 3  # GPIOs 23,22,21/27,18,(None)
        DISP28C    = AF_1983 = CAP28  = 4  # GPIOs 23,22,21/27,17,(18)
        DISP28RP   = AF_2298 = RES28P = 5  # GPIOs 17,22,23,27,(18)
        DISP28CP   = AF_2423 = CAP28P = 6  # GPIOs 17,22,23,27,(18)
        DISP32RP   = AF_2626 = RES32P = 7  # GPIOs 22,23,17,27,(18)
        DISP35R    = AF_2097 = RES35  = 8  # GPIOs (18)
        DISP35RP   = AF_2441 = RES35P = 9  # GPIOs (18)

        # Initialize touchscreen drivers
        if Defaults.tft_type is not DISP22NT:
            os.environ["SDL_FBDEV"] = Screen.FrameBuffDevTft  
            if Defaults.tft_type in Screen.EvDisplays:
                os.environ["SDL_MOUSEDEV"] = Screen.NullInput
                os.environ["SDL_MOUSEDRV"] = Screen.TouchDrvDummy
            else:
                os.environ["SDL_MOUSEDEV"] = Screen.TouchscreenInput
                os.environ["SDL_MOUSEDRV"] = Screen.TouchDrvTslib

I modified your code and put it in classes that I use internally. They are selected based on the type of supported display. Again, I can make this automatic in the future (I think). Resistive screens also allow a calibration setting (For defaults, I used the old Adafruit driver defaults). I think this can be more automated (if X-server is installed for instance). For now I just played around to get the lowest and highest values I could on my screen and used those for my calibration values for better touch accuracy.

My Selection Code:

        pygame.init()
        if Defaults.tft_type in Screen.EvDisplays:
            if Defaults.tft_type is DISP28C or Defaults.tft_type is DISP28CP:
                cls.event_device = TftCapacitiveEvHandler()
                cls.event_device.start(Orientation.Landscape, Resolution.SmallPortrait)
            if Defaults.tft_type is DISP35R or Defaults.tft_type is DISP35RP:
                cls.event_device = TftResistiveEvHandler()
                cls.event_device.start(Orientation.Landscape_Inverted, Resolution.MediumPortrait, [137, 3947, 97, 3870])
        if Defaults.tft_type is not DISP22NT:
            pygame.mouse.set_visible(False)

In addition to adding resistive support (which required some graph paper and math skills to get right), I have also added untested portrait support that I will need. Sorry for the long variable name changes, it matches current code though.

Modified code is here

class TftEvHandler(object):
    pitft = None
    prev_loc = {'x': False, 'y': False}
    event_state = 0
    rotation = 0
    resolution = [240, 320]

    def start(self, rotation=90, resolution=None, grab=False):
        if self.resolution is not None:
            self.resolution = resolution
        self.rotation = rotation
        self.pitft = TftTouchscreen(Screen.TouchscreenInput, grab=grab)
        self.pitft.start()

    def run(self):
        pass

    def stop(self):
        self.pitft.stop()

class TftResistiveEvHandler(TftEvHandler):

    def __init__(self):
        self.calibration = [200, 3900, 120, 3800]  # Adafruit driver defaults
        self.x_ratio = 1.0
        self.y_ratio = 1.0

    def start(self, rotation=270, resolution=None, calibration=None, grab=False):
        if calibration is not None:
            self.calibration = calibration
        self.x_ratio = float(1) / ((float(self.calibration[1]) - abs(self.calibration[0])) / self.resolution[0])
        self.y_ratio = float(1) / ((float(self.calibration[3]) - abs(self.calibration[2])) / self.resolution[1])
        super(TftResistiveEvHandler, self).start(rotation, resolution, grab)

    def run(self):
        while not self.pitft.queue_empty():
            for ts_event in self.pitft.get_event():
                # Set the pygame event coordinates to the last settings.  This
                # allows us to handle the case where a click occured in the
                # same spot on one or both of the axes.
                pg_event = {'y': self.prev_loc['y'], 'x': self.prev_loc['x']}
                if ts_event['x'] is not None:
                    pg_event['y'] = int(round((ts_event['x'] - self.calibration[0]) * self.x_ratio))
                if ts_event['y'] is not None:
                    pg_event['x'] = int(round((ts_event['y'] - self.calibration[2]) * self.y_ratio))
                # If there is still no X & Y coordinates at this point, throw
                # away the event....something strange is afoot
                if  pg_event['x'] is None or pg_event['y'] is None:
                    break
                pg_rel = (pg_event['x'] - self.prev_loc['x'], pg_event['y'] - self.prev_loc['y'])
                self.prev_loc = {'y': pg_event['y'], 'x': pg_event['x']}
                if self.rotation == 0:
                    pass
                elif self.rotation == 90:
                    pg_event = {'x': pg_event['x'], 'y': self.resolution[0] - pg_event['y']}
                elif self.rotation == 180:
                    pg_event = {'x': self.resolution[0] - pg_event['x'], 'y': self.resolution[1] - pg_event['y']}
                elif self.rotation == 270:
                    pg_event = {'x': self.resolution[1] - pg_event['x'], 'y': pg_event['y']}
                else:
                    raise Exception("Unsupported display rotation")
                pg_dict = {}
                pg_event_type = MOUSEBUTTONUP if ts_event['touch'] == 0 else (
                    MOUSEBUTTONDOWN if self.event_state == 0 else MOUSEMOTION)
                if pg_event_type == MOUSEBUTTONDOWN:
                    self.event_state = 1
                    pg_dict['button'] = 1
                    pg_dict['pos'] = (pg_event['x'], pg_event['y'])
                    pygame.mouse.set_pos(pg_event['x'], pg_event['y'])
                elif pg_event_type == MOUSEBUTTONUP:
                    self.event_state = 0
                    pg_dict['button'] = 1
                    pg_dict['pos'] = (pg_event['x'], pg_event['y'])
                else:
                    pg_dict['buttons'] = (True, False, False)
                    pg_dict['rel'] = pg_rel
                    pg_dict['pos'] = (pg_event['x'], pg_event['y'])
                    pygame.mouse.set_pos(pg_event['x'], pg_event['y'])
                pe = pygame.event.Event(pg_event_type, pg_dict)
                pygame.event.post(pe)

class TftCapacitiveEvHandler(TftEvHandler):

    def run(self):
        while not self.pitft.queue_empty():
            for ts_event in self.pitft.get_event():
                # Set the pygame event coordinates to the last settings.  This
                # allows us to handle the case where a click occured in the
                # same spot on one or both of the axes.
                pg_event = {'y': self.prev_loc['y'], 'x': self.prev_loc['x']}
                if ts_event['x'] is not None:
                    pg_event['y'] = ts_event['x']
                if ts_event['y'] is not None:
                    pg_event['x'] = ts_event['y']
                # If there is still no X & Y coordinates at this point, throw
                # away the event....something strange is afoot
                if  pg_event['x'] is None or pg_event['y'] is None:
                    break
                pg_rel = (pg_event['x'] - self.prev_loc['x'], pg_event['y'] - self.prev_loc['y'])
                self.prev_loc = {'y': pg_event['y'], 'x': pg_event['x']}
                if self.rotation == 0:
                    pass
                elif self.rotation == 90:
                    pg_event = {'x': pg_event['x'], 'y': self.resolution[0] - pg_event['y']}
                elif self.rotation == 180:
                    pg_event = {'x': self.resolution[0] - pg_event['x'], 'y': self.resolution[1] - pg_event['y']}
                elif self.rotation == 270:
                    pg_event = {'x': self.resolution[1] - pg_event['x'], 'y': pg_event['y']}
                else:
                    raise Exception("Unsupported display rotation")
                pg_dict = {}
                pg_event_type = MOUSEBUTTONUP if ts_event['touch'] == 0 else (
                    MOUSEBUTTONDOWN if self.event_state == 0 else MOUSEMOTION)
                if pg_event_type == MOUSEBUTTONDOWN:
                    self.event_state = 1
                    pg_dict['button'] = 1
                    pg_dict['pos'] = (pg_event['x'], pg_event['y'])
                    pygame.mouse.set_pos(pg_event['x'], pg_event['y'])
                elif pg_event_type == MOUSEBUTTONUP:
                    self.event_state = 0
                    pg_dict['button'] = 1
                    pg_dict['pos'] = (pg_event['x'], pg_event['y'])
                else:
                    pg_dict['buttons'] = (True, False, False)
                    pg_dict['rel'] = pg_rel
                    pg_dict['pos'] = (pg_event['x'], pg_event['y'])
                    pygame.mouse.set_pos(pg_event['x'], pg_event['y'])
                pe = pygame.event.Event(pg_event_type, pg_dict)
                pygame.event.post(pe)

And in my main loop, I just call the run method before processing pygame messages in loop.


            while cls.loop:
                if Defaults.tft_type in Screen.EvDisplays:
                    cls.event_device.run()    #Either TftCapacitiveEvHandleror or TftResistiveEvHandler```
nift4 commented 5 years ago

I must say: I have also class updates, in the branch morefnc :)

nift4 commented 5 years ago

For resistive support write and explain in #4 please, but I'm right the pointer jumping bug is closed, right?

BroMarduk commented 5 years ago

Your call. The current python code in branch morefnc still does not solve the issue with some touches occurring at the wrong places, but if you want to fix it all under issue #4 that is fine. With issue #2 you have the same basic fix where you really need to keep state in your code for the rel and for the last x and y coordinates received. Your method of attempting to get the missing coordinate from _pygame.mouse.getpos is not always working, at least for me:

e={"y":(r["x"] if r["x"] else pygame.mouse.get_pos()[0]),"x":(r["y"] if r["y"] else pygame.mouse.get_pos()[1])}

BTW, other than the issue above, this code has been pretty rock solid. You'll note I made almost no changes in my code other than variable naming and adding portrait mode.

I highlighted my changed lines with --->. All you really need to do is switch the method of getting the missing coordinate from pygame to getting it from the cached coordinate and the issue goes away.

while not self.pitft.queue_empty():
            for ts_event in self.pitft.get_event():
                # Set the pygame event coordinates to the last settings.  This
                # allows us to handle the case where a click occurred in the
                # same spot on one or both of the axes.
        ---> pg_event = {'y': self.prev_loc['y'], 'x': self.prev_loc['x']}
                if ts_event['x'] is not None:
                    pg_event['y'] = ts_event['x']
                if ts_event['y'] is not None:
                    pg_event['x'] = ts_event['y']
                # If there is still no X & Y coordinates at this point, throw
                # away the event....something strange is afoot
                if  pg_event['x'] is None or pg_event['y'] is None:
                    break
        --->  pg_rel = (pg_event['x'] - self.prev_loc['x'], pg_event['y'] - self.prev_loc['y'])
        --->  self.prev_loc = {'y': pg_event['y'], 'x': pg_event['x']}
                if self.rotation == 0:
                    pass
                elif self.rotation == 90:
                    pg_event = {'x': pg_event['x'], 'y': self.resolution[0] - pg_event['y']}
                elif self.rotation == 180:
                    pg_event = {'x': self.resolution[0] - pg_event['x'], 'y': self.resolution[1] - pg_event['y']}
                elif self.rotation == 270:
                    pg_event = {'x': self.resolution[1] - pg_event['x'], 'y': pg_event['y']}
                else:
                    raise Exception("Unsupported display rotation")
                pg_dict = {}
                pg_event_type = MOUSEBUTTONUP if ts_event['touch'] == 0 else (
                    MOUSEBUTTONDOWN if self.event_state == 0 else MOUSEMOTION)
                if pg_event_type == MOUSEBUTTONDOWN:
                    self.event_state = 1
                    pg_dict['button'] = 1
                    pg_dict['pos'] = (pg_event['x'], pg_event['y'])
                    pygame.mouse.set_pos(pg_event['x'], pg_event['y'])
                elif pg_event_type == MOUSEBUTTONUP:
                    self.event_state = 0
                    pg_dict['button'] = 1
                    pg_dict['pos'] = (pg_event['x'], pg_event['y'])
                else:
                    pg_dict['buttons'] = (True, False, False)
        --->        pg_dict['rel'] = pg_rel
                    pg_dict['pos'] = (pg_event['x'], pg_event['y'])
                    pygame.mouse.set_pos(pg_event['x'], pg_event['y'])
                pe = pygame.event.Event(pg_event_type, pg_dict)
                pygame.event.post(pe)
nift4 commented 5 years ago

SDL_MOUSEDRV and SDL_MOUSEDEV also hasn't fixed the issue?

nift4 commented 5 years ago

The thing why I get them from pygame is that eventually the application has also a mouse (not only a touchscreen), in your updates the pigame driver is "eating" other mouses.

nift4 commented 5 years ago

Rel fixed in #2

nift4 commented 5 years ago

Can you test the example code from https://github.com/nift4/Raspberry-Pi-Testing/blob/master/sdl.py with pigame from master and pitft_touchscreen from me? Is the cursor jumping around?

BroMarduk commented 5 years ago

I did run the above test code and got a similar issue. I ran the application and tapped repeatedly on the center of the 17off section of the screen...approximately 3 times a second. Of the 17 taps I made on this execution, 12 showed the correct 17off, 4 the incorrect 4off and one initiated a shutdown, which is when the output stopped. I can repeat this process at will, although the number of incorrect events will vary - it depends on how many touches have the X or Y coordinate exactly the same. I could see the mouse moving to places that were not being tapped.

This is on a Adafruit Captative touch 2.8 screen running the latest Raspian Lite (from 2018-11-13)

Here is the output from the test:

pygame 1.9.4.post1
Hello from the pygame community. https://www.pygame.org/contribute.html
Input device /dev/input/touchscreen found
93 182
93 182
17off
94 186
93 188
17off
188 182
92 184
17off
93 186
93 186
17off
186 188
186 188
4off
91 187
91 187
17off
187 185
187 185
4off
90 184
90 184
17off
92 187
92 187
17off
91 188
91 188
17off
93 195
93 195
17off
195 188
195 188
4off
188 45
92 190
17off
94 191
94 191
17off
93 190
93 190
17off
190 189
190 189
4off
95 50
95 50

Looking at these results, it was fairly easy to spot that you have the _pygame.mouse.getpos()[0] and _pygame.mouse.getpos()[1] swapped the first time is used (since the axes in Pygame are reversed from the event, the x should use [1] and y should use [0]). But even fixing this was still causing misplaced touches, albeit less often.

If I edit pigame.py as follows (adding and storing the previous location [pl]), the clicks occur as expected every time.

import pygame,pitft_touchscreen
from pygame.locals import *
pitft=pitft_touchscreen.pitft_touchscreen()
pitft.pigameevs=[]
pitft.pl={'x':0,'y':0}
def init(rotation:int=90):
    pitft.pigamerotr=rotation
    pitft.start()
def run():
    while not pitft.queue_empty():
        for r in pitft.get_event():
            e={"y":(r["x"] if r["x"] else pitft.pl["x"]),"x":(r["y"] if r["y"] else pitft.pl["y"])}
            if e["x"] is None or e["y"] is None:
                break
            rel=(e["x"]-pitft.pl["x"],e["y"]-pitft.pl["y"])
            pitft.pl={"x":e["x"],"y":e["y"]}
            if pitft.pigamerotr==90:
                e={"x":e["x"],"y":240-e["y"]}
            elif pitft.pigamerotr==270:
                e={"x":320-e["x"],"y":e["y"]}
            else:
                raise(Exception("PiTft rotation is unsupported"))
            d={}
            t=MOUSEBUTTONUP if r["touch"]==0 else (MOUSEMOTION if r["id"] in pitft.pigameevs else MOUSEBUTTONDOW$
            if t==MOUSEBUTTONDOWN:
                d["button"]=1
                d["pos"]=(e["x"],e["y"])
                pitft.pigameevs.append(r["id"])
                pygame.mouse.set_pos(e["x"],e["y"])
            elif t==MOUSEBUTTONUP:
                l=[]
                for x in pitft.pigameevs:
                    if x!=r["id"]:
                        l.append(x)
                pitft.pigameevs=l
                d["button"]=1
                d["pos"]=(e["x"],e["y"])
            else:
                d["buttons"]=(True,False,False)
                d["rel"]=rel
                d["pos"]=(e["x"],e["y"])
                pygame.mouse.set_pos(e["x"],e["y"])
            pe=pygame.event.Event(t,d)
            pygame.event.post(pe)
def quit():
    pitft.stop()

I'm just trying to share what I found as this code is linked to on the Adafruit site and it was working great for me except on those rare location errors. I spent a good amount of time getting to the bottom of this and solving it for myself. If a touch occurs at the same X or Y position as the last event, the next evdev event only shows deltas (or in cases where the X and Y tap were at the EXACT same position, you get no new X and Y values). For some reason using the _pygame.mouse.getpos to get and set the missing values does not work (even when corrected) and causes the missed hits. By storing the previous event state, you keep the actual locations stored and when you get an event missing an X or Y because it was in the exact same position, you can re-inject that value back in and they are always what EVDEV is telling us (or in this case NOT telling us :)).

If you could run your copy of pigame and attempt to do what I did by clicking repeatedly on the same part of the 17off part of the screen. Depending on how accurate your taps are at hitting an exact same X or Y coordinate, you should see the same results.

BroMarduk commented 5 years ago

__****

      The thing why I get them from pygame is that eventually the application has also a mouse (not only a touchscreen), in your updates the pigame driver is "eating" other mouses.

This is interesting as I do not have a mouse normally attached - I use the touch screen only in CLI mode and my previous code may very well reflect that. Looking at the modifications I made to your code in my previous comment, the only real difference is where the the missing values from EVDEV are being filled in. In your case you are using pygame and in mine I'm keeping state from EVDEV. Knowing what I know about EVDEV, I believe my way is more inline with the way EVDEV operates, but I don't really know your use case and you may have a very good reason to use pygame.

nift4 commented 5 years ago

Okay, you won :) If this fixes the issue (and i don't think anybody will need a mouse if you got a touchscreen, but there are guys that doing everything :)) I will commit your code. Please Test it at the end and if works close it :)

BroMarduk commented 5 years ago

Danke, but just trying to get working, efficient code out there - Hopefully you tried and saw what I was seeing. That said, you definitely identified a case that I had not thought of so I'm going to bring a wired mouse home today and see what happens. I really don't know how EVDEV reacts with a mouse attached, but I want to find out. Will let you know what I find.

Another case I want to support in the future is a multi-touch screen like the Pimoroni HyperPixel, but that requires working with EVDEV SLOT messages and is a whole lot more complicated with multiple states maintained.

I'll let you know when I get things stabilized.

On another note, Przemo and I modified the underlying pitft_touchscreen code with better threading support and some additional functionality. You may want to look at merging those changes into your fork.

nift4 commented 5 years ago

yes i merge, also speaking german?

nift4 commented 5 years ago

Hallo xD

nift4 commented 5 years ago

Created branch bug1_fix

BroMarduk commented 5 years ago
      yes i merge, also speaking german?

I used to have a company in German (Köln), so I picked a bunch up while working with the folks there. I can understand a bit, but fluent, no way :)

nift4 commented 5 years ago

:) f9f536b fixes some important things...

nift4 commented 5 years ago

Pull request that needs testing for the changes now live: #6

nift4 commented 5 years ago

Fir morefnc i will implement changes

nift4 commented 5 years ago

Here is the morefnc pull request: #7

nift4 commented 5 years ago

7 needed

BroMarduk commented 5 years ago

I tested at both 90 and 270 rotation and I can't see any issues. Recommend marking this closed if you are good with status.

goose2000 commented 5 years ago

Hey, will do, trying it today - sorry been pulled away