_MOUSEHIDE / _MOUSESHOW
#1
Here are some interesting observations about _MOUSEHIDE and _MOUSESHOW

See the remark statements at the top of the code.
Code: (Select All)
' _MOUSEHIDE _MOUSE SHOW DEMO
' Note: _MOUSEHIDE WILL BE DISENGAGED WHEN A MOUSE BUTTON IS HELD DOWN.
' A MOUSE TRIGGER EVENT LIKE _MOUSEMOVE IS NEEDED TO HIDE/SHOW MOUSE WHEN MOUSE IS IDLE.

REM PRESS ESC TO END. <==================================================

WHILE _MOUSEINPUT: WEND
DO UNTIL my
    my = _MOUSEY
    mx = _MOUSEX
LOOP
PALETTE 8, 0
DO
    _LIMIT 30
    COLOR 1, 0
    _MOUSESHOW
    WHILE _MOUSEINPUT: WEND: my = _MOUSEY: mx = _MOUSEX
    _MOUSEMOVE mx, my
    PALETTE 0, 63
    FOR i = 1 TO 10
        _DELAY .2
        PRINT i
        IF INKEY$ = CHR$(27) THEN EXIT DO
    NEXT
    COLOR 8, 0
    myhide = my: mxhide = mx
    _MOUSEHIDE
    PRINT "_MOUSEMOVEX ="; mxhide, "_MOUSEMOVEY ="; myhide
    WHILE _MOUSEINPUT: WEND: myhide = _MOUSEY: mxhide = _MOUSEX
    _MOUSEMOVE mxhide, myhide
    PALETTE 0, 4
    FOR i = 10 TO 1 STEP -1
        _DELAY .2
        PRINT i
        IF INKEY$ = CHR$(27) THEN EXIT DO
    NEXT
    oldmy = my: oldmy = mx
LOOP

So curious that if you continuously move the mouse with no button held, the pointer hides on the red screen and shows on the white, as expected, but... if you initiate and hold any mouse button down WHILE ON THE WHITE SCREEN, it shows up all the time, even on the red screen. Personally, I wish it would continue to show and hide regardless of mouse button status, but unless this is a "glitch" I wonder what was the thought process to have it coded this way?


Pete
Reply
#2
Those statements seem to have been provided "just in case", and otherwise shouldn't be needed. I don't remember well but programming MS-DOS and early Windows applications required the mouse cursor drawn, or it came from a driver, which made it a necessity to "hide" the cursor temporarily, draw all or part of the screen and then "show" the cursor again. It's because a driver cannot know what another program is doing with the screen. Also if the mouse cursor has to be drawn like a simple circle or rectangle in somebody's newb program, it definitely has to be managed "manually". These days, however, it's managed gracefully by the operating system. There's almost no worry of the cursor leaving trails somewhere...

Sometimes this combination could be dangerous. I had some programs disappearing the mouse cursor and unable to get it back which forced me to quit on it, or even log out the user session. Thankfully on Linux the mouse cursor seems to be managed by the desktop environment such as KDE Plasma. It should be alike on Macintosh or Windows.
Reply
#3
Hi

This only happens when the red screen lights up while you have already pressed a mouse button and not when you press a button while the red color is displayed.

Gaslouk
Reply
#4
Not a "glitch".   This is actual OS intended behavior.

Imagine this scenario -- you have a visible mouse cursor.  You're holding it down and drawing a pretty little line towards the latest country that annoyed you and you want to nuke... 

...suddenly...POOF!!  Your mouse pointer is gone!!...

...OH NO!! You just nuked your girlfriend's house by accident!!   AHHHHHHHHHHHH!!!



The OS can't know how important what you're doing is, nor what your threshold level is for things disrupting your work flow...  If you're interacting with the mouse, via a button down or other such "major event", the OS isn't going to touch those mouse settings with a ten-foot pole!   

