
요즘 나오는 마우스들 대부분에는 미디어 키가 추가되어 있습니다. 키보드 상단에 하드웨어 키가 따로 있는 경우도 있고, 오른쪽 사진의 제 키보드처럼 펑션키의 조합인 경우도 있는데요. 보통은 볼륨 업/다운, 다음곡/이전곡 이런 기능들이 연결되어 있지요.
또 요즘엔 마우스에도 웹브라우저의 앞으로, 뒤로튼이 추가되어 있는 경우가 많습니다. 저도 이 버튼 기능을 최근에야 쓰기 시작했는데, 한번 맛들이니 아주아주 편리하더군요. ^^
그럼, 델파이나 C++빌더 애플리케이션에서 이들 버튼과 키 동작을 감지할 수는 없을까요? 제 경우엔, 마우스의 앞으로/뒤로 버튼을 페이지컨트롤의 앞 페이지, 뒤 페이지 이런 기능에 연결하고 싶었습니다.

이런 특수 키, 버튼의 감지는 생각보다 아주 간단합니다. WM_APPCOMMAND라는 메시지를 검출하면 되는데요. 키가 눌려진 순간 현재 활성화된 프로그램으로 이 메시지가 날아옵니다. 따라서 메시지 핸들러 함수를만들고 이 메시지를 검출하면 됩니다.
이 WM_APPCOMMAND 메시지의 lParam을 GET_APPCOMMAND_LPARAM()이라는 API 함수로 걸러내면 어떤 키보드 키나 마우스 버튼이 눌려졌는지 알아낼 수 있습니다.
또 lParam을 GET_DEVICE_LPARAM() 함수로 거르면 어떤 디바이스(마우스/키보드/제3의 디바이스)에서 이벤트가 발생했는지 알 수 있지요. GET_KEYSTATE_LPARAM() 함수를 쓰면 해당 버튼/키가 눌린 순간에 컨트롤키나 마우스의 다른 버튼이 눌려진 상태인지도 알아낼 수 있습니다.
간단한 예제를 보지요. 아래는 델파이 예제입니다.
procedure TForm1.WMAppCommand(var Msg: TMessage);
var
sMessage: string;
begin
case GET_APPCOMMAND_LPARAM(Msg.LParam) of
APPCOMMAND_BROWSER_BACKWARD:
begin
PageControl1.ActivePageIndex := PageControl1.ActivePageIndex - 1;
sMessage := 'Browser backward';
end;
APPCOMMAND_BROWSER_FORWARD:
begin
PageControl1.ActivePageIndex := PageControl1.ActivePageIndex + 1;
sMessage := 'Browser forward';
end;
APPCOMMAND_BROWSER_HOME: sMessage := 'Browser Home';
APPCOMMAND_BROWSER_SEARCH: sMessage := 'Browser Search';
APPCOMMAND_VOLUME_MUTE: sMessage := 'Volume Mute';
APPCOMMAND_VOLUME_UP: sMessage := 'Volume Up';
APPCOMMAND_VOLUME_DOWN: sMessage := 'Volume Down';
APPCOMMAND_MEDIA_PREVIOUSTRACK: sMessage := 'Media Previous Track';
APPCOMMAND_MEDIA_NEXTTRACK: sMessage := 'Media Next Track';
APPCOMMAND_LAUNCH_MEDIA_SELECT: sMessage := 'Media Select';
APPCOMMAND_MEDIA_PAUSE: sMessage := 'Media Pause';
APPCOMMAND_MEDIA_PLAY: sMessage := 'Media Play';
APPCOMMAND_MEDIA_PLAY_PAUSE: sMessage := 'Media Paly/Pause';
APPCOMMAND_LAUNCH_APP1: sMessage := 'Launch App1';
APPCOMMAND_LAUNCH_APP2: sMessage := 'Launch App2';
APPCOMMAND_LAUNCH_MAIL: sMessage := 'Launch Mail';
end;
sMessage := sMessage + ' with ';
case GET_DEVICE_LPARAM(Msg.LParam) of
FAPPCOMMAND_KEY: sMessage := sMessage + 'Keyboard key';
FAPPCOMMAND_MOUSE: sMessage := sMessage + 'mouse button';
FAPPCOMMAND_OEM: sMessage := sMessage + 'unknown device';
end;
ShowMessage(sMessage);
inherited;
end;
C++빌더 버전의 예제는 아래와 같습니다.
// 헤더 파일
class TForm1 : public TForm
{
... // 생략
public:
__fastcall TForm1(TComponent* Owner);
void __fastcall WMAppCommand(TMessage &Msg);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_APPCOMMAND, TMessage, WMAppCommand)
END_MESSAGE_MAP(TForm)
};
//cpp 파일
void __fastcall TForm1::WMAppCommand(TMessage &Msg)
{
String sMessage;
switch GET_APPCOMMAND_LPARAM(Msg.LParam)
{
case APPCOMMAND_BROWSER_BACKWARD:
PageControl1->ActivePageIndex = PageControl1->ActivePageIndex - 1;
sMessage = "Browser backward";
break;
case APPCOMMAND_BROWSER_FORWARD:
PageControl1->ActivePageIndex = PageControl1->ActivePageIndex + 1;
sMessage = "Browser forward";
break;
case APPCOMMAND_BROWSER_HOME: sMessage = "Browser Home"; break;
case APPCOMMAND_BROWSER_SEARCH: sMessage = "Browser Search"; break;
case APPCOMMAND_VOLUME_MUTE: sMessage = "Volume Mute"; break;
case APPCOMMAND_VOLUME_UP: sMessage = "Volume Up"; break;
case APPCOMMAND_VOLUME_DOWN: sMessage = "Volume Down"; break;
case APPCOMMAND_MEDIA_PREVIOUSTRACK: sMessage = "Media Previous Track"; break;
case APPCOMMAND_MEDIA_NEXTTRACK: sMessage = "Media Next Track"; break;
case APPCOMMAND_LAUNCH_MEDIA_SELECT: sMessage = "Media Select"; break;
case APPCOMMAND_MEDIA_PAUSE: sMessage = "Media Pause"; break;
case APPCOMMAND_MEDIA_PLAY: sMessage = "Media Play"; break;
case APPCOMMAND_MEDIA_PLAY_PAUSE: sMessage = "Media Paly/Pause"; break;
case APPCOMMAND_LAUNCH_APP1: sMessage = "Launch App1"; break;
case APPCOMMAND_LAUNCH_APP2: sMessage = "Launch App2"; break;
case APPCOMMAND_LAUNCH_MAIL: sMessage = "Launch Mail"; break;
}
sMessage = sMessage + " with ";
switch GET_DEVICE_LPARAM(Msg.LParam)
{
case FAPPCOMMAND_KEY: sMessage = sMessage + "Keyboard key"; break;
case FAPPCOMMAND_MOUSE: sMessage = sMessage + "mouse button"; break;
case FAPPCOMMAND_OEM: sMessage = sMessage + "unknown device"; break;
}
ShowMessage(sMessage);
}
(델파이 코드에서 가장 아래의 inherited를 없애버릴 경우, 기본 동작이 막히게 됩니다.)
위 코드를 실제로 실행해보시면 아시겠지만, 이 코드를 활용하면 애플리케이션에서 볼륨 업다운이나 트랙 앞/뒤 등의 키보드 동작이 발생할 때 애플리케이션에서 특정 동작으로 연결할 수 있습니다. 예를 들자면, MDI 애플리케이션에서 여러 차일드 창을 열어놨을 때, 트랙 앞/뒤 키를 누르면 다음 창, 이전 창 이렇게 이동하게 할 수 있게 되지요.
위에서 나열한 키는 모두는 아니고 제 마우스와 키보드에 있는 것들만 추린 거구요. 전체 리스트를 보시려면 MSDN의 WM_APPCOMMAND 메시지에 대한 설명 페이지에서 보실 수 있습니다.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646275(v=vs.85).aspx