QB64.org Forum

Active Forums => QB64 Discussion => Topic started by: johannhowitzer on October 20, 2021, 12:41:11 am

Title: Mouse input lag
Post by: johannhowitzer on October 20, 2021, 12:41:11 am
Is there a way in a _limit 60 loop to have the mouse input data keep current?

Code: QB64: [Select]
  1. color 0, 15
  2.  
  3. const true = -1
  4. const false = 0
  5.  
  6. dim shared dev_keyboard as byte ' Store device index, to be re-checked whenever inputs are involved
  7. dim shared dev_gamepad  as byte
  8. dim shared dev_mouse    as byte
  9. const keyboard = 1
  10. const gamepad  = 2
  11. const mouse    = 3
  12.  
  13. dim shared mouse_press(3)     as byte
  14. dim shared mouse_hold(3)      as byte
  15. dim shared mouse_press_x(3)   as integer ' Records where mouse button press started
  16. dim shared mouse_press_y(3)   as integer
  17. dim shared mouse_release_x(3) as integer ' Records where mouse button was released
  18. dim shared mouse_release_y(3) as integer
  19.  
  20. call update_inputs
  21.  
  22.    limit 60
  23.    cls , 15
  24.  
  25.    r = 15
  26.    for b = 1 to 3
  27.       locate b: print mouse_press_x(b); mouse_press_y(b), , mouse_release_x(b); mouse_release_y(b)
  28.       print mousex, mousey
  29.       h = (b * 2) + 7
  30.  
  31.       x1 = mouse_press_x(b)
  32.       y1 = mouse_press_y(b)
  33.  
  34.       x2 = mouse_release_x(b)
  35.       y2 = mouse_release_y(b)
  36.  
  37.       circle(x1, y1), r, h
  38.       if mouse_press(b) = false and mouse_hold(b) = true then paint(x1, y1), 0, h
  39.  
  40.       circle(x2, y2), r, h + 1
  41.       if mouse_press(b) = false and mouse_hold(b) = true then paint(x2, y2), 0, h + 1
  42.    next b
  43.    display
  44.  
  45.    call update_inputs
  46.  
  47.  
  48. sub detect_devices
  49.  
  50. dev_keyboard = false
  51. dev_gamepad  = false
  52. dev_mouse    = false
  53.  
  54. d = devices
  55. for n = d to 1 step -1
  56.    if left$(device$(n), 10) = "[KEYBOARD]"   then dev_keyboard = n
  57.    if left$(device$(n), 12) = "[CONTROLLER]" then dev_gamepad  = n
  58.    if left$(device$(n),  7) = "[MOUSE]"      then dev_mouse    = n
  59.  
  60.  
  61.  
  62. sub update_inputs
  63.  
  64. call detect_devices
  65.  
  66. if dev_mouse <> false then
  67.    z = mouseinput
  68. '   z = deviceinput(dev_mouse)
  69.  
  70.    for b = 1 to 3
  71.       if b > lastbutton(dev_mouse) then exit for
  72.  
  73.       mouse_hold(b)  = mouse_press(b)
  74.       mouse_press(b) = mousebutton(b)
  75.  
  76.       ' Wait for mouse position read to catch up
  77.       x1 = mousex
  78.       y1 = mousey
  79.       do
  80. '         z = mouseinput
  81.          x2 = x1
  82.          y2 = y1
  83.          x1 = mousex
  84.          y1 = mousey
  85.       loop until x1 = x2 and y1 = y2
  86.  
  87.       if     mouse_press(b) = true and mouse_hold(b) = false then
  88.          mouse_press_x(b) = mousex
  89.          mouse_press_y(b) = mousey
  90.       elseif mouse_press(b) = false and mouse_hold(b) = true then
  91.          mouse_release_x(b) = mousex
  92.          mouse_release_y(b) = mousey
  93.       end if
  94.    next b
  95.  
  96.  

Running this, as you move the mouse around, you can see the numbers on row 4 lag way behind what the mouse is actually doing.  If I increase the limit to 30000, it stays current as far as user perception, but it will still be way behind for the same number of loops, it's just running too fast to see this.  It seems like data from mousex and mousey is just lagging behind for some reason, not actually returning the mouse's current position, but rather pulling the oldest value from a stack of position values.

In update_inputs, you can see I tried to counter this by waiting until the position information from subsequent calls was the same.  This does nothing without the z = mouseinput, if you uncomment that line, you can see it improves the speed dramatically, it still lags behind a bit, but catches up much faster.

