DAY 016: _MOUSEINPUT
#1
Today's Keyword of the Day is the first which has poor Steve shaking his head and sighing deeply over our documentation and wiki entries on it.  Guys, do me a favor and toss the wiki examples out of your brains, as they're NOT what you want to do with _MOUSEINPUT at all.  



Let me illustrate with the first example from the wiki:



Code: (Select All)
DO
  DO WHILE _MOUSEINPUT '      Check the mouse status
    PRINT _MOUSEX, _MOUSEY, _MOUSEBUTTON(1), _MOUSEWHEEL
  LOOP
LOOP UNTIL INKEY$ <> ""


Seems to work as advertised, so what's the problem here?



Nothing should go inside your _MOUSEINPUT loop, except for a _MOUSEWHEEL counter!



Let me show you why:



Code: (Select All)
Do
    Locate 1
    i = 1
    Do While _MouseInput '      Check the mouse status
        Locate i, 1: Print _MouseX, _MouseY, _MouseButton(1), _MouseWheel
        i = i + 1
    Loop
    If i <> 1 Then For z = i To 20: Locate z, 1: Print Space$(60): Next
    Locate 21, 1: Print _MouseX, _MouseY, _MouseButton(1)
    _Limit 120
Loop Until InKey$ <> ""




Take the first code and imagine trying to actually do something with it.  Printing it inside that example loop isn't actually doing anything constructive for us -- it's just displaying all the mouse's minute movements as it crosses the screen.  If we're going to check the mouse against a button, or some such, that we've draw upon our screen, we'll need to settle on o single value for that mouse position which we compare against -- and that's going to be AFTER WE EXIT THE LOOP.

Code: (Select All)
Do While _MOUSEINPUT
Loop


^The above says we're not going to actually do anything with our _MOUSEX and _MOUSEY values...  We'll only respond to them outside the loop.



And, as you can see from my second set of code, the end result is *always* going to print the same values as the last pass inside the loop did...



So why would we waste time processing a couple of dozen events, assigning them to overwrite the same values over and over and whatnot, when we're just going to toss those values out the door at the end of the loop??



IF both sets of the following code produce the same results, which is more efficient for us?



Code: (Select All)
While _MouseInput
    x = _MOUSEX:  y = _MOUSEY
Wend


Code: (Select All)
While _MouseInput; Wend
x = _MouseX: y = _MouseY


Both are going to generate the exact same values for x and y, so which is more efficient for us?  The first code is going to assign several dozen temporary values to x and y, before exiting and giving us a final value for x and y.  The second code skips all that intermittent assignment and just gives us the final result after the mouseinput loop.






Our second example in the wiki is just as poorly written, and is just as bad of an example.



Code: (Select All)
SCREEN 12

DO ' main program loop

  ' your program code

  DO WHILE _MOUSEINPUT'mouse status changes only
    x = _MOUSEX
    y = _MOUSEY
    IF x > 0 AND x < 640 AND y > 0 AND y < 480 THEN
      IF _MOUSEBUTTON(2) THEN
        PSET (x, y), 15
        LOCATE 1, 1: PRINT x, y
      END IF
    END IF
  LOOP

  ' your program code

LOOP UNTIL INKEY$ = CHR$(27)



Once again, the example is processing all sorts of crap inside that _MOUSEINPUT loop that it doesn't need to.  Compile it.  Run it.  Watch how it behaves.   And then compare to the following:



Code: (Select All)
Screen 12

Do ' main program loop

    ' your program code

    Do While _MouseInput: Loop 'mouse status changes only

    ' your program code
    x = _MouseX
    y = _MouseY
    If x > 0 And x < 640 And y > 0 And y < 480 Then
        If _MouseButton(2) Then
            PSet (x, y), 15
            Locate 1, 1: Print x, y
        End If
    End If

Loop Until InKey$ = Chr$(27)




The only thing that needs to go inside a _MOUSEINPUT loop is possibly a counter to deal with _MOUSEWHEEL.  Everything else should go outside it, or else you're going to end up lagging up your program to the point of uselessness.



MouseInput code should generally look like one of the two varieties below:



Code: (Select All)
While _MouseInput: Wend


Code: (Select All)
While _MouseInput
    scrollwheel = scrollwheel + _MOUSEWHEEL
Wend


Attempting to process other code inside that mouseinput loop is just asking for trouble.  Our wiki examples work for what they're showing, but what they're showing is about the worst possible structure I could imagine for use with _MOUSEINPUT.  Honestly, they must've just written into the wiki when _MOUSEINPUT was first added into the wiki and nobody knew much about it..  As it stands now, those examples need an overhaul to show how to actually use them properlyWink
Reply
#2
Yes, I call this step:
While _MouseInput: Wend ' polling the mouse for current location for current loop

@SMcNeill not sure if you want to deal with this here and now but, 

An issue that comes up with this is getting clear of last _MouseButton() so that you don't execute a Mouse click more than once for same click ie a little slow releasing the button.

As I recall you had a nice bit of code to resolve that issue.
b = b + ...
Reply
#3
(11-21-2022, 11:27 PM)SMcNeill Wrote: Attempting to process other code inside that mouseinput loop is just asking for trouble.  Our wiki examples work for what they're showing, but what they're showing is about the worst possible structure I could imagine for use with _MOUSEINPUT.  Honestly, they must've just written into the wiki when _MOUSEINPUT was first added into the wiki and nobody knew much about it..  As it stands now, those examples need an overhaul to show how to actually use them properlyWink
In almost all my programs using this function, I used it in the wrong way you described, which was the main reason why I was often frustrated. This included trying to fix that "Lights Out" game somewhere in bplus' forum, wanted mouse input instead of keyboard. I spent at least an hour trying to fix it for accuracy of left mouse button presses but was less successful trying to block the stream of messages, so it was possible to hold the button and move the mouse cursor.

