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.
Running/Exploring the Program
Suggestions for Further Explorations
If the Pause key was needed for some other purpose.
MonitorOff could let the user choose the key or key combination to be
used. The key information would then be passed to the initialization
call to the DLL.
|
Original Date: September 12, 2006 |
Modified:
March 13, 2008 |
|