QB64 Phoenix Edition
DAY 016: _MOUSEINPUT - Printable Version

+- QB64 Phoenix Edition (https://qb64phoenix.com/forum)
+-- Forum: Official Links (https://qb64phoenix.com/forum/forumdisplay.php?fid=16)
+--- Forum: Learning Resources and Archives (https://qb64phoenix.com/forum/forumdisplay.php?fid=13)
+---- Forum: Keyword of the Day! (https://qb64phoenix.com/forum/forumdisplay.php?fid=49)
+---- Thread: DAY 016: _MOUSEINPUT (/showthread.php?tid=1165)

Pages: 1 2 3


RE: DAY 016: _MOUSEINPUT - OldMoses - 12-06-2022

(11-22-2022, 02:00 AM)SMcNeill Wrote: @Pete If you're going that complex, use MBS: https://qb64phoenix.com/forum/showthread.php?tid=138

MBS pretty much does everything I need a mouse to do, and more that I haven't quite figured out yet. I haven't done any "hold and release" type stuff.

Once I've grabbed a mouse button event, the very first step in processing it is to clear the buffer with:

Code: (Select All)
SUB Clear_MB (var AS INTEGER)
    DO UNTIL NOT _MOUSEBUTTON(var)
        WHILE _MOUSEINPUT: WEND
    LOOP
END SUB 'Clear_MB

A bit loopy for a solution, but so far, I've had no more click through events.


RE: DAY 016: _MOUSEINPUT - Pete - 12-06-2022

(12-06-2022, 01:39 AM)OldMoses Wrote:
(11-22-2022, 02:00 AM)SMcNeill Wrote: @Pete If you're going that complex, use MBS: https://qb64phoenix.com/forum/showthread.php?tid=138

MBS pretty much does everything I need a mouse to do, and more that I haven't quite figured out yet. I haven't done any "hold and release" type stuff.

Once I've grabbed a mouse button event, the very first step in processing it is to clear the buffer with:

Code: (Select All)
SUB Clear_MB (var AS INTEGER)
    DO UNTIL NOT _MOUSEBUTTON(var)
        WHILE _MOUSEINPUT: WEND
    LOOP
END SUB 'Clear_MB

A bit loopy for a solution, but so far, I've had no more click through events.

Oh I've made mouse routines far more complex than that one. That's why I labeled it as, "mini_mouse".

One thing you might want to consider is...

Code: (Select All)
DO
    _LIMIT 30
    WHILE _MOUSEINPUT: WEND
    IF _MOUSEBUTTON(1) THEN
        Clear_MB var
        BEEP ' It will only beep when mouse button is released.
    END IF
LOOP

SUB Clear_MB (var AS INTEGER)
    DO: _LIMIT 5: WHILE _MOUSEINPUT: WEND: LOOP UNTIL NOT _MOUSEBUTTON(1)
END SUB

If I run it without _LIMIT in the SUB my CPU jumps from 6% to 52%. With _LIMIT it idles at 4%. I mean this will only happen if your cat decides to sit on your mouse. Yes, I have a cat... and yes, it sits wherever the hell it wants! Big Grin

What you use is what I also use when the apps are not very involved. Much faster to type it out and get things running.

Pete


RE: DAY 016: _MOUSEINPUT - OldMoses - 12-06-2022

Thanks for the heads up on that. I'm usually just doing click and release stuff, so it's worked well for me.

So a change of position makes a big difference...it should probably go last rather than first, depending on the application.

Code: (Select All)
DO
    _LIMIT 30
    WHILE _MOUSEINPUT: WEND
    IF _MOUSEBUTTON(1) THEN
        BEEP ' It will now beep when mouse button is pressed but...
        Clear_MB 1 'you're stuck here until you release
        PRINT "You've finally got the cat off the damned thing..."
    END IF
LOOP

SUB Clear_MB (var AS INTEGER)
    DO: _LIMIT 5: WHILE _MOUSEINPUT: WEND: LOOP UNTIL NOT _MOUSEBUTTON(var)
END SUB



RE: DAY 016: _MOUSEINPUT - Pete - 12-06-2022

LOL!

Well, if you are ever faced with a situation where you need to keep track of the time your cat is and is not on your mouse, you can't be stuck in a loop. That's why I made the more complicated routine, CATWATCH!

Code: (Select All)
DIM mse AS mm ' Let's do a TYPE instead of passing all variables or doing a DIM SHARE.
WIDTH 50, 25
_FONT 16
TYPE mm
    my AS INTEGER
    mx AS INTEGER
    oldmy AS INTEGER
    oldmx AS INTEGER
    lb AS INTEGER
END TYPE
PALETTE 1, 8
COLOR 9, 1: CLS

COLOR 0, 7
PALETTE 5, 63: PALETTE 6, 63
icon_x = _WIDTH - 1 ' Row.
icon_y = 2 ' Column.
COLOR 0, 6: LOCATE icon_y, 1: PRINT SPACE$(_WIDTH);
COLOR 0, 5: LOCATE icon_y, icon_x: PRINT "X"; ' Place an exit symbol on the screen.
VIEW PRINT 4 TO _HEIGHT
z1 = TIMER
DO
    _LIMIT 30

    mini_mouse mse ' Poll the mini mouse routine.

    IF mse.lb THEN ' Left button down.
        IF catwatch THEN
            SOUND 200, .2
            COLOR 15, 1: LOCATE 5, 1: PRINT " Miss Whiskers has her kitty-butt on your mouse!"
            catwatch = 1 - catwatch: z1 = TIMER
            IF trigger = hotspot THEN activate = hotspot ' Setting activate means we mouse clicked down on it but haven't released yet.
        END IF
    ELSE
        ' Highlight the exit icon on hover, but only once so it isn't going on and off like hell. The oldmx variables insure this once and done action.
        IF mse.my = icon_y AND mse.mx = icon_x AND mse_old.my <> mse.my AND mse_old.mx <> mse.mx THEN
            hotspot = ((mse.my - 1) * _WIDTH + mse.mx - 1) + 1 ' Matrix the screen to combine the row and column values as a single variable.
            trigger = hotspot ' Just a shorthand way so we don't keep using ((mse.my - 1) * _WIDTH + mse.mx - 1) + 1
            PALETTE 5, 4: PALETTE 0, 63
        ELSE ' When no longer hovering on exit icon reset the variables and lose the highlighting.
            hotspot = 0: trigger = 0
            PALETTE 5, 63: PALETTE 0, 0
        END IF

        IF catwatch = 0 THEN
            COLOR 15, 1: LOCATE 5, 1: PRINT " Miss Whiskers is eyeballing your laptop...      ";
            catwatch = 1 - catwatch: z1 = TIMER
        END IF

        IF activate THEN ' When button is released we check to see if the exit icon was clicked and if the mouse pointer is still on the icon.
            IF activate = hotspot THEN
                SYSTEM ' Quit.
            ELSE
                activate = 0: trigger = 0: hotspot = 0 ' The mouse cursor got moved so the exit was avoided.
            END IF
        END IF
    END IF
    LOCATE 7, 2: PRINT "Cat Watch Timer: "; INT(ABS(z1 - TIMER))
    REM LOCATE 7, 1: PRINT mse.my; mse.mx; mse_old.my; mse_old.mx; trigger; hotspot; activate; "    ";
LOOP

SUB mini_mouse (mse AS mm)
    mse_old.my = mse.my: mse_old.mx = mse.mx
    WHILE _MOUSEINPUT: WEND
    mse.mx = _MOUSEX
    mse.my = _MOUSEY
    mse.lb = _MOUSEINPUT(1)
    IF mse.lb AND _MOUSEBUTTON(1) = 0 THEN
        mse.lb = 0
    ELSE
        IF mse.lb = 0 AND _MOUSEBUTTON(1) THEN
            mse.lb = -1
        END IF
    END IF
END SUB

Oh, I also moved the highlighting routine from the first snippet into the mouse button NOT down condition. That way, if someone drags the held down mouse to the "X" the "X" won't be highlighted. It can now only be highlighted when hovering with the left mouse button up.

Pete


RE: DAY 016: _MOUSEINPUT - NasaCow - 12-10-2022

So.... I read through this and I want to check my conceptual understanding here.

Best to setup a mouse reading sub to poll the current state of the mouse. A basic sub should collect our x,y position (assuming that is in pixels in our program when it is active?), and the state of the left button (assuming the right button is as simple?). I get a little fuzzy on checking the prior state of the button to the current state... Is this to check if the button is still being held down and we don't execute as a general rule in such a state? Or did I miss something? Assuming I don't highlight items, I don't need to worry about holding and dragging?

In addition, I assume if I want mouse-reading ability, I would need to place a sub call in each of the do/loops I have in my program where I want to use said mouse? And similiar to keyboard input, I would use a select case and check if at this x and y (do I need to track the start x,y and release x,y to ensure I am still in a defined box click area?) with this mouse click and release flag then do this code. Am I getting the logic right or am missing something here.


So conceptual it would look like this, if I am understanding the logic right:

Code: (Select All)
    DO
        LIMIT LIMITRATE

        'INSERT MOUSE READING SUB HERE       

        CLS
        PUTIMAGE (0, 0), Intro
        SELECT CASE Pointer 'Used for keyboard selection
            CASE 0: PUTIMAGE (375, 221), CheckSelect
            CASE 1: PUTIMAGE (375, 292), CheckSelect
            CASE 2: PUTIMAGE (375, 365), CheckSelect
            CASE 3: PUTIMAGE (375, 437), CheckSelect
            CASE 4: PUTIMAGE (375, 510), CheckSelect
        END SELECT
        DISPLAY
        IF SelectFlag THEN PAUSE (TIME) 'Avoid double press delay
        SelectFlag = FALSE
        'Checking for key press (keyboard)
        IF KEYDOWN(CVI(CHR$(0) + "H")) THEN ' up case
            IF Pointer = 0 THEN Pointer = 4 ELSE Pointer = Pointer - 1
            SelectFlag = TRUE
        END IF
        IF KEYDOWN(CVI(CHR$(0) + "P")) THEN 'down case
            IF Pointer = 4 THEN Pointer = 0 ELSE Pointer = Pointer + 1
            SelectFlag = TRUE
        END IF
       
        'Some kind of if/then or select case to check for mouse actions?

    LOOP UNTIL KEYDOWN(13) OR KEYDOWN(32) 'Return/Spacebar to select - include a mouse flag that a choice was made???

Thank you Steve and Pete. I did start in the wiki but this was much more informative. Heart


RE: DAY 016: _MOUSEINPUT - Pete - 12-10-2022

>"In addition, I assume if I want mouse-reading ability, I would need to place a sub call in each of the do/loops I have in my program where I want to use said mouse?

Yes, and see comments below for options.

>" And similiar to keyboard input, I would use a select case and check if at this x and y (do I need to track the start x,y and release x,y to ensure I am still in a defined box click area?)

x, y do not need to be "released." If you want to track the previous coordinates, do this..

Code: (Select All)
DO

Do
    _Limit 30
    While _MouseInput: Wend
    x = _MouseX
    y = _MouseY
    ' Put other mouse stuff here like reading left and right button status.
    lb = _MouseButton(1)
    ' Put what to do here if a button is pressed.
    If lb Then
        If oldX <> x And oldY <> y Then Beep ' Only beeps again if mouse is moved to a new location.
        oldX = x: oldY = y
    End If
    Locate 1, 1: Print "x ="; x; "oldx ="; oldX, "y ="; y; "oldy ="; oldY; "  ";
Loop

So whatever action a click caused, it did so at the x and y coordinates. Those coordinates now become oldx and oldy, so if you move the mouse, the routine knows there was a location change.

For sub-routines, you have two choices I'll discuss here for mouse / keyboard setup.

1) Put the whole read mouse and or keyboard routines in one sub-routine.

Advantages: easy to access, debug, and if you put a new routine together, just add the conditions to that one sub

Disadvantages: If your routine gets big and complicated, your one mouse sub-routine could get hard to manage. I have one like that. My solution, because I do like having just one actually combined muse and keyboard routine, is to flag where the need for action is coming from, and then use a SELECT CASE in the mouse/keyboard routine to route to the proper action conditions. YOu may want to do a string flag, instead of a numeric one, as it is easier to debug: myflag$ = "draw-to-screen" rather than myflag% = 1.

2) Put together a single mouse reading sub-program and after each call make a separate set of conditions after that call, to handle what the mouse routine spits back.

Advantages: You can see what to expect everywhere in your program instead of trying to associate what each flag, in the other example, relates to.

Disadvantages: You have to go several places in your code to work on your mouse events.

-------------------------------------------------------




In your psuedo-code, I would put
Code: (Select All)
    'INSERT MOUSE READING SUB HERE

Together with your mouse actions sub-routine call, if you want to keep it that way. No need to separate them with code in-between.

As far as mixing mouse and keyboard, just make conditions, as needed, if anything conflicts where maybe say when a certain key press is made it takes priority over where the mouse is or any mouse action. A simple example would be if I wanted to hold down the "Z" key to block mouse clicks. I'd have to code the mouse routine to bypass mouse click reading until that key is released.

Anyway, try some stuff and if you get stuck, just post your code and ask for help in the Help ME! sub-forum.

Pete