Author Topic: WHILE: WEND and _MOUSEWHEEL  (Read 6485 times)

0 Members and 1 Guest are viewing this topic.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: WHILE: WEND and _MOUSEWHEEL
« Reply #15 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.


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

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: WHILE: WEND and _MOUSEWHEEL
« Reply #16 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?
« Last Edit: November 24, 2020, 01:28:37 pm by bplus »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: WHILE: WEND and _MOUSEWHEEL
« Reply #17 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.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: WHILE: WEND and _MOUSEWHEEL
« Reply #18 on: November 26, 2020, 09:34:24 pm »


IF _MOUSEINPUT <> 0 then
 
 
 
 
 
 
   
 

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: WHILE: WEND and _MOUSEWHEEL
« Reply #19 on: November 26, 2020, 09:35:04 pm »

IF _MOUSEINPUT <> 0 then
 
 
 
 
 
 
   

???????????


No.  The answer here is just NO. 
« Last Edit: November 26, 2020, 09:36:18 pm by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: WHILE: WEND and _MOUSEWHEEL
« Reply #20 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
« Last Edit: November 26, 2020, 11:15:44 pm by NOVARSEG »

Offline Richard Frost

  • Seasoned Forum Regular
  • Posts: 316
  • Needle nardle noo. - Peter Sellers
    • View Profile
Re: WHILE: WEND and _MOUSEWHEEL
« Reply #21 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.

It works better if you plug it in.

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: WHILE: WEND and _MOUSEWHEEL
« Reply #22 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?
« Last Edit: November 26, 2020, 11:58:46 pm by NOVARSEG »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: WHILE: WEND and _MOUSEWHEEL
« Reply #23 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.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: WHILE: WEND and _MOUSEWHEEL
« Reply #24 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 .

« Last Edit: November 27, 2020, 03:00:03 am by NOVARSEG »