요즘 나오는 마우스들 대부분에는 미디어 키가 추가되어 있습니다. 키보드 상단에 하드웨어 키가 따로 있는 경우도 있고, 오른쪽 사진의 제 키보드처럼 펑션키의 조합인 경우도 있는데요. 보통은 볼륨 업/다운, 다음곡/이전곡 이런 기능들이 연결되어 있지요.
또 요즘엔 마우스에도 웹브라우저의 앞으로, 뒤로튼이 추가되어 있는 경우가 많습니다. 저도 이 버튼 기능을 최근에야 쓰기 시작했는데, 한번 맛들이니 아주아주 편리하더군요. ^^
그럼, 델파이나 C++빌더 애플리케이션에서 이들 버튼과 키 동작을 감지할 수는 없을까요? 제 경우엔, 마우스의 앞으로/뒤로 버튼을 페이지컨트롤의 앞 페이지, 뒤 페이지 이런 기능에 연결하고 싶었습니다.
이런 특수 키, 버튼의 감지는 생각보다 아주 간단합니다. WM_APPCOMMAND라는 메시지를 검출하면 되는데요. 키가 눌려진 순간 현재 활성화된 프로그램으로 이 메시지가 날아옵니다. 따라서 메시지 핸들러 함수를만들고 이 메시지를 검출하면 됩니다.
이 WM_APPCOMMAND 메시지의 lParam을 GET_APPCOMMAND_LPARAM()이라는 API 함수로 걸러내면 어떤 키보드 키나 마우스 버튼이 눌려졌는지 알아낼 수 있습니다.
또 lParam을 GET_DEVICE_LPARAM() 함수로 거르면 어떤 디바이스(마우스/키보드/제3의 디바이스)에서 이벤트가 발생했는지 알 수 있지요. GET_KEYSTATE_LPARAM() 함수를 쓰면 해당 버튼/키가 눌린 순간에 컨트롤키나 마우스의 다른 버튼이 눌려진 상태인지도 알아낼 수 있습니다.
간단한 예제를 보지요. 아래는 델파이 예제입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
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++빌더 버전의 예제는 아래와 같습니다.
1 2 3 4 5 6 7 8 9 10 11 12 |
// 헤더 파일 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) }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
//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
[…] […]