QA: How can I assign my program to a certain hardware key?

Vassili Philippov (vasja@spbteam.com), November 19, 2001.

Question

I need to bind my program to a hardware key so that it will be called every time when this hardware key is pressed. How can I do it?

Answer

I already wrote (How can I handle hardware keys in my application?) about handling hardware keys in your application. But if you want to assign your application to a certain hardware key for all situations that method will not work. You should change registry that contains information about programs assigned to hardware buttons and then force system to reload settings from registry.

A user can assign programs to hardware buttons using Settings\Personal\Buttons applet in the Control Panel. You can do it by changing the following registry values:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shell\Keys\40C1 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shell\Keys\40C2 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shell\Keys\40C3 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shell\Keys\40C4 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shell\Keys\40C5

Each value is responsible for one hardware button. Some Pocket PC devices can contain more or less than 5 buttons. You should write full path to your program with the value that corresponds to necessary button. If the path contains spaces then you should use quotes like "\Program files\MyApp\MyProgram.exe".

I suggest using CVORegistry library if you work with registry. Your code in that case will be

CVORegistry reg(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Shell\\Keys\\40C5")); reg.WriteString(_T(""), _T("\"\\Program files\\MyApp\\MyProgram.exe\""));

One problem is that the shell sometimes does not reload settings from registry. Usually is happens with the sound recorder hardware button. To force the system to reload settings you should either soft-reset Pocket PC or use an undocumented function UnregisterFunc1 from coredll.dll. Register all the hardware keys to your application and then release them. It will force the shell to take your changes. Here is a sample code for that:

HINSTANCE hCoreDll; UnregisterFunc1Proc procUndergisterFunc; hCoreDll = LoadLibrary(_T("coredll.dll")); ASSERT(hCoreDll); procUndergisterFunc = (UnregisterFunc1Proc)GetProcAddress( hCoreDll, _T("UnregisterFunc1")); ASSERT(procUndergisterFunc); for (int i=0xc1; i<=0xcf; i++) { procUndergisterFunc(MOD_WIN, i); RegisterHotKey(NULL, i, MOD_WIN, i); } FreeLibrary(hCoreDll);

Launcher

If you assign your application to a hardware button then the shell will start it every time the button is pressed. Most Pocket PC applications (all MFC based) do not create another instance if the application is already running but activate the running instance. It can be a problem for you because you are not able to find whether it is a normal activation or hardware button pressing. You can use a launcher program to solve this challenge. You should use a small launcher program that checks if the main program is running now rather than the main application. Start the launcher if the main program is not running now and send a special window message to your main program. In the main program you will be able to handle hardware button press event by handling the special message.

In many cases it is easier to handle hardware button inside the launcher program and not to disturb the main program for that.

Related resources: