unit Inputs;

interface

uses
  Windows, Controls, Messages, Vec2f;

type
  TInputKeys = class
  public
  const
    SYSRQ      = $B7;
    PAUSE      = $C5;
    ESCAPE     = $01;
    ENTER      = $1C;
    KP_ENTER   = $9C;

    UP         = $C8;
    DOWN       = $D0;
    LEFT       = $CB;
    RIGHT      = $CD;

    BACKSPACE  = $0E;
    SPACE      = $39;
    TAB        = $0F;
    TILDE      = $29;

    INSERT     = $D2;
    DELETE     = $D3;
    HOME       = $C7;
    KEND       = $CF;
    PAGEUP     = $C9;
    PAGEDOWN   = $D1;

    CTRL       = $FF - $01;
    CTRL_L     = $1D;
    CTRL_R     = $9D;
    ALT        = $FF - $02;
    ALT_L      = $38;
    ALT_R      = $B8;
    SHIFT      = $FF - $03;
    SHIFT_L    = $2A;
    SHIFT_R    = $36;
    SUPER      = $FF - $04;
    SUPER_L    = $DB;
    SUPER_R    = $DC;
    APP_MENU   = $DD;

    CAPSLOCK   = $3A;
    NUMLOCK    = $45;
    SCROLL     = $46;

    BRACKET_L  = $1A; // [ {
    BRACKET_R  = $1B; // ] }
    BACKSLASH  = $2B; // \
    SLASH      = $35; // /
    COMMA      = $33; // ,
    DECIMAL    = $34; // .
    SEMICOLON  = $27; // : ;
    APOSTROPHE = $28; // ' "

    _0          = $0B;
    _1          = $02;
    _2          = $03;
    _3          = $04;
    _4          = $05;
    _5          = $06;
    _6          = $07;
    _7          = $08;
    _8          = $09;
    _9          = $0A;

    MINUS      = $0C;
    EQUALS     = $0D;

    A          = $1E;
    B          = $30;
    C          = $2E;
    D          = $20;
    E          = $12;
    F          = $21;
    G          = $22;
    H          = $23;
    I          = $17;
    J          = $24;
    K          = $25;
    L          = $26;
    M          = $32;
    N          = $31;
    O          = $18;
    P          = $19;
    Q          = $10;
    R          = $13;
    S          = $1F;
    T          = $14;
    U          = $16;
    V          = $2F;
    W          = $11;
    X          = $2D;
    Y          = $15;
    Z          = $2C;

    KP_0       = $52;
    KP_1       = $4F;
    KP_2       = $50;
    KP_3       = $51;
    KP_4       = $4B;
    KP_5       = $4C;
    KP_6       = $4D;
    KP_7       = $47;
    KP_8       = $48;
    KP_9       = $49;

    KP_SUB     = $4A;
    KP_ADD     = $4E;
    KP_MUL     = $37;
    KP_DIV     = $B5;
    KP_DECIMAL = $53;

    F1         = $3B;
    F2         = $3C;
    F3         = $3D;
    F4         = $3E;
    F5         = $3F;
    F6         = $40;
    F7         = $41;
    F8         = $42;
    F9         = $43;
    F10        = $44;
    F11        = $57;
    F12        = $58;

    KA_DOWN      = 0;
    KA_UP        = 1;
  end;

  TInput = class
  private
    FKeysDown: array[0..255] of Boolean;
    FKeysUp: array[0..255] of Boolean;
    FKeysPress: array[0..255] of Boolean;
    FKeysCanPress: array[0..255] of Boolean;

    FMouseCord: TVec2f;
    FMouseWheel: array[0..1] of Boolean;
    FMouseDown: array[TMouseButton] of Boolean;
    FMouseUp: array[TMouseButton] of Boolean;
    FMouseClick: array[TMouseButton] of Boolean;
    FMouseCanClick: array[TMouseButton] of Boolean;

    function GetKeyDown(index: Integer): Boolean;
    function GetKeyUp(index: Integer): Boolean;
    function GetKeyPress(index: Integer): Boolean;
    procedure doKeyPress(index: Integer);
    procedure doMouseClick(Button: TMouseButton);
    function KeyToCode(AKey: Integer): Integer;
    procedure SetKeyDown(index: Integer);
    procedure SetKeyUp(index: Integer);
    function GetMouseDown(index: TMouseButton): Boolean;
    function GetMouseUp(index: TMouseButton): Boolean;
    function GetMouseClick(index: TMouseButton): Boolean;
  public
    Key: TInputKeys;
    constructor Create;
    destructor Destroy; override;
    procedure SetMsg(var Msg: TMessage);
    procedure Clear;
    procedure SetMouseDown(Button: TMouseButton);
    procedure SetMouseUp(Button: TMouseButton);

    property KeyDown[index: Integer]: Boolean read GetKeyDown;
    property KeyUp[index: Integer]: Boolean read GetKeyUp;
    property KeyPress[index: Integer]: Boolean read GetKeyPress;
    property Mouse: TVec2f read FMouseCord;
    property MouseWheelUp: Boolean read FMouseWheel[0];
    property MouseWheelDown: Boolean read FMouseWheel[1];
    property MouseDown[index: TMouseButton]: Boolean read GetMouseDown;
    property MouseUp[index: TMouseButton]: Boolean read GetMouseUp;
    property MouseClick[index: TMouseButton]: Boolean read GetMouseClick;
  end;