Do you know of a way to make mousex and mousey be current on every frame, in a limit 60 loop?
Title: Re: Mouse input lag
Post by: luke on October 20, 2021, 01:01:42 am
I have a long-winded discussion of things at https://www.qb64.org/forum/index.php?topic=2377.0 but I think you might be okay with the naive solution:
Code: [Select]
Sub update_inputs

    Call detect_devices

    If dev_mouse <> false Then
        ' Wait for mouse position read to catch up
        Do: Loop While MouseInput

        For b = 1 To 3
            If b > LastButton(dev_mouse) Then Exit For

            mouse_hold(b) = mouse_press(b)
            mouse_press(b) = MouseButton(b)

            If mouse_press(b) = true And mouse_hold(b) = false Then
                mouse_press_x(b) = MouseX
                mouse_press_y(b) = MouseY
            ElseIf mouse_press(b) = false And mouse_hold(b) = true Then
                mouse_release_x(b) = MouseX
                mouse_release_y(b) = MouseY
            End If
        Next b
    End If

End Sub

If you do have issues with missed clicks you'll likely need the "more advanced method" linked above.
Title: Re: Mouse input lag
Post by: Pete on October 20, 2021, 03:28:17 am
Similar to luke's solution...

Code: QB64: [Select]
  1. COLOR 0, 15
  2.  
  3. CONST true = -1
  4. CONST false = 0
  5.  
  6. DIM SHARED dev_keyboard AS BYTE ' Store device index, to be re-checked whenever inputs are involved
  7. DIM SHARED dev_gamepad AS BYTE
  8. DIM SHARED dev_mouse AS BYTE
  9. CONST keyboard = 1
  10. CONST gamepad = 2
  11. CONST mouse = 3
  12.  
  13. DIM SHARED mouse_press(3) AS BYTE
  14. DIM SHARED mouse_hold(3) AS BYTE
  15. DIM SHARED mouse_press_x(3) AS INTEGER ' Records where mouse button press started
  16. DIM SHARED mouse_press_y(3) AS INTEGER
  17. DIM SHARED mouse_release_x(3) AS INTEGER ' Records where mouse button was released
  18. DIM SHARED mouse_release_y(3) AS INTEGER
  19.  
  20. CALL update_inputs
  21.  
  22.     LIMIT 60
  23.     CLS , 15
  24.  
  25.     r = 15
  26.     FOR b = 1 TO 3
  27.         LOCATE b: PRINT mouse_press_x(b); mouse_press_y(b), , mouse_release_x(b); mouse_release_y(b)
  28.         PRINT MOUSEX, MOUSEY
  29.         h = (b * 2) + 7
  30.  
  31.         x1 = mouse_press_x(b)
  32.         y1 = mouse_press_y(b)
  33.  
  34.         x2 = mouse_release_x(b)
  35.         y2 = mouse_release_y(b)
  36.  
  37.         CIRCLE (x1, y1), r, h
  38.         IF mouse_press(b) = false AND mouse_hold(b) = true THEN PAINT (x1, y1), 0, h
  39.  
  40.         CIRCLE (x2, y2), r, h + 1
  41.         IF mouse_press(b) = false AND mouse_hold(b) = true THEN PAINT (x2, y2), 0, h + 1
  42.     NEXT b
  43.     DISPLAY
  44.  
  45.     CALL update_inputs
  46.  
  47.  
  48. SUB detect_devices
  49.  
  50.     dev_keyboard = false
  51.     dev_gamepad = false
  52.     dev_mouse = false
  53.  
  54.     d = DEVICES
  55.     FOR n = d TO 1 STEP -1
  56.         IF LEFT$(DEVICE$(n), 10) = "[KEYBOARD]" THEN dev_keyboard = n
  57.         IF LEFT$(DEVICE$(n), 12) = "[CONTROLLER]" THEN dev_gamepad = n
  58.         IF LEFT$(DEVICE$(n), 7) = "[MOUSE]" THEN dev_mouse = n
  59.     NEXT n
  60.  
  61.  
  62.  
  63. SUB update_inputs
  64.  
  65.     CALL detect_devices
  66.  
  67.     IF dev_mouse <> false THEN
  68.         '''z = MOUSEINPUT
  69.         '   z = deviceinput(dev_mouse)
  70.  
  71.         FOR b = 1 TO 3
  72.             IF b > LASTBUTTON(dev_mouse) THEN EXIT FOR
  73.  
  74.             mouse_hold(b) = mouse_press(b)
  75.             mouse_press(b) = MOUSEBUTTON(b)
  76.  
  77.             ' Wait for mouse position read to catch up
  78.             x1 = MOUSEX
  79.             y1 = MOUSEY
  80.             '''DO
  81.             WHILE MOUSEINPUT: WEND
  82.             '         '''z = mouseinput
  83.             x2 = x1
  84.             y2 = y1
  85.             x1 = MOUSEX
  86.             y1 = MOUSEY
  87.             ''''LOOP UNTIL x1 = x2 AND y1 = y2
  88.  
  89.             IF mouse_press(b) = true AND mouse_hold(b) = false THEN
  90.                 mouse_press_x(b) = MOUSEX
  91.                 mouse_press_y(b) = MOUSEY
  92.             ELSEIF mouse_press(b) = false AND mouse_hold(b) = true THEN
  93.                 mouse_release_x(b) = MOUSEX
  94.                 mouse_release_y(b) = MOUSEY
  95.             END IF
  96.         NEXT b
  97.     END IF
  98.  
  99.  

See the added WHILE MOUSEINPUT: WEND and the removed code with ''' remark signs.

