From: Jacek Caban jacek@codeweavers.com
Signed-off-by: Jacek Caban jacek@codeweavers.com --- dlls/user32/menu.c | 204 +------------------------ dlls/user32/user32.spec | 2 +- dlls/win32u/gdiobj.c | 1 + dlls/win32u/menu.c | 279 +++++++++++++++++++++++++++++++++++ dlls/win32u/win32u.spec | 2 +- dlls/win32u/win32u_private.h | 1 + dlls/win32u/wrappers.c | 6 + 7 files changed, 291 insertions(+), 204 deletions(-)
diff --git a/dlls/user32/menu.c b/dlls/user32/menu.c index 9f51fa555f8..669d838bf61 100644 --- a/dlls/user32/menu.c +++ b/dlls/user32/menu.c @@ -56,7 +56,6 @@ #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(menu); -WINE_DECLARE_DEBUG_CHANNEL(accel);
/* internal flags for menu tracking */
@@ -4768,170 +4767,6 @@ DWORD WINAPI CalcMenuBar(HWND hwnd, DWORD left, DWORD right, DWORD top, RECT *re }
-/********************************************************************** - * translate_accelerator - */ -static BOOL translate_accelerator( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, - BYTE fVirt, WORD key, WORD cmd ) -{ - INT mask = 0; - UINT mesg = 0; - - if (wParam != key) return FALSE; - - if (NtUserGetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL; - if (NtUserGetKeyState(VK_MENU) & 0x8000) mask |= FALT; - if (NtUserGetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT; - - if (message == WM_CHAR || message == WM_SYSCHAR) - { - if ( !(fVirt & FVIRTKEY) && (mask & FALT) == (fVirt & FALT) ) - { - TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", LOWORD(wParam) & 0xff); - goto found; - } - } - else - { - if(fVirt & FVIRTKEY) - { - TRACE_(accel)("found accel for virt_key %04lx (scan %04x)\n", - wParam, 0xff & HIWORD(lParam)); - - if(mask == (fVirt & (FSHIFT | FCONTROL | FALT))) goto found; - TRACE_(accel)(", but incorrect SHIFT/CTRL/ALT-state\n"); - } - else - { - if (!(lParam & 0x01000000)) /* no special_key */ - { - if ((fVirt & FALT) && (lParam & 0x20000000)) - { /* ^^ ALT pressed */ - TRACE_(accel)("found accel for Alt-%c\n", LOWORD(wParam) & 0xff); - goto found; - } - } - } - } - return FALSE; - - found: - if (message == WM_KEYUP || message == WM_SYSKEYUP) - mesg = 1; - else - { - HMENU hMenu, hSubMenu, hSysMenu; - UINT uSysStat = (UINT)-1, uStat = (UINT)-1, nPos; - POPUPMENU *menu; - - hMenu = (GetWindowLongW( hWnd, GWL_STYLE ) & WS_CHILD) ? 0 : GetMenu(hWnd); - hSysMenu = get_win_sys_menu( hWnd ); - - /* find menu item and ask application to initialize it */ - /* 1. in the system menu */ - if ((menu = find_menu_item(hSysMenu, cmd, MF_BYCOMMAND, NULL))) - { - hSubMenu = menu->obj.handle; - release_menu_ptr(menu); - - if (GetCapture()) - mesg = 2; - if (!IsWindowEnabled(hWnd)) - mesg = 3; - else - { - SendMessageW(hWnd, WM_INITMENU, (WPARAM)hSysMenu, 0L); - if(hSubMenu != hSysMenu) - { - nPos = MENU_FindSubMenu(&hSysMenu, hSubMenu); - TRACE_(accel)("hSysMenu = %p, hSubMenu = %p, nPos = %d\n", hSysMenu, hSubMenu, nPos); - SendMessageW(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, TRUE)); - } - uSysStat = GetMenuState(GetSubMenu(hSysMenu, 0), cmd, MF_BYCOMMAND); - } - } - else /* 2. in the window's menu */ - { - if ((menu = find_menu_item(hMenu, cmd, MF_BYCOMMAND, NULL))) - { - hSubMenu = menu->obj.handle; - release_menu_ptr(menu); - - if (GetCapture()) - mesg = 2; - if (!IsWindowEnabled(hWnd)) - mesg = 3; - else - { - SendMessageW(hWnd, WM_INITMENU, (WPARAM)hMenu, 0L); - if(hSubMenu != hMenu) - { - nPos = MENU_FindSubMenu(&hMenu, hSubMenu); - TRACE_(accel)("hMenu = %p, hSubMenu = %p, nPos = %d\n", hMenu, hSubMenu, nPos); - SendMessageW(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, FALSE)); - } - uStat = GetMenuState(hMenu, cmd, MF_BYCOMMAND); - } - } - } - - if (mesg == 0) - { - if (uSysStat != (UINT)-1) - { - if (uSysStat & (MF_DISABLED|MF_GRAYED)) - mesg=4; - else - mesg=WM_SYSCOMMAND; - } - else - { - if (uStat != (UINT)-1) - { - if (IsIconic(hWnd)) - mesg=5; - else - { - if (uStat & (MF_DISABLED|MF_GRAYED)) - mesg=6; - else - mesg=WM_COMMAND; - } - } - else - mesg=WM_COMMAND; - } - } - } - - if( mesg==WM_COMMAND ) - { - TRACE_(accel)(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd); - SendMessageW(hWnd, mesg, 0x10000 | cmd, 0L); - } - else if( mesg==WM_SYSCOMMAND ) - { - TRACE_(accel)(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd); - SendMessageW(hWnd, mesg, cmd, 0x00010000L); - } - else - { - /* some reasons for NOT sending the WM_{SYS}COMMAND message: - * #0: unknown (please report!) - * #1: for WM_KEYUP,WM_SYSKEYUP - * #2: mouse is captured - * #3: window is disabled - * #4: it's a disabled system menu option - * #5: it's a menu option, but window is iconic - * #6: it's a menu option, but disabled - */ - TRACE_(accel)(", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg); - if(mesg==0) - ERR_(accel)(" unknown reason - please report!\n"); - } - return TRUE; -} - /********************************************************************** * TranslateAcceleratorA (USER32.@) * TranslateAccelerator (USER32.@) @@ -4942,7 +4777,7 @@ INT WINAPI TranslateAcceleratorA( HWND hWnd, HACCEL hAccel, LPMSG msg ) { case WM_KEYDOWN: case WM_SYSKEYDOWN: - return TranslateAcceleratorW( hWnd, hAccel, msg ); + return NtUserTranslateAccelerator( hWnd, hAccel, msg );
case WM_CHAR: case WM_SYSCHAR: @@ -4952,45 +4787,10 @@ INT WINAPI TranslateAcceleratorA( HWND hWnd, HACCEL hAccel, LPMSG msg ) WCHAR wch; MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wch, 1); msgW.wParam = MAKEWPARAM(wch, HIWORD(msg->wParam)); - return TranslateAcceleratorW( hWnd, hAccel, &msgW ); + return NtUserTranslateAccelerator( hWnd, hAccel, &msgW ); }
default: return 0; } } - -/********************************************************************** - * TranslateAcceleratorW (USER32.@) - */ -INT WINAPI TranslateAcceleratorW( HWND hWnd, HACCEL hAccel, LPMSG msg ) -{ - ACCEL data[32], *ptr = data; - int i, count; - - if (!hWnd) return 0; - - if (msg->message != WM_KEYDOWN && - msg->message != WM_SYSKEYDOWN && - msg->message != WM_CHAR && - msg->message != WM_SYSCHAR) - return 0; - - TRACE_(accel)("hAccel %p, hWnd %p, msg->hwnd %p, msg->message %04x, wParam %08lx, lParam %08lx\n", - hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam); - - if (!(count = NtUserCopyAcceleratorTable( hAccel, NULL, 0 ))) return 0; - if (count > ARRAY_SIZE( data )) - { - if (!(ptr = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*ptr) ))) return 0; - } - count = NtUserCopyAcceleratorTable( hAccel, ptr, count ); - for (i = 0; i < count; i++) - { - if (translate_accelerator( hWnd, msg->message, msg->wParam, msg->lParam, - ptr[i].fVirt, ptr[i].key, ptr[i].cmd)) - break; - } - if (ptr != data) HeapFree( GetProcessHeap(), 0, ptr ); - return (i < count); -} diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 298a0fa3150..26f2d1caf45 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -767,7 +767,7 @@ @ stdcall TrackPopupMenuEx(long long long long long ptr) @ stdcall TranslateAccelerator(long long ptr) TranslateAcceleratorA @ stdcall TranslateAcceleratorA(long long ptr) -@ stdcall TranslateAcceleratorW(long long ptr) +@ stdcall TranslateAcceleratorW(long long ptr) NtUserTranslateAccelerator @ stdcall TranslateMDISysAccel(long ptr) @ stdcall TranslateMessage(ptr) # @ stub TranslateMessageEx diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c index c5db1bfcc30..ad04ba7ff78 100644 --- a/dlls/win32u/gdiobj.c +++ b/dlls/win32u/gdiobj.c @@ -1224,6 +1224,7 @@ static struct unix_funcs unix_funcs = NtUserSystemParametersInfoForDpi, NtUserToUnicodeEx, NtUserTrackMouseEvent, + NtUserTranslateAccelerator, NtUserTranslateMessage, NtUserUnregisterClass, NtUserUnregisterHotKey, diff --git a/dlls/win32u/menu.c b/dlls/win32u/menu.c index 8544cca47b4..d41aba956f2 100644 --- a/dlls/win32u/menu.c +++ b/dlls/win32u/menu.c @@ -235,6 +235,23 @@ static BOOL is_menu( HMENU handle ) return is_menu; }
+/*********************************************************************** + * get_win_sys_menu + * + * Get the system menu of a window + */ +static HMENU get_win_sys_menu( HWND hwnd ) +{ + HMENU ret = 0; + WND *win = get_win_ptr( hwnd ); + if (win && win != WND_OTHER_PROCESS && win != WND_DESKTOP) + { + ret = win->hSysMenu; + release_win_ptr( win ); + } + return ret; +} + static POPUPMENU *find_menu_item( HMENU handle, UINT id, UINT flags, UINT *pos ) { UINT fallback_pos = ~0u, i; @@ -346,6 +363,48 @@ static BOOL is_win_menu_disallowed( HWND hwnd ) return (get_window_long(hwnd, GWL_STYLE) & (WS_CHILD | WS_POPUP)) == WS_CHILD; }
+/*********************************************************************** + * find_submenu + * + * Find a Sub menu. Return the position of the submenu, and modifies + * *hmenu in case it is found in another sub-menu. + * If the submenu cannot be found, NO_SELECTED_ITEM is returned. + */ +static UINT find_submenu( HMENU *handle_ptr, HMENU target ) +{ + POPUPMENU *menu; + MENUITEM *item; + UINT i; + + if (*handle_ptr == (HMENU)0xffff || !(menu = grab_menu_ptr( *handle_ptr ))) + return NO_SELECTED_ITEM; + + item = menu->items; + for (i = 0; i < menu->nItems; i++, item++) + { + if(!(item->fType & MF_POPUP)) continue; + if (item->hSubMenu == target) + { + release_menu_ptr( menu ); + return i; + } + else + { + HMENU hsubmenu = item->hSubMenu; + UINT pos = find_submenu( &hsubmenu, target ); + if (pos != NO_SELECTED_ITEM) + { + *handle_ptr = hsubmenu; + release_menu_ptr( menu ); + return pos; + } + } + } + + release_menu_ptr( menu ); + return NO_SELECTED_ITEM; +} + /* see GetMenu */ HMENU get_menu( HWND hwnd ) { @@ -932,6 +991,25 @@ BOOL WINAPI NtUserSetMenuContextHelpId( HMENU handle, DWORD id ) return TRUE; }
+/* see GetSubMenu */ +static HMENU get_sub_menu( HMENU handle, INT pos ) +{ + POPUPMENU *menu; + HMENU submenu; + UINT i; + + if (!(menu = find_menu_item( handle, pos, MF_BYPOSITION, &i ))) + return 0; + + if (menu->items[i].fType & MF_POPUP) + submenu = menu->items[i].hSubMenu; + else + submenu = 0; + + release_menu_ptr(menu); + return submenu; +} + /********************************************************************** * NtUserSetMenuDefaultItem (win32u.@) */ @@ -979,3 +1057,204 @@ BOOL WINAPI NtUserSetMenuDefaultItem( HMENU handle, UINT item, UINT bypos ) release_menu_ptr( menu ); return ret; } + +/********************************************************************** + * translate_accelerator + */ +static BOOL translate_accelerator( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam, + BYTE virt, WORD key, WORD cmd ) +{ + INT mask = 0; + UINT msg = 0; + + if (wparam != key) return FALSE; + + if (NtUserGetKeyState( VK_CONTROL ) & 0x8000) mask |= FCONTROL; + if (NtUserGetKeyState( VK_MENU ) & 0x8000) mask |= FALT; + if (NtUserGetKeyState( VK_SHIFT ) & 0x8000) mask |= FSHIFT; + + if (message == WM_CHAR || message == WM_SYSCHAR) + { + if (!(virt & FVIRTKEY) && (mask & FALT) == (virt & FALT)) + { + TRACE_(accel)( "found accel for WM_CHAR: ('%c')\n", LOWORD(wparam) & 0xff ); + goto found; + } + } + else + { + if (virt & FVIRTKEY) + { + TRACE_(accel)( "found accel for virt_key %04lx (scan %04x)\n", + wparam, 0xff & HIWORD(lparam) ); + + if (mask == (virt & (FSHIFT | FCONTROL | FALT))) goto found; + TRACE_(accel)( ", but incorrect SHIFT/CTRL/ALT-state\n" ); + } + else + { + if (!(lparam & 0x01000000)) /* no special_key */ + { + if ((virt & FALT) && (lparam & 0x20000000)) /* ALT pressed */ + { + TRACE_(accel)( "found accel for Alt-%c\n", LOWORD(wparam) & 0xff ); + goto found; + } + } + } + } + return FALSE; + +found: + if (message == WM_KEYUP || message == WM_SYSKEYUP) + msg = 1; + else + { + HMENU menu_handle, submenu, sys_menu; + UINT sys_stat = ~0u, stat = ~0u, pos; + POPUPMENU *menu; + + menu_handle = (get_window_long( hwnd, GWL_STYLE ) & WS_CHILD) ? 0 : get_menu(hwnd); + sys_menu = get_win_sys_menu( hwnd ); + + /* find menu item and ask application to initialize it */ + /* 1. in the system menu */ + if ((menu = find_menu_item( sys_menu, cmd, MF_BYCOMMAND, NULL ))) + { + submenu = menu->obj.handle; + release_menu_ptr( menu ); + + if (get_capture()) + msg = 2; + if (!is_window_enabled( hwnd )) + msg = 3; + else + { + send_message( hwnd, WM_INITMENU, (WPARAM)sys_menu, 0 ); + if (submenu != sys_menu) + { + pos = find_submenu( &sys_menu, submenu ); + TRACE_(accel)( "sys_menu = %p, submenu = %p, pos = %d\n", + sys_menu, submenu, pos ); + send_message( hwnd, WM_INITMENUPOPUP, (WPARAM)submenu, MAKELPARAM(pos, TRUE) ); + } + sys_stat = get_menu_state( get_sub_menu( sys_menu, 0 ), cmd, MF_BYCOMMAND ); + } + } + else /* 2. in the window's menu */ + { + if ((menu = find_menu_item( menu_handle, cmd, MF_BYCOMMAND, NULL ))) + { + submenu = menu->obj.handle; + release_menu_ptr( menu ); + + if (get_capture()) + msg = 2; + if (!is_window_enabled( hwnd )) + msg = 3; + else + { + send_message( hwnd, WM_INITMENU, (WPARAM)menu_handle, 0 ); + if(submenu != menu_handle) + { + pos = find_submenu( &menu_handle, submenu ); + TRACE_(accel)( "menu_handle = %p, submenu = %p, pos = %d\n", + menu_handle, submenu, pos ); + send_message( hwnd, WM_INITMENUPOPUP, (WPARAM)submenu, + MAKELPARAM(pos, FALSE) ); + } + stat = get_menu_state( menu_handle, cmd, MF_BYCOMMAND ); + } + } + } + + if (msg == 0) + { + if (sys_stat != ~0u) + { + if (sys_stat & (MF_DISABLED|MF_GRAYED)) + msg = 4; + else + msg = WM_SYSCOMMAND; + } + else + { + if (stat != ~0u) + { + if (is_iconic( hwnd )) + msg = 5; + else + { + if (stat & (MF_DISABLED|MF_GRAYED)) + msg = 6; + else + msg = WM_COMMAND; + } + } + else + msg = WM_COMMAND; + } + } + } + + if (msg == WM_COMMAND) + { + TRACE_(accel)( ", sending WM_COMMAND, wparam=%0x\n", 0x10000 | cmd ); + send_message( hwnd, msg, 0x10000 | cmd, 0 ); + } + else if (msg == WM_SYSCOMMAND) + { + TRACE_(accel)( ", sending WM_SYSCOMMAND, wparam=%0x\n", cmd ); + send_message( hwnd, msg, cmd, 0x00010000 ); + } + else + { + /* some reasons for NOT sending the WM_{SYS}COMMAND message: + * #0: unknown (please report!) + * #1: for WM_KEYUP,WM_SYSKEYUP + * #2: mouse is captured + * #3: window is disabled + * #4: it's a disabled system menu option + * #5: it's a menu option, but window is iconic + * #6: it's a menu option, but disabled + */ + TRACE_(accel)( ", but won't send WM_{SYS}COMMAND, reason is #%d\n", msg ); + if (!msg) ERR_(accel)( " unknown reason\n" ); + } + return TRUE; +} + +/********************************************************************** + * NtUserTranslateAccelerator (win32u.@) + */ +INT WINAPI NtUserTranslateAccelerator( HWND hwnd, HACCEL accel, MSG *msg ) +{ + ACCEL data[32], *ptr = data; + int i, count; + + if (!hwnd) return 0; + + if (msg->message != WM_KEYDOWN && + msg->message != WM_SYSKEYDOWN && + msg->message != WM_CHAR && + msg->message != WM_SYSCHAR) + return 0; + + TRACE_(accel)("accel %p, hwnd %p, msg->hwnd %p, msg->message %04x, wParam %08lx, lParam %08lx\n", + accel,hwnd,msg->hwnd,msg->message,msg->wParam,msg->lParam); + + if (!(count = NtUserCopyAcceleratorTable( accel, NULL, 0 ))) return 0; + if (count > ARRAY_SIZE( data )) + { + if (!(ptr = malloc( count * sizeof(*ptr) ))) return 0; + } + count = NtUserCopyAcceleratorTable( accel, ptr, count ); + for (i = 0; i < count; i++) + { + if (translate_accelerator( hwnd, msg->message, msg->wParam, msg->lParam, + ptr[i].fVirt, ptr[i].key, ptr[i].cmd)) + break; + } + if (ptr != data) free( ptr ); + return (i < count); +} diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 07da23f633a..483b3d52289 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1281,7 +1281,7 @@ @ stub NtUserTrackPopupMenuEx @ stub NtUserTransformPoint @ stub NtUserTransformRect -@ stub NtUserTranslateAccelerator +@ stdcall NtUserTranslateAccelerator(long long ptr) @ stdcall NtUserTranslateMessage(ptr long) @ stub NtUserUndelegateInput @ stdcall -syscall NtUserUnhookWinEvent(long) diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 537eec38a34..5a0787afca7 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -296,6 +296,7 @@ struct unix_funcs INT (WINAPI *pNtUserToUnicodeEx)( UINT virt, UINT scan, const BYTE *state, WCHAR *str, int size, UINT flags, HKL layout ); BOOL (WINAPI *pNtUserTrackMouseEvent)( TRACKMOUSEEVENT *info ); + INT (WINAPI *pNtUserTranslateAccelerator)( HWND hwnd, HACCEL accel, MSG *msg ); BOOL (WINAPI *pNtUserTranslateMessage)( const MSG *msg, UINT flags ); BOOL (WINAPI *pNtUserUnregisterClass)( UNICODE_STRING *name, HINSTANCE instance, struct client_menu_name *client_menu_name ); diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c index 05107352dfa..9a87bccbb7a 100644 --- a/dlls/win32u/wrappers.c +++ b/dlls/win32u/wrappers.c @@ -1258,6 +1258,12 @@ BOOL WINAPI NtUserTrackMouseEvent( TRACKMOUSEEVENT *info ) return unix_funcs->pNtUserTrackMouseEvent( info ); }
+INT WINAPI NtUserTranslateAccelerator( HWND hwnd, HACCEL accel, MSG *msg ) +{ + if (!unix_funcs) return 0; + return unix_funcs->pNtUserTranslateAccelerator( hwnd, accel, msg ); +} + BOOL WINAPI NtUserTranslateMessage( const MSG *msg, UINT flags ) { if (!unix_funcs) return 0;