Posted: 2nd Jul 2022 0:21
Years ago I found SetRawMouseVisible() to be unreliable. So, I thought I'd try to figure out what was going on:
At first, I thought it was just the WinAPI being janky. However, after a bit of testing, it appears it's not an ON/OFF flag, but instead it buffers every time the command is sent. If you do SetRawMouseVisible(1) 5 times, then you must do SetRawMouseVisible(0) 6 times to have it actually set visibility OFF.
I don't know if this is a bug or intended behavior, but I at least find it undesirable behavior.

A quick test program to demonstrate the behavior:
+ Code Snippet
ClickCount AS INTEGER
DO
    IF GetRawKeyPressed(27) THEN END // [Esc]
    Print(ScreenFPS())
    Print("ClickCount: "+str(ClickCount))
    IF GetRawMouseLeftPressed()  : SetRawMouseVisible(1) : INC ClickCount : ENDIF
    IF GetRawMouseRightPressed() : SetRawMouseVisible(0) : DEC ClickCount : ENDIF
    Sync()
LOOP


Here's a hack to work around the issue:
+ Code Snippet
ClickCount AS INTEGER
DO
    IF GetRawKeyPressed(27) THEN END // [Esc]
    Print(ScreenFPS())
    Print("ClickCount: "+str(ClickCount))
    IF GetRawMouseLeftPressed()  : SetMouseVisibleHack(1) : INC ClickCount : ENDIF
    IF GetRawMouseRightPressed() : SetMouseVisibleHack(0) : DEC ClickCount : ENDIF
    Sync()
LOOP
GLOBAL _____MouseVisible AS INTEGER = 1 // An instance where LOCAL STATIC variables would be nice.
FUNCTION SetMouseVisibleHack(SetTo AS INTEGER)
    IF     (SetTo = 1 AND _____MouseVisible = 0) : _____MouseVisible = 1 : SetRawMouseVisible(1)
    ELSEIF (SetTo = 0 AND _____MouseVisible = 1) : _____MouseVisible = 0 : SetRawMouseVisible(0)
    ENDIF
ENDFUNCTION
Posted: 2nd Jul 2022 2:03
i'm no guru, but:
he Show and Hide method calls must be balanced. For every call to the Hide method there must be a corresponding call to the Show method.

which, according to your findings above, is true?

otherwise, another way to skin your cat?
+ Code Snippet
GLOBAL Vis = 1
do
    If GetRawKeyState(27) then End

	If GetRawMouseLeftPressed() then SetMouseVis(1)
	If GetRawMouseRightPressed() then SetMouseVis(0)
	
	Print(Vis)
    Sync()
loop

Function SetMouseVis(this)
	If Vis <> this
		Vis = this
		SetRawMouseVisible(Vis)
	EndIf
EndFunction

admittedly, i'm not quite sure which cat needs fleecing
Posted: 2nd Jul 2022 3:57
Ah, so it is WinAPI jank.

Perhaps we could update AppGameKit to intervene and handle this in a not-stupid way. Like our work-around functions.
Posted: 3rd Jul 2022 4:53
It's not stupid depending on what you're doing.

The fact that it stores an internal count eliminates the need of remembering cursor states everywhere in external code.
+ Code Snippet
WasMouseVisible = GetCursorVisibility();
ShowCursor(false);
<stuff>
ShowCursor(WasMouseVisible);

This opens up the possibility for external code somewhere not doing this and instead doing what you want it to do introducing a bug where the cursor becomes visible too early that could be difficult to track down. The API keeping track itself takes care of this.

In a game scenario, though, what you're saying is probably what most people would expect.
Posted: 4th Jul 2022 0:10
You could turn it off entirely an make you own cursor using a sprite.
Posted: 4th Jul 2022 13:42
Microsoft are usually in a difficult position when it comes to updating their APIs.
What might seem like strange or clumsy approaches today., made more sense when they were first implemented.

Something to keep in mind is that during the Early 90s with the advent of the Graphics Card, came the 2D Accelerator.
These weren't just Display Adapters., but Graphics Chips that would accelerate various Graphics Tasks... one such task was a Hardware Mouse Cursor., as well Graphics User Interface Operating Systems (Windows) were becoming more common.
A Software Mouse Cursor was quite a performance heavy task... so, offloading it to Hardware helped quite substantially with System Performance.

This however poses a problem... as Hardware doesn't work like Software., they don't "Store" per se; they merely act upon the last state you set and you can't really get any feedback.
As such, there is no way to know if the Hardware Mouse Cursor is Hidden or Visible.
What we also have to consider is that flooding the Window Message Queue with a Hide/Show Command every Synchronisation Loop., well that would add CPU Overhead.

As a result., this message is sent once and is passed on to the Graphics Card; which then behaves based on the last state sent to it.
If we want to change that; then we'd have to see a different command to it.

Now Graphics Cards had (dedicated) 2D Acceleration Components until 2009., the introduction of the AMD Compute and NVIDIA Unified Shader Architectures.
As a result the Cursor switched back from Hardware to Software., although it's still Hardware Accelerated as now it's a Shader Sprite; but here's the thing of it... Microsoft can't simply change how this works.
Why? Well because there is at least a Decade of Software that still remained 100% Compatible with Modern Windows; that still uses these commands how they used to work.

So they can't just change how this works. Even IF there is arguably a much better way, not without breaking all those old applications.
...

I mean *we* as Developers can easily switch this into being a Flag.

MouseCursor.agc
+ Code Snippet
#Constant True -1
#Constant False 0
#Constant Enable 1
#Constant Disable 0

Type MouseCursor_t
	bShow As Integer
EndType

Global Cursor As MouseCursor_t : Cursor.bShow = True

Function ShowMouseCursor( )
	If Cursor.bShow = False
		SetRawMouseVisible( Enable )
		Cursor.bShow = True
	EndIf
EndFunction

Function HideMouseCursor( )
	If Cursor.bShow = True
		SetRawMouseVisible( Disable )
		Cursor.bShow = False
	EndIf
EndFunction


Main.agc
+ Code Snippet
// show all errors

SetErrorMode(2)

// set window properties
SetWindowTitle( "PrototypeDependancy" )
SetWindowSize( 1024, 768, 0 )
SetWindowAllowResize( 1 ) // allow the user to resize the window

// set display properties
SetVirtualResolution( 1024, 768 ) // doesn't have to match the window
SetOrientationAllowed( 1, 1, 1, 1 ) // allow both portrait and landscape on mobile devices
SetSyncRate( 60, 1 ) // 30fps instead of 60 to save battery
SetScissor( 0,0,0,0 ) // use the maximum available screen space, no black borders
UseNewDefaultFonts( 1 )

#Include "MouseCursor.agc"

Do
	If GetRawKeyState( 32 ) And GetRawKeyPressed( 32 ) <> False
		Select Cursor.bShow
			Case True:
				HideMouseCursor()
			EndCase
			Case False:
				ShowMouseCursor()
			EndCase
			Case Default:
				// ignore
			EndCase
		EndSelect
	EndIf
	
	If Cursor.bShow = True
		Print( "Mouse Cursor Visible" )
	Else
		Print( "Mouse Cursor Hidden" )
	EndIf		
		
    Sync()
Loop


It works every time