QB64.org Forum
Active Forums => QB64 Discussion => Topic started 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
-
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.
-
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.”
-
from the wiki on mouseinput
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
To clear all previous mouse data, use _MOUSEINPUT in a loop until it returns 0.
-
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.
-
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
WHILE _MOUSEINPUT: WEND
my% = _MOUSEY
mx% = _MOUSEX
lb% = _MOUSEBUTTON(1)
mw% = mw% + _MOUSEWHEEL
-
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.
-
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.
-
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
-
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
-
Thanks all
**** code
WHILE _MOUSEINPUT: WEND
my% = _MOUSEY
mx% = _MOUSEX
lb% = _MOUSEBUTTON(1)
****
why does it work for
_MOUSEY
_MOUSEX
_MOUSEBUTTON(1)
-
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:
Notice when read _MOUSEWHEEL here:
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.
-
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.
-
Ok Thanks
****
Gets the buffer size as well?
****
DO
IF _MOUSEINPUT = 0 THEN EXIT DO
mw% = mw% + _MOUSEWHEEL
buffersize% = buffersize% + 1
LOOP
****
-
WHILE _MOUSEINPUT
mw% = mw% + _MOUSEWHEEL
WEND
my% = _MOUSEY
mx% = _MOUSEX
lb% = _MOUSEBUTTON(1)
Looks like a winner to me!
Pete
-
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:
Now, Why does this work? Let me steal from my example above, so I can supply an explaination:
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?
Or:
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.
-
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
an equivalent alternative to this method:
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?
-
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...
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.
-
IF _MOUSEINPUT <> 0 then
-
IF _MOUSEINPUT <> 0 then
???????????
No. The answer here is just NO.
-
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
-
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.
-
Found this from here
https://www.qb64.org/forum/index.php?topic=2377.0
_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?
-
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.
-
SMcNeill
I appreciate your explanations. I'm good with 16 bit stuff but new to windows programming.
_MOUSEINPUT reads many more events in a second than PRINT can display to the screen
.
Ok did not know that.
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
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 .