Important screensaver tip for Windows emulator authors

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Important screensaver tip for Windows emulator authors

Post by koitsu »

This is something I have seen happen over the past, oh I dunno, 10+ years in all sorts of games (many commercial and from very large companies): the games do not inhibit screen savers or monitor blanking (power-off) from occurring while the emulator/game is running.

The solution for this is incredibly simple and takes virtually zero CPU time. Some emulators like Nestopia implement this methodology. I thought I'd document it for those writing Win32-based emulators so that they know how simple it is to do this and what the proper methodology is. I recently had to describe it over on the Steam forums for the recent Angry Video Game Nerd game that came out yesterday:

http://steamcommunity.com/app/237740/di ... 769796832/

I hope this benefits folks here. Please implement this when doing a Windows-based emulator. If your programming language or environment doesn't give you this degree of control, then start hounding on the language or framework authors to provide it. Every Win32 application has a WndProc equivalent, so every Win32 application should be able to accomplish this -- just that many crappy frameworks and abstract garbage don't give you this degree of control, and for no justified reason.

If you need further workarounds I can provide one (it does involve changing the power scheme, I can provide code for such -- but I STRONGLY do not recommend it, as it makes changes to the users' profile without their consent, and if your game/program crashes it can leave the profile indefinitely with no blanking/screen saver configured, which is bad. The method I described in the above URL is indeed the best/proper solution).

HTH.
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: An important tip for Windows emulator authors

Post by tepples »

In case that post gets deleted (or paywalled or moved to another URL with no redirect), may I reproduce that post somewhere?
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: An important tip for Windows emulator authors

Post by koitsu »

Sure thing. I wasn't sure what page on the Wiki would be most relevant for it, sadly. :(

And if needed I can add the code for the power profile adjustment I mentioned (though again, really should not do this).
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: An important tip for Windows emulator authors

Post by Near »

I really think the problem is that Windows doesn't treat gamepad input like it does keyboard and mouse input. It should also restart the screen saver counter, which would solve this problem for everyone. (And sure, ignore small analog movements since low-quality gamepads can stutter with no actual user input. Or even just ignore analog axes entirely.)

I never like 'solutions' that require every individual piece of software in a given category to implement the 'fix'. We should be putting the pressure on OS vendors to do the right thing as well.

That said, I'll share the Linux equivalent. Here, you want to use XTestFakeKeyEvent, and call it every few seconds. Nothing else is reliable. Sample code:

Code: Select all

//call this once during each frame
//preferably only if your emulator has window focus
void supressScreenSaver() {
  //XSetScreenSaver(timeout = 0) does not work
  //XResetScreenSaver() does not work
  //XScreenSaverSuspend() does not work
  //DPMSDisable() does not work
  //XSendEvent(KeyPressMask) does not work
  //xdg-screensaver often isn't available
  //use XTest extension to send fake keypress every few seconds.
  //keycode of 255 does not map to any actual key,
  //but it will block screensaver and power management.
  Display *display = XOpenDisplay(0);
  XTestFakeKeyEvent(display, 255, True,  0);
  XTestFakeKeyEvent(display, 255, False, 0);
  XCloseDisplay(display);
}
snarfblam
Posts: 143
Joined: Fri May 13, 2011 7:36 pm

Re: An important tip for Windows emulator authors

Post by snarfblam »

koitsu wrote:And if needed I can add the code for the power profile adjustment I mentioned (though again, really should not do this).
Changing a user's settings without asking first, especially something like power settings, is never, ever acceptable IMO. If you include code to adjust these settings, the need to make the behavior opt-in can't be understated.
zzo38
Posts: 1096
Joined: Mon Feb 07, 2011 12:46 pm

Re: An important tip for Windows emulator authors

Post by zzo38 »

In some cases it might be a cross-platform library such as SDL or whatever, so the programmer may not want to normally to include such things (unless the library used already has such a function; even then there ought to be a way to turn off the suppress screen saver function since it isn't always wanted).
(Free Hero Mesh - FOSS puzzle game engine)
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: An important tip for Windows emulator authors

Post by rainwarrior »

SDL has SDL_DisableScreensaver() which does what koitsu suggested for Windows. (I dunno what it does on other platforms.)
User avatar
Anes
Posts: 702
Joined: Tue Dec 21, 2004 8:35 pm
Location: Mendoza, Argentina

Re: An important tip for Windows emulator authors

Post by Anes »

Good link, i tought about this issue and were going to google it. Thanks!!
ANes
User avatar
Quietust
Posts: 1920
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: An important tip for Windows emulator authors

Post by Quietust »

There's actually two minor flaws in the sample code you posted on the Steam forums:
1. wParam needs to be ANDed with 0xFFF0 first.
MSDN wrote:In WM_SYSCOMMAND messages, the four low-order bits of the wParam parameter are used internally by the system. To obtain the correct result when testing the value of wParam, an application must combine the value 0xFFF0 with the wParam value by using the bitwise AND operator.
2. The checks should only be done when emulation is actually active, otherwise if you leave emulation paused and walk away it'll never go into power saving mode.

There's also the minor detail that if you've got Windows set to lock the workstation when the screen saver kicks in, it will ignore your program's request to not do so.
MSDN wrote:If password protection is enabled by policy, the screen saver is started regardless of what an application does with the SC_SCREENSAVE notification—even if fails to pass it to DefWindowProc.
Thus, the correct code should probably look something like this (copy/pasted from Nintendulator):

Code: Select all

	case WM_SYSCOMMAND:
		// disallow screen saver while emulating (doesn't work if password protected)
		if (running && (((wParam & 0xFFF0) == SC_SCREENSAVE) || ((wParam & 0xFFF0) == SC_MONITORPOWER)))
			return 0;
		// otherwise, proceed to DefWindowProc
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
User avatar
James
Posts: 431
Joined: Sat Jan 22, 2005 8:51 am
Location: Chicago, IL
Contact:

Re: Important screensaver tip for Windows emulator authors

Post by James »

The following works even when Windows is set to lock the workstation:

Set a timer somewhere

Code: Select all

SetTimer(hWnd, 0, 30000, NULL);
And in your WindowProc

Code: Select all

	case WM_TIMER:
		switch (wParam)
		{
		case 0:
			INPUT input;
			input.type = INPUT_KEYBOARD;
			input.ki.wVk = 0x88; //Unassigned virtual keycode
			input.ki.dwFlags = KEYEVENTF_KEYUP;
			SendInput(1, &input, sizeof(INPUT));
			return 0;
		}
I suppose there is some risk that your choice of keycode conflicts with some other program that's using it, but I haven't had or heard of any problems so far.
get nemulator
http://nemulator.com
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Important screensaver tip for Windows emulator authors

Post by tepples »

So you reset the timer by periodically sending a keypress through the Windows event loop. I can think of a couple improvements. One would be to send the keypress only when the emulator is focused, ensuring that the key code won't conflict. Another would be to send the keypress whenever a button is pressed on the joystick, keeping the screensaver working as expected should the user walk away from a paused game. But then I don't program in Win32 currently; are there problems with my suggestion?
User avatar
James
Posts: 431
Joined: Sat Jan 22, 2005 8:51 am
Location: Chicago, IL
Contact:

Re: Important screensaver tip for Windows emulator authors

Post by James »

tepples wrote:So you reset the timer by periodically sending a keypress through the Windows event loop. I can think of a couple improvements. One would be to send the keypress only when the emulator is focused, ensuring that the key code won't conflict. Another would be to send the keypress whenever a button is pressed on the joystick, keeping the screensaver working as expected should the user walk away from a paused game. But then I don't program in Win32 currently; are there problems with my suggestion?
Nope. All of these are fine suggestions.

re: SendInput focus. I think my concern was with applications that listen to all keyboard events (e.g., hotkey type stuff). Last time I did any testing with this was probably ~8 years ago, so I really have no idea. :lol:
get nemulator
http://nemulator.com
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Important screensaver tip for Windows emulator authors

Post by tepples »

Then send something innocent like the down arrow or the spacebar or the X key, as that's what players would already be pressing when playing an NES game with a keyboard.

In any case, Windows Vista didn't exist 8 years ago, and your product requires it or newer.
User avatar
James
Posts: 431
Joined: Sat Jan 22, 2005 8:51 am
Location: Chicago, IL
Contact:

Re: Important screensaver tip for Windows emulator authors

Post by James »

tepples wrote:Then send something innocent like the down arrow or the spacebar or the X key, as that's what players would already be pressing when playing an NES game with a keyboard.
So every x seconds, the emulator would 'see' you pressing down. How does that make sense?
tepples wrote:In any case, Windows Vista didn't exist 8 years ago, and your product requires it or newer.
In it's current incarnation, sure. Prior to 2.0, it ran on XP. But I guess you would know better. :roll:
get nemulator
http://nemulator.com
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Important screensaver tip for Windows emulator authors

Post by tepples »

James wrote:
tepples wrote:Then send something innocent like the down arrow or the spacebar or the X key, as that's what players would already be pressing when playing an NES game with a keyboard.
So every x seconds, the emulator would 'see' you pressing down. How does that make sense?
The window system would see a key being pressed, but the emulator would ignore it. Perhaps use a key that happens not to be bound to a game button.
Post Reply