QB64.org Forum

Active Forums => QB64 Discussion => Topic started by: Pete on November 23, 2020, 09:57:32 pm

Title: WHILE: WEND and _MOUSEWHEEL
Post by: Pete on November 23, 2020, 09:57:32 pm
https://www.qb64.org/forum/index.php?topic=3236.msg125173#msg125173

I updated my highlighting routine to include shift + mouse wheel highlighting... but...

I had to change the WHILE _MOUSEINPUT: WEND to wrap around the mouse calls, in order to get the wheel to register.

In other words, this doesn't work with _MOUSEWHEEL

    WHILE _MOUSEINPUT: WEND
        my% = _MOUSEY
        mx% = _MOUSEX
        lb% = _MOUSEBUTTON(1)
        mw% = mw% + _MOUSEWHEEL

but this does...

    WHILE _MOUSEINPUT
        my% = _MOUSEY
        mx% = _MOUSEX
        lb% = _MOUSEBUTTON(1)
        mw% = mw% + _MOUSEWHEEL
    WEND

The first way works fine, if the mouse wheel is not included.

I'm still using v1.3, if that makes any difference. I know the wiki example uses a DO/LOOP instead of WHILE/WEND.

Any thoughts of making the WHILE _MOUSEINPUT: WEND work with _MOUSEWHEEL, like it does with the other mouse calls?

Pete
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: bplus on November 23, 2020, 10:16:47 pm
https://www.qb64.org/forum/index.php?topic=3236.msg125173#msg125173

I updated my highlighting routine to include shift + mouse wheel highlighting... but...

I had to change the WHILE _MOUSEINPUT: WEND to wrap around the mouse calls, in order to get the wheel to register.

In other words, this doesn't work with _MOUSEWHEEL

    WHILE _MOUSEINPUT: WEND
        my% = _MOUSEY
        mx% = _MOUSEX
        lb% = _MOUSEBUTTON(1)
        mw% = mw% + _MOUSEWHEEL

but this does...

    WHILE _MOUSEINPUT
        my% = _MOUSEY
        mx% = _MOUSEX
        lb% = _MOUSEBUTTON(1)
        mw% = mw% + _MOUSEWHEEL
    WEND

The first way works fine, if the mouse wheel is not included.

I'm still using v1.3, if that makes any difference. I know the wiki example uses a DO/LOOP instead of WHILE/WEND.

Any thoughts of making the WHILE _MOUSEINPUT: WEND work with _MOUSEWHEEL, like it does with the other mouse calls?

Pete

Yes, that's right _MOUSEWHEEL has to be inside the loop. Learned that from Wiki under _MOUSEWHEEL.
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: SMcNeill on November 23, 2020, 10:21:59 pm
Code: QB64: [Select]
  1.         mw% = mw% + _MOUSEWHEEL
  2. my% = _MOUSEY
  3. mx% = _MOUSEX
  4. lb% = _MOUSEBUTTON(1)

Go this route (points above). 

Think for just a moment on how your mouse works.  How many times do you press the button down in a second?  How many times can that mouse wheel click in a second? 

You’ll never have an event where you need to know what the mouse x/y position is, 1000 times a second, but you do need to count up the number of times that wheel scrolled in that second.

_MOUSEWHEEL is the only event that needs to be inside your update loop.



And from the wiki, you can see why:

“After an event has been read, the value resets to 0 automatically so cumulative position values must be added.”
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: NOVARSEG on November 23, 2020, 10:40:38 pm
from the wiki on mouseinput

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

all the parameters are inside the loop what is the difference?
****
Also from the wiki
Quote
To clear all previous mouse data, use _MOUSEINPUT in a loop until it returns 0.
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: bplus on November 23, 2020, 10:49:45 pm
The way I learned it, _MOUSEWHEEL is accumulative thing that needs the constant update inside the LOOP with _MOUSEINPUT but the others mouse position or mouse buttons down you just want a snapshot of the latest info which is returned after you exit the _MOUSEINPUT loop usually with WHILE.
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: NOVARSEG on November 23, 2020, 11:00:15 pm
 Ya the code works but why?

Why do you need to accumulate the mouse wheel clicks?

a mouse wheel scrolls text one click at a time
****
from code posted above

