Windowed game losing focus

BlitzMax Forums/BlitzMax Programming/Windowed game losing focus

GfK(Posted 2006) [#1]
Hello

Thought it'd be pretty good to have my game pause automatically if its being played in a window and loses focus.

Is there any way of achieving this?

PS I do have MaxGUI and I don't know if I can do it with that, but I'd hate to have to include such a large mod for a small task like this.


popcade(Posted 2006) [#2]
Gray Alien's Game Framework has this and working well...


GfK(Posted 2006) [#3]
Don't have that.

Never mind anyway, done it.

Extern "win32"
 Function GetActiveWindow%()
End Extern
Graphics 800,600

While Not KeyDown(key_escape)
	Cls
	If getactivewindow()
		DrawText "has focus",20,20
	Else
		DrawText "no focus",20,20
	EndIf
	Flip
Wend



FlameDuck(Posted 2006) [#4]
Or alternatively you could just use the AppSuspend and AppResume Events.


GfK(Posted 2006) [#5]
Thanks - will that work on MacOS/Linux as well?


FlameDuck(Posted 2006) [#6]
I dunno. I would assume so, but have neither to test it on ATM.


GfK(Posted 2006) [#7]
Me either, but its not really important at this stage. Was just curious. :)


Grey Alien(Posted 2006) [#8]
use the events as they are cross platform. You might alway want to call Delay(1) when the docus is lost to give more CPU power to windows.


Yan(Posted 2006) [#9]
.


sswift(Posted 2007) [#10]
I was just trying to figure out how to do this myself, but APPSUSPEND and APPRESUME don't seem to work properly in debug mode at least.

When running in debug mode, if I open an explorer window, and then click that as my game is running, I get an APPSUSPEND event, but then immediately get an APPRESUME event as well.

I haven't yet tested whether this occurs outside of debug mode.


GfK(Posted 2007) [#11]
I just use AppSuspend to pause my game, then let the user un-pause it manually when they want to.

It seems to be working fine, debug or not.


Grey Alien(Posted 2007) [#12]
I just set a flag and then skip the logic but still to the drawing code, works fine.


GfK(Posted 2007) [#13]
I just set a flag and then skip the logic but still to the drawing code, works fine.
Same. I also revert to the standard Windows mouse pointer if its running in a window. A custom mouse pointer looks 'odd' while the game is paused.


sswift(Posted 2007) [#14]
Well requiring the user to unpause the game is a clever idea and all, and maybe it's a perfectly fine solution, but I'd still like to know if this is only an issue in debug mode and if not, how you're expected to determine the window doesn't have focus.


GfK(Posted 2007) [#15]
Does my code (3rd post) do what you need?


sswift(Posted 2007) [#16]
I assume so, but it is Windows specific, so not suitable for my needs.


Grey Alien(Posted 2007) [#17]
sswift: just use AppSuspend and AppResume Events like Flameduck says. My framework does this. Basically if you are playing in windowed mode and click the desktop or alt tab to another app it pasues and stops music, then a click back in the window unpasues, simple.


sswift(Posted 2007) [#18]
Grey:
Yes, but if you read my post, then you'd see that those events don't work right in debug mode. I haven't tested yet to see if they work the way you say they do normally, but there's still the unexplained debug mode behavior.


Grey Alien(Posted 2007) [#19]
They work find in debug mode here...



However, just noticed I have this code as well:

		'Sometimes APPRESUME doesn't work so make a windows call.
		?Win32
		If Suspended = 1 And SuspendedEvent=1 And GetForegroundWindow()=WindowHandle Then SuspendedEvent = 0
		?


This is like a manual APP_RESUME event.


Dreamora(Posted 2007) [#20]
Sure you don't have some kind of totally outdated BM version which might have this problem? (or some kind of DLL Module that uses callbacks / threading to catch events?)

The only other thing I know which can and tends to create problems is crap like WindowBlinds which interfers in many spots.


sswift(Posted 2007) [#21]
I have nothing screwy like that installed, and my version of BM is up to date.

Grey:
Have you tried printing the events to the debug window as they occur? I'd like to see what events you get when you run the game in debug, click another window, then click the game window again.

It's possible that it is the printing to the debug window which is causing the issue.


sswift(Posted 2007) [#22]
Could this possibly be the cause of my problems? And if so, what would be the sugested alternative method?


	AddHook EmitEventHook, MyHook	
		
	Function MyHook:Object(iId:Int, tData:Object, tContext:Object)
	
 		Local Event:TEvent=TEvent(tData)
		
		If App.Canvas <> Null
			If (Event.Source = App.Canvas) And (Event.ID = EVENT_GADGETPAINT)
				Flip		
				Return Null
			EndIf	
		EndIf

		Return tData
		
	End Function



sswift(Posted 2007) [#23]
Okay I did some testing in non-debug mode, and I get the same results.

When I run the game, and I click the explorer window, I get:
APPSUSPEND
APPRESUME
WINDOW ACTIVATE

When I click the game again, the game resumes, but as far as events go, I get nothing, because as far as the window is concenred it is still active apparently.

I suspect this has something to do with my canvas being redrawn, but I don't know how or why, or what to do to fix it.


sswift(Posted 2007) [#24]
Well, I removed the hook, but the only difference now in debug mode is that when I click the window after it has gone out of focus I do get a single gadgetpaint event.


Dreamora(Posted 2007) [#25]
Above shouldn't make a problem.
Are there any other event hooks you have which return NULL instead of tData and thus cause problems?


sswift(Posted 2007) [#26]
No.


sswift(Posted 2007) [#27]
I found out what was causing the issue. It was a line of code I had which would activate my canvas each frame.

I did that because I wanted to use polled input while in a window, and if the canvas lost focus because the user activated the window menu or something then they wouldn't be able to control the game anymore.

Why use polled input? Cause it's easier to code. I'd just have to recode all the polled input functions myself otherwise. There's no other good way to do it.

Anyway, I solved the issue by using a function I was going to code myself until I typed in the name and found it already exists. AppSuspended(). So when AppSuspended() is true, I simply don't activate the canvas. Or call any of the game update code. I also pause my music channel.

Pausing the channels for all the other sounds that are playing though is gonna be a bit difficult since I don't keep track of every channel currently playing.


Grey Alien(Posted 2007) [#28]
Sorry I was away, doesn't sound like I'd have helped though.

Make a channel array and pause them. (I know you know this!)

I don't use polledinput, it's off in my framework, works well.


sswift(Posted 2007) [#29]
If you don't use polled input then you have to keep track of all the keys and mouse buttons and whether they're being held down, or were clicked since the last time you checked... What a pain!

As for a channel array, don't be silly. What you need is a channel linked list! One link for each sound you play.

But then you have to keep track of when the sounds end and update the thing so you can free the channel pointers. That's what's a pain. Have to write a whole type for that.

I'm not doing that right now in my code. I just store a channel pointer for the music. The other stuff just gets played one shot, and I don't keep the pointer. If I wanted to support looped sounds though, that I could stop or pause, then I'd definitely need to keep track of those channel pointers.


Dreamora(Posted 2007) [#30]
You are aware that this "keep track of" is exactly what BM internally does as well ^^ So you could just copy that if you really need it ;-)

And I wouldn't use a channel linked list but a TMAP, so you can search for them by key (name, filename, reference - depends on yuor needs) but iterate through them as a list for pause / cleanup.


Grey Alien(Posted 2007) [#31]
re: keep track of keys, I just overode the BlitzMAx commands for my own input :-) (like Dreamora suggests, I think)

[quote]As for a channel array, don't be silly. What you need is a channel linked list! One link for each sound you play.

But then you have to keep track of when the sounds end and update the thing so you can free the channel pointers. That's what's a pain. Have to write a whole type for that.
[quote]hehe, sounds like you talked yourself out of using a list. Channel arrays have some advantages a) you can make a max number of channels thus limit the max noise b) you can assign on channel for a certain sound that you don't want to have multiple occurences of, c) you can have channels that be freely used by any sound d) you don't need to track when they stop playing, you can just iterate throught the channels and test ChannelPlaying e) easy to iterate through and dim the volume on them each frame during fades etc.


sswift(Posted 2007) [#32]
Grey:
Well maybe if it had more than eight channels or something like Blitz3D had, it would be okay. But that method was really a pain in Blitz3D because you'd have some sounds that trigger continuously and which you want to be overridden if another sound needs to be played, and other sounds which you don't want to ever be overridden if they're playing, and which you don't want to be ignored if all channels are full and playing. In the Lego Builder bots game I had to have a priority set for every sound and a complicated bit of code to decide what to do when different combinations of looped or unlooped and different priorities were played, just so that the most important sounds wouldn't get cut off.

I like the linked list thing because it means I don't have to worry about any of that.

Dreamora says that Blitzmax keeps a list of channels internally so I'll lokk for that I guess.

As for using a tmap, with the small number of channels you have, you're not gonna get a big speed savings by using a binary tree to store the channels in order of channel name or pointer. I don't even do that in my sprite system. It's just not a bottleneck in most realistic scenarios.