Unit m_Input_Windows; {$I M_OPS.PAS} Interface Uses Windows; Type TInputWindows = Class ConIn : THandle; Buffer : Array[1..64] of Char; BufPos : Byte; BufSize : Byte; DoingNumChars : Boolean; DoingNumCode : Byte; Constructor Create; Destructor Destroy; Override; Procedure AddBuffer (Ch: Char); Function RemapScanCode (ScanCode: Word; CtrlKeyState: dWord; Keycode: Word) : Byte; Function ProcessQueue : Boolean; Function KeyWait (MS: Cardinal) : Boolean; Function KeyPressed : Boolean; Function ReadKey : Char; End; Implementation Constructor TInputWindows.Create; Begin Inherited Create; ConIn := GetStdHandle(STD_INPUT_HANDLE); SetConsoleMode (ConIn, 0); BufPos := 0; BufSize := 0; End; Destructor TInputWindows.Destroy; Begin Inherited Destroy; End; Procedure TInputWindows.AddBuffer (Ch: Char); Begin Inc (BufSize); If BufSize > 64 Then BufSize := 1; Buffer[BufSize] := Ch; End; Function TInputWindows.RemapScanCode (ScanCode: Word; CtrlKeyState: dWord; keycode: Word) : Byte; Var AltKey, CtrlKey, ShiftKey : Boolean; Const CtrlKeypadKeys: Array[$47..$53] of Byte = ( $77, $8D, $84, $8E, $73, $8F, $74, $4E, $75, $91, $76, $92, $93 ); Begin AltKey := ((CtrlKeyState AND (RIGHT_ALT_PRESSED OR LEFT_ALT_PRESSED)) > 0); CtrlKey := ((CtrlKeyState AND (RIGHT_CTRL_PRESSED OR LEFT_CTRL_PRESSED)) > 0); ShiftKey := ((CtrlKeyState AND SHIFT_PRESSED) > 0); If AltKey Then Begin Case KeyCode of VK_NUMPAD0 .. VK_NUMPAD9 : Begin DoingNumChars := True; DoingNumCode := Byte((DoingNumCode * 10) + (KeyCode - VK_NUMPAD0)); End; End; Case ScanCode of $02..$0D: Inc(ScanCode, $76); // Digits, -, = $3B..$44: Inc(ScanCode, $2D); // Function keys $57..$58: Inc(ScanCode, $34); // Function keys $47..$49, $4B, $4D, $4F..$53: Inc(ScanCode, $50); $1C : ScanCode := $A6; // Enter $35 : ScanCode := $A4; // / End End Else If CtrlKey Then Case ScanCode of $0F : ScanCode := $94; // TAB $3B..$44: Inc(ScanCode, $23); // Function keys $57..$58: Inc(ScanCode, $32); // Function keys $35: ScanCode := $95; // \ $37: ScanCode := $96; // * $47..$53: ScanCode := CtrlKeypadKeys[ScanCode]; End Else If ShiftKey Then Case ScanCode of $3B..$44: Inc(ScanCode, $19); $57..$58: Inc(ScanCode, $30); End Else Case ScanCode of $57..$58: Inc(Scancode, $2E); // F11 and F12 End; Result := ScanCode; End; Function TInputWindows.ProcessQueue : Boolean; Var InputRec : TInputRecord; NumRead : ULong; Begin Result := False; Repeat ReadConsoleInput(ConIn, InputRec, 1, NumRead); If InputRec.EventType = key_event then If InputRec.Event.KeyEvent.bKeyDown then begin If not(InputRec.Event.KeyEvent.wVirtualKeyCode in [VK_SHIFT, VK_MENU, VK_CONTROL, VK_CAPITAL, VK_NUMLOCK, VK_SCROLL]) then begin If (Ord(InputRec.Event.KeyEvent.AsciiChar) = 0) or (InputRec.Event.KeyEvent.dwControlKeyState and (LEFT_ALT_PRESSED or ENHANCED_KEY or RIGHT_ALT_PRESSED) > 0) Then Begin If (Ord(InputRec.Event.KeyEvent.AsciiChar) = 13) and (InputRec.Event.KeyEvent.wVirtualKeyCode = VK_RETURN) Then Begin addBuffer(#13); Result := True; Exit; End Else Begin addBuffer(#0); addBuffer(Chr(RemapScanCode(InputRec.Event.KeyEvent.wVirtualScanCode, InputRec.Event.KeyEvent.dwControlKeyState, InputRec.Event.KeyEvent.wVirtualKeyCode))); Result := True; Exit; End; End Else Begin addBuffer(Chr(Ord(InputRec.Event.KeyEvent.AsciiChar))); Result := True; Exit; End; end; End Else If (InputRec.Event.KeyEvent.wVirtualKeyCode in [VK_MENU]) Then If DoingNumChars Then If DoingNumCode > 0 Then Begin AddBuffer(Chr(DoingNumCode)); DoingNumChars := False; DoingNumCode := 0; Result := True; Break; End; GetNumberOfConsoleInputEvents(ConIn, NumRead); Until NumRead = 0; End; Function TInputWindows.KeyWait (MS: Cardinal) : Boolean; Begin If BufPos <> BufSize Then Begin Result := True; Exit; End; Repeat Case WaitForSingleObject(ConIn, MS) of Wait_Object_0 : Result := ProcessQueue; Else Result := False; Break; End; Until Result; End; Function TInputWindows.ReadKey : Char; Begin If BufPos = BufSize then keyWait (Infinite); Inc (BufPos); If BufPos > 64 Then BufPos := 1; Result := Buffer[BufPos]; End; Function TInputWindows.KeyPressed : Boolean; Var Temp : ULong; Begin If BufPos = BufSize Then Begin GetNumberOfConsoleInputEvents(ConIn, Temp); If Temp > 0 Then keyWait(1); End; Result := BufPos <> BufSize; End; End.