It is currently Sun Mar 26, 2017 7:55 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 31 posts ]  Go to page 1, 2, 3  Next
Author Message
PostPosted: Sat Sep 21, 2013 4:34 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
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.


Top
 Profile  
 
PostPosted: Sat Sep 21, 2013 6:54 pm 
Online

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 17980
Location: NE Indiana, USA (NTSC)
In case that post gets deleted (or paywalled or moved to another URL with no redirect), may I reproduce that post somewhere?


Top
 Profile  
 
PostPosted: Sat Sep 21, 2013 7:54 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
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).


Top
 Profile  
 
PostPosted: Sun Sep 22, 2013 5:36 am 
Offline

Joined: Mon Mar 27, 2006 5:23 pm
Posts: 1262
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:
//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);
}


Top
 Profile  
 
PostPosted: Sun Sep 22, 2013 8:54 am 
Offline

Joined: Fri May 13, 2011 7:36 pm
Posts: 142
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.


Top
 Profile  
 
PostPosted: Sun Sep 22, 2013 9:53 am 
Offline
User avatar

Joined: Mon Feb 07, 2011 12:46 pm
Posts: 880
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).

_________________
.


Top
 Profile  
 
PostPosted: Sun Sep 22, 2013 1:44 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 4904
Location: Canada
SDL has SDL_DisableScreensaver() which does what koitsu suggested for Windows. (I dunno what it does on other platforms.)


Top
 Profile  
 
PostPosted: Wed Oct 02, 2013 11:24 am 
Offline
User avatar

Joined: Tue Dec 21, 2004 8:35 pm
Posts: 581
Location: Argentina
Good link, i tought about this issue and were going to google it. Thanks!!

_________________
ANes

Yanese is dead!!! Im happy about that...
http://www.yanese.com


Top
 Profile  
 
PostPosted: Thu Oct 03, 2013 6:38 am 
Offline
User avatar

Joined: Sun Sep 19, 2004 10:59 pm
Posts: 1349
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:
   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.


Top
 Profile  
 
PostPosted: Thu Oct 03, 2013 7:51 am 
Offline
User avatar

Joined: Sat Jan 22, 2005 8:51 am
Posts: 424
Location: Chicago, IL
The following works even when Windows is set to lock the workstation:

Set a timer somewhere
Code:
SetTimer(hWnd, 0, 30000, NULL);


And in your WindowProc
Code:
   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


Top
 Profile  
 
PostPosted: Thu Oct 03, 2013 8:49 am 
Online

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 17980
Location: NE Indiana, USA (NTSC)
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?


Top
 Profile  
 
PostPosted: Thu Oct 03, 2013 9:24 am 
Offline
User avatar

Joined: Sat Jan 22, 2005 8:51 am
Posts: 424
Location: Chicago, IL
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


Top
 Profile  
 
PostPosted: Thu Oct 03, 2013 11:24 am 
Online

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 17980
Location: NE Indiana, USA (NTSC)
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.


Top
 Profile  
 
PostPosted: Thu Oct 03, 2013 12:28 pm 
Offline
User avatar

Joined: Sat Jan 22, 2005 8:51 am
Posts: 424
Location: Chicago, IL
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


Top
 Profile  
 
PostPosted: Thu Oct 03, 2013 1:55 pm 
Online

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 17980
Location: NE Indiana, USA (NTSC)
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.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 31 posts ]  Go to page 1, 2, 3  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: Yahoo [Bot] and 7 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group