mysticbbs/mdl/m_input_windows.pas

219 lines
5.6 KiB
ObjectPascal

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
If ((InputRec.Event.KeyEvent.dwControlKeyState AND (RIGHT_ALT_PRESSED OR LEFT_CTRL_PRESSED)) = (RIGHT_ALT_PRESSED OR LEFT_CTRL_PRESSED)) and (Ord(InputRec.Event.KeyEvent.AsciiChar) <> 0) Then Begin
AddBuffer(Chr(Ord(InputRec.Event.KeyEvent.AsciiChar)));
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.