Pete
Title: Re: Mouse input lag
Post by: johannhowitzer on October 20, 2021, 04:06:45 am
Thanks, that's exactly what I was looking for.  My solution probably didn't work perfectly because due to rounding, there would be some back to back identical coordinate pairs in the stream of mouse data.  I read the more in-depth stuff, and I'll add in the button state change catch too.

First time using mouse in anything qbasic related!  In the past I've only ever cared about keyboard and gamepad, but I'm trying to make a manual-input tracker for a game, and clicking is way more user-friendly for that.
Title: Re: Mouse input lag
Post by: Pete on October 20, 2021, 10:57:38 am
Mouse and Keyboard Library

If it helps, this is something I cooked up awhile ago and I use it with most of my programs. It does not detect gaming devices, as I don't really do game applications, but is does handle all mouse usage, including left, right, and middle button down and release status, mouse wheel up and down, left double click, left drag, etc. It also handles key press identification for INKEY$ and returns values for Alt, Ctrl, and Shift keys when held down.

I made this particular using TYPE declared variables, but as you already know, that could be changed to standard variable use. I like TYPE usage for a library use, because it is easy to pass the variables as a TYPE rather than long list of parameters or using DIM SHARED to pass them.

Code: QB64: [Select]
  1. mydemo% = -1
  2. DIM UI AS UserInput
  3.  
  4. TYPE UserInput
  5.     KeyPress AS STRING
  6.     KeyCombos AS INTEGER
  7.     MbStatus AS INTEGER
  8.     MbEnvoked AS INTEGER
  9.     drag AS INTEGER
  10.     DoubleClick AS INTEGER
  11.     MbLeftx AS INTEGER
  12.     MbLefty AS INTEGER
  13.     mx AS INTEGER
  14.     oldmx AS INTEGER
  15.     my AS INTEGER
  16.     oldmy AS INTEGER
  17.  
  18. PRINT "Press keys or use mouse for demo.";
  19.     CALL keyboard_mouse(UI, mydemo%)
  20.     IF UI.MbStatus < 0 AND UI.MbEnvoked = 0 THEN
  21.         SOUND 1000, .3: UI.MbEnvoked = -1
  22.     END IF
  23.     IF UI.KeyPress = CHR$(13) THEN BEEP: EXIT DO
  24.  
  25.     CALL keyboard_mouse(UI, mydemo%)
  26.     IF UI.MbStatus > 0 AND UI.MbEnvoked = 0 THEN
  27.         SOUND 300, .3: UI.MbEnvoked = 1
  28.     END IF
  29.  
  30.  
  31. SUB keyboard_mouse (UI AS UserInput, mydemo%)
  32.     STATIC z1, lclick
  33.  
  34.     _LIMIT 30
  35.  
  36.     DEF SEG = 0
  37.     IF PEEK(1047) MOD 16 = 1 OR PEEK(1047) MOD 16 = 2 THEN
  38.         UI.KeyCombos = 1 ' Shift  % = -1 ELSE shift% = 0
  39.     ELSEIF PEEK(1047) MOD 16 = 3 OR PEEK(1047) MOD 16 = 4 THEN
  40.         UI.KeyCombos = 2 ' Ctrl  % = -1 ELSE ctrl% = 0
  41.     ELSEIF PEEK(1047) MOD 16 = 7 OR PEEK(1047) MOD 16 = 8 THEN
  42.         UI.KeyCombos = 3 ' Alt  % = -1
  43.     ELSEIF PEEK(1047) MOD 16 = 5 OR PEEK(1047) MOD 16 = 6 THEN
  44.         UI.KeyCombos = 4 ' Ctrl+Shift  % = -1 ELSE ctrlshift% = 0
  45.     ELSE
  46.         UI.KeyCombos = 0
  47.     END IF
  48.     DEF SEG
  49.  
  50.     IF mydemo% THEN GOSUB check_UI.KeyCombos
  51.  
  52.     UI.KeyPress = INKEY$
  53.     IF LEN(UI.KeyPress) THEN ' A key was pressed.
  54.         UI.MbEnvoked = 0: UI.MbLeftx = 0
  55.         SELECT CASE LEN(UI.KeyPress)
  56.             CASE 1 ' 1-byte key A-Z, etc.
  57.                 IF mydemo% THEN mydemo% = 1: GOSUB mydemo
  58.                 SELECT CASE UI.KeyPress
  59.                     ' Place key selection routine here...
  60.                     CASE CHR$(27): SYSTEM
  61.                 END SELECT
  62.             CASE 2 '2-byte key F1-F12, etc.
  63.                 IF mydemo% THEN mydemo% = 2: GOSUB mydemo
  64.                 SELECT CASE RIGHT$(UI.KeyPress, 1)
  65.                     ' Place key selection routine here...
  66.                 END SELECT
  67.         END SELECT
  68.     ELSE ' Check for mouse input since no keyboard input was detected.
  69.  
  70.         IF lclick THEN ' Check timer for double-clicks.
  71.             IF TIMER < z1 THEN z1 = z1 - 86400 ' Midnight adjustment.
  72.             IF TIMER - z1 > .33 THEN lclick = 0 ' Too much time ellapsed for a double click.
  73.         END IF
  74.  
  75.         WHILE _MOUSEINPUT
  76.             mw = mw + _MOUSEWHEEL ' Check for mouse wheel use.
  77.         WEND
  78.  
  79.         ' Get mouse status.
  80.         UI.mx = _MOUSEX
  81.         UI.my = _MOUSEY
  82.         lb = _MOUSEBUTTON(1)
  83.         rb = _MOUSEBUTTON(2)
  84.         mb = _MOUSEBUTTON(3)
  85.  
  86.         SELECT CASE UI.MbEnvoked
  87.             CASE 0
  88.                 IF lb OR rb OR mb THEN
  89.  
  90.                 END IF
  91.             CASE 1
  92.                 IF lb OR rb OR mb THEN UI.MbEnvoked = 0
  93.             CASE -1
  94.                 IF lb = 0 AND rb = 0 AND mb = 0 THEN UI.MbEnvoked = 0
  95.         END SELECT
  96.  
  97.         ' Check for mouse movement.
  98.         IF UI.mx <> UI.oldmx OR UI.my <> UI.oldmy THEN
  99.             oldcsrlin = CSRLIN: oldpos = POS(0)
  100.             LOCATE 3, 1: PRINT "Mouse row/col ="; UI.my; UI.mx; "     ";: LOCATE oldcsrlin, oldpos
  101.         END IF
  102.  
  103.         IF UI.MbStatus < 0 THEN ' Mouse button pressed. UI.MbStatus identity is by number. -1=left, -2=right, -3=middle.
  104.             SELECT CASE UI.MbStatus
  105.                 CASE -1 ' Left button was pressed.
  106.                     IF lb = 0 THEN ' Left button released.
  107.                         SELECT CASE lclick ' Single or double click analysis.
  108.                             CASE 0
  109.                                 IF mydemo% THEN mydemo% = 3: GOSUB mydemo
  110.                                 lclick = lclick + 1
  111.                             CASE ELSE ' Double click. Completed upon 2nd left button release.
  112.                                 IF mydemo% THEN mydemo% = 11: GOSUB mydemo
  113.                                 UI.DoubleClick = -1
  114.                                 lclick = 0
  115.                         END SELECT
  116.                         UI.MbStatus = 1
  117.  
  118.                         IF UI.MbLeftx THEN
  119.                             IF UI.mx <> UI.MbLeftx OR UI.my <> UI.MbLefty THEN UI.MbStatus = 0: lclick = 0
  120.                             UI.MbLeftx = 0: UI.MbLefty = 0
  121.                         END IF
  122.  
  123.                         IF UI.drag THEN UI.drag = 0
  124.                     ELSE ' Left button is being held down. Check for UI.drag.
  125.                         IF UI.mx <> UI.oldmx OR UI.my <> UI.oldmy THEN ' Mouse cursor has moved. UI.drag.
  126.                             IF mydemo% THEN mydemo% = 12: GOSUB mydemo
  127.                             UI.drag = -1
  128.                         END IF
  129.                     END IF
  130.                 CASE -2 ' Right button was pressed.
  131.                     IF rb = 0 THEN ' Right button was relased.
  132.                         IF mydemo% THEN mydemo% = 4: GOSUB mydemo
  133.                         UI.MbStatus = 2
  134.                     END IF
  135.                 CASE -3 ' Middle button was pressed
  136.                     IF mb = 0 THEN ' Middle button was released.
  137.                         IF mydemo% THEN mydemo% = 5: GOSUB mydemo
  138.                         UI.MbStatus = 3
  139.                     END IF
  140.             END SELECT
  141.         ELSE
  142.             IF lb THEN ' Left button just pressed.
  143.                 IF mydemo% THEN mydemo% = 6: GOSUB mydemo
  144.                 UI.MbStatus = -1
  145.                 IF UI.MbLeftx = 0 THEN UI.MbLeftx = UI.mx: UI.MbLefty = UI.my
  146.                 z1 = TIMER
  147.             ELSEIF rb THEN ' Right button just pressed.
  148.                 IF mydemo% THEN mydemo% = 7: GOSUB mydemo
  149.                 IF UI.MbLeftx = 0 THEN UI.MbLeftx = UI.mx: UI.MbLefty = UI.my
  150.                 UI.MbStatus = -2
  151.             ELSEIF mb THEN ' Middle button just pressed.
  152.                 IF mydemo% THEN mydemo% = 8: GOSUB mydemo
  153.                 IF UI.MbLeftx = 0 THEN UI.MbLeftx = UI.mx: UI.MbLefty = UI.my
  154.                 UI.MbStatus = -3
  155.             ELSEIF mw THEN ' Mouse wheel just moved.
  156.                 SELECT CASE mw
  157.                     CASE IS > 0 ' Scroll down.
  158.                         IF mydemo% THEN mydemo% = 9: GOSUB mydemo
  159.                     CASE IS < 0 ' Scroll up.
  160.                         IF mydemo% THEN mydemo% = 10: GOSUB mydemo
  161.                 END SELECT
  162.             END IF
  163.         END IF
  164.  
  165.         UI.oldmx = UI.mx: UI.oldmy = UI.my: mw = 0 ' Mouse position past and present.
  166.     END IF
  167.     EXIT SUB
  168.  
  169.     mydemo:
  170.     LOCATE 1, 1: PRINT "Last User Status:                                    ";
  171.     LOCATE , 19
  172.     SELECT CASE mydemo%
  173.         CASE 1
  174.             PRINT "1-byte Key = "; UI.KeyPress
  175.         CASE 2
  176.             PRINT "2-byte Key = "; UI.KeyPress
  177.         CASE 3
  178.             PRINT "Left button released."
  179.         CASE 4
  180.             PRINT "Right button released."
  181.         CASE 5
  182.             PRINT "Middle button released."
  183.         CASE 6
  184.             PRINT "Left button down."
  185.         CASE 7
  186.             PRINT "Right button down."
  187.         CASE 8
  188.             PRINT "Middle button down."
  189.         CASE 9
  190.             PRINT "Wheel scroll down."
  191.         CASE 10
  192.             PRINT "Wheel scroll up."
  193.         CASE 11
  194.             PRINT "Left button double click."
  195.         CASE 12
  196.             PRINT "Drag..."
  197.     END SELECT
  198.     mydemo% = -1
  199.     RETURN
  200.  
  201.     check_UI.KeyCombos:
  202.     IF UI.KeyCombos THEN
  203.         LOCATE 1, 50
  204.         SELECT CASE UI.KeyCombos
  205.             CASE 1
  206.                 PRINT "Shift key down.        ";
  207.             CASE 2
  208.                 PRINT "Ctrl key down.         ";
  209.             CASE 3
  210.                 PRINT "Alt key down.          ";
  211.             CASE 4
  212.                 PRINT "Ctrl + Shift key down. ";
  213.         END SELECT
  214.     ELSE
  215.         LOCATE 1, 50: PRINT SPACE$(29);
  216.     END IF
  217.     RETURN
  218.  
