Author Topic: Mouse input lag  (Read 8410 times)

0 Members and 1 Guest are viewing this topic.

Offline johannhowitzer

  • Forum Regular
  • Posts: 118
    • View Profile
Mouse input lag
« 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?

Offline luke

  • Administrator
  • Seasoned Forum Regular
  • Posts: 324
    • View Profile
Re: Mouse input lag
« Reply #1 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.

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Mouse input lag
« Reply #2 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
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline johannhowitzer

  • Forum Regular
  • Posts: 118
    • View Profile
Re: Mouse input lag
« Reply #3 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.

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Mouse input lag
« Reply #4 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.  
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline Dimster

  • Forum Resident
  • Posts: 500
    • View Profile
Re: Mouse input lag
« Reply #5 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?

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Mouse input lag
« Reply #6 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
« Last Edit: October 20, 2021, 05:34:47 pm by Pete »
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline Dimster

  • Forum Resident
  • Posts: 500
    • View Profile
Re: Mouse input lag
« Reply #7 on: October 20, 2021, 05:06:40 pm »
Thanks Pete

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Mouse input lag
« Reply #8 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

https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Dimster

  • Forum Resident
  • Posts: 500
    • View Profile
Re: Mouse input lag
« Reply #9 on: October 21, 2021, 08:20:36 am »
And the light bulb goes off...thanks Steve.

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: Mouse input lag
« Reply #10 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.
Granted after becoming radioactive I only have a half-life!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Mouse input lag
« Reply #11 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 ;-))

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Mouse input lag
« Reply #12 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.)  ;-))

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Mouse input lag
« Reply #13 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
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: Mouse input lag
« Reply #14 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.
Granted after becoming radioactive I only have a half-life!