The _mouseinput has detected mouse activity (_mousewheel) but does not update _mousewheel . Why

Quote
WHILE _MOUSEINPUT: WEND
        my% = _MOUSEY
        mx% = _MOUSEX
        lb% = _MOUSEBUTTON(1)
        mw% = mw% + _MOUSEWHEEL
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: bplus on November 23, 2020, 11:11:01 pm
Don't get me wrong, the mouse positions or the mouse buttons info works fine from inside the WHILE _MOUSEINPUT loop but the _MOUSEWHEEL sure doesn't work outside that loop.

As I said, I learned it as a logical rule you only want the latest info on position or button status but _MOUSEWHEEL accumulates a number of clicks only while inside the loop for scroll amounts usually though fun to use for other things as well.
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: SMcNeill on November 23, 2020, 11:12:55 pm
Ya the code works but why?

Why do you need to accumulate the mouse wheel clicks?

When I use the wheel it scrolls one click at a time

Let’s look at the behavior up close.

You check and clear the mouse buffer....

A few milliseconds pass.

You check the buffer again for wheel events:

BUFFER START
wheel normal (0)
wheel down (-1)
wheel normal (0)
wheel down (-1)
wheel normal (0)
BUFFER STOP

As you can see, a mouse wheel isn’t just an “up or down” event.  It tracks “up (+1), down (-1), normal (0)”.  After every click, the wheel resets to normal (0), waiting for the next change.

If you only take that value of that last event state, it’s always going to be 0, as the wheel automatically resets back to 0 (normal) after a scroll.

Your button might have a “click and hold” event, but have you ever considered the wheel working in that same manner?  The wheel and the buttons are two completely different beasts.  (In fact, I think _DEVICES reads thewheel as an _AXIS, rather than a _BUTTON.)

Different tool, different required behavior to interact with it.
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: NOVARSEG on November 23, 2020, 11:30:24 pm
What would happen if there was a delay.

would _MOUSEWHEEL be 1 or -1  or 0

WHILE _MOUSEINPUT
        (a delay of one second)
        mw% = mw% + _MOUSEWHEEL
WEND
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: SMcNeill on November 23, 2020, 11:38:18 pm
What would happen if there was a delay.

would _MOUSEWHEEL be 1 or -1  or 0

WHILE _MOUSEINPUT
        (a delay of one second)
        mw% = mw% + _MOUSEWHEEL
WEND

Doesn’t matter.  You read several hundred mouse events every few milliseconds...   x/y position, button 1,2,3 position, wheel events...   You toss a 1 second delay in there, it’d take 100 seconds to clear a millisecond’s buffer., which would have MORE events going in much faster than you’re reading them out.

It may not be an endless loop, but the lag would be so great you’d never do anything with your program with it.



You might could try something like:

WHILE  _MOUSEINPUT AND NOT _MOUSEWHEEL: WEND
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: NOVARSEG on November 24, 2020, 12:05:45 am
Thanks all


**** code
WHILE _MOUSEINPUT: WEND
        my% = _MOUSEY
        mx% = _MOUSEX
        lb% = _MOUSEBUTTON(1)
****
why does it work for
_MOUSEY
 _MOUSEX
 _MOUSEBUTTON(1)
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: bplus on November 24, 2020, 12:22:05 am
Thanks all


**** code
WHILE _MOUSEINPUT: WEND
        my% = _MOUSEY
        mx% = _MOUSEX
        lb% = _MOUSEBUTTON(1)
****
why does it work for
_MOUSEY
 _MOUSEX
 _MOUSEBUTTON(1)

Because those variables hold the last known status of mouse since mouse was polled with:
Code: QB64: [Select]

Notice when read _MOUSEWHEEL here:
Code: QB64: [Select]
  1.         mw% = mw% + _MOUSEWHEEL
  2.  

We don't want to know the last _MOUSEWHEEL reading, no the variable above is counting up ALL the changes _MOUSEWHEEL reported WHILE there was _MOUSEINPUT and that's the info we want to work with the total of + or minus changes.
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: SMcNeill on November 24, 2020, 12:27:51 am
why does it work for
_MOUSEY
 _MOUSEX
 _MOUSEBUTTON(1)