Title: Re: Mouse input lag
Post by: Dimster on October 20, 2021, 03:35:44 pm
@Pete - Back in Jan of 2020, you had a routine which had the mouse highlighting menu items which were the various States. In that routine you use a _limit 60 but I don't think you used a While MouseInput:Wend line in your code and yet there was no lag that I could see in the selection of any of the items on the menu. I would be interested in knowing what the difference (in terms of Lag/No Lag) between your coding results and what Johannhowitzer is experiencing. I have looked at both codes (myopic as I am) and can't see where the While MouseInput:wend would be inserted tp correct the lag or how your code didn't need that line of code?
Title: Re: Mouse input lag
Post by: Pete on October 20, 2021, 04:06:30 pm
@Dimster Actually, that one from Jan 2020 did have the WHILE _MOUSEINPUT: WEND in the code.

https://www.tapatalk.com/groups/qbasic/a-library-to-make-mouse-selections-from-row-and-co-t39567.html#p213107

What appeared to be slowing up johann's routine was a DO/LOOP

Code: QB64: [Select]
  1. ' Wait for mouse position read to catch up
  2.       x1 = mousex
  3.       y1 = mousey
  4.          x2 = x1
  5.          y2 = y1
  6.          x1 = mousex
  7.          y1 = mousey
  8. loop until x1 = x2 and y1 = y2
  9.  

