I found a patch from about 3 years ago for implementing RegisterHotKey
and UnregisterHotKey. I've updated it to apply to the current wine
source tree and essentially copied what metacity does to cover any
missing functionality.
The original patch is here:
http://www.winehq.com/hypermail/wine-devel/2003/02/0636.html
Unfortunately, trying to register an in-use hotkey with this patch
causes a crash:
X Error of failed request: BadAccess (attempt to access private
resource denied)
Major opcode of failed request: 33 (X_GrabKey)
Serial number of failed request: 58
Current serial number in output stream: 62
RegisterHotKey is implemented as if XGrabKey returns 0 if it fails. Do
I need to do something special to "watch" for the error?
--
Vincent Povirk aka MadEwokHerd
Primary email: [EMAIL PROTECTED]
Secondary email: [EMAIL PROTECTED]
Tertiary email: [EMAIL PROTECTED]
Jabber: [EMAIL PROTECTED]
? 01-hotkey.diff
? evil-window-size-hack
? hotkeys.patch
? wa-hack
? wa_hack_complete
? dlls/commdlg/800.bmp
? dlls/commdlg/Makefile
? dlls/commdlg/cdrom.ico
? dlls/commdlg/floppy.ico
? dlls/commdlg/folder.ico
? dlls/commdlg/folder2.ico
? dlls/commdlg/fontpics.bmp
Index: dlls/user/driver.c
===================================================================
RCS file: /home/wine/wine/dlls/user/driver.c,v
retrieving revision 1.4
diff -u -r1.4 driver.c
--- dlls/user/driver.c 3 Apr 2006 19:46:56 -0000 1.4
+++ dlls/user/driver.c 7 May 2006 20:15:34 -0000
@@ -76,6 +76,8 @@
GET_USER_FUNC(ActivateKeyboardLayout);
GET_USER_FUNC(Beep);
+ GET_USER_FUNC(RegisterHotKey);
+ GET_USER_FUNC(UnregisterHotKey);
GET_USER_FUNC(GetAsyncKeyState);
GET_USER_FUNC(GetKeyNameText);
GET_USER_FUNC(GetKeyboardLayout);
@@ -216,6 +218,16 @@
return -1;
}
+static BOOL nulldrv_RegisterHotKey(HWND hwnd,INT id,UINT modifiers,UINT vk)
+{
+ return FALSE;
+}
+
+static BOOL nulldrv_UnregisterHotKey(HWND hwnd,INT id)
+{
+ return FALSE;
+}
+
static void nulldrv_SetCursor( struct tagCURSORICONINFO *info )
{
}
@@ -421,6 +433,8 @@
nulldrv_ToUnicodeEx,
nulldrv_UnloadKeyboardLayout,
nulldrv_VkKeyScanEx,
+ nulldrv_RegisterHotKey,
+ nulldrv_UnregisterHotKey,
/* mouse functions */
nulldrv_SetCursor,
nulldrv_GetCursorPos,
@@ -538,6 +552,16 @@
return load_driver()->pVkKeyScanEx( ch, layout );
}
+static BOOL loaderdrv_RegisterHotKey(HWND hwnd,INT id,UINT modifiers,UINT vk)
+{
+ return load_driver()->pRegisterHotKey( hwnd, id, modifiers, vk );
+}
+
+static BOOL loaderdrv_UnregisterHotKey(HWND hwnd,INT id)
+{
+ return load_driver()->pUnregisterHotKey( hwnd, id );
+}
+
static void loaderdrv_SetCursor( struct tagCURSORICONINFO *info )
{
load_driver()->pSetCursor( info );
@@ -737,6 +761,8 @@
loaderdrv_ToUnicodeEx,
loaderdrv_UnloadKeyboardLayout,
loaderdrv_VkKeyScanEx,
+ loaderdrv_RegisterHotKey,
+ loaderdrv_UnregisterHotKey,
/* mouse functions */
loaderdrv_SetCursor,
loaderdrv_GetCursorPos,
Index: dlls/user/input.c
===================================================================
RCS file: /home/wine/wine/dlls/user/input.c,v
retrieving revision 1.10
diff -u -r1.10 input.c
--- dlls/user/input.c 27 Mar 2006 20:51:17 -0000 1.10
+++ dlls/user/input.c 7 May 2006 20:15:35 -0000
@@ -653,8 +653,10 @@
*/
BOOL WINAPI RegisterHotKey(HWND hwnd,INT id,UINT modifiers,UINT vk)
{
- FIXME_(keyboard)("(%p,%d,0x%08x,%d): stub\n",hwnd,id,modifiers,vk);
- return TRUE;
+ TRACE_(keyboard)("(%p,0x%x,0x%08x,0x%08x)\n",hwnd,id,modifiers,vk);
+ if (USER_Driver->pRegisterHotKey)
+ return USER_Driver->pRegisterHotKey( hwnd, id, modifiers, vk );
+ return FALSE;
}
/***********************************************************************
@@ -662,8 +664,10 @@
*/
BOOL WINAPI UnregisterHotKey(HWND hwnd,INT id)
{
- FIXME_(keyboard)("(%p,%d): stub\n",hwnd,id);
- return TRUE;
+ TRACE_(keyboard)("(%p,%d)\n",hwnd,id);
+ if (USER_Driver->pUnregisterHotKey)
+ return USER_Driver->pUnregisterHotKey( hwnd, id );
+ return FALSE;
}
/***********************************************************************
Index: dlls/user/user_private.h
===================================================================
RCS file: /home/wine/wine/dlls/user/user_private.h,v
retrieving revision 1.20
diff -u -r1.20 user_private.h
--- dlls/user/user_private.h 10 Aug 2005 09:56:23 -0000 1.20
+++ dlls/user/user_private.h 7 May 2006 20:15:35 -0000
@@ -114,6 +114,8 @@
INT (*pToUnicodeEx)(UINT, UINT, LPBYTE, LPWSTR, int, UINT, HKL);
BOOL (*pUnloadKeyboardLayout)(HKL);
SHORT (*pVkKeyScanEx)(WCHAR, HKL);
+ BOOL (*pRegisterHotKey)(HWND, INT, UINT, UINT);
+ BOOL (*pUnregisterHotKey)(HWND, INT);
/* mouse functions */
void (*pSetCursor)(struct tagCURSORICONINFO *);
BOOL (*pGetCursorPos)(LPPOINT);
Index: dlls/x11drv/keyboard.c
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/keyboard.c,v
retrieving revision 1.90
diff -u -r1.90 keyboard.c
--- dlls/x11drv/keyboard.c 20 Apr 2006 09:41:15 -0000 1.90
+++ dlls/x11drv/keyboard.c 7 May 2006 20:15:38 -0000
@@ -89,7 +89,7 @@
static int min_keycode, max_keycode, keysyms_per_keycode;
static WORD keyc2vkey[256], keyc2scan[256];
-static int NumLockMask, AltGrMask; /* mask in the XKeyEvent state */
+static int NumLockMask, ScrollLockMask, AnyLockMask, AltGrMask, MetaMask, SuperMask; /* mask in the XKeyEvent state */
static int kcControl, kcAlt, kcShift, kcNumLock, kcCapsLock; /* keycodes */
static char KEYBOARD_MapDeadKeysym(KeySym keysym);
@@ -1075,6 +1075,91 @@
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
};
+/***********************************************************************
+ * HotKey
+ */
+typedef struct GRABKEY_INFO {
+ HWND hWnd; /* windows window to receive hot-key notification */
+ INT id; /* windows identifier of hot key */
+ UINT fsModifiers; /* windows key-modifier flag */
+ UINT vk; /* windows virtual-key code */
+ int x_keycode; /* X keycode */
+ unsigned int x_modifiers; /* X modifiers */
+} GRABKEY_INFO;
+
+static GRABKEY_INFO * pKeys = 0;
+static int nKeys = 0;
+static int nKeysMax = 0;
+
+static int add_grab(HWND hwnd, INT id, UINT modifiers, UINT vk, unsigned int x_modifiers, int x_keycode)
+{
+ TRACE("(%p,%x,%x,%x,%x,%x)\n",hwnd,id,modifiers,vk,x_modifiers,x_keycode);
+
+ if ( (pKeys == 0) || (nKeys == nKeysMax) ) {
+ GRABKEY_INFO * temp;
+ if (nKeys)
+ temp = (GRABKEY_INFO *)HeapReAlloc(GetProcessHeap(),0, pKeys, (nKeysMax + 10) * sizeof(GRABKEY_INFO));
+ else
+ temp = (GRABKEY_INFO *)HeapAlloc(GetProcessHeap(),0, 10 * sizeof(GRABKEY_INFO));
+ if (temp) {
+ pKeys = temp;
+ nKeysMax += 10;
+ } else
+ return False;
+ }
+
+ pKeys[nKeys].hWnd = hwnd;
+ pKeys[nKeys].id = id;
+ pKeys[nKeys].fsModifiers = modifiers;
+ pKeys[nKeys].vk = vk;
+ pKeys[nKeys].x_keycode = x_keycode;
+ pKeys[nKeys].x_modifiers = x_modifiers;
+ nKeys++;
+ return True;
+}
+
+static GRABKEY_INFO * find_grab(INT id)
+{
+ int i;
+ TRACE("(%x)\n", id);
+ for (i = 0; i < nKeys; i++) {
+ if (pKeys[i].id == id)
+ return &pKeys[i];
+ }
+ return 0;
+}
+
+static GRABKEY_INFO * has_grab(XKeyEvent *event)
+{
+ int i;
+ int modifiers = event->state & ~AnyLockMask;
+ TRACE("(%p) event->keycode=%d\n",event,event->keycode);
+ for (i = 0; i < nKeys; i++) {
+ if ((pKeys[i].x_keycode == event->keycode) && (pKeys[i].x_modifiers == modifiers))
+ return &pKeys[i];
+ }
+ return 0;
+}
+
+static int remove_grab(INT id)
+{
+ int i,j;
+ TRACE("(%x)\n", id);
+ for (i = 0; i < nKeys; i++) {
+ if (pKeys[i].id == id) {
+ for (j = i; j < (nKeys - 1); j++)
+ pKeys[j] = pKeys[j + 1];
+ nKeys--;
+ if (nKeys == 0) {
+ HeapFree(GetProcessHeap(),0, pKeys);
+ pKeys = 0;
+ nKeysMax = 0;
+ }
+ return True;
+ }
+ }
+ return False;
+}
/* Returns the Windows virtual key code associated with the X event <e> */
/* x11 lock must be held */
@@ -1325,6 +1410,15 @@
TRACE_(key)("type %d, window %lx, state 0x%04x, keycode 0x%04x\n",
event->type, event->window, event->state, event->keycode);
+ if (event->type == KeyPress) {
+ GRABKEY_INFO * hotkey = has_grab(event);
+
+ if (hotkey) {
+ PostMessageA(hotkey->hWnd, WM_HOTKEY, hotkey->id, MAKEWORD(hotkey->fsModifiers, hotkey->vk));
+ return;
+ }
+ }
+
wine_tsx11_lock();
if (xic)
ascii_chars = XmbLookupString(xic, event, Str, sizeof(Str), &keysym, &status);
@@ -1576,15 +1670,36 @@
{
int k;
- for (k = 0; k < keysyms_per_keycode; k += 1)
- if (XKeycodeToKeysym(display, *kcp, k) == XK_Num_Lock)
- {
- NumLockMask = 1 << i;
+ for (k = 0; k < keysyms_per_keycode; k += 1) {
+ KeySym sym = XKeycodeToKeysym(display, *kcp, k);
+ switch (sym) {
+ case XK_Num_Lock:
+ NumLockMask |= 1 << i;
TRACE_(key)("NumLockMask is %x\n", NumLockMask);
+ break;
+
+ case XK_Scroll_Lock:
+ ScrollLockMask |= 1 << i;
+ TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask);
+ break;
+
+ case XK_Meta_L: case XK_Meta_R:
+ MetaMask |= 1 << i;
+ TRACE_(key)("MetaMask is %x\n", MetaMask);
+ break;
+
+ case XK_Super_L: case XK_Super_R:
+ SuperMask |= 1 << i;
+ TRACE_(key)("SuperMask is %x\n", SuperMask);
+ break;
+
+ default: break;
}
+ }
}
}
XFreeModifiermap(mmp);
+ AnyLockMask = LockMask|NumLockMask|ScrollLockMask;
/* Detect the keyboard layout */
X11DRV_KEYBOARD_DetectLayout();
@@ -2521,3 +2636,98 @@
XBell(thread_display(), 0);
wine_tsx11_unlock();
}
+
+/***********************************************************************
+ * RegisterHotKey (X11DRV.@)
+ */
+BOOL X11DRV_RegisterHotKey(HWND hwnd,INT id,UINT modifiers,UINT vk)
+{
+ Display *display;
+ Window window;
+ BOOL ret;
+ int x_modifiers = 0, grab_mask, ungrab_mask;
+ int x_keycode = 0;
+ int err;
+ int keyc;
+
+ TRACE("(%p,0x%x,0x%08x,0x%08x)\n",hwnd,id,modifiers,vk);
+
+ display = thread_display();
+ window = X11DRV_get_whole_window(hwnd);
+
+ if (modifiers & MOD_ALT)
+ x_modifiers |= MetaMask;
+ if (modifiers & MOD_CONTROL)
+ x_modifiers |= ControlMask;
+ if (modifiers & MOD_SHIFT)
+ x_modifiers |= ShiftMask;
+ if (modifiers & MOD_WIN)
+ x_modifiers |= SuperMask;
+
+ for (keyc=min_keycode; keyc<=max_keycode; keyc++) {
+ if ((keyc2vkey[keyc] & 0xFF) == vk) {
+ TRACE("keycode found\n");
+ x_keycode = keyc;
+ break;
+ }
+ }
+
+ if (keyc > max_keycode) {
+ TRACE("keycode not found\n");
+ return FALSE;
+ }
+
+ /* We need to register every combination of the locks to ignore them */
+ wine_tsx11_lock();
+ grab_mask = AnyLockMask;
+ do {
+ err = XGrabKey(display, x_keycode, x_modifiers|grab_mask, DefaultRootWindow(display), False, GrabModeAsync, GrabModeAsync);
+ if (err == 0) break;
+ grab_mask = (grab_mask-1) & AnyLockMask;
+ } while (grab_mask != AnyLockMask);
+
+ if (err == 0) {
+ FIXME("failed to grab keycode=0x%04x modifiers=0x%04x", x_keycode, x_modifiers);
+ /* FIXME: set proper error value */
+ SetLastError(ERROR_HOTKEY_ALREADY_REGISTERED);
+ /* unregister anything we succeeded in grabbing */
+ ungrab_mask = AnyLockMask;
+ while (ungrab_mask != grab_mask) {
+ XUngrabKey(display, x_keycode, x_modifiers|ungrab_mask, DefaultRootWindow(display));
+ ungrab_mask = (ungrab_mask-1) & AnyLockMask;
+ }
+ ret = FALSE;
+ } else {
+ add_grab(hwnd, id, modifiers, vk, x_modifiers, x_keycode);
+ ret = TRUE;
+ }
+ wine_tsx11_unlock();
+
+ return ret;
+}
+
+/***********************************************************************
+ * UnregisterHotKey (X11DRV.@)
+ */
+BOOL X11DRV_UnregisterHotKey(HWND hwnd,INT id)
+{
+ Display *display = thread_display();
+ Window window = X11DRV_get_whole_window(hwnd);
+ GRABKEY_INFO * grab = find_grab(id);
+ int ungrab_mask;
+
+ TRACE("(%lx,%d)\n",(DWORD)hwnd,id);
+
+ if (grab) {
+ wine_tsx11_lock();
+ ungrab_mask = AnyLockMask;
+ do {
+ XUngrabKey(display, grab->x_keycode, grab->x_modifiers|ungrab_mask, window);
+ ungrab_mask = (ungrab_mask-1) & AnyLockMask;
+ } while (ungrab_mask != AnyLockMask);
+ wine_tsx11_unlock();
+ remove_grab(id);
+ return TRUE;
+ }
+ return FALSE;
+}
Index: dlls/x11drv/winex11.drv.spec
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/winex11.drv.spec,v
retrieving revision 1.5
diff -u -r1.5 winex11.drv.spec
--- dlls/x11drv/winex11.drv.spec 27 Mar 2006 20:51:24 -0000 1.5
+++ dlls/x11drv/winex11.drv.spec 7 May 2006 20:15:38 -0000
@@ -76,6 +76,8 @@
@ cdecl ToUnicodeEx(long long ptr ptr long long long) X11DRV_ToUnicodeEx
@ cdecl UnloadKeyboardLayout(long) X11DRV_UnloadKeyboardLayout
@ cdecl VkKeyScanEx(long long) X11DRV_VkKeyScanEx
+@ cdecl RegisterHotKey(long long long long) X11DRV_RegisterHotKey
+@ cdecl UnregisterHotKey(long long) X11DRV_UnregisterHotKey
@ cdecl SetCursor(ptr) X11DRV_SetCursor
@ cdecl GetCursorPos(ptr) X11DRV_GetCursorPos
@ cdecl SetCursorPos(long long) X11DRV_SetCursorPos
Index: include/winbase.h
===================================================================
RCS file: /home/wine/wine/include/winbase.h,v
retrieving revision 1.253
diff -u -r1.253 winbase.h
--- include/winbase.h 16 Mar 2006 20:41:46 -0000 1.253
+++ include/winbase.h 7 May 2006 20:15:40 -0000
@@ -1844,6 +1844,7 @@
HANDLE WINAPI RegisterEventSourceA(LPCSTR,LPCSTR);
HANDLE WINAPI RegisterEventSourceW(LPCWSTR,LPCWSTR);
#define RegisterEventSource WINELIB_NAME_AW(RegisterEventSource)
+BOOL WINAPI RegisterHotKey(HWND,INT,UINT,UINT);
BOOL WINAPI RegisterWaitForSingleObject(PHANDLE,HANDLE,WAITORTIMERCALLBACK,PVOID,ULONG,ULONG);
HANDLE WINAPI RegisterWaitForSingleObjectEx(HANDLE,WAITORTIMERCALLBACK,PVOID,ULONG,ULONG);
VOID WINAPI ReleaseActCtx(HANDLE);
@@ -1971,6 +1972,7 @@
BOOL WINAPI UnlockFileEx(HANDLE,DWORD,DWORD,DWORD,LPOVERLAPPED);
#define UnlockSegment(handle) GlobalUnfix((HANDLE)(handle))
BOOL WINAPI UnmapViewOfFile(LPVOID);
+BOOL WINAPI UnregisterHotKey(HWND,INT);
BOOL WINAPI UnregisterWait(HANDLE);
BOOL WINAPI UnregisterWaitEx(HANDLE,HANDLE);
BOOL WINAPI UpdateResourceA(HANDLE,LPCSTR,LPCSTR,WORD,LPVOID,DWORD);