Problem Description
Required: A program which will turn off the
computer screen whenever a specific key is pressed, regardless of the active
program at the time.
Background & Techniques
We recently bought a new weather station (Oregon Scientific WMR968) that
will display current weather on a small LCD display console but can also
connect to a PC to display weather info. I took an old Dell
Latitude out of retirement and put it to work for this purpose. It
works nicely sitting on a bookshelf in one corner of the room. A
program called Virtual Weather not only displays weather conditions but also
collects history and builds web pages that can be called up from any
computer in the house.
I wanted a way to turn the monitor off overnight but the program needs to
keep running to capture weather history data. Windows
Power Management will turn the monitor off after a preset amount of time
with no mouse or keyboard activity, but that is not a very satisfactory
solution.
This program turns the monitor off whenever the
"Pause" key is pressed. It uses the same technique as Windows, so any
mouse movement or key-press will restore the display. It uses a
Windows facility called "Global Keyboard Hook" which gets to look at every
key press from any program and decide whether to process it or pass it on.
I this case, we look for the "Pause" key code and generate a "Monitor off"
message when we see one.
Non-programmers are welcome to read on, but may
want to skip to the bottom of this page to download
executable version of the program.
Notes for Programmers
The code here is based on sample code found at
delphi.about.com which also has an excellent description of the process.
I won't try to improve on that introduction but here is a summary:
Global hooks must run from a separate DLL (Dynamic
Link Library) module, so we need two projects, one to build the DLL with the
key processing logic and one to load the DLL into memory and initialize it.
First the initialization program,
MonitorOff .
The following steps are all contained in the form create procedure.
- Call LoadLibrary to load the DLL
(MonitorOffDLL
in this case) containing the hook procedure.
- Call GetProcAddress to get the
addresses in the DLL of the procedures to be called to initialize
the hook (SetHookHandle
in this case) and one to be called when a key is pressed (GlobalKeyboardHook
in thsi case).
- Call SetWindowsHookEx specifying
WH_KEYBOARD as the hook type and the
addresses obtained in step 2. Set the ThreadId parameter
to 0 to indicate a global hook. The handled assigned to this hook
must be passed to the DLL because it is used to define the chain of
hooks in case other guys are also using hooks to watch the keyboard.
- Call the hook initialization procedure in the
DLL to pass the handle assigned to the hook.
That's all
MonitorOff has to do except call
FreeLibrary to release the DLL then the program is closed.
In MonitorOffDLL,
procedure SetHookhandle
simply saves the handle assigned to this
hook for use by the GlobalKeyboardHook
which now gets called whenever a key is pressed. The logic in the hook
procedure is quite simple - just look for the "Pause" key to be released and
send a Syscommand windows message with the parameters necessary to turn off
the monitor power.
Addendum March 13, 2008: A viewer recently
discovered that the program did not work under his version of Vista. After a
little checking, I discovered that the problem was probably that not all
monitors recognize the "standby" command that was previously issued.
At least in my case, the only version of Vista running here is on a laptop
which does not "Standby". The "Poweroff" command does work
however, so the current update allows you to specify which command "Standby"
or "Poweroff" is to be issued when the Pause key is pressed.
Addendum March 17, 2010: Version 2 fixes
a problem with the alternative code for blanking the monitor (Code value 2,
Power-Off), should now work when the default code value 1, Standby, does
not. I have tested it under Windows 7 on my first laptop to require
its use, a Dell Studio 17. In the process of testing, I also found
that the Studio 17 uses the Fn + F12 keys to emulate the missing Pause key.
I have no experience with other company's laptops, but I suspect that thay
all use a similar technique to replace the real Pause key with a
virtual alternative. Dell does not document the "feature" that I could
find, but my Key Codes program
will help find the hidden key in short order. This version also
fixes a bug that only showed up under Windows 7 - when the program is
closed, the "key hook" that was checking for the Pause key was not being
"unhooked" at close time. It now is.
Running/Exploring the Program