We’re reading from a buffer a few nanoseconds long.

We read the buffer with the mouse in the top left corner: X = 0, Y = 0, Wheel = 0

3 nanoseconds later, we read the buffer again:

BUFFER START
0.5 Nanoseconds: Mouse X = 1
1.0 Nanoseconds: Y = 1
1.5 Nanoseconds: X = 2, Y = 2
2.0 Nanoseconds: Wheel = +1 (scrolled up)
2.5 Nanoseconds: Wheel = 0 (back to normal, after it “clicked”)
3.0 Nanoseconds: X = 3
BUFFER STOP

X = 3, Y = 2, Wheel = 0

Who cares what x and y was while in that buffer?  We’re only going to use the value of where it’s at currently in our program.

But that wheel?  At the moment we check it, what’s its current state?  It’s not at that perfect moment of “click”, so it’s back to normal.

You want to know where x/y is after you clear the buffer, but you want to know if the wheel changed at all during the buffer.
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: NOVARSEG on November 24, 2020, 12:51:33 am
Ok Thanks
****
 Gets the buffer size as well?
****
DO
IF _MOUSEINPUT  = 0  THEN EXIT DO
mw% = mw% + _MOUSEWHEEL
buffersize% = buffersize% + 1
LOOP

****
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: Pete on November 24, 2020, 01:40:43 am
    WHILE _MOUSEINPUT
            mw% = mw% + _MOUSEWHEEL
    WEND
    my% = _MOUSEY
    mx% = _MOUSEX
    lb% = _MOUSEBUTTON(1)

Looks like a winner to me!

Pete

Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: SMcNeill on November 24, 2020, 05:32:08 am
I think I've did a fairly decent job explaining about WHY the mousewheel behaves the way it does  above, but here's one last demo to illustrate the behavior for us, and to highlight HOW we can move checking it outside out WHILE:WEND loop as well:

Code: QB64: [Select]
  1.     Scroll = Scroll + _MOUSEWHEEL
  2.     LOCATE 1, 1: PRINT Scroll, _MOUSEX, _MOUSEY, _MOUSEBUTTON(1), _MOUSEBUTTON(2)
  3.     _LIMIT 10
  4.     _DISPLAY

Now, Why does this work?  Let me steal from my example above, so I can supply an explaination:

Quote
We’re reading from a buffer a few nanoseconds long.

We read the buffer with the mouse in the top left corner: X = 0, Y = 0, Wheel = 0

3 nanoseconds later, we read the buffer again:

BUFFER START
0.5 Nanoseconds: Mouse X = 1
1.0 Nanoseconds: Y = 1
1.5 Nanoseconds: X = 2, Y = 2
2.0 Nanoseconds: Wheel = +1 (scrolled up)
2.5 Nanoseconds: Wheel = 0 (back to normal, after it “clicked”)
3.0 Nanoseconds: X = 3
BUFFER STOP

Basicallly, the WHILE conditions we set for our main loop are WHILE THERE'S MOUSE INPUT AND NO WHEEL ACTIVITY, CLEAR THE BUFFER.   ( WHILE _MOUSEINPUT <> 0 AND _MOUSEWHEEL = 0: WEND)

So we end up reading only a small portion of our buffer:

0.5 Nanoseconds: Mouse X = 1
1.0 Nanoseconds: Y = 1
1.5 Nanoseconds: X = 2, Y = 2
2.0 Nanoseconds: Wheel = +1 (scrolled up)    <---  AT THIS POINT, WE EXIT THE BUFFER!