Now if you could move at lightning speed, like Steve does when dinner is ready, x1 might be at 5 and y1 at 20. All of a sudden, you move the mouse as you enter the loop, so X1 is now 6 and y1 is 21, but x2 will always be 5 in the loop and y2 will always be 5. So you won't be exiting that loop until you mouse around back to 5, 20 again!

Always remember when it comes to mousing around...

WHILE: WEND is your best friend.

Pete
Title: Re: Mouse input lag
Post by: Dimster on October 20, 2021, 05:06:40 pm
Thanks Pete
Title: Re: Mouse input lag
Post by: SMcNeill on October 20, 2021, 06:27:56 pm
IF you guys want to see why mouseinput lags up, here's a quick example for you explaining the situation:

Code: QB64: [Select]
  1. $Let ONLYCHANGES = TRUE
  2.  
  3. f = _LoadFont("courbd.ttf", 36, "monospace")
  4. MX = _MouseX: MY = _MouseY
  5. Dim mx(1000), my(1000)
  6.         $If ONLYCHANGES = TRUE Then
  7.             If MX <> _MouseX Or MY <> _MouseY Then
  8.                 count = count + 1
  9.                 mx(count) = _MouseX: my(count) = _MouseY
  10.                 MX = _MouseX: MY = _MouseY
  11.                 runtimer = -1
  12.             End If
  13.         $Else
  14.             If MX <> _MouseX Or MY <> _MouseY Then runtimer = -1
  15.             If runtimer Then
  16.             count = count + 1
  17.             mx(count) = _MouseX: my(count) = _MouseY
  18.             End If
  19.         $End If
  20.     Wend
  21.     If runtimer = -1 And StartTimer = 0 Then StartTimer = Timer + 1
  22.     If Timer > StartTimer And StartTimer <> 0 Then Exit Do
  23.  
  24. Print count; "mouse events in one second."
  25.  
  26.  

Run the program, drag the mouse around...  See how many mouse x/y change events you generate in a single second.  On my laptop, with the trackpad, I get close to 100 updates per second.

Now, change the $LET to false.  You are now tracking ALL mouse reports in a single second and not just the change events that I marked before.  With my laptop, with the trackpad, I'm getting close to 600 updates per second.

Now, toss that in a program that runs with a _LIMIT of 60 times per second, and it's going to take you one and  a half seconds to just read and react to the change states, and about 10 seconds if you try to process each and every mouse update in that second!

There's no two ways about it, in a situation like that, you end up generating lag with each user input!  It takes 1.5 seconds to process 1 second of mouse activity (at _LIMIT 60... _LIMIT 30, would of course, take twice as long, whereas a _LIMIT 120 may not have noticeable lag at all, as long as the program and PC allows you to run at such a high number of loops per second.)

The way we fix this issue is to simply clear the buffer and only deal with the state when we need it.

DO
    WHILE _MOUSEINPUT:WEND
    x = _mousex: y = _mousey
    LOCATE 1,1: PRINT x, y
    _LIMIT 30
LOOP UNTIL _MOUSEBUTTON(1)

With the above, we clear the mouse buffer with the while-wend statements, and only deal with the mouse state 30 times a second, when our loop processes.  Why would we give a crap where our mouse was located at in the microseconds before we read it??

At 0.000 microseconds the mouse was at 100,100
At 0.010 microseconds the mouse was at 101,100
At 0.020 microseconds the mouse was at 101,101
At 0.030 microseconds the mouse was at 102,101
At 0.040 microseconds the mouse was at 102,102  >-- We read it here.
At 0.050 microseconds the mouse was at 103,102
At 0.060 microseconds the mouse was at 103,103 >-- We read it here.

Every 0.033 seconds we make a loop (30 times a second).  Why do we care where the mouse was at 0.01 seconds?  At 0.02 seconds?  We can toss those X/Y coordinates out as we can't process them without generating a backlog of activity.  Our program is running a loop ever 0.033 seconds, so we only need to know the X/Y coordinates during the refresh of each run cycle.

While-wend the buffer away to only deal with updates when your main loop cycles back around. 

The ONLY thing that you should ever have inside those while-wend loops is a mousewheel checker, if you're using it in your program.  Everything else is just doing it wrong.

WHILE _MOUSEINPUT
    MouseScroll = MouseScroll + _MouseWheel
WEND

Title: Re: Mouse input lag
Post by: Dimster on October 21, 2021, 08:20:36 am
And the light bulb goes off...thanks Steve.
Title: Re: Mouse input lag
Post by: Cobalt on October 21, 2021, 11:05:14 am
A simple:

 DO: nul%% = _MOUSEINPUT: LOOP WHILE nul%%

at the end of my main loop tends to do it for me.
Title: Re: Mouse input lag
Post by: bplus on October 21, 2021, 12:07:56 pm
And the light bulb goes off...thanks Steve.

Doesn't he mean On? But he does call himself the Dimster ;-))
Title: Re: Mouse input lag
Post by: bplus on October 21, 2021, 12:12:16 pm
A simple:

 DO: nul%% = _MOUSEINPUT: LOOP WHILE nul%%

at the end of my main loop tends to do it for me.

This is the same thing with less fuss:

While _MouseInput: Wend

But then again, Cobalt is still shouting keywords at himself. (And I am still underlining.)  ;-))
Title: Re: Mouse input lag
Post by: Pete on October 21, 2021, 12:40:03 pm
It could have been worse...

