hedgewars/uInputHandler.pas
changeset 6954 a61458a81480
parent 6942 11f52445e8cd
child 6982 8d41d22a291d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/uInputHandler.pas	Sat Apr 28 15:03:52 2012 +0200
@@ -0,0 +1,485 @@
+(*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *)
+
+{$INCLUDE "options.inc"}
+
+unit uInputHandler;
+interface
+uses SDLh, uTypes;
+
+procedure initModule;
+procedure freeModule;
+
+function  KeyNameToCode(name: shortstring): word;
+procedure ProcessKbd;
+procedure ProcessMouse(event: TSDL_MouseButtonEvent; ButtonDown: boolean);
+procedure ProcessKey(event: TSDL_KeyboardEvent);
+procedure ResetKbd;
+procedure FreezeEnterKey;
+procedure InitKbdKeyTable;
+
+procedure SetBinds(var binds: TBinds);
+procedure SetDefaultBinds;
+
+procedure ControllerInit;
+procedure ControllerClose;
+procedure ControllerAxisEvent(joy, axis: Byte; value: Integer);
+procedure ControllerHatEvent(joy, hat, value: Byte);
+procedure ControllerButtonEvent(joy, button: Byte; pressed: Boolean);
+
+implementation
+uses uConsole, uCommands, uMisc, uVariables, uConsts, uUtils, uDebug;
+
+var tkbd, tkbdn: TKeyboardState;
+    quitKeyCode: Byte;
+    KeyNames: array [0..cKeyMaxIndex] of string[15];
+    
+
+function KeyNameToCode(name: shortstring): word;
+var code: Word;
+begin
+    name:= LowerCase(name);
+    code:= cKeyMaxIndex;
+    while (code > 0) and (KeyNames[code] <> name) do dec(code);
+    KeyNameToCode:= code;
+end;
+
+procedure ProcessKbd;
+var  i, j, k: LongInt;
+     s: shortstring;
+     Trusted: boolean;
+     pkbd: PByteArray;
+begin
+
+// move cursor/camera
+// TODO: Scale on screen dimensions and/or axis value (game controller)?
+//TODO what is this for?
+movecursor(5 * CursorMovementX, 5 * CursorMovementY);
+
+
+{$IFNDEF MOBILE}
+
+//TODO reimplement
+// Controller(s)
+k:= j; // should we test k for hitting the limit? sounds rather unlikely to ever reach it
+for j:= 0 to Pred(ControllerNumControllers) do
+    begin
+    for i:= 0 to Pred(ControllerNumAxes[j]) do
+        begin
+        if ControllerAxes[j][i] > 20000 then
+            tkbdn[k + 0]:= 1
+        else
+            tkbdn[k + 0]:= 0;
+        if ControllerAxes[j][i] < -20000 then
+            tkbdn[k + 1]:= 1
+        else
+            tkbdn[k + 1]:= 0;
+        inc(k, 2);
+        end;
+    for i:= 0 to Pred(ControllerNumHats[j]) do
+        begin
+        tkbdn[k + 0]:= ControllerHats[j][i] and SDL_HAT_UP;
+        tkbdn[k + 1]:= ControllerHats[j][i] and SDL_HAT_RIGHT;
+        tkbdn[k + 2]:= ControllerHats[j][i] and SDL_HAT_DOWN;
+        tkbdn[k + 3]:= ControllerHats[j][i] and SDL_HAT_LEFT;
+        inc(k, 4);
+        end;
+    for i:= 0 to Pred(ControllerNumButtons[j]) do
+        begin
+        tkbdn[k]:= ControllerButtons[j][i];
+        inc(k, 1);
+        end;
+    end;
+{$ENDIF}
+
+end;
+
+
+procedure ProcessKey(code: LongInt; KeyDown: boolean);
+var
+    Trusted: boolean;
+    s      : string;
+begin
+hideAmmoMenu:= false;
+Trusted:= (CurrentTeam <> nil)
+          and (not CurrentTeam^.ExtDriven)
+          and (CurrentHedgehog^.BotLevel = 0);
+
+tkbdn[code]:= ord(KeyDown);
+
+// ctrl/cmd + q to close engine and frontend
+if(KeyDown and (code = quitKeyCode)) then
+    begin
+{$IFDEF DARWIN}
+    if ((tkbdn[KeyNameToCode('left_meta')] = 1) or (tkbdn[KeyNameToCode('right_meta')] = 1)) then
+{$ELSE}
+    if ((tkbdn[KeyNameToCode('left_ctrl')] = 1) or (tkbdn[KeyNameToCode('right_ctrl')] = 1)) then
+{$ENDIF}
+        ParseCommand('halt', true);    
+    end;
+
+if CurrentBinds[code][0] <> #0 then
+    begin
+    if (code > 3) and (tkbdn[code] <> 0) and not ((CurrentBinds[code] = 'put') or (CurrentBinds[code] = 'ammomenu') or (CurrentBinds[code] = '+cur_u') or (CurrentBinds[code] = '+cur_d') or (CurrentBinds[code] = '+cur_l') or (CurrentBinds[code] = '+cur_r')) then hideAmmoMenu:= true;
+    if (tkbd[code] = 0) and (tkbdn[code] <> 0) then
+        begin
+        ParseCommand(CurrentBinds[code], Trusted);
+        if (CurrentTeam <> nil) and (not CurrentTeam^.ExtDriven) and (ReadyTimeLeft > 1) then
+            ParseCommand('gencmd R', true)
+        end
+    else if (CurrentBinds[code][1] = '+') and (tkbdn[code] = 0) and (tkbd[code] <> 0) then
+        begin
+        s:= CurrentBinds[code];
+        s[1]:= '-';
+        ParseCommand(s, Trusted);
+        if (CurrentTeam <> nil) and (not CurrentTeam^.ExtDriven) and (ReadyTimeLeft > 1) then
+            ParseCommand('gencmd R', true)
+        end;
+    tkbd[code]:= tkbdn[code]
+    end
+
+end;
+
+procedure ProcessKey(event: TSDL_KeyboardEvent); 
+begin
+    ProcessKey(event.keysym.sym, event.type_ = SDL_KEYDOWN);
+end;
+
+procedure ProcessMouse(event: TSDL_MouseButtonEvent; ButtonDown: boolean);
+begin
+case event.button of
+    SDL_BUTTON_LEFT:
+        ProcessKey(KeyNameToCode('mousel'), ButtonDown);
+    SDL_BUTTON_MIDDLE:
+        ProcessKey(KeyNameToCode('mousem'), ButtonDown);
+    SDL_BUTTON_RIGHT:
+        ProcessKey(KeyNameToCode('mouser'), ButtonDown);
+    SDL_BUTTON_WHEELDOWN:
+        ProcessKey(KeyNameToCode('wheeldown'), ButtonDown);
+    SDL_BUTTON_WHEELUP:
+        ProcessKey(KeyNameToCode('wheelup'), ButtonDown);
+    end;
+end;
+
+procedure ResetKbd;
+var j, k, t: LongInt;
+    i: LongInt;
+    pkbd: PByteArray;
+begin
+
+k:= SDL_GetMouseState(nil, nil);
+pkbd:=SDL_GetKeyState(@j);
+
+//TryDo(j < cKeyMaxIndex, 'SDL keys number is more than expected (' + IntToStr(j) + ')', true);
+
+for i:= 1 to pred(j) do
+    tkbdn[i]:= pkbd^[i];
+
+{$IFNDEF MOBILE}
+// Controller(s)
+k:= j; // should we test k for hitting the limit? sounds rather unlikely to ever reach it
+for j:= 0 to Pred(ControllerNumControllers) do
+    begin
+    for i:= 0 to Pred(ControllerNumAxes[j]) do
+        begin
+        if ControllerAxes[j][i] > 20000 then
+            tkbdn[k + 0]:= 1
+        else
+            tkbdn[k + 0]:= 0;
+        if ControllerAxes[j][i] < -20000 then
+            tkbdn[k + 1]:= 1
+        else
+            tkbdn[k + 1]:= 0;
+        inc(k, 2);
+        end;
+    for i:= 0 to Pred(ControllerNumHats[j]) do
+        begin
+        tkbdn[k + 0]:= ControllerHats[j][i] and SDL_HAT_UP;
+        tkbdn[k + 1]:= ControllerHats[j][i] and SDL_HAT_RIGHT;
+        tkbdn[k + 2]:= ControllerHats[j][i] and SDL_HAT_DOWN;
+        tkbdn[k + 3]:= ControllerHats[j][i] and SDL_HAT_LEFT;
+        inc(k, 4);
+        end;
+    for i:= 0 to Pred(ControllerNumButtons[j]) do
+        begin
+        tkbdn[k]:= ControllerButtons[j][i];
+        inc(k, 1);
+        end;
+    end;
+{$ENDIF}
+
+// what is this final loop for?
+for t:= 0 to cKeyMaxIndex do
+    tkbd[t]:= tkbdn[t]
+end;
+
+procedure InitKbdKeyTable;
+var i, j, k, t: LongInt;
+    s: string[15];
+begin
+//TODO in sdl13 this overrides some values (A and B) change indices to some other values at the back perhaps?
+KeyNames[1]:= 'mousel';
+KeyNames[2]:= 'mousem';
+KeyNames[3]:= 'mouser';
+KeyNames[4]:= 'wheelup';
+KeyNames[5]:= 'wheeldown';
+
+for i:= 6 to cKeyMaxIndex do
+    begin
+{$IFDEF SDL13}
+    s:= shortstring(SDL_GetScancodeName(i));
+{$ELSE}
+    s:= shortstring(sdl_getkeyname(i));
+{$ENDIF}
+    WriteToConsole(IntToStr(i) + ': ' + s + ' ' + IntToStr(cKeyMaxIndex));
+    if s = 'unknown key' then KeyNames[i]:= ''
+    else 
+        begin
+        for t:= 1 to Length(s) do
+            if s[t] = ' ' then
+                s[t]:= '_';
+        KeyNames[i]:= LowerCase(s)
+        end;
+    end;
+
+quitKeyCode:= KeyNameToCode('q');
+
+// get the size of keyboard array
+SDL_GetKeyState(@k);
+
+// Controller(s)
+for j:= 0 to Pred(ControllerNumControllers) do
+    begin
+    for i:= 0 to Pred(ControllerNumAxes[j]) do
+        begin
+        keynames[k + 0]:= 'j' + IntToStr(j) + 'a' + IntToStr(i) + 'u';
+        keynames[k + 1]:= 'j' + IntToStr(j) + 'a' + IntToStr(i) + 'd';
+        inc(k, 2);
+        end;
+    for i:= 0 to Pred(ControllerNumHats[j]) do
+        begin
+        keynames[k + 0]:= 'j' + IntToStr(j) + 'h' + IntToStr(i) + 'u';
+        keynames[k + 1]:= 'j' + IntToStr(j) + 'h' + IntToStr(i) + 'r';
+        keynames[k + 2]:= 'j' + IntToStr(j) + 'h' + IntToStr(i) + 'd';
+        keynames[k + 3]:= 'j' + IntToStr(j) + 'h' + IntToStr(i) + 'l';
+        inc(k, 4);
+        end;
+    for i:= 0 to Pred(ControllerNumButtons[j]) do
+        begin
+        keynames[k]:= 'j' + IntToStr(j) + 'b' + IntToStr(i);
+        inc(k, 1);
+        end;
+    end;
+
+DefaultBinds[KeyNameToCode('escape')]:= 'quit';
+DefaultBinds[KeyNameToCode('grave')]:= 'history';
+DefaultBinds[KeyNameToCode('delete')]:= 'rotmask';
+
+//numpad
+//DefaultBinds[265]:= '+volup';
+//DefaultBinds[256]:= '+voldown';
+
+DefaultBinds[KeyNameToCode('0')]:= '+volup';
+DefaultBinds[KeyNameToCode('9')]:= '+voldown';
+DefaultBinds[KeyNameToCode('c')]:= 'capture';
+DefaultBinds[KeyNameToCode('h')]:= 'findhh';
+DefaultBinds[KeyNameToCode('p')]:= 'pause';
+DefaultBinds[KeyNameToCode('s')]:= '+speedup';
+DefaultBinds[KeyNameToCode('t')]:= 'chat';
+DefaultBinds[KeyNameToCode('y')]:= 'confirm';
+
+DefaultBinds[KeyNameToCode('mousem')]:= 'zoomreset';
+DefaultBinds[KeyNameToCode('wheelup')]:= 'zoomout';
+DefaultBinds[KeyNameToCode('wheeldown')]:= 'zoomin';
+
+DefaultBinds[KeyNameToCode('f12')]:= 'fullscr';
+
+
+DefaultBinds[KeyNameToCode('mousel')]:= '/put';
+DefaultBinds[KeyNameToCode('mouser')]:= 'ammomenu';
+DefaultBinds[KeyNameToCode('backspace')]:= 'hjump';
+DefaultBinds[KeyNameToCode('tab')]:= 'switch';
+DefaultBinds[KeyNameToCode('return')]:= 'ljump';
+DefaultBinds[KeyNameToCode('space')]:= '+attack';
+DefaultBinds[KeyNameToCode('up')]:= '+up';
+DefaultBinds[KeyNameToCode('down')]:= '+down';
+DefaultBinds[KeyNameToCode('left')]:= '+left';
+DefaultBinds[KeyNameToCode('right')]:= '+right';
+DefaultBinds[KeyNameToCode('left_shift')]:= '+precise';
+
+for i:= 1 to 10 do DefaultBinds[KeyNameToCode('f'+IntToStr(i))]:= 'slot '+IntToStr(i);
+for i:= 1 to 5  do DefaultBinds[KeyNameToCode(IntToStr(i))]:= 'timer '+IntToStr(i);
+
+SetDefaultBinds();
+end;
+
+procedure SetBinds(var binds: TBinds);
+begin
+{$IFDEF MOBILE}
+    binds:= binds; // avoid hint
+    CurrentBinds:= DefaultBinds;
+{$ELSE}
+    CurrentBinds:= binds;
+{$ENDIF}
+end;
+
+procedure SetDefaultBinds;
+begin
+    CurrentBinds:= DefaultBinds;
+end;
+
+procedure FreezeEnterKey;
+begin
+    tkbd[3]:= 1;
+    tkbd[13]:= 1;
+    tkbd[27]:= 1;
+    tkbd[271]:= 1;
+end;
+
+var Controller: array [0..5] of PSDL_Joystick;
+
+procedure ControllerInit;
+var i, j: Integer;
+begin
+ControllerEnabled:= 0;
+{$IFDEF MOBILE}
+exit; // joystick subsystem disabled on iPhone
+{$ENDIF}
+
+SDL_InitSubSystem(SDL_INIT_JOYSTICK);
+ControllerNumControllers:= SDL_NumJoysticks();
+
+if ControllerNumControllers > 6 then
+    ControllerNumControllers:= 6;
+
+WriteLnToConsole('Number of game controllers: ' + IntToStr(ControllerNumControllers));
+
+if ControllerNumControllers > 0 then
+    begin
+    for j:= 0 to pred(ControllerNumControllers) do
+        begin
+        WriteLnToConsole('Using game controller: ' + SDL_JoystickName(j));
+        Controller[j]:= SDL_JoystickOpen(j);
+        if Controller[j] = nil then
+            WriteLnToConsole('* Failed to open game controller!')
+        else
+            begin
+            ControllerNumAxes[j]:= SDL_JoystickNumAxes(Controller[j]);
+            //ControllerNumBalls[j]:= SDL_JoystickNumBalls(Controller[j]);
+            ControllerNumHats[j]:= SDL_JoystickNumHats(Controller[j]);
+            ControllerNumButtons[j]:= SDL_JoystickNumButtons(Controller[j]);
+            WriteLnToConsole('* Number of axes: ' + IntToStr(ControllerNumAxes[j]));
+            //WriteLnToConsole('* Number of balls: ' + IntToStr(ControllerNumBalls[j]));
+            WriteLnToConsole('* Number of hats: ' + IntToStr(ControllerNumHats[j]));
+            WriteLnToConsole('* Number of buttons: ' + IntToStr(ControllerNumButtons[j]));
+            ControllerEnabled:= 1;
+
+            if ControllerNumAxes[j] > 20 then
+                ControllerNumAxes[j]:= 20;
+            //if ControllerNumBalls[j] > 20 then ControllerNumBalls[j]:= 20;
+            
+            if ControllerNumHats[j] > 20 then
+                ControllerNumHats[j]:= 20;
+                
+            if ControllerNumButtons[j] > 20 then
+                ControllerNumButtons[j]:= 20;
+
+            // reset all buttons/axes
+            for i:= 0 to pred(ControllerNumAxes[j]) do
+                ControllerAxes[j][i]:= 0;
+            (*for i:= 0 to pred(ControllerNumBalls[j]) do
+                begin
+                ControllerBalls[j][i][0]:= 0;
+                ControllerBalls[j][i][1]:= 0;
+                end;*)
+            for i:= 0 to pred(ControllerNumHats[j]) do
+                ControllerHats[j][i]:= SDL_HAT_CENTERED;
+            for i:= 0 to pred(ControllerNumButtons[j]) do
+                ControllerButtons[j][i]:= 0;
+            end;
+        end;
+    // enable event generation/controller updating
+    SDL_JoystickEventState(1);
+    end
+else
+    WriteLnToConsole('Not using any game controller');
+end;
+
+procedure ControllerClose;
+var j: Integer;
+begin
+    if ControllerEnabled > 0 then
+        for j:= 0 to pred(ControllerNumControllers) do
+            SDL_JoystickClose(Controller[j]);
+end;
+
+procedure ControllerAxisEvent(joy, axis: Byte; value: Integer);
+begin
+    ControllerAxes[joy][axis]:= value;
+end;
+
+procedure ControllerHatEvent(joy, hat, value: Byte);
+begin
+    ControllerHats[joy][hat]:= value;
+end;
+
+procedure ControllerButtonEvent(joy, button: Byte; pressed: Boolean);
+begin
+    if pressed then
+        ControllerButtons[joy][button]:= 1
+    else
+        ControllerButtons[joy][button]:= 0;
+end;
+
+procedure initModule;
+begin
+    wheelUp:= false;
+    wheelDown:= false;
+{$IFDEF HWLIBRARY}
+    // this function is called by HW_allKeysUp so be careful
+
+    // mouse emulation
+    leftClick:= false;
+    middleClick:= false;
+    rightClick:= false;
+
+    // arrow key emulation
+    upKey:= false;
+    downKey:= false;
+    rightKey:= false;
+    leftKey:= false;
+    preciseKey:= false;
+
+    // action key emulation
+    backspaceKey:= false;
+    spaceKey:= false;
+    enterKey:= false;
+    tabKey:= false;
+
+    // other key emulation
+    chatAction:= false;
+    pauseAction:= false;
+{$ENDIF}
+end;
+
+procedure freeModule;
+begin
+
+end;
+
+end.