The rest of our information stays buffered, waiting for the next pass to process, but if we go ahead and run our program at this point, X = 2, Y = 2, and the wheel = +1.  (The truth is, our mouse is actually at X =3 currently -- we just haven't read our buffer fully yet -- but it was at X/Y point 2, 2 when the scrolling occurred.)

On the next loop of our program, as soon as we start reading from the mouse buffer again, the next 2 events will be:

BUFFER START
0.5 Nanoseconds: Wheel = 0 (back to normal, after it “clicked”)
1.0 Nanoseconds: X = 3
BUFFER CONTINUES...

Reading the mouse wheel doesn't have to be inside your update loop, as proven here, but it's generally the easiest way for folks to deal with it and just forget about it.

Which seems simpler?

Code: QB64: [Select]
  1. WHILE _MOUSEINPUT: scroll = scroll + _MOUSEWHEEL :WEND

Or:

Code: QB64: [Select]

It's really just an instance of coding style, as both work perfectly fine the way they are.  The important thing is knowing WHY they both work for us, though that can't be quite as important as simply knowing HOW to make it work properly.  Even if the concept behind the two methods is something you forget in the future, at least remember the syntax so you can utilize one or the other of them, so you can have access to mouse wheel information in your programs.


Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: bplus on November 24, 2020, 01:15:13 pm
Hi @SMcNeill

That was very interesting in theory but when I try out the code and spin the wheel I see very, very, very slow updating of mouse position AND scroll totals until the scroll has caught up to all the changes made with wheel. The loop updates 10 times a second but takes way, way longer than second to update simple mouse position until the scroll total is settled.

As it stands, I don't think this
Code: QB64: [Select]
  1.     Scroll = Scroll + _MOUSEWHEEL
  2.     LOCATE 1, 1: PRINT Scroll, _MOUSEX, _MOUSEY, _MOUSEBUTTON(1), _MOUSEBUTTON(2)
  3.     _LIMIT 10
  4.     _DISPLAY
  5.  

an equivalent alternative to this method:
Code: QB64: [Select]
  1.             mw% = mw% + _MOUSEWHEEL
  2.     WEND
  3.     my% = _MOUSEY
  4.     mx% = _MOUSEX
  5.     lb% = _MOUSEBUTTON(1)
  6.  

To paraphrase Pete, "Looks like the winner."

Update: On the other hand, I think the missing first click of the mouse wheel might have been found, maybe?
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: SMcNeill on November 24, 2020, 02:41:53 pm
Hi @SMcNeill

That was very interesting in theory but when I try out the code and spin the wheel I see very, very, very slow updating of mouse position AND scroll totals until the scroll has caught up to all the changes made with wheel. The loop updates 10 times a second but takes way, way longer than second to update simple mouse position until the scroll total is settled.

Aye, but that's because I deliberately set my limit so low to help highlight the issue.

In a second, we can generate dozens of mouse events.  By limiting the loop to only running 10 times a second, we're not pulling information out of the buffer as fast as we're putting it into it, causing the program to lag up and fall behind on us.

Think of it as turning the faucet on in your bathtub, and then trying to empty it with a teaspoon...  As long as water is coming in, you'll never catch up, and even when you turn the faucet off, you'll need a while to empty the tub out.  The only way to keep up is to either grab a bigger bucket, or -- in the case of our program here -- dip our spoon into the tub faster and faster...

Code: [Select]
DO
    WHILE _MOUSEINPUT <> 0 AND _MOUSEWHEEL = 0: WEND
    Scroll = Scroll + _MOUSEWHEEL
    LOCATE 1, 1: PRINT Scroll, _MOUSEX, _MOUSEY, _MOUSEBUTTON(1), _MOUSEBUTTON(2)
    _LIMIT 120
    _DISPLAY
LOOP

Personally, I wouldn't use the above method for my own needs, but it highlights what I was saying about how and why the _MOUSEWHEEL works the way it does.

As far as I'm concerned, folks should just stick to these simple rules:

1) Use a simple WHILE _MOUSEINPUT: WEND routine to update the mouse buffer.
2) In the instances where you want to use the mouse wheel, it's the only thing you should put inside that WHILE:WEND loop.
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: NOVARSEG on November 26, 2020, 09:34:24 pm


IF _MOUSEINPUT <> 0 then
 
 
 
 
 
 
   
 
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: SMcNeill on November 26, 2020, 09:35:04 pm

IF _MOUSEINPUT <> 0 then
 
 
 
 
 
 
   

???????????


No.  The answer here is just NO. 
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: NOVARSEG on November 26, 2020, 09:36:48 pm
spilled coffee on keyboard

wait . . .


 ****
DO
I$ = INKEY$
IF I$ <>"" then EXIT DO