DO: INT(nul%%) = _MOUSEINPUT: LOOP UNTIL INT(nul%%) > -1 and INT(nul%%) <  1

But it takes FreeBASIC for that!

Pete
Title: Re: Mouse input lag
Post by: Cobalt on October 21, 2021, 01:46:34 pm
But then again, Cobalt is still shouting keywords at himself. (And I am still underlining.)  ;-))

Can I help it that I speak with authority? Not like some little whelp.

I have tried it as

DO:LOOP WHILE _MOUSEINPUT

But that tended to cause issues. Can't remember just what it did now though.
Title: Re: Mouse input lag
Post by: Pete on October 21, 2021, 03:10:29 pm
Can I help it that I speak with authority? Not like some little whelp.

I have tried it as

DO:LOOP WHILE _MOUSEINPUT

But that tended to cause issues. Can't remember just what it did now though.

I vaguely remember issues with either that, or some other similar method. These days, I just stick to using WHILE:WEND.

Pete

DO: LOOP UNTIL SCREEN_0
Title: Re: Mouse input lag
Post by: johannhowitzer on October 22, 2021, 05:09:41 am
Code: QB64: [Select]
  1. sub update_inputs
  2.  
  3. call detect_devices
  4.  
  5. if dev_mouse = false then exit sub
  6.  
  7. dim mb(3)
  8. for b = 1 to 3
  9.    mb(b) = mouse_press(b)
  10.  
  11. mouse_change = false
  12. do while mouseinput <> false and mouse_change = false
  13.    mx = mousex
  14.    my = mousey
  15.    for b = 1 to 3
  16.       mb(b) = mousebutton(b)
  17.       if mb(b) <> mouse_press(b) then mouse_change = true
  18.    next b
  19.  
  20. for b = 1 to 3
  21.    mouse_hold(b) = mouse_press(b)
  22.    mouse_press(b) = mb(b)
  23.  
  24.    if mouse_press(b) = true and mouse_hold(b) = false then
  25.       mouse_press_x(b) = mx ' Store position mouse button was pressed
  26.       mouse_press_y(b) = my
  27.    elseif mouse_press(b) = false and mouse_hold(b) = true then
  28.       mouse_release_x(b) = mx ' Store position mouse button was released
  29.       mouse_release_y(b) = my
  30.    end if
  31.  
  32.  

After reading up on all this, here's the changes I made to the routine.  As I drain mouseinput, I stop it short whenever there's a change in one of the three button states, this way it keeps up, even in limit 60, but it also doesn't miss any clicks - which I read was a concern.  This appears to have no issues at all.
Title: Re: Mouse input lag
Post by: SMcNeill on October 22, 2021, 05:43:02 am
The only clicks you really have to worry about missing are your scroll wheel events.  They update and clear almost instantly, so you need to track them inside your WHILE:WEND loop, but regular left/right mouse input should never be an issue for you.  ;)
Title: Re: Mouse input lag
Post by: luke on October 22, 2021, 07:05:06 am
To demonstrate precisely why a simple Do: Loop While _Mouseinput is insufficient in some cases, consider the following two programs:
Code: [Select]
'Program A
$noprefix
Do
    Do: Loop While MouseInput
    If MouseButton(1) Then
        i = i + 1
        Print "Click"; i; "processing...";
        Delay 0.5
        Print "Done"
    End If
    Limit 30
Loop
Code: [Select]
'Program B
$noprefix
Do
    If MouseInput Then
        If MouseButton(1) = mouse_down Then 'Is the button still in the same position?
            Do While MouseInput
                If MouseButton(1) <> mouse_down Then Exit Do 'Process through the queue until the button changes state
            Loop
        End If
        mouse_down = MouseButton(1)
        'Do mouse processing here
        If mouse_down Then
            i = i + 1
            Print "Click"; i; "processing...";
            Delay 0.5
            Print "Done"
        End If
    End If
    Limit 30
Loop

In both cases, the intention is to capture each mouse click and perform some "processing" on it. Here our "processing" is just a delay to simulate some actual code. Run each program and do some clicks. You should see a new message printed for each click. Now try a double click (two clicks in rapid succession). Assuming you're reasonably quick, you'll notice that program A will only register the first click - any clicks done during the "processing" time are ignored. Program B avoids this by scanning through the input buffer to see if there were any click events that need to be processed.
Title: Re: Mouse input lag
Post by: Pete on October 22, 2021, 11:20:51 am
@luke makes a good point about more advanced mouse usage such as double-clicks, and I'll add drag in that mix. @johannhowitzer  Personally, I strive for flow through code, so all my routines are free of _DELAY statements and continuously cycle back to the main. In the code I posted, you will notice the effects like double-click and drag are obtained by tracking time and mouse button states (pressed and released.) Frankly, I'd wish you'd change your code to the WHILE:WEND model, as it would be easier to help you implement these other features, including _MOUSEWHEEL, as @SMcNeill posted. Of course if you have all that you will ever need for this and other routines cooked into the code you posted, that's fine. I rank creativity over dogma most of the time.