var
  Input: TInput;

implementation

{ TInput }


procedure TInput.Clear;
var
  i : Integer;
begin
  for i := 0 to 255 do
  begin
    FKeysUp[i] := False;
    FKeysPress[i] := False;
    FKeysCanPress[i] := True;
  end;

  FMouseWheel[0] := False;
  FMouseWheel[1] := False;
            {
  FMouseDown[mbLeft] := False;
  FMouseUp[mbLeft] := False;  }
  FMouseClick[mbLeft] := False;
  FMouseCanClick[mbLeft] := True;

  FMouseDown[mbRight] := False;
  FMouseUp[mbRight] := False;
  FMouseClick[mbRight] := False;
  FMouseCanClick[mbRight] := True;

  FMouseDown[mbMiddle] := False;
  FMouseUp[mbMiddle] := False;
  FMouseClick[mbMiddle] := False;
  FMouseCanClick[mbMiddle] := True;
end;

constructor TInput.Create;
begin
  Clear;
  Key := TInputKeys.Create;
end;

destructor TInput.Destroy;
begin
  Key.Free;
  inherited;
end;

procedure TInput.doKeyPress(index: Integer);
begin
  if FKeysCanPress[index] Then
  begin
    FKeysPress[index] := True;
    FKeysCanPress[index] := False;
  end;
end;

function TInput.GetKeyDown(index: Integer): Boolean;
begin
  Result := FKeysDown[index];
end;

function TInput.GetKeyPress(index: Integer): Boolean;
begin
  Result := FKeysPress[index];
end;

function TInput.GetKeyUp(index: Integer): Boolean;
begin
  Result := FKeysUp[index];
end;

function TInput.GetMouseClick(index: TMouseButton): Boolean;
begin
  Result := FMouseClick[index];
end;

function TInput.GetMouseDown(index: TMouseButton): Boolean;
begin
  Result := FMouseDown[index];
end;

function TInput.GetMouseUp(index: TMouseButton): Boolean;
begin
  Result := FMouseUp[index];
end;

procedure TInput.SetKeyDown(index: Integer);
begin
  FKeysDown[index] := True;
  FKeysUp[index] := False;
  doKeyPress(index);
end;

procedure TInput.SetKeyUp(index: Integer);
begin
  FKeysDown[index] := False;
  FKeysUp[index] := True;
end;

procedure TInput.SetMouseDown(Button: TMouseButton);
begin
  FMouseClick[Button] := False;
  FMouseDown[Button] := True;
  FMouseUp[Button] := False;
  //doMouseClick(Button);
end;

procedure TInput.SetMouseUp(Button: TMouseButton);
begin
  FMouseClick[Button] := FMouseDown[Button];
  FMouseDown[Button] := False;
  FMouseUp[Button] := True;
end;

procedure TInput.doMouseClick(Button: TMouseButton);
begin
  FMouseDown[Button] := True;
  if FMouseCanClick[Button] Then
  begin
    FMouseClick[ Button ] := True;
    FMouseCanClick[ Button ] := False;
  {  if timer_GetTicks() - FMouseDblCTime[ Button ] < 250 Then
      FMouseDblClick[Button] := True;
    FMouseDblCTime[Button] := timer_GetTicks();  }
  end;
end;

function TInput.KeyToCode(AKey: Integer): Integer;
begin
  case AKey of
    $26: Result := Key.UP;
    $28: Result := Key.DOWN;
    $25: Result := Key.LEFT;
    $27: Result := Key.RIGHT;

    $2D: Result := Key.INSERT;
    $2E: Result := Key.DELETE;
    $24: Result := Key.HOME;
    $23: Result := Key.KEND;
    $21: Result := Key.PAGEUP;
    $22: Result := Key.PAGEDOWN;
  else
    Result := MapVirtualKey(AKey, 0);
  end;
end;

procedure TInput.SetMsg(var Msg: TMessage);
var
  Key: LongWord;
begin
  case Msg.Msg of
  WM_KEYDOWN, WM_SYSKEYDOWN: SetKeyDown(KeyToCode(Msg.wParam));
  WM_KEYUP, WM_SYSKEYUP: SetKeyUp(KeyToCode(Msg.wParam));
  WM_MOUSEMOVE: FMouseCord := TVec2f.Create(Msg.LParamLo, Msg.LParamHi);
  WM_MOUSEWHEEL:
    begin
      FMouseWheel[0] := Msg.WParam > 0;
      FMouseWheel[1] := Msg.WParam < 0;
    end;
  end;
end;

initialization
  Input := TInput.Create;

finalization
  Input.Free;

end.
