diff --git a/reactos/include/funcs.h b/reactos/include/funcs.h index efd46f3488f..7003a8810bd 100644 --- a/reactos/include/funcs.h +++ b/reactos/include/funcs.h @@ -8360,8 +8360,7 @@ ToAsciiEx( int STDCALL -ToUnicode( - UINT wVirtKey, +ToUnicode(UINT wVirtKey, UINT wScanCode, PBYTE lpKeyState, LPWSTR pwszBuff, diff --git a/reactos/include/napi/win32.h b/reactos/include/napi/win32.h index 5e7e79e5c3c..e1c564acee5 100644 --- a/reactos/include/napi/win32.h +++ b/reactos/include/napi/win32.h @@ -6,6 +6,7 @@ typedef struct _W32THREAD PVOID MessageQueue; FAST_MUTEX WindowListLock; LIST_ENTRY WindowListHead; + struct _KBDTABLES* KeyboardLayout; struct _DESKTOP_OBJECT* Desktop; } __attribute__((packed)) W32THREAD, *PW32THREAD; @@ -15,6 +16,7 @@ typedef struct _W32PROCESS LIST_ENTRY ClassListHead; FAST_MUTEX MenuListLock; LIST_ENTRY MenuListHead; + struct _KBDTABLES* KeyboardLayout; struct _WINSTATION_OBJECT* WindowStation; } W32PROCESS, *PW32PROCESS; diff --git a/reactos/include/win32k/ntuser.h b/reactos/include/win32k/ntuser.h index f1ffbadf7cd..46a97ce6451 100644 --- a/reactos/include/win32k/ntuser.h +++ b/reactos/include/win32k/ntuser.h @@ -156,6 +156,7 @@ NtUserCallNextHookEx( DWORD Unknown2, DWORD Unknown3); +#define NOPARAM_ROUTINE_REGISTER_PRIMITIVE 0xffff0001 /* Private ROS */ DWORD STDCALL NtUserCallNoParam( @@ -745,10 +746,7 @@ NtUserGetKeyboardState( DWORD STDCALL -NtUserGetKeyNameText( - DWORD Unknown0, - DWORD Unknown1, - DWORD Unknown2); +NtUserGetKeyNameText( LONG lParam, LPWSTR lpString, int nSize ); DWORD STDCALL @@ -999,13 +997,12 @@ DWORD STDCALL NtUserLockWorkStation(VOID); -DWORD +UINT STDCALL -NtUserMapVirtualKeyEx( - DWORD Unknown0, - DWORD Unknown1, - DWORD Unknown2, - DWORD Unknown3); +NtUserMapVirtualKeyEx( UINT keyCode, + UINT transType, + DWORD keyboardId, + HKL dwhkl ); BOOL STDCALL @@ -1652,16 +1649,16 @@ NtUserThunkedMenuItemInfo( LPMENUITEMINFOW lpmii, PUNICODE_STRING lpszCaption); -DWORD +int STDCALL NtUserToUnicodeEx( - DWORD Unknown0, - DWORD Unknown1, - DWORD Unknown2, - DWORD Unknown3, - DWORD Unknown4, - DWORD Unknown5, - DWORD Unknown6); + UINT wVirtKey, + UINT wScanCode, + PBYTE lpKeyState, + LPWSTR pwszBuff, + int cchBuff, + UINT wFlags, + HKL dwhkl ); DWORD STDCALL @@ -1689,7 +1686,7 @@ BOOL STDCALL NtUserTranslateMessage( LPMSG lpMsg, - DWORD Unknown1); + HKL dwhkl ); DWORD STDCALL diff --git a/reactos/lib/kbdus/kbdus.c b/reactos/lib/kbdus/kbdus.c index fe4697939e1..cb8b9acca69 100644 --- a/reactos/lib/kbdus/kbdus.c +++ b/reactos/lib/kbdus/kbdus.c @@ -80,10 +80,10 @@ ROSDATA USHORT scancode_to_vk[] = { /* - 0f - */ /* First Letters Row */ VK_TAB, 'Q', 'W', 'E', - 'R', 'T', 'U', 'I', - 'O', 'P', + 'R', 'T', 'Y', 'U', + 'I', 'O', 'P', VK_OEM_4, VK_OEM_6, VK_RETURN, - /* - 1c - */ + /* - 1d - */ /* Second Letters Row */ VK_LCONTROL, 'A', 'S', 'D', 'F', @@ -95,11 +95,9 @@ ROSDATA USHORT scancode_to_vk[] = { 'Z', 'X', 'C', 'V', 'B', 'N', 'M', VK_OEM_COMMA, VK_OEM_PERIOD,VK_OEM_2, VK_RSHIFT, - /* - 35 - */ + /* - 37 - */ /* Bottom Row */ - VK_EMPTY, VK_RSHIFT | KEXT, - VK_MULTIPLY, VK_LMENU, - ' ', VK_CAPITAL, + VK_MULTIPLY, VK_LMENU, VK_SPACE, VK_CAPITAL, /* - 3b - */ /* F-Keys */ @@ -153,8 +151,6 @@ ROSDATA VSC_VK extcode1_to_vk[] = { { 0, 0 }, }; -#define VK_ALT - ROSDATA VK_TO_BIT modifier_keys[] = { { VK_SHIFT, KSHIFT }, { VK_CONTROL, KCTRL }, @@ -164,8 +160,8 @@ ROSDATA VK_TO_BIT modifier_keys[] = { typedef struct _mymod { PVOID mod_keys; - int maxmod; - int mod_max[4]; + WORD maxmod; + BYTE mod_max[4]; } INTERNAL_KBD_MODIFIERS; ROSDATA INTERNAL_KBD_MODIFIERS modifier_bits[] = { @@ -285,7 +281,7 @@ ROSDATA VK_TO_WCHAR_TABLE vk_to_wchar_master_table[] = { }; ROSDATA VSC_LPWSTR key_names[] = { - { 0x00, L"Error" }, + { 0x00, L"" }, { 0x01, L"Esc" }, { 0x0e, L"Backspace" }, { 0x0f, L"Tab" }, @@ -369,7 +365,7 @@ ROSDATA VSC_LPWSTR extended_key_names[] = { /* Finally, the master table */ ROSDATA KBDTABLES keyboard_layout_table = { /* modifier assignments */ - (PMODIFIERS)modifier_bits, + (PMODIFIERS)&modifier_bits, /* character from vk tables */ vk_to_wchar_master_table, diff --git a/reactos/lib/kernel32/mem/isbad.c b/reactos/lib/kernel32/mem/isbad.c index 2ac0e941cdc..5e9c9062df5 100644 --- a/reactos/lib/kernel32/mem/isbad.c +++ b/reactos/lib/kernel32/mem/isbad.c @@ -1,4 +1,4 @@ -/* $Id: isbad.c,v 1.7 2003/07/10 18:50:51 chorns Exp $ +/* $Id: isbad.c,v 1.8 2003/10/09 06:13:04 gvg Exp $ * * lib/kernel32/mem/isbad.c * @@ -28,7 +28,7 @@ wcsnlen ( /* FIXME: Stubs. What is it for? */ /* - * @unimplemented + * @implemented */ UINT strnlen ( @@ -36,9 +36,9 @@ strnlen ( UINT uiMax ) { - DPRINT1("strnlen stub called\n"); - - return 0; + UINT i = 0; + while( lpsz[i] && i < uiMax ) i++; + return i; } /* --- --- --- */ diff --git a/reactos/lib/user32/include/user32.h b/reactos/lib/user32/include/user32.h index 1aceca3c6dc..409f109d83b 100644 --- a/reactos/lib/user32/include/user32.h +++ b/reactos/lib/user32/include/user32.h @@ -10,6 +10,7 @@ typedef struct _USER32_THREAD_DATA { MSG LastMessage; + HKL KeyboardLayoutHandle; } USER32_THREAD_DATA, *PUSER32_THREAD_DATA; PUSER32_THREAD_DATA User32GetThreadData(); diff --git a/reactos/lib/user32/windows/input.c b/reactos/lib/user32/windows/input.c index 8542dcc8c74..58459dcf1fa 100644 --- a/reactos/lib/user32/windows/input.c +++ b/reactos/lib/user32/windows/input.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: input.c,v 1.18 2003/09/12 12:54:26 weiden Exp $ +/* $Id: input.c,v 1.19 2003/10/09 06:13:04 gvg Exp $ * * PROJECT: ReactOS user32.dll * FILE: lib/user32/windows/input.c @@ -31,6 +31,7 @@ #include #include #include +#include /* FUNCTIONS *****************************************************************/ @@ -134,33 +135,47 @@ GetKBCodePage(VOID) /* - * @unimplemented + * @implemented */ int STDCALL GetKeyNameTextA(LONG lParam, LPSTR lpString, int nSize) { - UNIMPLEMENTED; - return 0; + LPWSTR intermediateString = + HeapAlloc(GetProcessHeap(),0,nSize * sizeof(WCHAR)); + int ret = 0; + UINT wstrLen = 0; + BOOL defChar = FALSE; + + if( !intermediateString ) return 0; + ret = GetKeyNameTextW(lParam,intermediateString,nSize); + if( ret == 0 ) { lpString[0] = 0; return 0; } + + wstrLen = wcslen( intermediateString ); + ret = WideCharToMultiByte(CP_ACP, 0, + intermediateString, wstrLen, + lpString, nSize, ".", &defChar ); + lpString[ret] = 0; + HeapFree(GetProcessHeap(),0,intermediateString); + + return ret; } - /* - * @unimplemented + * @implemented */ int STDCALL GetKeyNameTextW(LONG lParam, LPWSTR lpString, int nSize) { - UNIMPLEMENTED; - return 0; + return NtUserGetKeyNameText( lParam, lpString, nSize ); } /* - * @unimplemented + * @implemented */ SHORT STDCALL GetKeyState(int nVirtKey) @@ -261,52 +276,48 @@ LoadKeyboardLayoutW(LPCWSTR pwszKLID, /* - * @unimplemented + * @implemented */ UINT STDCALL MapVirtualKeyA(UINT uCode, UINT uMapType) { - UNIMPLEMENTED; - return 0; + return MapVirtualKeyExA( uCode, uMapType, GetKeyboardLayout( 0 ) ); } /* - * @unimplemented + * @implemented */ UINT STDCALL MapVirtualKeyExA(UINT uCode, UINT uMapType, HKL dwhkl) { - UNIMPLEMENTED; - return 0; + return MapVirtualKeyExW( uCode, uMapType, dwhkl ); } /* - * @unimplemented + * @implemented */ UINT STDCALL MapVirtualKeyExW(UINT uCode, UINT uMapType, HKL dwhkl) { - UNIMPLEMENTED; - return 0; + return NtUserMapVirtualKeyEx( uCode, uMapType, 0, dwhkl ); } /* - * @unimplemented + * @implemented */ UINT STDCALL MapVirtualKeyW(UINT uCode, UINT uMapType) { - UNIMPLEMENTED; - return 0; + return MapVirtualKeyExW( uCode, uMapType, GetKeyboardLayout( 0 ) ); } @@ -401,7 +412,7 @@ ToAsciiEx(UINT uVirtKey, /* - * @unimplemented + * @implemented */ int STDCALL ToUnicode(UINT wVirtKey, @@ -411,8 +422,8 @@ ToUnicode(UINT wVirtKey, int cchBuff, UINT wFlags) { - UNIMPLEMENTED; - return 0; + return ToUnicodeEx( wVirtKey, wScanCode, lpKeyState, pwszBuff, cchBuff, + wFlags, 0 ); } @@ -428,8 +439,8 @@ ToUnicodeEx(UINT wVirtKey, UINT wFlags, HKL dwhkl) { - UNIMPLEMENTED; - return 0; + return NtUserToUnicodeEx( wVirtKey, wScanCode, lpKeyState, pwszBuff, cchBuff, + wFlags, dwhkl ); } diff --git a/reactos/lib/user32/windows/message.c b/reactos/lib/user32/windows/message.c index 1efff5075a9..931dc72f49e 100644 --- a/reactos/lib/user32/windows/message.c +++ b/reactos/lib/user32/windows/message.c @@ -1,4 +1,4 @@ -/* $Id: message.c,v 1.24 2003/08/14 20:25:52 royce Exp $ +/* $Id: message.c,v 1.25 2003/10/09 06:13:04 gvg Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS user32.dll @@ -698,7 +698,7 @@ TranslateMessage(CONST MSG *lpMsg) WINBOOL STDCALL TranslateMessageEx(CONST MSG *lpMsg, DWORD unk) { - return(NtUserTranslateMessage((LPMSG)lpMsg, unk)); + return(NtUserTranslateMessage((LPMSG)lpMsg, (HKL)unk)); } diff --git a/reactos/subsys/csrss/api.h b/reactos/subsys/csrss/api.h index 85d2066f152..df2d00ace96 100644 --- a/reactos/subsys/csrss/api.h +++ b/reactos/subsys/csrss/api.h @@ -21,6 +21,7 @@ typedef struct ConsoleInput_t LIST_ENTRY ListEntry; INPUT_RECORD InputEvent; BOOLEAN Echoed; // already been echoed or not + BOOLEAN Fake; // synthesized, not a real event } ConsoleInput; diff --git a/reactos/subsys/csrss/api/conio.c b/reactos/subsys/csrss/api/conio.c index 44e8fc8e809..79dee00e413 100644 --- a/reactos/subsys/csrss/api/conio.c +++ b/reactos/subsys/csrss/api/conio.c @@ -1,4 +1,4 @@ -/* $Id: conio.c,v 1.52 2003/08/28 13:38:23 gvg Exp $ +/* $Id: conio.c,v 1.53 2003/10/09 06:13:04 gvg Exp $ * * reactos/subsys/csrss/api/conio.c * @@ -15,6 +15,7 @@ #include "api.h" #include #include +#include #define NDEBUG #include @@ -29,11 +30,9 @@ extern VOID CsrConsoleCtrlEvent(DWORD Event, PCSRSS_PROCESS_DATA ProcessData); /* GLOBALS *******************************************************************/ static HANDLE ConsoleDeviceHandle; -static HANDLE KeyboardDeviceHandle; static PCSRSS_CONSOLE ActiveConsole; CRITICAL_SECTION ActiveConsoleLock; static COORD PhysicalConsoleSize; -static BOOL KeyReadInhibit = FALSE; /* FUNCTIONS *****************************************************************/ @@ -164,18 +163,30 @@ CSR_API(CsrAllocConsole) CSR_API(CsrFreeConsole) { + PCSRSS_CONSOLE Console; + Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY); Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - sizeof(LPC_MESSAGE); - if (ProcessData == NULL) + LOCK; + if (ProcessData == NULL || ProcessData->Console == NULL) { + UNLOCK; return(Reply->Status = STATUS_INVALID_PARAMETER); } - Reply->Status = STATUS_NOT_IMPLEMENTED; + Console = ProcessData->Console; + Console->Header.ReferenceCount--; + ProcessData->Console = 0; + if( Console->Header.ReferenceCount == 0 ) { + if( Console != ActiveConsole ) + CsrDeleteConsole( Console ); + } + + UNLOCK; - return(STATUS_NOT_IMPLEMENTED); + return(STATUS_SUCCESS); } CSR_API(CsrReadConsole) @@ -242,7 +253,9 @@ CSR_API(CsrReadConsole) Input->Echoed = TRUE; // mark as echoed so we don't echo it below } // do not copy backspace to buffer - else Buffer[i] = Input->InputEvent.Event.KeyEvent.uChar.AsciiChar; + else { + Buffer[i] = Input->InputEvent.Event.KeyEvent.uChar.AsciiChar; + } // echo to screen if enabled and we did not already echo the char if( Console->Mode & ENABLE_ECHO_INPUT && !Input->Echoed && @@ -895,6 +908,8 @@ VOID STDCALL CsrInitConsoleSupport(VOID) CONSOLE_SCREEN_BUFFER_INFO ScrInfo; DPRINT("CSR: CsrInitConsoleSupport()\n"); + + /* Should call LoadKeyboardLayout */ RtlInitUnicodeStringFromLiteral(&DeviceName, L"\\??\\BlueScreen"); InitializeObjectAttributes(&ObjectAttributes, @@ -913,23 +928,6 @@ VOID STDCALL CsrInitConsoleSupport(VOID) DbgPrint("CSR: Failed to open console. Expect problems.\n"); } - RtlInitUnicodeStringFromLiteral(&DeviceName, L"\\??\\Keyboard"); - InitializeObjectAttributes(&ObjectAttributes, - &DeviceName, - 0, - NULL, - NULL); - Status = NtOpenFile(&KeyboardDeviceHandle, - FILE_ALL_ACCESS, - &ObjectAttributes, - &Iosb, - 0, - 0); - if (!NT_SUCCESS(Status)) - { - DbgPrint("CSR: Failed to open keyboard. Expect problems.\n"); - } - ActiveConsole = 0; RtlInitializeCriticalSection( &ActiveConsoleLock ); Status = NtDeviceIoControlFile( ConsoleDeviceHandle, NULL, NULL, NULL, &Iosb, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO, 0, 0, &ScrInfo, sizeof( ScrInfo ) ); @@ -941,302 +939,406 @@ VOID STDCALL CsrInitConsoleSupport(VOID) PhysicalConsoleSize = ScrInfo.dwSize; } +static void CsrpProcessChar( PCSRSS_CONSOLE Console, + ConsoleInput *KeyEventRecord ) { + BOOL updown; + BOOL bClientWake = FALSE; + ConsoleInput *TempInput; + + /* process Ctrl-C and Ctrl-Break */ + if (Console->Mode & ENABLE_PROCESSED_INPUT && + KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown && + ((KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_PAUSE) || + (KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == 'C')) && + (KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))) + { + PCSRSS_PROCESS_DATA current; + PLIST_ENTRY current_entry; + DPRINT1("Console_Api Ctrl-C\n"); + LOCK; + current_entry = Console->ProcessList.Flink; + while (current_entry != &Console->ProcessList) + { + current = CONTAINING_RECORD(current_entry, CSRSS_PROCESS_DATA, ProcessEntry); + current_entry = current_entry->Flink; + CsrConsoleCtrlEvent((DWORD)CTRL_C_EVENT, current); + } + UNLOCK; + RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord ); + return; + } + if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState & + ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED ) && + ( KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP || + KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_DOWN) ) + { + if( KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE ) + { + /* scroll up or down */ + LOCK; + if( Console == 0 ) + { + DbgPrint( "CSR: No Active Console!\n" ); + UNLOCK; + RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord ); + return; + } + if( KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP ) + { + /* only scroll up if there is room to scroll up into */ + if( Console->ActiveBuffer->ShowY != ((Console->ActiveBuffer->CurrentY + 1) % + Console->ActiveBuffer->MaxY) ) + Console->ActiveBuffer->ShowY = (Console->ActiveBuffer->ShowY + + Console->ActiveBuffer->MaxY - 1) % Console->ActiveBuffer->MaxY; + } + else if( Console->ActiveBuffer->ShowY != Console->ActiveBuffer->CurrentY ) + /* only scroll down if there is room to scroll down into */ + if( Console->ActiveBuffer->ShowY % Console->ActiveBuffer->MaxY != + Console->ActiveBuffer->CurrentY ) + + if( ((Console->ActiveBuffer->CurrentY + 1) % Console->ActiveBuffer->MaxY) != + (Console->ActiveBuffer->ShowY + PhysicalConsoleSize.Y) % Console->ActiveBuffer->MaxY ) + Console->ActiveBuffer->ShowY = (Console->ActiveBuffer->ShowY + 1) % + Console->ActiveBuffer->MaxY; + CsrDrawConsole( Console->ActiveBuffer ); + UNLOCK; + } + RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord ); + return; + } + if( Console == 0 ) + { + DbgPrint( "CSR: No Active Console!\n" ); + UNLOCK; + RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord ); + return; + } + + if( Console->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT) ) + switch( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar ) + { + case '\r': + // first add the \r + KeyEventRecord->InputEvent.EventType = KEY_EVENT; + updown = KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown; + KeyEventRecord->Echoed = FALSE; + KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode = VK_RETURN; + KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\r'; + InsertTailList(&Console->InputEvents, &KeyEventRecord->ListEntry); + Console->WaitingChars++; + KeyEventRecord = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( ConsoleInput ) ); + if( !KeyEventRecord ) + { + DbgPrint( "CSR: Failed to allocate KeyEventRecord\n" ); + return; + } + KeyEventRecord->InputEvent.EventType = KEY_EVENT; + KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown = updown; + KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode = 0; + KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualScanCode = 0; + KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\n'; + KeyEventRecord->Fake = TRUE; + } + // add event to the queue + InsertTailList(&Console->InputEvents, &KeyEventRecord->ListEntry); + Console->WaitingChars++; + // if line input mode is enabled, only wake the client on enter key down + if( !(Console->Mode & ENABLE_LINE_INPUT ) || + Console->EarlyReturn || + ( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' && + KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == FALSE) ) + { + if( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' ) + Console->WaitingLines++; + bClientWake = TRUE; + NtSetEvent( Console->ActiveEvent, 0 ); + } + KeyEventRecord->Echoed = FALSE; + if( Console->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT) && + KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' && + KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown ) + { + // walk the input queue looking for a char to backspace + for( TempInput = (ConsoleInput *)Console->InputEvents.Blink; + TempInput != (ConsoleInput *)&Console->InputEvents && + (TempInput->InputEvent.EventType != KEY_EVENT || + TempInput->InputEvent.Event.KeyEvent.bKeyDown == FALSE || + TempInput->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' ); + TempInput = (ConsoleInput *)TempInput->ListEntry.Blink ); + // if we found one, delete it, otherwise, wake the client + if( TempInput != (ConsoleInput *)&Console->InputEvents ) + { + // delete previous key in queue, maybe echo backspace to screen, and do not place backspace on queue + RemoveEntryList(&TempInput->ListEntry); + if( TempInput->Echoed ) + CsrpWriteConsole( Console->ActiveBuffer, &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE ); + RtlFreeHeap( CsrssApiHeap, 0, TempInput ); + RemoveEntryList(&KeyEventRecord->ListEntry); + RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord ); + Console->WaitingChars -= 2; + } + else { + NtSetEvent( Console->ActiveEvent, 0 ); + } + } + else { + // echo chars if we are supposed to and client is waiting for some + if( ( Console->Mode & ENABLE_ECHO_INPUT ) && Console->EchoCount && + KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar && + KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE && + KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar != '\r' ) + { + // mark the char as already echoed + CsrpWriteConsole( Console->ActiveBuffer, &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE ); + Console->EchoCount--; + KeyEventRecord->Echoed = TRUE; + } + } + /* Console->WaitingChars++; */ + if( bClientWake || !(Console->Mode & ENABLE_LINE_INPUT) ) { + NtSetEvent( Console->ActiveEvent, 0 ); + } +} + +static DWORD CsrpGetShiftState( PBYTE KeyState ) { + int i; + DWORD ssOut = 0; + + for( i = 0; i < 0x100; i++ ) { + if( KeyState[i] & 0x80 ) { + UINT vk = NtUserMapVirtualKeyEx( i, 3, 0, 0 ) & 0xff; + switch( vk ) { + case VK_LSHIFT: + case VK_RSHIFT: + case VK_SHIFT: + ssOut |= SHIFT_PRESSED; + break; + + case VK_LCONTROL: + case VK_CONTROL: + ssOut |= LEFT_CTRL_PRESSED; + break; + + case VK_RCONTROL: + ssOut |= RIGHT_CTRL_PRESSED | ENHANCED_KEY; + break; + + case VK_LMENU: + case VK_MENU: + ssOut |= LEFT_ALT_PRESSED; + break; + + case VK_RMENU: + ssOut |= RIGHT_ALT_PRESSED | ENHANCED_KEY; + break; + } + } + } + + return ssOut; +} + VOID Console_Api( DWORD RefreshEvent ) { /* keep reading events from the keyboard and stuffing them into the current console's input queue */ - ConsoleInput *KeyEventRecord; - ConsoleInput *TempInput; - IO_STATUS_BLOCK Iosb; - NTSTATUS Status; - HANDLE Events[2]; // 0 = keyboard, 1 = refresh - int c; - int updown; PCSRSS_CONSOLE SwapConsole = 0; // console we are thinking about swapping with + MSG msg; + ConsoleInput *ConInRec; + UINT RepeatCount; + WCHAR UnicodeChar; + UINT VirtualKeyCode; + UINT VirtualScanCode; + UINT AsciiChar; + DWORD ShiftState; + BOOL SubmitKey; + BOOL Down = FALSE; + BOOL Ext = FALSE; + BYTE KeyState[256] = { 0 }; + int RetChars; + WCHAR Chars[2] = { 0 }; + INPUT_RECORD er; + NTSTATUS Status; + IO_STATUS_BLOCK Iosb; + BYTE Mask; - Events[0] = 0; - Status = NtCreateEvent( &Events[0], STANDARD_RIGHTS_ALL, NULL, FALSE, FALSE ); - if( !NT_SUCCESS( Status ) ) - { - DbgPrint( "CSR: NtCreateEvent failed: %x\n", Status ); - NtTerminateProcess( NtCurrentProcess(), Status ); + /* This call establishes our message queue */ + NtUserPeekMessage( &msg, 0,0,0, PM_NOREMOVE ); + /* This call registers our message queue */ + NtUserCallNoParam( NOPARAM_ROUTINE_REGISTER_PRIMITIVE ); + /* This call turns on the input system in win32k */ + NtUserAcquireOrReleaseInputOwnership( FALSE ); + + while( TRUE ) { + NtUserGetMessage( &msg, 0,0,0 ); + NtUserTranslateMessage( &msg, 0 ); + + SubmitKey = FALSE; + + if( msg.message == WM_KEYDOWN || msg.message == WM_KEYUP || + msg.message == WM_SYSKEYDOWN || msg.message == WM_SYSKEYUP ) { + RepeatCount = 1; + VirtualScanCode = (msg.lParam >> 16) & 0xff; + VirtualKeyCode = msg.wParam; + Down = msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN; + Ext = msg.lParam & 0x01000000 ? TRUE : FALSE; + + if (Ext) + Mask = 0x40; + else + Mask = 0x80; + + if( Down ) + KeyState[VirtualScanCode] |= Mask; + else + KeyState[VirtualScanCode] &= ~Mask; + + + ShiftState = CsrpGetShiftState( KeyState ); + + RetChars = NtUserToUnicodeEx( VirtualKeyCode, + VirtualScanCode, + KeyState, + Chars, + 2, + 0, + 0 ); + + if( RetChars == 1 ) + UnicodeChar = Chars[0]; + else + UnicodeChar = 0; + + ULONG ResultSize; + + RtlUnicodeToOemN (&AsciiChar, + 1, + &ResultSize, + &UnicodeChar, + 2); + if( ResultSize == 0 ) AsciiChar = 0; + + SubmitKey = TRUE; } - Events[1] = (HANDLE)RefreshEvent; - while( 1 ) - { - KeyEventRecord = RtlAllocateHeap(CsrssApiHeap, - 0, - sizeof(ConsoleInput)); - if ( KeyEventRecord == 0 ) - { - DbgPrint( "CSR: Memory allocation failure!" ); - continue; - } - KeyEventRecord->InputEvent.EventType = KEY_EVENT; - if( !KeyReadInhibit ) { - Status = NtReadFile( KeyboardDeviceHandle, Events[0], NULL, NULL, &Iosb, - &KeyEventRecord->InputEvent.Event.KeyEvent, sizeof( KEY_EVENT_RECORD ), NULL, 0 ); - } else { - Status = STATUS_PENDING; - } - if( !NT_SUCCESS( Status ) ) - { - DbgPrint( "CSR: ReadFile on keyboard device failed\n" ); - RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord ); - continue; - } - if( Status == STATUS_PENDING ) - { - while( 1 ) - { - Status = NtWaitForMultipleObjects( 2, Events, WaitAny, FALSE, NULL ); - if( Status == STATUS_WAIT_0 + 1 ) - { - LOCK; - CsrDrawConsole( ActiveConsole->ActiveBuffer ); - UNLOCK; - continue; - } - else if( Status != STATUS_WAIT_0 ) - { - DbgPrint( "CSR: NtWaitForMultipleObjects failed: %x, exiting\n", Status ); - NtTerminateProcess( NtCurrentProcess(), Status ); - } - else break; - } - } - if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState & - ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED )&& - KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_TAB ) - if( KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE ) - { - ANSI_STRING Title; - void * Buffer; - COORD *pos; - - /* alt-tab, swap consoles */ - // move SwapConsole to next console, and print its title - LOCK; - if( !SwapConsole ) - SwapConsole = ActiveConsole; - - if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED ) - SwapConsole = SwapConsole->Prev; - else SwapConsole = SwapConsole->Next; - Title.MaximumLength = RtlUnicodeStringToAnsiSize( &SwapConsole->Title ); - Title.Length = 0; - Buffer = RtlAllocateHeap( CsrssApiHeap, - 0, - sizeof( COORD ) + Title.MaximumLength); - pos = (COORD *)Buffer; - Title.Buffer = Buffer + sizeof( COORD ); - RtlUnicodeStringToAnsiString(&Title, &SwapConsole->Title, FALSE); - pos->Y = PhysicalConsoleSize.Y / 2; - pos->X = ( PhysicalConsoleSize.X - Title.Length ) / 2; - // redraw the console to clear off old title - CsrDrawConsole( ActiveConsole->ActiveBuffer ); - Status = NtDeviceIoControlFile( ConsoleDeviceHandle, - NULL, - NULL, - NULL, - &Iosb, - IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER, - Buffer, - sizeof (COORD) + Title.Length, - NULL, - 0); - if( !NT_SUCCESS( Status ) ) - { - DPRINT1( "Error writing to console\n" ); - } - RtlFreeHeap( CsrssApiHeap, 0, Buffer ); + if( !SubmitKey ) continue; + + er.EventType = KEY_EVENT; + er.Event.KeyEvent.bKeyDown = Down; + er.Event.KeyEvent.wRepeatCount = RepeatCount; +// er.Event.KeyEvent.uChar.AsciiChar = AsciiChar; +// er.Event.KeyEvent.uChar.UnicodeChar = UnicodeChar; + er.Event.KeyEvent.uChar.UnicodeChar = AsciiChar; + er.Event.KeyEvent.dwControlKeyState = ShiftState; + er.Event.KeyEvent.wVirtualKeyCode = VirtualKeyCode; + er.Event.KeyEvent.wVirtualScanCode = VirtualScanCode; + + if (ShiftState & ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED )&& + VirtualKeyCode == VK_TAB ) + { + if( Down == TRUE ) + { + ANSI_STRING Title; + void * Buffer; + COORD *pos; - UNLOCK; - RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord ); - continue; - } - else { - RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord ); - continue; - } - else if( SwapConsole && - KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_MENU && - KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == FALSE ) - { - // alt key released, swap consoles - PCSRSS_CONSOLE tmp; - - LOCK; - if( SwapConsole != ActiveConsole ) - { - // first remove swapconsole from the list - SwapConsole->Prev->Next = SwapConsole->Next; - SwapConsole->Next->Prev = SwapConsole->Prev; - // now insert before activeconsole - SwapConsole->Next = ActiveConsole; - SwapConsole->Prev = ActiveConsole->Prev; - ActiveConsole->Prev->Next = SwapConsole; - ActiveConsole->Prev = SwapConsole; - } - ActiveConsole = SwapConsole; - SwapConsole = 0; - CsrDrawConsole( ActiveConsole->ActiveBuffer ); - - UNLOCK; - } - /* process Ctrl-C and Ctrl-Break */ - if (ActiveConsole->Mode & ENABLE_PROCESSED_INPUT && - KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown && - ((KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_PAUSE) || - (KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == 'C')) && - (KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))) - { - PCSRSS_PROCESS_DATA current; - PLIST_ENTRY current_entry; - DPRINT1("Console_Api Ctrl-C\n"); + /* alt-tab, swap consoles */ + // move SwapConsole to next console, and print its title LOCK; - current_entry = ActiveConsole->ProcessList.Flink; - while (current_entry != &ActiveConsole->ProcessList) - { - current = CONTAINING_RECORD(current_entry, CSRSS_PROCESS_DATA, ProcessEntry); - current_entry = current_entry->Flink; - CsrConsoleCtrlEvent((DWORD)CTRL_C_EVENT, current); - } - UNLOCK; - RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord ); - continue; - } - if( KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState & - ( RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED ) && - ( KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP || - KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_DOWN) ) - { - if( KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE ) - { - /* scroll up or down */ - LOCK; - if( ActiveConsole == 0 ) - { - DbgPrint( "CSR: No Active Console!\n" ); - UNLOCK; - RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord ); - continue; - } - if( KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP ) - { - /* only scroll up if there is room to scroll up into */ - if( ActiveConsole->ActiveBuffer->ShowY != ((ActiveConsole->ActiveBuffer->CurrentY + 1) % - ActiveConsole->ActiveBuffer->MaxY) ) - ActiveConsole->ActiveBuffer->ShowY = (ActiveConsole->ActiveBuffer->ShowY + - ActiveConsole->ActiveBuffer->MaxY - 1) % ActiveConsole->ActiveBuffer->MaxY; - } - else if( ActiveConsole->ActiveBuffer->ShowY != ActiveConsole->ActiveBuffer->CurrentY ) - /* only scroll down if there is room to scroll down into */ - if( ActiveConsole->ActiveBuffer->ShowY % ActiveConsole->ActiveBuffer->MaxY != - ActiveConsole->ActiveBuffer->CurrentY ) + if( !SwapConsole ) + { + SwapConsole = ActiveConsole; + } + + if( ShiftState & SHIFT_PRESSED ) + { + SwapConsole = SwapConsole->Prev; + } + else + { + SwapConsole = SwapConsole->Next; + } + Title.MaximumLength = RtlUnicodeStringToAnsiSize( &SwapConsole->Title ); + Title.Length = 0; + Buffer = RtlAllocateHeap( CsrssApiHeap, + 0, + sizeof( COORD ) + Title.MaximumLength); + pos = (COORD *)Buffer; + Title.Buffer = Buffer + sizeof( COORD ); - if( ((ActiveConsole->ActiveBuffer->CurrentY + 1) % ActiveConsole->ActiveBuffer->MaxY) != - (ActiveConsole->ActiveBuffer->ShowY + PhysicalConsoleSize.Y) % ActiveConsole->ActiveBuffer->MaxY ) - ActiveConsole->ActiveBuffer->ShowY = (ActiveConsole->ActiveBuffer->ShowY + 1) % - ActiveConsole->ActiveBuffer->MaxY; - CsrDrawConsole( ActiveConsole->ActiveBuffer ); - UNLOCK; - } - RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord ); - continue; - } - LOCK; - if( ActiveConsole == 0 ) - { - DbgPrint( "CSR: No Active Console!\n" ); + RtlUnicodeStringToAnsiString(&Title, &SwapConsole->Title, FALSE); + pos->Y = PhysicalConsoleSize.Y / 2; + pos->X = ( PhysicalConsoleSize.X - Title.Length ) / 2; + // redraw the console to clear off old title + CsrDrawConsole( ActiveConsole->ActiveBuffer ); + Status = NtDeviceIoControlFile( ConsoleDeviceHandle, + NULL, + NULL, + NULL, + &Iosb, + IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER, + Buffer, + sizeof (COORD) + Title.Length, + NULL, + 0); + if( !NT_SUCCESS( Status ) ) + { + DPRINT1( "Error writing to console\n" ); + } + RtlFreeHeap( CsrssApiHeap, 0, Buffer ); + UNLOCK; - RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord ); - continue; - } - // process special keys if enabled - if( ActiveConsole->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT) ) - switch( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar ) - { - case '\r': - // add a \n to the queue as well - // first add the \r - updown = KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown; - KeyEventRecord->Echoed = FALSE; - KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\r'; - InsertTailList(&ActiveConsole->InputEvents, &KeyEventRecord->ListEntry); - ActiveConsole->WaitingChars++; - KeyEventRecord = RtlAllocateHeap( CsrssApiHeap, 0, sizeof( ConsoleInput ) ); - if( !KeyEventRecord ) - { - DbgPrint( "CSR: Failed to allocate KeyEventRecord\n" ); - UNLOCK; - continue; - } - KeyEventRecord->InputEvent.EventType = KEY_EVENT; - KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown = updown; - KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode = 0; - KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualScanCode = 0; - KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\n'; - } - // add event to the queue - InsertTailList(&ActiveConsole->InputEvents, &KeyEventRecord->ListEntry); - // if line input mode is enabled, only wake the client on enter key down - if( !(ActiveConsole->Mode & ENABLE_LINE_INPUT ) || - ActiveConsole->EarlyReturn || - ( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' && - KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE ) ) - { - NtSetEvent( ActiveConsole->ActiveEvent, 0 ); - if( KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' ) - ActiveConsole->WaitingLines++; - } - KeyEventRecord->Echoed = FALSE; - if( ActiveConsole->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT) && - KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' && - KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown ) - { - // walk the input queue looking for a char to backspace - for( TempInput = (ConsoleInput *)ActiveConsole->InputEvents.Blink; - TempInput != (ConsoleInput *)&ActiveConsole->InputEvents && - (TempInput->InputEvent.EventType != KEY_EVENT || - TempInput->InputEvent.Event.KeyEvent.bKeyDown == FALSE || - TempInput->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\b' ); - TempInput = (ConsoleInput *)TempInput->ListEntry.Blink ); - // if we found one, delete it, otherwise, wake the client - if( TempInput != (ConsoleInput *)&ActiveConsole->InputEvents ) - { - // delete previous key in queue, maybe echo backspace to screen, and do not place backspace on queue - RemoveEntryList(&TempInput->ListEntry); - if( TempInput->Echoed ) - CsrpWriteConsole( ActiveConsole->ActiveBuffer, &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE ); - RtlFreeHeap( CsrssApiHeap, 0, TempInput ); - RemoveEntryList(&KeyEventRecord->ListEntry); - RtlFreeHeap( CsrssApiHeap, 0, KeyEventRecord ); - ActiveConsole->WaitingChars -= 2; - } - else NtSetEvent( ActiveConsole->ActiveEvent, 0 ); - } - else { - // echo chars if we are supposed to and client is waiting for some - if( ( ActiveConsole->Mode & ENABLE_ECHO_INPUT ) && ActiveConsole->EchoCount && - KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar && - KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown == TRUE && - KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar != '\r' ) - { - // mark the char as already echoed - CsrpWriteConsole( ActiveConsole->ActiveBuffer, &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE ); - ActiveConsole->EchoCount--; - KeyEventRecord->Echoed = TRUE; - } + } + continue; + } + else if( SwapConsole && VirtualKeyCode == VK_MENU && !Down) + { + // alt key released, swap consoles + PCSRSS_CONSOLE tmp; + + LOCK; + if( SwapConsole != ActiveConsole ) + { + // first remove swapconsole from the list + SwapConsole->Prev->Next = SwapConsole->Next; + SwapConsole->Next->Prev = SwapConsole->Prev; + // now insert before activeconsole + SwapConsole->Next = ActiveConsole; + SwapConsole->Prev = ActiveConsole->Prev; + ActiveConsole->Prev->Next = SwapConsole; + ActiveConsole->Prev = SwapConsole; + } + ActiveConsole = SwapConsole; + SwapConsole = 0; + CsrDrawConsole( ActiveConsole->ActiveBuffer ); + UNLOCK; + continue; } - - ActiveConsole->WaitingChars++; - if( !(ActiveConsole->Mode & ENABLE_LINE_INPUT) ) - NtSetEvent( ActiveConsole->ActiveEvent, 0 ); - UNLOCK; - } + LOCK; + if (ActiveConsole == NULL) + { + UNLOCK; + continue; + } + + ConInRec = RtlAllocateHeap(CsrssApiHeap, 0, sizeof(ConsoleInput)); + + if(ConInRec == NULL) + { + UNLOCK; + break; + } + + ConInRec->InputEvent = er; + ConInRec->Fake = FALSE; + ConInRec->Echoed = FALSE; + + CsrpProcessChar( ActiveConsole, ConInRec ); + UNLOCK; + } + + NtUserAcquireOrReleaseInputOwnership( TRUE ); } CSR_API(CsrGetScreenBufferInfo) @@ -1445,6 +1547,7 @@ CSR_API(CsrReadInputEvent) PLIST_ENTRY CurrentEntry; PCSRSS_CONSOLE Console; NTSTATUS Status; + BOOLEAN Done = FALSE; ConsoleInput *Input; Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY); @@ -1462,50 +1565,36 @@ CSR_API(CsrReadInputEvent) } // only get input if there is any - if( Console->InputEvents.Flink != &Console->InputEvents ) + while( Console->InputEvents.Flink != &Console->InputEvents && + !Done ) { CurrentEntry = RemoveHeadList(&Console->InputEvents); Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry); + Done = !Input->Fake; Reply->Data.ReadInputReply.Input = Input->InputEvent; if( Input->InputEvent.EventType == KEY_EVENT ) { if( Console->Mode & ENABLE_LINE_INPUT && - Input->InputEvent.Event.KeyEvent.bKeyDown == FALSE && - Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' ) + Input->InputEvent.Event.KeyEvent.bKeyDown == TRUE && + Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\r' ) { Console->WaitingLines--; + } Console->WaitingChars--; } RtlFreeHeap( CsrssApiHeap, 0, Input ); - if (Console->InputEvents.Flink != &Console->InputEvents && - Reply->Data.ReadInputReply.Input.EventType == KEY_EVENT && - Reply->Data.ReadInputReply.Input.Event.KeyEvent.uChar.AsciiChar == '\r') - { - Input = CONTAINING_RECORD(Console->InputEvents.Flink, ConsoleInput, ListEntry); - if (Input->InputEvent.EventType == KEY_EVENT && - Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' && - ((Input->InputEvent.Event.KeyEvent.bKeyDown && Reply->Data.ReadInputReply.Input.Event.KeyEvent.bKeyDown) || - (Input->InputEvent.Event.KeyEvent.bKeyDown==FALSE && Reply->Data.ReadInputReply.Input.Event.KeyEvent.bKeyDown==FALSE))) - { - if(Console->Mode & ENABLE_LINE_INPUT && - Input->InputEvent.Event.KeyEvent.bKeyDown == FALSE && - Input->InputEvent.Event.KeyEvent.uChar.AsciiChar == '\n' ) - Console->WaitingLines--; - Console->WaitingChars--; - RemoveHeadList(&Console->InputEvents); - RtlFreeHeap( CsrssApiHeap, 0, Input ); - } - } - Reply->Data.ReadInputReply.MoreEvents = (Console->InputEvents.Flink != &Console->InputEvents) ? TRUE : FALSE; Status = STATUS_SUCCESS; Console->EarlyReturn = FALSE; // clear early return } - else { - Status = STATUS_PENDING; - Console->EarlyReturn = TRUE; // mark for early return - } + + if( !Done ) + { + Status = STATUS_PENDING; + Console->EarlyReturn = TRUE; // mark for early return + } + UNLOCK; return Reply->Status = Status; } @@ -2424,14 +2513,14 @@ CSR_API(CsrReadConsoleOutput) ReadRegion.Bottom = ReadRegion.Top + SizeY; ReadRegion.Right = ReadRegion.Left + SizeX; - CsrpInitRect(ScreenRect, 0, 0, ScreenBuffer->MaxY - 1, ScreenBuffer->MaxX - 1); + CsrpInitRect(ScreenRect, 0, 0, ScreenBuffer->MaxY, ScreenBuffer->MaxX); if (!CsrpGetIntersection(&ReadRegion, ScreenRect, ReadRegion)) { UNLOCK; Reply->Status = STATUS_SUCCESS; return Reply->Status; } - + for(i = 0, Y = ReadRegion.Top; Y < ReadRegion.Bottom; ++i, ++Y) { CurCharInfo = CharInfo + (i * BufferSize.X); @@ -2509,9 +2598,13 @@ CSR_API(CsrWriteConsoleInput) Reply->Status = STATUS_INSUFFICIENT_RESOURCES; return Reply->Status; } - + + Record->Echoed = FALSE; + Record->Fake = FALSE; Record->InputEvent = *InputRecord++; - InsertTailList(&Console->InputEvents, &Record->ListEntry); + if( Record->InputEvent.EventType == KEY_EVENT ) { + CsrpProcessChar( Console, Record ); + } } UNLOCK; @@ -2542,15 +2635,6 @@ static NTSTATUS FASTCALL SetConsoleHardwareState (PCSRSS_CONSOLE Console, DWORD if ( (CONSOLE_HARDWARE_STATE_GDI_MANAGED == ConsoleHwState) ||(CONSOLE_HARDWARE_STATE_DIRECT == ConsoleHwState)) { - /* Inhibit keyboard input when hardware state == - * CONSOLE_HARDWARE_STATE_GDI_MANAGED */ - if (CONSOLE_HARDWARE_STATE_GDI_MANAGED == ConsoleHwState) { - DbgPrint( "Keyboard Inhibited.\n" ); - KeyReadInhibit = TRUE; - } else { - DbgPrint( "Keyboard Enabled.\n" ); - KeyReadInhibit = FALSE; - } if (Console->HardwareState != ConsoleHwState) { /* TODO: implement switching from full screen to windowed mode */ diff --git a/reactos/subsys/win32k/eng/mem.c b/reactos/subsys/win32k/eng/mem.c index 3fff378f21b..f2596d04a20 100644 --- a/reactos/subsys/win32k/eng/mem.c +++ b/reactos/subsys/win32k/eng/mem.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: mem.c,v 1.12 2003/09/26 10:45:44 gvg Exp $ +/* $Id: mem.c,v 1.13 2003/10/09 06:13:04 gvg Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -81,6 +81,7 @@ EngAllocUserMem(ULONG cj, ULONG Tag) ULONG MemSize = sizeof(USERMEMHEADER) + cj; PUSERMEMHEADER Header; + DbgPrint("EngAllocUserMem\n"); Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &NewMem, 0, &MemSize, MEM_COMMIT, PAGE_READWRITE); if (! NT_SUCCESS(Status)) diff --git a/reactos/subsys/win32k/include/input.h b/reactos/subsys/win32k/include/input.h index 415644ba837..1d3cbaa70b4 100644 --- a/reactos/subsys/win32k/include/input.h +++ b/reactos/subsys/win32k/include/input.h @@ -1,7 +1,12 @@ #ifndef __WIN32K_MOUSE_H #define __WIN32K_MOUSE_H +#include + NTSTATUS FASTCALL InitInputImpl(VOID); +PUSER_MESSAGE_QUEUE W32kGetPrimitiveMessageQueue(VOID); +PKBDTABLES W32kGetDefaultKeyLayout(VOID); +VOID FASTCALL W32kKeyProcessMessage(LPMSG Msg, PKBDTABLES KeyLayout); #endif /* __WIN32K_MOUSE_H */ diff --git a/reactos/subsys/win32k/main/dllmain.c b/reactos/subsys/win32k/main/dllmain.c index d0f9a9383b5..4155e7cd905 100644 --- a/reactos/subsys/win32k/main/dllmain.c +++ b/reactos/subsys/win32k/main/dllmain.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: dllmain.c,v 1.44 2003/08/19 11:48:49 weiden Exp $ +/* $Id: dllmain.c,v 1.45 2003/10/09 06:13:04 gvg Exp $ * * Entry Point for win32k.sys */ @@ -73,6 +73,7 @@ Win32kProcessCallback (struct _EPROCESS *Process, InitializeListHead(&Win32Process->MenuListHead); ExInitializeFastMutex(&Win32Process->MenuListLock); + Win32Process->KeyboardLayout = W32kGetDefaultKeyLayout(); Win32Process->WindowStation = NULL; if (Process->Win32WindowStation != NULL) { @@ -125,6 +126,7 @@ Win32kThreadCallback (struct _ETHREAD *Thread, #endif Win32Thread->MessageQueue = MsqCreateMessageQueue(); + Win32Thread->KeyboardLayout = W32kGetDefaultKeyLayout(); InitializeListHead(&Win32Thread->WindowListHead); ExInitializeFastMutex(&Win32Thread->WindowListLock); diff --git a/reactos/subsys/win32k/ntuser/input.c b/reactos/subsys/win32k/ntuser/input.c index 11ce0f57b15..c2938646abf 100644 --- a/reactos/subsys/win32k/ntuser/input.c +++ b/reactos/subsys/win32k/ntuser/input.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: input.c,v 1.13 2003/09/30 22:04:24 gvg Exp $ +/* $Id: input.c,v 1.14 2003/10/09 06:13:04 gvg Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -50,6 +50,7 @@ static CLIENT_ID KeyboardThreadId; static HANDLE KeyboardDeviceHandle; static KEVENT InputThreadsStart; static BOOLEAN InputThreadsRunning = FALSE; +PUSER_MESSAGE_QUEUE pmPrimitiveMessageQueue = 0; /* FUNCTIONS *****************************************************************/ @@ -84,11 +85,13 @@ KeyboardThreadMain(PVOID StartContext) /* * Wait to start input. */ + DbgPrint( "Input Thread Waiting for start event\n" ); Status = KeWaitForSingleObject(&InputThreadsStart, 0, UserMode, TRUE, NULL); + DbgPrint( "Input Thread Starting...\n" ); /* * Receive and process keyboard input. @@ -96,8 +99,8 @@ KeyboardThreadMain(PVOID StartContext) while (InputThreadsRunning) { KEY_EVENT_RECORD KeyEvent; - LPARAM lParam; - BOOLEAN SysKey; + LPARAM lParam = 0; + BOOLEAN SysKey; Status = NtReadFile (KeyboardDeviceHandle, NULL, @@ -144,8 +147,9 @@ KeyboardThreadMain(PVOID StartContext) lParam |= (1 << 29); /* Context mode. 1 if ALT if pressed while the key is pressed */ } - MsqPostKeyboardMessage(SysKey ? WM_SYSKEYDOWN : WM_KEYDOWN, KeyEvent.wVirtualKeyCode, - lParam); + MsqPostKeyboardMessage(SysKey ? WM_SYSKEYDOWN : WM_KEYDOWN, + KeyEvent.wVirtualKeyCode, + lParam); } else { @@ -166,16 +170,19 @@ KeyboardThreadMain(PVOID StartContext) lParam); } } + DbgPrint( "Input Thread Stopped...\n" ); } } NTSTATUS STDCALL NtUserAcquireOrReleaseInputOwnership(BOOLEAN Release) { - if (Release && InputThreadsRunning) + if (Release && InputThreadsRunning && !pmPrimitiveMessageQueue) { + DbgPrint( "Releasing input: PM = %08x\n", pmPrimitiveMessageQueue ); KeClearEvent(&InputThreadsStart); InputThreadsRunning = FALSE; + NtAlertThread(KeyboardThreadHandle); } else if (!Release && !InputThreadsRunning) @@ -183,6 +190,7 @@ NtUserAcquireOrReleaseInputOwnership(BOOLEAN Release) InputThreadsRunning = TRUE; KeSetEvent(&InputThreadsStart, IO_NO_INCREMENT, FALSE); } + return(STATUS_SUCCESS); } @@ -304,5 +312,4 @@ NtUserDragDetect( return 0; } - /* EOF */ diff --git a/reactos/subsys/win32k/ntuser/keyboard.c b/reactos/subsys/win32k/ntuser/keyboard.c index 8631420c1bd..89f7e85e712 100644 --- a/reactos/subsys/win32k/ntuser/keyboard.c +++ b/reactos/subsys/win32k/ntuser/keyboard.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: keyboard.c,v 1.9 2003/08/19 11:48:49 weiden Exp $ +/* $Id: keyboard.c,v 1.10 2003/10/09 06:13:04 gvg Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -44,9 +44,8 @@ #define NDEBUG #include -DWORD ModBits = 0; BYTE QueueKeyStateTable[256]; -static PVOID pkKeyboardLayout = 0; +PKBDTABLES pkKeyboardLayout = 0; /* arty -- These should be phased out for the general kbdxx.dll tables */ @@ -171,68 +170,141 @@ static const struct accent_char accent_chars[] = /*** Statics used by TranslateMessage ***/ +static UINT DontDistinguishShifts( UINT ret ) { + if( ret == VK_LSHIFT || ret == VK_RSHIFT ) ret = VK_SHIFT; + if( ret == VK_LCONTROL || ret == VK_RCONTROL ) ret = VK_CONTROL; + if( ret == VK_LMENU || ret == VK_RMENU ) ret = VK_MENU; + return ret; +} + static VOID STDCALL SetKeyState(DWORD key, BOOL down) { - if( key >= 'a' && key <= 'z' ) key += 'A' - 'a'; - QueueKeyStateTable[key] = down; + QueueKeyStateTable[key] = down ? 0x80 : 0; } -static BOOL SetModKey( PKBDTABLES pkKT, WORD wVK, BOOL down ) { +VOID DumpKeyState( PBYTE KeyState ) { int i; - - for( i = 0; pkKT->pCharModifiers->pVkToBit[i].Vk; i++ ) { - DbgPrint( "vk[%d] = { %04x, %x }\n", i, - pkKT->pCharModifiers->pVkToBit[i].Vk, - pkKT->pCharModifiers->pVkToBit[i].ModBits ); - if( pkKT->pCharModifiers->pVkToBit[i].Vk == wVK ) { - if( down ) ModBits |= pkKT->pCharModifiers->pVkToBit[i].ModBits; - else ModBits &= ~pkKT->pCharModifiers->pVkToBit[i].ModBits; - DbgPrint( "ModBits: %x\n", ModBits ); - return TRUE; - } - } - return FALSE; + DbgPrint( "KeyState { " ); + for( i = 0; i < 0x100; i++ ) { + if( KeyState[i] ) DbgPrint( "%02x(%02x) ", i, KeyState[i] ); + } + DbgPrint( "};\n" ); } -static BOOL TryToTranslateChar( WORD wVirtKey, - PVK_TO_WCHAR_TABLE vtwTbl, - DWORD ModBits, - PBOOL pbDead, - PBOOL pbLigature, - PWCHAR pwcTranslatedChar ) { - int i,j; - size_t size_this_entry = vtwTbl->cbSize; - int nStates = vtwTbl->nModifications; - PVK_TO_WCHARS10 vkPtr; +static BYTE KeysSet( PKBDTABLES pkKT, PBYTE KeyState, + int Mod, int FakeModLeft, int FakeModRight ) { + int i; - for( i = 0;; i++ ) { - vkPtr = (PVK_TO_WCHARS10) - (((BYTE *)vtwTbl->pVkToWchars) + i * size_this_entry); + if( !KeyState || !pkKT ) return 0; - if( !vkPtr->VirtualKey ) return FALSE; - if( wVirtKey == vkPtr->VirtualKey ) { - for( j = 0; j < nStates; j++ ) { - if( j == (int) ModBits ) { /* OK, we found a wchar with the correct - shift state and vk */ - *pbDead = vkPtr->wch[j] == WCH_DEAD; - *pbLigature = vkPtr->wch[j] == WCH_LGTR; - *pwcTranslatedChar = vkPtr->wch[j]; - if( *pbDead ) { - i++; - vkPtr = (PVK_TO_WCHARS10) - (((BYTE *)vtwTbl->pVkToWchars) + i * size_this_entry); - if( vkPtr->VirtualKey != 0xff ) { - DPRINT( "Found dead key with no trailer in the table.\n" ); - DPRINT( "VK: %04x, ADDR: %08x\n", wVirtKey, (int)vkPtr ); - return FALSE; - } - *pwcTranslatedChar = vkPtr->wch[j]; - } - return TRUE; - } - } + for( i = 0; i < pkKT->bMaxVSCtoVK; i++ ) { + if( KeyState[i] & 0xC0 && + ((pkKT->pusVSCtoVK[i] & 0xff) == Mod || + (pkKT->pusVSCtoVK[i] & 0xff) == FakeModLeft || + (pkKT->pusVSCtoVK[i] & 0xff) == FakeModRight ) ) { + return KeyState[i]; } } + + return 0; +} + +static DWORD ModBits( PKBDTABLES pkKT, PBYTE KeyState ) { + int i; + DWORD ModBits = 0; + BYTE Mask; + + if( !KeyState ) return 0; + + /* DumpKeyState( KeyState ); */ + + for( i = 0; pkKT->pCharModifiers->pVkToBit[i].Vk; i++ ) { + int Vk = pkKT->pCharModifiers->pVkToBit[i].Vk; + switch(Vk) + { + case VK_SHIFT: + Mask = KeysSet( pkKT, KeyState, Vk, VK_LSHIFT, VK_RSHIFT ); + if (Mask & 0xc0) + ModBits |= pkKT->pCharModifiers->pVkToBit[i].ModBits; + break; + case VK_CONTROL: + Mask = KeysSet( pkKT, KeyState, Vk, VK_LCONTROL, VK_RCONTROL ); + if (Mask & 0xc0) + ModBits |= pkKT->pCharModifiers->pVkToBit[i].ModBits; + break; + case VK_MENU: + Mask = KeysSet( pkKT, KeyState, Vk, VK_LMENU, VK_RMENU ); + if (Mask & 0xc0) + ModBits |= pkKT->pCharModifiers->pVkToBit[i].ModBits; + if (Mask & 0x40) + ModBits |= 0x02 /* KCTRL */; + break; + default: + Mask = KeysSet( pkKT, KeyState, Vk, 0, 0 ); + if (Mask & 0x80) + ModBits |= pkKT->pCharModifiers->pVkToBit[i].ModBits; + break; + } + } + + DPRINT( "Current Mod Bits: %x\n", ModBits ); + + return ModBits; +} + +static BOOL TryToTranslateChar(WORD wVirtKey, + DWORD ModBits, + PBOOL pbDead, + PBOOL pbLigature, + PWCHAR pwcTranslatedChar, + PKBDTABLES keyLayout ) +{ + PVK_TO_WCHAR_TABLE vtwTbl; + PVK_TO_WCHARS10 vkPtr; + size_t size_this_entry; + int nMod, shift; + + DPRINT ( "TryToTranslate: %04x %x\n", wVirtKey, ModBits ); + + if (ModBits > keyLayout->pCharModifiers->wMaxModBits) + { + return FALSE; + } + shift = keyLayout->pCharModifiers->ModNumber[ModBits]; + + for (nMod = 0; keyLayout->pVkToWcharTable[nMod].nModifications; nMod++) + { + if (shift >= keyLayout->pVkToWcharTable[nMod].nModifications) + { + continue; + } + vtwTbl = &keyLayout->pVkToWcharTable[nMod]; + size_this_entry = vtwTbl->cbSize; + vkPtr = (PVK_TO_WCHARS10)((BYTE *)vtwTbl->pVkToWchars); + while(vkPtr->VirtualKey) + { + if( wVirtKey == vkPtr->VirtualKey ) + { + *pbDead = vkPtr->wch[shift] == WCH_DEAD; + *pbLigature = vkPtr->wch[shift] == WCH_LGTR; + *pwcTranslatedChar = vkPtr->wch[shift]; + if( *pbDead ) + { + vkPtr = (PVK_TO_WCHARS10)(((BYTE *)vkPtr) + size_this_entry); + if( vkPtr->VirtualKey != 0xff ) + { + DPRINT( "Found dead key with no trailer in the table.\n" ); + DPRINT( "VK: %04x, ADDR: %08x\n", wVirtKey, (int)vkPtr ); + return FALSE; + } + *pwcTranslatedChar = vkPtr->wch[shift]; + } + return TRUE; + } + vkPtr = (PVK_TO_WCHARS10)(((BYTE *)vkPtr) + size_this_entry); + } + } + return FALSE; } static @@ -243,38 +315,32 @@ ToUnicodeInner(UINT wVirtKey, LPWSTR pwszBuff, int cchBuff, UINT wFlags, - DWORD ModBits, PKBDTABLES pkKT) { - int i; + WCHAR wcTranslatedChar; + BOOL bDead; + BOOL bLigature; - DbgPrint("wVirtKey=%08x, wScanCode=%08x, lpKeyState=[], " - "pwszBuff=%S, cchBuff=%d, wFlags=%x\n", - wVirtKey, wScanCode, /* lpKeyState, */ pwszBuff, - cchBuff, wFlags ); + if( !pkKT ) return 0; - for( i = 0; pkKT->pVkToWcharTable[i].nModifications; i++ ) { - WCHAR wcTranslatedChar; - BOOL bDead; - BOOL bLigature; - - if( TryToTranslateChar( wVirtKey, - &pkKT->pVkToWcharTable[i], - ModBits, - &bDead, - &bLigature, - &wcTranslatedChar ) ) { - if( bLigature ) { - DPRINT("Not handling ligature (yet)\n" ); - return 0; - } + if( TryToTranslateChar( wVirtKey, + ModBits( pkKT, lpKeyState ), + &bDead, + &bLigature, + &wcTranslatedChar, + pkKT ) ) + { + if( bLigature ) + { + DPRINT("Not handling ligature (yet)\n" ); + return 0; + } + /* DbgPrint( "Trans: %04x\n", wcTranslatedChar ); */ if( cchBuff > 0 ) pwszBuff[0] = wcTranslatedChar; - if( bDead ) return -1; - else return 1; + return bDead ? -1 : 1; } - } return 0; } @@ -286,11 +352,30 @@ NtUserGetKeyState( { DWORD ret; - if (key >= 'a' && key <= 'z') key += 'A' - 'a'; + if( key < 0x100 ) { ret = ((DWORD)(QueueKeyStateTable[key] & 0x80) << 8 ) | - (QueueKeyStateTable[key] & 0x80) | - (QueueKeyStateTable[key] & 0x01); + (QueueKeyStateTable[key] & 0x80) | + (QueueKeyStateTable[key] & 0x01); return ret; + } + return 0; +} + +int STDCALL ToUnicodeEx( UINT wVirtKey, + UINT wScanCode, + PBYTE lpKeyState, + LPWSTR pwszBuff, + int cchBuff, + UINT wFlags, + HKL dwhkl ) { + return ToUnicodeInner( wVirtKey, + wScanCode, + lpKeyState, + pwszBuff, + cchBuff, + wFlags, + PsGetWin32Thread() ? + PsGetWin32Thread()->KeyboardLayout : 0 ); } int STDCALL ToUnicode( UINT wVirtKey, @@ -299,14 +384,13 @@ int STDCALL ToUnicode( UINT wVirtKey, LPWSTR pwszBuff, int cchBuff, UINT wFlags ) { - return ToUnicodeInner( wVirtKey, - wScanCode, - QueueKeyStateTable, - pwszBuff, - cchBuff, - wFlags, - ModBits, - pkKeyboardLayout ); + return ToUnicodeEx( wVirtKey, + wScanCode, + QueueKeyStateTable, + pwszBuff, + cchBuff, + wFlags, + 0 ); } typedef PVOID (*KbdLayerDescriptor)(VOID); @@ -339,56 +423,51 @@ void InitKbdLayout( PVOID *pkKeyboardLayout ) { } } +PKBDTABLES W32kGetDefaultKeyLayout() { + if( !pkKeyboardLayout ) InitKbdLayout( (PVOID) &pkKeyboardLayout ); + return pkKeyboardLayout; +} + BOOL STDCALL NtUserTranslateMessage(LPMSG lpMsg, - DWORD Unknown1) /* Used to pass the kbd layout */ + HKL dwhkl) /* Used to pass the kbd layout */ { static INT dead_char = 0; + UINT ScanCode = 0; LONG UState = 0; WCHAR wp[2] = { 0 }; MSG NewMsg = { 0 }; + MSG InMsg = { 0 }; PUSER_MESSAGE UMsg; + PKBDTABLES keyLayout; - /* FIXME: Should pass current keyboard layout for this thread. */ - /* At the moment, the keyboard layout is global. */ - /* Also, we're fixed at kbdus.dll ... */ - if( !pkKeyboardLayout ) InitKbdLayout( &pkKeyboardLayout ); - if( !pkKeyboardLayout ) { - DbgPrint( "Not Translating due to empty layout.\n" ); + if( !NT_SUCCESS(MmCopyFromCaller(&InMsg, lpMsg, sizeof(InMsg))) ) { return FALSE; } - if (lpMsg->message != WM_KEYDOWN && lpMsg->message != WM_SYSKEYDOWN) + keyLayout = PsGetWin32Thread()->KeyboardLayout; + if( !keyLayout ) return 0; + + ScanCode = (InMsg.lParam >> 16) & 0xff; + + if (InMsg.message != WM_KEYDOWN && InMsg.message != WM_SYSKEYDOWN) { - if (lpMsg->message == WM_KEYUP) { - DbgPrint( "About to SetKeyState( %04x, FALSE );\n", lpMsg->wParam ); - SetKeyState( lpMsg->wParam, FALSE ); /* Release key */ - DbgPrint( "About to SetModKey();\n" ); - SetModKey( pkKeyboardLayout, lpMsg->wParam, FALSE ); - /* Release Mod if any */ - DbgPrint( "Done with keys.\n" ); + if (InMsg.message == WM_KEYUP) { + SetKeyState( ScanCode, FALSE ); /* Release key */ } return(FALSE); } - DbgPrint( "About to SetKeyState( %04x, TRUE );\n", lpMsg->wParam ); - SetKeyState( lpMsg->wParam, TRUE ); /* Strike key */ - - /* Pass 1: Search for modifiers */ - DbgPrint( "About to SetModKey();\n" ); - if( SetModKey( pkKeyboardLayout, lpMsg->wParam, TRUE ) ) return TRUE; - DbgPrint( "Done with keys.\n" ); + SetKeyState( ScanCode, TRUE ); /* Strike key */ /* Pass 2: Get Unicode Character */ - DbgPrint( "Calling ToUnicodeString()\n" ); - UState = ToUnicodeInner(lpMsg->wParam, HIWORD(lpMsg->lParam), - QueueKeyStateTable, wp, 2, 0, ModBits, - pkKeyboardLayout); + UState = ToUnicodeInner(InMsg.wParam, HIWORD(InMsg.lParam) & 0xff, + QueueKeyStateTable, wp, 2, 0, + keyLayout ); - DbgPrint( "UState is %d after key %04x\n", UState, wp[0] ); if (UState == 1) { - NewMsg.message = (lpMsg->message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR; + NewMsg.message = (InMsg.message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR; if (dead_char) { ULONG i; @@ -412,21 +491,21 @@ NtUserTranslateMessage(LPMSG lpMsg, dead_char = 0; } } - NewMsg.hwnd = lpMsg->hwnd; + NewMsg.hwnd = InMsg.hwnd; NewMsg.wParam = wp[0]; - NewMsg.lParam = lpMsg->lParam; + NewMsg.lParam = InMsg.lParam; UMsg = MsqCreateMessage(&NewMsg); - DbgPrint( "CHAR='%c' %04x %08x\n", wp[0], wp[0], lpMsg->lParam ); + DPRINT( "CHAR='%c' %04x %08x\n", wp[0], wp[0], InMsg.lParam ); MsqPostMessage(PsGetWin32Thread()->MessageQueue, UMsg); return(TRUE); } else if (UState == -1) { NewMsg.message = - (lpMsg->message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR; - NewMsg.hwnd = lpMsg->hwnd; + (InMsg.message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR; + NewMsg.hwnd = InMsg.hwnd; NewMsg.wParam = wp[0]; - NewMsg.lParam = lpMsg->lParam; + NewMsg.lParam = InMsg.lParam; dead_char = wp[0]; UMsg = MsqCreateMessage(&NewMsg); MsqPostMessage(PsGetWin32Thread()->MessageQueue, UMsg); @@ -465,5 +544,221 @@ NtUserSetKeyboardState( return TRUE; } +static UINT VkToScan( UINT Code, BOOL ExtCode, PKBDTABLES pkKT ) { + int i; + + for( i = 0; i < pkKT->bMaxVSCtoVK; i++ ) { + if( pkKT->pusVSCtoVK[i] == Code ) { return i; } + } + + return 0; +} + +UINT ScanToVk( UINT Code, BOOL ExtKey, PKBDTABLES pkKT ) { + if( ExtKey ) { + int i; + + for( i = 0; pkKT->pVSCtoVK_E0[i].Vsc; i++ ) { + if( pkKT->pVSCtoVK_E0[i].Vsc == Code ) + return pkKT->pVSCtoVK_E0[i].Vk & 0xff; + } + for( i = 0; pkKT->pVSCtoVK_E1[i].Vsc; i++ ) { + if( pkKT->pVSCtoVK_E1[i].Vsc == Code ) + return pkKT->pVSCtoVK_E1[i].Vk & 0xff; + } + + return 0; + } else { + if( Code >= pkKT->bMaxVSCtoVK ) { return 0; } + return pkKT->pusVSCtoVK[Code] & 0xff; + } +} + +/* + * Map a virtual key code, or virtual scan code, to a scan code, key code, + * or unshifted unicode character. + * + * Code: See Below + * Type: + * 0 -- Code is a virtual key code that is converted into a virtual scan code + * that does not distinguish between left and right shift keys. + * 1 -- Code is a virtual scan code that is converted into a virtual key code + * that does not distinguish between left and right shift keys. + * 2 -- Code is a virtual key code that is converted into an unshifted unicode + * character. + * 3 -- Code is a virtual scan code that is converted into a virtual key code + * that distinguishes left and right shift keys. + * KeyLayout: Keyboard layout handle (currently, unused) + * + * @implemented + */ + +UINT +STDCALL +NtUserMapVirtualKeyEx( UINT Code, UINT Type, DWORD keyboardId, HKL dwhkl ) { + UINT ret = 0; + PKBDTABLES keyLayout = PsGetWin32Thread()->KeyboardLayout; + + if( !keyLayout ) return 0; + + switch( Type ) { + case 0: + if( Code == VK_RSHIFT ) Code = VK_LSHIFT; + if( Code == VK_RMENU ) Code = VK_LMENU; + if( Code == VK_RCONTROL ) Code = VK_LCONTROL; + ret = VkToScan( Code, FALSE, keyLayout ); + break; + + case 1: + ret = + DontDistinguishShifts + (NtUserMapVirtualKeyEx( Code, 3, keyboardId, dwhkl ) ); + break; + + case 2: { + WCHAR wp[2]; + + ret = VkToScan( Code, FALSE, keyLayout ); + ToUnicodeInner( Code, ret, 0, wp, 2, 0, keyLayout ); + ret = wp[0]; + } break; + + case 3: + ret = ScanToVk( Code, FALSE, keyLayout ); + break; + } + + return ret; +} + + +int +STDCALL +NtUserToUnicodeEx( + UINT wVirtKey, + UINT wScanCode, + PBYTE lpKeyState, + LPWSTR pwszBuff, + int cchBuff, + UINT wFlags, + HKL dwhkl ) { + BYTE KeyStateBuf[0x100]; + PWCHAR OutPwszBuff = 0; + int ret = 0; + + + if( !NT_SUCCESS(MmCopyFromCaller(KeyStateBuf, + lpKeyState, + sizeof(KeyStateBuf))) ) { + DbgPrint( "Couldn't copy key state from caller.\n" ); + return 0; + } + OutPwszBuff = ExAllocatePool(NonPagedPool,sizeof(WCHAR) * cchBuff); + if( !OutPwszBuff ) { + DbgPrint( "ExAllocatePool(%d) failed\n", sizeof(WCHAR) * cchBuff); + return 0; + } + RtlZeroMemory( OutPwszBuff, sizeof( WCHAR ) * cchBuff ); + + ret = ToUnicodeEx( wVirtKey, + wScanCode, + KeyStateBuf, + OutPwszBuff, + cchBuff, + wFlags, + dwhkl ); + + MmCopyToCaller(pwszBuff,OutPwszBuff,sizeof(WCHAR)*cchBuff); + ExFreePool(OutPwszBuff); + + return ret; +} + +static int W32kSimpleToupper( int ch ) { + if( ch >= 'a' && ch <= 'z' ) ch = ch - 'a' + 'A'; + return ch; +} + +DWORD +STDCALL +NtUserGetKeyNameText( LONG lParam, LPWSTR lpString, int nSize ) { + int i; + DWORD ret = 0; + UINT CareVk = 0; + UINT VkCode = 0; + UINT ScanCode = (lParam >> 16) & 0xff; + BOOL ExtKey = lParam & (1<<24) ? TRUE : FALSE; + PKBDTABLES keyLayout = + PsGetWin32Thread() ? + PsGetWin32Thread()->KeyboardLayout : 0; + + if( !keyLayout || nSize < 1 ) return 0; + + if( lParam & (1<<25) ) { + CareVk = VkCode = ScanToVk( ScanCode, ExtKey, keyLayout ); + if( VkCode == VK_LSHIFT || VkCode == VK_RSHIFT ) + VkCode = VK_LSHIFT; + if( VkCode == VK_LCONTROL || VkCode == VK_RCONTROL ) + VkCode = VK_LCONTROL; + if( VkCode == VK_LMENU || VkCode == VK_RMENU ) + VkCode = VK_LMENU; + } else { + VkCode = ScanToVk( ScanCode, ExtKey, keyLayout ); + } + + VSC_LPWSTR *KeyNames = 0; + + if( CareVk != VkCode ) + ScanCode = VkToScan( VkCode, ExtKey, keyLayout ); + + if( ExtKey ) + KeyNames = keyLayout->pKeyNamesExt; + else + KeyNames = keyLayout->pKeyNames; + + for( i = 0; KeyNames[i].pwsz; i++ ) { + if( KeyNames[i].vsc == ScanCode ) { + UINT StrLen = wcslen(KeyNames[i].pwsz); + UINT StrMax = StrLen > (nSize - 1) ? (nSize - 1) : StrLen; + WCHAR null_wc = 0; + if( NT_SUCCESS( MmCopyToCaller( lpString, + KeyNames[i].pwsz, + StrMax * sizeof(WCHAR) ) ) && + NT_SUCCESS( MmCopyToCaller( lpString + StrMax, + &null_wc, + sizeof( WCHAR ) ) ) ) { + ret = StrMax; + break; + } + } + } + + if( ret == 0 ) { + WCHAR UCName[2]; + + UCName[0] = W32kSimpleToupper(NtUserMapVirtualKeyEx( VkCode, 2, 0, 0 )); + UCName[1] = 0; + ret = 1; + + if( !NT_SUCCESS(MmCopyToCaller( lpString, UCName, 2 * sizeof(WCHAR) )) ) + return 0; + } + + return ret; +} + +/* + * Filter this message according to the current key layout, setting wParam + * appropriately. + */ + +VOID FASTCALL W32kKeyProcessMessage(LPMSG Msg, PKBDTABLES KeyboardLayout) { + if( !KeyboardLayout || !Msg) return; + if( Msg->message != WM_KEYDOWN && Msg->message != WM_SYSKEYDOWN && + Msg->message != WM_KEYUP && Msg->message != WM_SYSKEYUP ) { + return; + } + Msg->wParam = NtUserMapVirtualKeyEx( (Msg->lParam >> 16) & 0xff, 1, 0, 0 ); +} /* EOF */ diff --git a/reactos/subsys/win32k/ntuser/message.c b/reactos/subsys/win32k/ntuser/message.c index 61aebf0e6a6..10077e4373c 100644 --- a/reactos/subsys/win32k/ntuser/message.c +++ b/reactos/subsys/win32k/ntuser/message.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: message.c,v 1.29 2003/09/27 15:41:54 gvg Exp $ +/* $Id: message.c,v 1.30 2003/10/09 06:13:04 gvg Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -39,6 +39,7 @@ #include #include #include +#include #include #define NDEBUG @@ -91,6 +92,8 @@ NtUserDispatchMessage(CONST MSG* UnsafeMsg) } } + if( Msg.hwnd == 0 ) return 0; + /* Get the window object. */ Status = ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable, @@ -184,6 +187,7 @@ IntPeekMessage(LPMSG Msg, { MsqDestroyMessage(Message); } + W32kKeyProcessMessage(Msg,PsGetWin32Thread()->KeyboardLayout); return TRUE; } @@ -536,7 +540,7 @@ IntSendMessage(HWND hWnd, { Result = IntCallWindowProc(Window->WndProcA, hWnd, Msg, wParam, lParam); } - return Result; + return Result; } } else @@ -615,7 +619,6 @@ NtUserWaitMessage(VOID) return IntWaitMessage(NULL, 0, 0); } - DWORD STDCALL NtUserGetQueueStatus(BOOL ClearChanges) { diff --git a/reactos/subsys/win32k/ntuser/misc.c b/reactos/subsys/win32k/ntuser/misc.c index c86a2597b54..efdea2f3e81 100644 --- a/reactos/subsys/win32k/ntuser/misc.c +++ b/reactos/subsys/win32k/ntuser/misc.c @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.18 2003/09/24 21:09:22 weiden Exp $ +/* $Id: misc.c,v 1.19 2003/10/09 06:13:05 gvg Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -23,27 +23,48 @@ #define NDEBUG #include +void W32kRegisterPrimitiveMessageQueue() { + extern PUSER_MESSAGE_QUEUE pmPrimitiveMessageQueue; + if( !pmPrimitiveMessageQueue ) { + PW32THREAD pThread; + pThread = PsGetWin32Thread(); + if( pThread && pThread->MessageQueue ) { + pmPrimitiveMessageQueue = pThread->MessageQueue; + DbgPrint( "Installed primitive input queue.\n" ); + } + } else { + DbgPrint( "Alert! Someone is trying to steal the primitive queue.\n" ); + } +} + +PUSER_MESSAGE_QUEUE W32kGetPrimitiveMessageQueue() { + extern PUSER_MESSAGE_QUEUE pmPrimitiveMessageQueue; + return pmPrimitiveMessageQueue; +} /* * @unimplemented */ DWORD STDCALL -NtUserCallNoParam( - DWORD Routine) +NtUserCallNoParam(DWORD Routine) { -/* - switch(Routine) - { - case 0: - break; - } -*/ - DPRINT1("Calling invalid routine number 0x%x in NtUserCallNoParam()\n", Routine); - SetLastWin32Error(ERROR_INVALID_PARAMETER); - return 0; -} + DWORD Result; + switch(Routine) { + case NOPARAM_ROUTINE_REGISTER_PRIMITIVE: + W32kRegisterPrimitiveMessageQueue(); + Result = TRUE; + break; + + default: + DPRINT1("Calling invalid routine number 0x%x in NtUserCallTwoParam\n"); + SetLastWin32Error(ERROR_INVALID_PARAMETER); + Result = 0; + break; + } + return 0; + } /* * @implemented diff --git a/reactos/subsys/win32k/ntuser/msgqueue.c b/reactos/subsys/win32k/ntuser/msgqueue.c index 73c2444932e..ab55bf5ad0b 100644 --- a/reactos/subsys/win32k/ntuser/msgqueue.c +++ b/reactos/subsys/win32k/ntuser/msgqueue.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: msgqueue.c,v 1.25 2003/09/29 19:38:30 weiden Exp $ +/* $Id: msgqueue.c,v 1.26 2003/10/09 06:13:05 gvg Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -37,6 +37,7 @@ #include #include #include +#include #define NDEBUG #include @@ -299,6 +300,9 @@ MsqPeekHardwareMessage(PUSER_MESSAGE_QUEUE MessageQueue, HWND hWnd, ULONG ActiveStamp; PWINDOW_OBJECT DesktopWindow; + if( !IntGetScreenDC() || + PsGetWin32Thread()->MessageQueue == W32kGetPrimitiveMessageQueue() ) + return FALSE; DesktopWindow = IntGetWindowObject(IntGetDesktopWindow()); /* Process messages in the message queue itself. */ @@ -433,27 +437,45 @@ MsqPostKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) uMsg, wParam, lParam); FocusMessageQueue = IntGetFocusMessageQueue(); - if (FocusMessageQueue == NULL) - { - DPRINT("No focus message queue\n"); - return; - } + if( !IntGetScreenDC() ) { + Msg.hwnd = 0; + Msg.message = uMsg; + Msg.wParam = wParam; + Msg.lParam = lParam; + /* FIXME: Initialize time and point. */ - if (FocusMessageQueue->FocusWindow != (HWND)0) - { - Msg.hwnd = FocusMessageQueue->FocusWindow; + if( W32kGetPrimitiveMessageQueue() ) { + Msg.hwnd = 0; Msg.message = uMsg; Msg.wParam = wParam; Msg.lParam = lParam; /* FIXME: Initialize time and point. */ - Message = MsqCreateMessage(&Msg); - MsqPostMessage(FocusMessageQueue, Message); - } - else - { - DPRINT("Invalid focus window handle\n"); + MsqPostMessage(W32kGetPrimitiveMessageQueue(), Message); } + } else { + if (FocusMessageQueue == NULL) + { + DPRINT("No focus message queue\n"); + return; + } + + if (FocusMessageQueue->FocusWindow != (HWND)0) + { + Msg.hwnd = FocusMessageQueue->FocusWindow; + Msg.message = uMsg; + Msg.wParam = wParam; + Msg.lParam = lParam; + /* FIXME: Initialize time and point. */ + + Message = MsqCreateMessage(&Msg); + MsqPostMessage(FocusMessageQueue, Message); + } + else + { + DPRINT("Invalid focus window handle\n"); + } + } } VOID FASTCALL diff --git a/reactos/subsys/win32k/ntuser/stubs.c b/reactos/subsys/win32k/ntuser/stubs.c index 42a742ac8b7..2c574174284 100644 --- a/reactos/subsys/win32k/ntuser/stubs.c +++ b/reactos/subsys/win32k/ntuser/stubs.c @@ -1,4 +1,4 @@ -/* $Id: stubs.c,v 1.28 2003/09/12 12:54:26 weiden Exp $ +/* $Id: stubs.c,v 1.29 2003/10/09 06:13:05 gvg Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -643,18 +643,6 @@ NtUserGetKeyboardLayoutName( return 0; } -DWORD -STDCALL -NtUserGetKeyNameText( - DWORD Unknown0, - DWORD Unknown1, - DWORD Unknown2) -{ - UNIMPLEMENTED - - return 0; -} - DWORD STDCALL NtUserGetListBoxInfo( @@ -811,19 +799,6 @@ NtUserLockWorkStation(VOID) return 0; } -DWORD -STDCALL -NtUserMapVirtualKeyEx( - DWORD Unknown0, - DWORD Unknown1, - DWORD Unknown2, - DWORD Unknown3) -{ - UNIMPLEMENTED - - return 0; -} - DWORD STDCALL NtUserMinMaximize( @@ -1070,22 +1045,6 @@ NtUserShowCaret( return 0; } -DWORD -STDCALL -NtUserToUnicodeEx( - DWORD Unknown0, - DWORD Unknown1, - DWORD Unknown2, - DWORD Unknown3, - DWORD Unknown4, - DWORD Unknown5, - DWORD Unknown6) -{ - UNIMPLEMENTED - - return 0; -} - DWORD STDCALL NtUserTrackMouseEvent( diff --git a/reactos/subsys/win32k/ntuser/winsta.c b/reactos/subsys/win32k/ntuser/winsta.c index 755c8e62677..d14a17c0649 100644 --- a/reactos/subsys/win32k/ntuser/winsta.c +++ b/reactos/subsys/win32k/ntuser/winsta.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: winsta.c,v 1.36 2003/09/25 20:09:56 ekohl Exp $ +/* $Id: winsta.c,v 1.37 2003/10/09 06:13:05 gvg Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -714,6 +714,7 @@ NtUserCreateDesktop(PUNICODE_STRING lpszDesktopName, IntCreateDesktopWindow(DesktopObject->WindowStation, DesktopWindowClass, 640, 480); + DbgPrint( "Created Desktop Window: %08x\n", DesktopObject->DesktopWindow ); Status = ObInsertObject ((PVOID)DesktopObject, NULL,