Pete
Title: Re: Mouse input lag
Post by: johannhowitzer on October 22, 2021, 03:23:56 pm
I didn't put double click tracking in there yet, but my code does support dragging, as it not only tracks press and release, but where each happened.  This is partly so I can make sure both happened over the same hotspot - so if you click a button, hold, then release the mouse while not over the button, it won't activate it.
Title: Re: Mouse input lag
Post by: Dimster on October 27, 2021, 10:15:08 am
I'm thinking this thread may have come to an end as interesting and helpful as it was.... but felt I needed to defend myself (ie @bplus .. on/off). Mark is correct, typically a light goes ON but the interchangeable use of ON/OFF is rampant in the English language .. ie "the gun when off" doesn't mean it was turned off and inactive, it means it was turned on and very active... same with the horse races "..and their off" doesn't mean the horses are off the track, it does mean they are very much on the race track and running.

And here's one which is very confusing but logical "..and the Dimster is Off, ON another of his rants."
Title: Re: Mouse input lag
Post by: bplus on October 27, 2021, 10:56:01 am
I'm thinking this thread may have come to an end as interesting and helpful as it was.... but felt I needed to defend myself (ie @bplus .. on/off). Mark is correct, typically a light goes ON but the interchangeable use of ON/OFF is rampant in the English language .. ie "the gun when off" doesn't mean it was turned off and inactive, it means it was turned on and very active... same with the horse races "..and their off" doesn't mean the horses are off the track, it does mean they are very much on the race track and running.

And here's one which is very confusing but logical "..and the Dimster is Off, ON another of his rants."

Always nice to get a peek into how another thinks, very nice logical explanation, thankyou I am smiling.
Title: Re: Mouse input lag
Post by: Pete on October 27, 2021, 04:35:20 pm
I find this conversation to be on the whole, OFF topic.

The
.. ie "the gun when off" doesn't mean it was turned off and inactive, it means it was turned on and very active... same with the horse races "..and their off" doesn't mean the horses are off the track, it does mean they are very much on the race track and running.

 "the gun when off" Huh? How can the gun go off "when" the gun is off? Oh well, maybe a better question for that idiot actor, Alex Baldwin.

Pete

In Soviet Russia, to stay on top, you have to stay off bottom of things.
Title: Re: Mouse input lag
Post by: Cobalt on October 27, 2021, 07:29:35 pm
Mark is correct, typically a light goes ON but the interchangeable use of ON/OFF is rampant in the English language .. ie "the gun when off" doesn't mean it was turned off and inactive, it means it was turned on and very active... same with the horse races "..and their off" doesn't mean the horses are off the track, it does mean they are very much on the race track and running.

And here's one which is very confusing but logical "..and the Dimster is Off, ON another of his rants."

side note:
 When a gun discharges it is off, because it is safe at that point. Once a new round is chambered the gun is now "charged" or ON and is again very dangerous. as with a light bulb, when the line is unloaded(off[aka no power]) it is safe to change, how ever when the line is loaded(ON [aka has power]) you can fry yourself!

I would like to think of it as "Dimster is Off, ON another journey seeking enlightenment!"
Title: Re: Mouse input lag
Post by: Dimster on October 28, 2021, 10:24:08 am
You're right @Pete, that should have read "went off" and not " when". Not sure how I missed that typo. Off my game I guess.
And @Cobalt, when it comes to the On and Off of light switches, I'm starting to hear the phrase "open/closed" with electricians, rather than On/Off. But I do agree with you, @blus called me on that use of On/Off for the proverbial enlightening light bulb.
Title: Re: Mouse input lag
Post by: Dimster on October 28, 2021, 11:14:06 am
@Cobalt ... just to elaborate on that light switch "open/closed". I recently had an electrician install a water pump for me. Because there would be more people switching that switch I asked him to label the on/off positions. He labelled "pump on/ pump off". I suggested he could have just labelled on/off. He said a switch is like a circuit breaker which opens and closes but the object at the end of the line of the power will be either on or off. That phase "switched on" should in fact be "switched open"..
Title: Re: Mouse input lag
Post by: bplus on October 28, 2021, 12:19:43 pm
You're right @Pete, that should have read "went off" and not " when". Not sure how I missed that typo. Off my game I guess.
And @Cobalt, when it comes to the On and Off of light switches, I'm starting to hear the phrase "open/closed" with electricians, rather than On/Off. But I do agree with you, @blus called me on that use of On/Off for the proverbial enlightening light bulb.

Oh ha! I am blus now, I like it! I type that allot, @Dimster I guess you are On your game now by being Off a bit ;-))
Title: Re: Mouse input lag
Post by: Dimster on October 28, 2021, 12:56:19 pm
Freudian slip ... always felt it should be Aplus.