Maybe I could show what I did with the source code of "Lights Out" but I limited it to 4, 5 or 6 squares across and down LOL.

I think the "_MOUSEINPUT" explanations in the Wiki, and the related functions, kept screaming to call that function or mouse events aren't detected by the QB64(PE) user program. It was interpreted by many people (including me) to call it to get every event and not let a single event get away...
Reply
#4
I've experimented with _mouse functions in the past (in my own simple way) and never had any joy. Now, I may give it another try. Thanks Steve.
Of all the places on Earth, and all the planets in the Universe, I'd rather live here (Perth, W.A.) Big Grin
Reply
#5
(11-21-2022, 11:41 PM)bplus Wrote: Yes, I call this step:
While _MouseInput: Wend ' polling the mouse for current location for current loop

@SMcNeill not sure if you want to deal with this here and now but, 

An issue that comes up with this is getting clear of last _MouseButton() so that you don't execute a Mouse click more than once for same click ie a little slow releasing the button.

As I recall you had a nice bit of code to resolve that issue.

The trick for this is really simple -- like so:

Code: (Select All)
oldmb = -1 'count as if the mouse is down to begin with
'this is so the mouse event has to have an UP then DOWN event to count as a click

Do
    While _MouseInput: Wend
    mb = _MouseButton(1)
    If mb And Not oldmb Then
        count = count + 1
        Print "You just clicked the button! For a total of"; count
    End If
    oldmb = mb
    _Limit 15
Loop Until _MouseButton(2) Or _KeyHit

Now this isn't going to process your mouse hold events (such as when you're going to do a click-and-drag), as it relies upon a complete UP-then-DOWN action to count as a mouseclick, but it makes certain that those clicks are processed once and only once, rather than anytime the mousebutton happens to be down.  Wink
Reply
#6
(11-22-2022, 12:09 AM)SMcNeill Wrote:
(11-21-2022, 11:41 PM)bplus Wrote: Yes, I call this step:
While _MouseInput: Wend ' polling the mouse for current location for current loop

@SMcNeill not sure if you want to deal with this here and now but, 

An issue that comes up with this is getting clear of last _MouseButton() so that you don't execute a Mouse click more than once for same click ie a little slow releasing the button.

As I recall you had a nice bit of code to resolve that issue.

The trick for this is really simple -- like so:

Code: (Select All)
oldmb = -1 'count as if the mouse is down to begin with
'this is so the mouse event has to have an UP then DOWN event to count as a click

Do
    While _MouseInput: Wend
    mb = _MouseButton(1)
    If mb And Not oldmb Then
        count = count + 1
        Print "You just clicked the button! For a total of"; count
    End If
    oldmb = mb
    _Limit 15
Loop Until _MouseButton(2) Or _KeyHit

Now this isn't going to process your mouse hold events (such as when you're going to do a click-and-drag), as it relies upon a complete UP-then-DOWN action to count as a mouseclick, but it makes certain that those clicks are processed once and only once, rather than anytime the mousebutton happens to be down.  Wink
Works exactly as you described. Now I'm getting somewhere (at least, off the starting blocks)!
Of all the places on Earth, and all the planets in the Universe, I'd rather live here (Perth, W.A.) Big Grin
Reply
#7
Can someone verify if I understand this line correctly?   The overall routine makes sense but this particular line was interesting.
Code: (Select All)
If mb And Not oldmb then
I'm not used to this exact phrasing...but I believe it means literally that if mb is true and not equal to oldmb?   In other words if mb <> oldmb ?   Sorry for the sidetracking question
Reply
#8
(11-22-2022, 12:20 AM)james2464 Wrote: Can someone verify if I understand this line correctly?   The overall routine makes sense but this particular line was interesting.
Code: (Select All)
If mb And Not oldmb then
I'm not used to this exact phrasing...but I believe it means literally that if mb is true and not equal to oldmb?   In other words if mb <> oldmb ?   Sorry for the sidetracking question


This is basically the same as:

IF mb <> 0 AND NOT oldmb <> 0 THEN...

If YourButtonIsDownNow AND YourButtonWasNOTdownPreviously THEN....


It's not quite the same as mb <> oldmb.  For example:  

mb = 0, oldmb = -1 -- Your mouse button is now up, but it was down last loop....  Is it a click this loop??

See the difference in the two?

You're basically checking: IF mb = -1 AND oldmb = 0 THEN...
Reply
#9
I think my confusion centers around the "AND NOT".  I have never used this and I need to give this a try in the future.   Thanks!
Reply
#10
Now I see Kernelpanic creating another thread about this "AND NOT"...

Back on topic. Sometimes the check for mouse cursor could become elaborate such as checking for buttons drawn on the screen, and only if that screen button is mouse-clicked, then perform the function promised by that button. This is even if a section of the user program's screen was dedicated to a "toolbar" full of buttons. My frustration caused me to shelf a freehand drawing program in text mode for a file format I invented. :/
Reply




Users browsing this thread: 16 Guest(s)