Think of it much like trying to delete a file and getting the message, "You can't do that Pete.  That file's open in another program!"  New processes generally don't engage with resources or their settings if they're in use by another process.  (Unless you've jumped through hoops and specifically marked them as multi-process enabled, which I don't even know if that's possible with the mouse.)
Reply
#5
That's what I've been finding from doing some experimenting and research. What I still haven't figured out is how Windows sticks that damn mouse pointer to one spot, regardless of how fast you move the window.

I put this little demo together with a loop event to exaggerate how the mouse cursor races the window.

Start the drag and then swirl the mouse around in a big circle and watch the window chase the mouse...

Code: (Select All)
DIM WinMse AS POINTAPI
TYPE POINTAPI
    X_Pos AS LONG
    Y_Pos AS LONG
END TYPE

DECLARE DYNAMIC LIBRARY "User32"
    FUNCTION GetWindowLongA& (BYVAL hwnd AS LONG, BYVAL nIndex AS LONG)
    FUNCTION SetWindowLongA& (BYVAL hwnd AS LONG, BYVAL nIndex AS LONG, BYVAL dwNewLong AS LONG)
    FUNCTION SetWindowPos& (BYVAL hwnd AS LONG, BYVAL hWndInsertAfter AS LONG, BYVAL x AS LONG, BYVAL y AS LONG, BYVAL cx AS LONG, BYVAL cy AS LONG, BYVAL wFlags AS LONG)
    FUNCTION GetAsyncKeyState% (BYVAL vkey AS LONG)
    FUNCTION GetCursorPos (lpPoint AS POINTAPI)
    FUNCTION SetCursorPos& (BYVAL x AS INTEGER, BYVAL y AS INTEGER)
END DECLARE

DIM AS INTEGER setxy

WIDTH 50, 25
DO: LOOP UNTIL _SCREENEXISTS
GWL_STYLE = -16
ws_border = &H800000
WS_VISIBLE = &H10000000
_TITLE "No Border"
hwnd& = _WINDOWHANDLE
winstyle& = GetWindowLongA&(hwnd&, GWL_STYLE)
_DELAY .25
a& = SetWindowLongA&(hwnd&, GWL_STYLE, winstyle& AND WS_VISIBLE)
a& = SetWindowPos&(hwnd&, 0, 0, 200, 400, 0, 39)

LOCATE 1, 1
COLOR 0, 7
PRINT SPACE$(_WIDTH);
fw = _FONTWIDTH
fh = _FONTHEIGHT
x = _SCREENX: y = _SCREENY

DO
    _LIMIT 60

    IF GetAsyncKeyState(1) < 0 THEN
        IF lb = 0 THEN lb = 1
    ELSE
        IF lb THEN lb = 0: dragx = 0: dragy = 0
    END IF

    z = GetCursorPos(WinMse)

    IF lb THEN
        IF dragx THEN
            IF WinMse.X_Pos <> oldxpos OR WinMse.Y_Pos <> oldypos THEN
                j1 = (WinMse.X_Pos - oldxpos)
                j2 = (WinMse.Y_Pos - oldypos)
                x = x + j1: y = y + j2
                _SCREENMOVE x, y
                z1 = TIMER
                DO
                    setxy = SetCursorPos(x + dragx, y + dragy)
                LOOP UNTIL ABS(TIMER - z1) > .001
            END IF
            z = GetCursorPos(WinMse)
        ELSE
            IF WinMse.Y_Pos >= _SCREENY AND WinMse.Y_Pos <= _SCREENY + fh THEN
                x = _SCREENX: y = _SCREENY
                dragx = (WinMse.X_Pos - x)
                dragy = fw \ 2 ' Set to middle of the title bar vertical height.
            END IF
        END IF
    END IF
    IF LEN(INKEY$) THEN SYSTEM
    oldypos = WinMse.Y_Pos
    oldxpos = WinMse.X_Pos
LOOP

So what I was aiming to do before was hide the mouse during any off the drag point phase, but that is not possible since a button held negates the _MOUSEHIDE command. So still looking for the method that keeps the two married. I even tried the Win32 API MoveWindow approach, but it works the same as _SCREENMOVE. Obviously the mouse pointer has to move off the fixed point a bit to get the new position, but try a drag on a small resized QB64 IDE window and see how much better the pointer stays fixed to the drag point even during very rapid movement.

Oh well, in California, life's a beach. Good surf today, sunny and 75.

Pete
Reply
#6
Try this.  How's it perform on your machine?

Code: (Select All)
Screen _NewImage(800, 600, 32)
$Color:32

Declare Dynamic Library "User32"
    Function GetWindowLongA& (ByVal hwnd As Long, Byval nIndex As Long)
    Function SetWindowLongA& (ByVal hwnd As Long, Byval nIndex As Long, Byval dwNewLong As Long)
    Function SetWindowPos& (ByVal hwnd As Long, Byval hWndInsertAfter As Long, Byval x As Long, Byval y As Long, Byval cx As Long, Byval cy As Long, Byval wFlags As Long)
End Declare

Do: Loop Until _ScreenExists
GWL_STYLE = -16
ws_border = &H800000
WS_VISIBLE = &H10000000
hwnd& = _WindowHandle
winstyle& = GetWindowLongA&(hwnd&, GWL_STYLE)
a& = SetWindowLongA&(hwnd&, GWL_STYLE, winstyle& And WS_VISIBLE)
a& = SetWindowPos&(hwnd&, 0, 0, 200, 400, 0, 39)

Line (0, 0)-(_Width, 30), SkyBlue, BF 'My custom titlebar
pw = _PrintWidth("ð Steve's Tripple Line Title ð")
_PrintString ((_Width - pw) \ 2, 2), "ð Steve's Tripple Line Tittle ð"

Do
    x = _ScreenX: y = _ScreenY
    result = MBS
    If (result And 64) And (_MouseY <= 30) Then startdrag = -1 '            we're in the title bar and triggered a hold event.
    If startdrag Then
        _ScreenMove x + MMX, y + MMY '                                      drag the window from the title bar
        _MouseMove Mouse_StartX, Mouse_StartY '                              keep the mouse in its original position
    End If
    If (result And 1) = 0 Then startdrag = 0 '                              hold event is over, quit dragging
    _Limit 60
Loop Until _KeyDown(27)


Function MBS% 'Mouse Button Status
    Static StartTimer As _Float
    Static ButtonDown As Integer
    Static ClickCount As Integer
    Const ClickLimit## = 0.2 'Less than 1/4th of a second to down, up a key to count as a CLICK.
    '                          Down longer counts as a HOLD event.
    Shared Mouse_StartX, Mouse_StartY, Mouse_EndX, Mouse_EndY, MMX, MMY

    MMX = 0: MMY = 0
    While _MouseInput 'Remark out this block, if mouse main input/clear is going to be handled manually in main program.
        Select Case Sgn(_MouseWheel)
            Case 1: tempMBS = tempMBS Or 512
            Case -1: tempMBS = tempMBS Or 1024
        End Select
        MMX = MMX + _MouseMovementX
        MMY = MMY + _MouseMovementY
    Wend


    If _MouseButton(1) Then tempMBS = tempMBS Or 1
    If _MouseButton(2) Then tempMBS = tempMBS Or 2
    If _MouseButton(3) Then tempMBS = tempMBS Or 4


    If StartTimer = 0 Then
        If _MouseButton(1) Then 'If a button is pressed, start the timer to see what it does (click or hold)
            ButtonDown = 1: StartTimer = Timer(0.01)
            Mouse_StartX = _MouseX: Mouse_StartY = _MouseY
        ElseIf _MouseButton(2) Then
            ButtonDown = 2: StartTimer = Timer(0.01)
            Mouse_StartX = _MouseX: Mouse_StartY = _MouseY
        ElseIf _MouseButton(3) Then
            ButtonDown = 3: StartTimer = Timer(0.01)
            Mouse_StartX = _MouseX: Mouse_StartY = _MouseY
        End If
    Else
        BD = ButtonDown Mod 3
        If BD = 0 Then BD = 3
        If Timer(0.01) - StartTimer <= ClickLimit Then 'Button was down, then up, within time limit.  It's a click
            If _MouseButton(BD) = 0 Then tempMBS = 4 * 2 ^ ButtonDown: ButtonDown = 0: StartTimer = 0
        Else
            If _MouseButton(BD) = 0 Then 'hold event has now ended
                tempMBS = 0: ButtonDown = 0: StartTimer = 0
                Mouse_EndX = _MouseX: Mouse_EndY = _MouseY
            Else 'We've now started the hold event
                tempMBS = tempMBS Or 32 * 2 ^ ButtonDown
            End If
        End If
    End If
    MBS = tempMBS
End Function


That seems to pretty well stick the mouse to my window, wherever I start dragging it from.
Reply
#7
In a word, nope. Same results I get when I run mine. Move the mouse quickly and it separates approximately 30 - 40 pixels from the drag point and back. Do exactly the same thing with a Windows app, and it sticks like glue. So if you can't see this much difference on your machine, it's probably a difference in whatever components control speed issues, the processor, video card, whatever.

About the only thing I haven't tried replacing to an API method are the _SCREENX and _SCREENY statements, but I really have my doubts that they are slower than whatever API function is used for reporting upper left window coordinates.

BTW - The routine I made for reporting the desktop coordinates is...

Code: (Select All)
DIM Rec AS Rectangle
DIM hWnd AS LONG

TYPE Rectangle
    left AS LONG
    top AS LONG
    right AS LONG
    bottom AS LONG
END TYPE

DECLARE DYNAMIC LIBRARY "user32"
    FUNCTION GetWindowRect& (BYVAL Hwnd AS LONG, Rec AS Rectangle)
END DECLARE

hWnd = _WINDOWHANDLE
fwp$ = "Find Windows Position"
_TITLE fwp$
_DELAY .25

' What's interesting is Windows will not report the change in location until the window stops moving. Same if using _SCREENX _SCREENY.
DO
    _LIMIT 10
    SOUND 1000, .1 ' Shows the loop run continuously while being dragged.
    y& = GetWindowRect&(hWnd, Rec)
    LOCATE 1, 1
    PRINT "top ="; Rec.top; "    ";
    PRINT "right ="; Rec.right; "    ";
    PRINT "left ="; Rec.left; "    ";
    PRINT "Bottom ="; Rec.bottom; "    ";
LOOP UNTIL LEN(INKEY$)


I found it interesting it only reports after you stop dragging your Win around, not during. So Stevie Nicks aside for a moment, I wonder why that is? The same thing happens if you stick _SCREENX and SCREENY in that loop. Maybe it was designed that way by Windows to ignore the changing positions while dragging to increase speed. Certainly not good for collision detection. Help! My IDE window crashed into my browser window and there's BOLD everywhere!

Now if you will excuse me, I have to get back to that other Stevie... Kidding aside, and true story, I saw Fleetwood Mac the first time when I was 18. Stevie would change tops on stage, in a somewhat secluded area. Of course I was glad I invested in those premium high powered binoculars, so... Anyway, in later years I told my wife that story and she replied, "When Stevie Nicks sings she bleats like a sheep!" I agreed, and told her that was half the fantasy. Well, we didn't discuss the matter much after that comment, and frankly, I was also glad I invested in that premium pullout living room sofa.

Pete
Reply
#8
(11-26-2022, 04:55 PM)Pete Wrote: Now if you will excuse me, I have to get back to that other Stevie... Kidding aside, and true story, I saw Fleetwood Mac the first time when I was 18. Stevie would change tops on stage, in a somewhat secluded area. Of course I was glad I invested in those premium high powered binoculars, so... Anyway, in later years I told my wife that story and she replied, "When Stevie Nicks sings she bleats like a sheep!" I agreed, and told her that was half the fantasy. Well, we didn't discuss the matter much after that comment, and frankly, I was also glad I invested in that premium pullout living room sofa.

Pete
There's a song by her that I swear she roars like a lioness and I think it's fantastic -- STAND BACK!
Arrow Otherwise likes electronic music from the mid-1990's...
Reply




Users browsing this thread: 2 Guest(s)