IF _MOUSEINPUT <> 0 then
cls
PRINT "mouse wheel ";_MOUSEWHEEL
PRINT "Y pos ";_MOUSEY
PRINT "X pos ";_MOUSEX
PRINT" mouse button 1 ";_MOUSEBUTTON(1)
PRINT" mouse button 2 ";_MOUSEBUTTON(2)

END IF

LOOP
****
_MOUSEWHEEL should be -1,1, or 0

I have not tested the code
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: Richard Frost on November 26, 2020, 10:25:46 pm
The bathtub analogy is highly suspect, as it does not take into account the interference  of
the rubber ducks, who will oppose a teaspoon (or bucket) trying to destroy their world.

Translation: Very nice explanation.

Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: NOVARSEG on November 26, 2020, 11:46:09 pm
Found this from here

https://www.qb64.org/forum/index.php?topic=2377.0

Quote
_MOUSEHWEEL: Returns the amount of scroll on the scroll wheel. Unlike other functions that simply inspect the current mouse message, _MOUSEHWEEL keeps a running tally of mouse wheel activity, examing every mouse message as it comes to the front of the queue automatically. Whenever _MOUSEHWEEL sees the wheel scrolled towards the user, it adds 1 to its internal count. When it is scrolled away, it subtracts 1. When _MOUSEWHEEL is read, its value is reset to 0. Thus, _MOUSEWHEEL's return value reflects the net amount of scroll since _MOUSEWHEEL was last called.

So _MOUSEHWEEL has an internal counter. Need code to show  the internal count .
Or was this an outdated description of how _MOUSEWHEEL works?
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: SMcNeill on November 27, 2020, 01:34:56 am
spilled coffee on keyboard

wait . . .


 ****
DO
I$ = INKEY$
IF I$ <>"" then EXIT DO

IF _MOUSEINPUT <> 0 then
cls
PRINT "mouse wheel ";_MOUSEWHEEL
PRINT "Y pos ";_MOUSEY
PRINT "X pos ";_MOUSEX
PRINT" mouse button 1 ";_MOUSEBUTTON(1)
PRINT" mouse button 2 ";_MOUSEBUTTON(2)

END IF

LOOP
****
_MOUSEWHEEL should be -1,1, or 0

I have not tested the code

AS I said:

No.   The answer is just NO.

_MOUSEINPUT reads many more events in a second than PRINT can display to the screen.  The code you have will generate a bottleneck where the mouse buffer fills faster than it empties, and the more you move/interact with the mouse, the greater the lag in response times will be.  Once you sit the mouse down and quit touching it, your program will need several seconds/minutes to catch up and clear the buffer.

What’s so hard to comprehend about the following??

WHILE _MOUSEINPUT
    scroll = scroll + _MOUSEWHEEL
WEND

All I can say at this point is just try it.  Write your programs however you want, and over time you’ll learn what the best practices are to make things work properly.  If you’re lucky, maybe eventually, you’ll also understand *why* they work the way they do.  Trial and error may be the only hope for you, as explaining things with words and code isn’t working.
Title: Re: WHILE: WEND and _MOUSEWHEEL
Post by: NOVARSEG on November 27, 2020, 01:52:28 am
SMcNeill

I appreciate your explanations.  I'm good with 16 bit stuff but new to windows programming.

Quote
_MOUSEINPUT reads many more events in a second than PRINT can display to the screen
.

Ok did not know that.

Quote
What’s so hard to comprehend about the following??

WHILE _MOUSEINPUT
    scroll = scroll + _MOUSEWHEEL
WEND

I understand the concept, not 100% though.

Ok from here:
https://docs.microsoft.com/en-us/windows/win32/inputdev/about-mouse-input#mouse-messages

Quote
Mouse Messages
The mouse generates an input event when the user moves the mouse, or presses or releases a mouse button. The system converts mouse input events into messages and posts them to the appropriate thread's message queue. When mouse messages are posted faster than a thread can process them, the system discards all but the most recent mouse message.

So say, if the mouse is moved , messages are sent to the thread's message que. As you say many messages per second can end up in the que.   Also the system discards messages if there is a lag in processing.

So in my code example, it looks like PRINT is slowing down the rate that  _MOUSEINPUT should be called in order prevent a backup of  messages in the que.

 
Looks like PRINT won't work in this case .