diff --git a/reactos/ChangeLog b/reactos/ChangeLog index d6c9f85f7bb..d8ea03350b1 100644 --- a/reactos/ChangeLog +++ b/reactos/ChangeLog @@ -1,3 +1,14 @@ +2003-12-07 Casper S. Hornstrup + + * lib/user32/windows/accel.c (U32IsValidAccelMessage): Translate WM_KEYUP + and WM_SYSKEYUP messages. + (TranslateAcceleratorA): Returntype of RtlMultiByteToUnicodeN is NTSTATUS, + so interpret it as such. + * subsys/win32k/ntuser/accelerator.c (NtUserDestroyAcceleratorTable): + Call ObmCloseHandle() before destroying the object. + (IntTranslateAccelerator): New function. + (NtUserTranslateAccelerator): Partial implementation. + 2003-12-07 Casper S. Hornstrup * subsys/win32k/include/accelerator.h: New file. diff --git a/reactos/lib/user32/windows/accel.c b/reactos/lib/user32/windows/accel.c index 1b03f7af5b0..37771091cc3 100644 --- a/reactos/lib/user32/windows/accel.c +++ b/reactos/lib/user32/windows/accel.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: accel.c,v 1.11 2003/07/23 20:39:45 gvg Exp $ +/* $Id: accel.c,v 1.12 2003/12/07 16:54:44 chorns Exp $ * * PROJECT: ReactOS user32.dll * FILE: lib/user32/windows/input.c @@ -162,9 +162,10 @@ BOOL WINAPI U32IsValidAccelMessage(UINT uMsg) switch(uMsg) { case WM_KEYDOWN: + case WM_KEYUP: case WM_CHAR: case WM_SYSKEYDOWN: - case WM_SYSCHAR: + case WM_SYSKEYUP: return TRUE; default: @@ -352,16 +353,14 @@ int WINAPI TranslateAcceleratorA(HWND hWnd, HACCEL hAccTable, LPMSG lpMsg) MSG mCopy = *lpMsg; CHAR cChar; WCHAR wChar; - NTSTATUS nErrCode; + NTSTATUS Status; if(!U32IsValidAccelMessage(lpMsg->message)) return 0; - nErrCode = - RtlMultiByteToUnicodeN(&wChar, sizeof(wChar), NULL, &cChar, sizeof(cChar)); - - if(!nErrCode) + Status = RtlMultiByteToUnicodeN(&wChar, sizeof(wChar), NULL, &cChar, sizeof(cChar)); + if(!NT_SUCCESS(Status)) { - SetLastError(RtlNtStatusToDosError(nErrCode)); + SetLastError(RtlNtStatusToDosError(Status)); return 0; } diff --git a/reactos/subsys/win32k/ntuser/accelerator.c b/reactos/subsys/win32k/ntuser/accelerator.c index 1194ea8b385..6d2c96629fc 100644 --- a/reactos/subsys/win32k/ntuser/accelerator.c +++ b/reactos/subsys/win32k/ntuser/accelerator.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: accelerator.c,v 1.2 2003/12/07 14:21:00 weiden Exp $ +/* $Id: accelerator.c,v 1.3 2003/12/07 16:54:44 chorns Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -26,6 +26,27 @@ * REVISION HISTORY: * 06-06-2001 CSH Created */ + +/* + * Copyright 1993 Martin Ayotte + * Copyright 1994 Alexandre Julliard + * Copyright 1997 Morten Welinder + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + /* INCLUDES ******************************************************************/ #include @@ -37,6 +58,7 @@ #include #include #include +#include #include #define NDEBUG @@ -193,7 +215,6 @@ NtUserDestroyAcceleratorTable( PWINSTATION_OBJECT WindowStation; PACCELERATOR_TABLE AcceleratorTable; NTSTATUS Status; - HACCEL Handle; /* FIXME: If the handle table is from a call to LoadAcceleratorTable, decrement it's usage count (and return TRUE). @@ -220,19 +241,19 @@ NtUserDestroyAcceleratorTable( (PVOID*)&AcceleratorTable); if (!NT_SUCCESS(Status)) { - SetLastNtError(STATUS_INVALID_HANDLE); + SetLastWin32Error(ERROR_INVALID_ACCEL_HANDLE); ObDereferenceObject(WindowStation); DbgPrint("E2\n"); return FALSE; } + ObmCloseHandle(WindowStation->HandleTable, Table); + if (AcceleratorTable->Table != NULL) { ExFreePool(AcceleratorTable->Table); } - ObmCloseHandle(WindowStation->HandleTable, Handle); - ObDereferenceObject(WindowStation); DbgPrint("NtUserDestroyAcceleratorTable(Table %x)\n", @@ -241,6 +262,187 @@ NtUserDestroyAcceleratorTable( return TRUE; } +static BOOLEAN +IntTranslateAccelerator(HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam, + BYTE fVirt, + WORD key, + WORD cmd) +{ + UINT mesg = 0; + + DbgPrint("IntTranslateAccelerator(hWnd %x, message %x, wParam %x, lParam %x, fVirt %d, key %x, cmd %x)\n", + hWnd, message, wParam, lParam, fVirt, key, cmd); + + if (wParam != key) + { + DbgPrint("T0\n"); + return FALSE; + } + + if (message == WM_CHAR) + { + if (!(fVirt & FALT) && !(fVirt & FVIRTKEY)) + { + DbgPrint("found accel for WM_CHAR: ('%c')\n", wParam & 0xff); + goto found; + } + } + else + { + if ((fVirt & FVIRTKEY) > 0) + { + INT mask = 0; + DbgPrint("found accel for virt_key %04x (scan %04x)\n", + wParam, 0xff & HIWORD(lParam)); + + DbgPrint("NtUserGetKeyState(VK_SHIFT) = 0x%x\n", + NtUserGetKeyState(VK_SHIFT)); + DbgPrint("NtUserGetKeyState(VK_CONTROL) = 0x%x\n", + NtUserGetKeyState(VK_CONTROL)); + DbgPrint("NtUserGetKeyState(VK_MENU) = 0x%x\n", + NtUserGetKeyState(VK_MENU)); + + if (NtUserGetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT; + if (NtUserGetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL; + if (NtUserGetKeyState(VK_MENU) & 0x8000) mask |= FALT; + if (mask == (fVirt & (FSHIFT | FCONTROL | FALT))) goto found; + DbgPrint(", but incorrect SHIFT/CTRL/ALT-state\n"); + } + else + { + if (!(lParam & 0x01000000)) /* no special_key */ + { + if ((fVirt & FALT) && (lParam & 0x20000000)) + { /* ^^ ALT pressed */ + DbgPrint("found accel for Alt-%c\n", wParam & 0xff); + goto found; + } + } + } + } + + DbgPrint("IntTranslateAccelerator(hWnd %x, message %x, wParam %x, lParam %x, fVirt %d, key %x, cmd %x) = FALSE\n", + hWnd, message, wParam, lParam, fVirt, key, cmd); + + return FALSE; + + found: + if (message == WM_KEYUP || message == WM_SYSKEYUP) + mesg = 1; + else if (IntGetCaptureWindow()) + mesg = 2; + else if (!IntIsWindowVisible(hWnd)) /* FIXME: WINE IsWindowEnabled == IntIsWindowVisible? */ + mesg = 3; + else + { +#if 0 + HMENU hMenu, hSubMenu, hSysMenu; + UINT uSysStat = (UINT)-1, uStat = (UINT)-1, nPos; + + hMenu = (NtUserGetWindowLongW(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 */ + hSubMenu = hSysMenu; + nPos = cmd; + if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND)) + { + NtUserSendMessage(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); + NtUserSendMessage(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, TRUE)); + } + uSysStat = GetMenuState(GetSubMenu(hSysMenu, 0), cmd, MF_BYCOMMAND); + } + else /* 2. in the window's menu */ + { + hSubMenu = hMenu; + nPos = cmd; + if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND)) + { + NtUserSendMessage(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); + NtUserSendMessage(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, FALSE)); + } + uStat = GetMenuState(hMenu, cmd, MF_BYCOMMAND); + } + } + + 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; + } + } +#else + DPRINT1("menu search not implemented"); + mesg = WM_COMMAND; +#endif + } + + if (mesg == WM_COMMAND) + { + DbgPrint(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd); + NtUserSendMessage(hWnd, mesg, 0x10000 | cmd, 0L); + } + else if (mesg == WM_SYSCOMMAND) + { + DbgPrint(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd); + NtUserSendMessage(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 + */ + DbgPrint(", but won't send WM_{SYS}COMMAND, reason is #%d\n", mesg); + if (mesg == 0) + { + DbgPrint(" unknown reason - please report!"); + } + } + + DbgPrint("IntTranslateAccelerator(hWnd %x, message %x, wParam %x, lParam %x, fVirt %d, key %x, cmd %x) = TRUE\n", + hWnd, message, wParam, lParam, fVirt, key, cmd); + + return TRUE; +} + int STDCALL NtUserTranslateAccelerator( @@ -248,7 +450,87 @@ NtUserTranslateAccelerator( HACCEL Table, LPMSG Message) { - UNIMPLEMENTED + PWINSTATION_OBJECT WindowStation; + PACCELERATOR_TABLE AcceleratorTable; + NTSTATUS Status; + ULONG i; + + DbgPrint("NtUserTranslateAccelerator(Window %x, Table %x, Message %p)\n", + Window, Table, Message); + + if (Message == NULL) + { + SetLastNtError(STATUS_INVALID_PARAMETER); + DbgPrint("E0a\n"); + return 0; + } + + if (Table == NULL) + { + SetLastWin32Error(ERROR_INVALID_ACCEL_HANDLE); + DbgPrint("E0b\n"); + return 0; + } + + if ((Message->message != WM_KEYDOWN) && + (Message->message != WM_KEYUP) && + (Message->message != WM_SYSKEYDOWN) && + (Message->message != WM_SYSKEYUP) && + (Message->message != WM_CHAR)) + { + DbgPrint("E0c\n"); + return 0; + } + + Status = IntValidateWindowStationHandle(NtUserGetProcessWindowStation(), + UserMode, + 0, + &WindowStation); + if (!NT_SUCCESS(Status)) + { + SetLastNtError(STATUS_ACCESS_DENIED); + DbgPrint("E1\n"); + return 0; + } + + Status = ObmReferenceObjectByHandle(WindowStation->HandleTable, + Table, + otAcceleratorTable, + (PVOID*)&AcceleratorTable); + if (!NT_SUCCESS(Status)) + { + SetLastWin32Error(ERROR_INVALID_ACCEL_HANDLE); + ObDereferenceObject(WindowStation); + DbgPrint("E2\n"); + return 0; + } + + /* FIXME: Associate AcceleratorTable with the current thread */ + + /* FIXME: If Window is active and no window has focus, translate WM_SYSKEYUP and WM_SYSKEY_DOWN instead */ + + for (i = 0; i < AcceleratorTable->Count; i++) + { + if (IntTranslateAccelerator(Window, Message->message, Message->wParam, Message->lParam, + AcceleratorTable->Table[i].fVirt, AcceleratorTable->Table[i].key, + AcceleratorTable->Table[i].cmd)) + { + ObDereferenceObject(WindowStation); + DbgPrint("NtUserTranslateAccelerator(Window %x, Table %x, Message %p) = %i end\n", + Window, Table, Message, 1); + return 1; + } + if (((AcceleratorTable->Table[i].fVirt & 0x80) > 0)) + { + break; + } + i++; + } + + ObDereferenceObject(WindowStation); + + DbgPrint("NtUserTranslateAccelerator(Window %x, Table %x, Message %p) = %i end\n", + Window, Table, Message, 0); return 0; }