hedgewars/uKeys.pas
changeset 6954 a61458a81480
parent 6953 4c2dd25630a7
child 6955 71498ea59193
equal deleted inserted replaced
6953:4c2dd25630a7 6954:a61458a81480
     1 (*
       
     2  * Hedgewars, a free turn based strategy game
       
     3  * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or modify
       
     6  * it under the terms of the GNU General Public License as published by
       
     7  * the Free Software Foundation; version 2 of the License
       
     8  *
       
     9  * This program is distributed in the hope that it will be useful,
       
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12  * GNU General Public License for more details.
       
    13  *
       
    14  * You should have received a copy of the GNU General Public License
       
    15  * along with this program; if not, write to the Free Software
       
    16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
       
    17  *)
       
    18 
       
    19 {$INCLUDE "options.inc"}
       
    20 
       
    21 unit uKeys;
       
    22 interface
       
    23 uses SDLh, uTypes;
       
    24 
       
    25 procedure initModule;
       
    26 procedure freeModule;
       
    27 
       
    28 function  KeyNameToCode(name: shortstring): word;
       
    29 procedure ProcessKbd;
       
    30 procedure ProcessMouse(event: TSDL_MouseButtonEvent; ButtonDown: boolean);
       
    31 procedure ProcessKey(event: TSDL_KeyboardEvent);
       
    32 procedure ResetKbd;
       
    33 procedure FreezeEnterKey;
       
    34 procedure InitKbdKeyTable;
       
    35 
       
    36 procedure SetBinds(var binds: TBinds);
       
    37 procedure SetDefaultBinds;
       
    38 
       
    39 procedure ControllerInit;
       
    40 procedure ControllerClose;
       
    41 procedure ControllerAxisEvent(joy, axis: Byte; value: Integer);
       
    42 procedure ControllerHatEvent(joy, hat, value: Byte);
       
    43 procedure ControllerButtonEvent(joy, button: Byte; pressed: Boolean);
       
    44 
       
    45 implementation
       
    46 uses uConsole, uCommands, uMisc, uVariables, uConsts, uUtils, uDebug;
       
    47 
       
    48 var tkbd, tkbdn: TKeyboardState;
       
    49     quitKeyCode: Byte;
       
    50     KeyNames: array [0..cKeyMaxIndex] of string[15];
       
    51     
       
    52 
       
    53 function KeyNameToCode(name: shortstring): word;
       
    54 var code: Word;
       
    55 begin
       
    56     name:= LowerCase(name);
       
    57     code:= cKeyMaxIndex;
       
    58     while (code > 0) and (KeyNames[code] <> name) do dec(code);
       
    59     KeyNameToCode:= code;
       
    60 end;
       
    61 
       
    62 procedure ProcessKbd;
       
    63 var  i, j, k: LongInt;
       
    64      s: shortstring;
       
    65      Trusted: boolean;
       
    66      pkbd: PByteArray;
       
    67 begin
       
    68 
       
    69 // move cursor/camera
       
    70 // TODO: Scale on screen dimensions and/or axis value (game controller)?
       
    71 //TODO what is this for?
       
    72 movecursor(5 * CursorMovementX, 5 * CursorMovementY);
       
    73 
       
    74 
       
    75 {$IFNDEF MOBILE}
       
    76 
       
    77 //TODO reimplement
       
    78 // Controller(s)
       
    79 k:= j; // should we test k for hitting the limit? sounds rather unlikely to ever reach it
       
    80 for j:= 0 to Pred(ControllerNumControllers) do
       
    81     begin
       
    82     for i:= 0 to Pred(ControllerNumAxes[j]) do
       
    83         begin
       
    84         if ControllerAxes[j][i] > 20000 then
       
    85             tkbdn[k + 0]:= 1
       
    86         else
       
    87             tkbdn[k + 0]:= 0;
       
    88         if ControllerAxes[j][i] < -20000 then
       
    89             tkbdn[k + 1]:= 1
       
    90         else
       
    91             tkbdn[k + 1]:= 0;
       
    92         inc(k, 2);
       
    93         end;
       
    94     for i:= 0 to Pred(ControllerNumHats[j]) do
       
    95         begin
       
    96         tkbdn[k + 0]:= ControllerHats[j][i] and SDL_HAT_UP;
       
    97         tkbdn[k + 1]:= ControllerHats[j][i] and SDL_HAT_RIGHT;
       
    98         tkbdn[k + 2]:= ControllerHats[j][i] and SDL_HAT_DOWN;
       
    99         tkbdn[k + 3]:= ControllerHats[j][i] and SDL_HAT_LEFT;
       
   100         inc(k, 4);
       
   101         end;
       
   102     for i:= 0 to Pred(ControllerNumButtons[j]) do
       
   103         begin
       
   104         tkbdn[k]:= ControllerButtons[j][i];
       
   105         inc(k, 1);
       
   106         end;
       
   107     end;
       
   108 {$ENDIF}
       
   109 
       
   110 end;
       
   111 
       
   112 
       
   113 procedure ProcessKey(code: LongInt; KeyDown: boolean);
       
   114 var
       
   115     Trusted: boolean;
       
   116     s      : string;
       
   117 begin
       
   118 hideAmmoMenu:= false;
       
   119 Trusted:= (CurrentTeam <> nil)
       
   120           and (not CurrentTeam^.ExtDriven)
       
   121           and (CurrentHedgehog^.BotLevel = 0);
       
   122 
       
   123 tkbdn[code]:= ord(KeyDown);
       
   124 
       
   125 // ctrl/cmd + q to close engine and frontend
       
   126 if(KeyDown and (code = quitKeyCode)) then
       
   127     begin
       
   128 {$IFDEF DARWIN}
       
   129     if ((tkbdn[KeyNameToCode('left_meta')] = 1) or (tkbdn[KeyNameToCode('right_meta')] = 1)) then
       
   130 {$ELSE}
       
   131     if ((tkbdn[KeyNameToCode('left_ctrl')] = 1) or (tkbdn[KeyNameToCode('right_ctrl')] = 1)) then
       
   132 {$ENDIF}
       
   133         ParseCommand('halt', true);    
       
   134     end;
       
   135 
       
   136 if CurrentBinds[code][0] <> #0 then
       
   137     begin
       
   138     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;
       
   139     if (tkbd[code] = 0) and (tkbdn[code] <> 0) then
       
   140         begin
       
   141         ParseCommand(CurrentBinds[code], Trusted);
       
   142         if (CurrentTeam <> nil) and (not CurrentTeam^.ExtDriven) and (ReadyTimeLeft > 1) then
       
   143             ParseCommand('gencmd R', true)
       
   144         end
       
   145     else if (CurrentBinds[code][1] = '+') and (tkbdn[code] = 0) and (tkbd[code] <> 0) then
       
   146         begin
       
   147         s:= CurrentBinds[code];
       
   148         s[1]:= '-';
       
   149         ParseCommand(s, Trusted);
       
   150         if (CurrentTeam <> nil) and (not CurrentTeam^.ExtDriven) and (ReadyTimeLeft > 1) then
       
   151             ParseCommand('gencmd R', true)
       
   152         end;
       
   153     tkbd[code]:= tkbdn[code]
       
   154     end
       
   155 
       
   156 end;
       
   157 
       
   158 procedure ProcessKey(event: TSDL_KeyboardEvent); 
       
   159 begin
       
   160     ProcessKey(event.keysym.sym, event.type_ = SDL_KEYDOWN);
       
   161 end;
       
   162 
       
   163 procedure ProcessMouse(event: TSDL_MouseButtonEvent; ButtonDown: boolean);
       
   164 begin
       
   165 case event.button of
       
   166     SDL_BUTTON_LEFT:
       
   167         ProcessKey(KeyNameToCode('mousel'), ButtonDown);
       
   168     SDL_BUTTON_MIDDLE:
       
   169         ProcessKey(KeyNameToCode('mousem'), ButtonDown);
       
   170     SDL_BUTTON_RIGHT:
       
   171         ProcessKey(KeyNameToCode('mouser'), ButtonDown);
       
   172     SDL_BUTTON_WHEELDOWN:
       
   173         ProcessKey(KeyNameToCode('wheeldown'), ButtonDown);
       
   174     SDL_BUTTON_WHEELUP:
       
   175         ProcessKey(KeyNameToCode('wheelup'), ButtonDown);
       
   176     end;
       
   177 end;
       
   178 
       
   179 procedure ResetKbd;
       
   180 var j, k, t: LongInt;
       
   181     i: LongInt;
       
   182     pkbd: PByteArray;
       
   183 begin
       
   184 
       
   185 k:= SDL_GetMouseState(nil, nil);
       
   186 pkbd:=SDL_GetKeyState(@j);
       
   187 
       
   188 //TryDo(j < cKeyMaxIndex, 'SDL keys number is more than expected (' + IntToStr(j) + ')', true);
       
   189 
       
   190 for i:= 1 to pred(j) do
       
   191     tkbdn[i]:= pkbd^[i];
       
   192 
       
   193 {$IFNDEF MOBILE}
       
   194 // Controller(s)
       
   195 k:= j; // should we test k for hitting the limit? sounds rather unlikely to ever reach it
       
   196 for j:= 0 to Pred(ControllerNumControllers) do
       
   197     begin
       
   198     for i:= 0 to Pred(ControllerNumAxes[j]) do
       
   199         begin
       
   200         if ControllerAxes[j][i] > 20000 then
       
   201             tkbdn[k + 0]:= 1
       
   202         else
       
   203             tkbdn[k + 0]:= 0;
       
   204         if ControllerAxes[j][i] < -20000 then
       
   205             tkbdn[k + 1]:= 1
       
   206         else
       
   207             tkbdn[k + 1]:= 0;
       
   208         inc(k, 2);
       
   209         end;
       
   210     for i:= 0 to Pred(ControllerNumHats[j]) do
       
   211         begin
       
   212         tkbdn[k + 0]:= ControllerHats[j][i] and SDL_HAT_UP;
       
   213         tkbdn[k + 1]:= ControllerHats[j][i] and SDL_HAT_RIGHT;
       
   214         tkbdn[k + 2]:= ControllerHats[j][i] and SDL_HAT_DOWN;
       
   215         tkbdn[k + 3]:= ControllerHats[j][i] and SDL_HAT_LEFT;
       
   216         inc(k, 4);
       
   217         end;
       
   218     for i:= 0 to Pred(ControllerNumButtons[j]) do
       
   219         begin
       
   220         tkbdn[k]:= ControllerButtons[j][i];
       
   221         inc(k, 1);
       
   222         end;
       
   223     end;
       
   224 {$ENDIF}
       
   225 
       
   226 // what is this final loop for?
       
   227 for t:= 0 to cKeyMaxIndex do
       
   228     tkbd[t]:= tkbdn[t]
       
   229 end;
       
   230 
       
   231 procedure InitKbdKeyTable;
       
   232 var i, j, k, t: LongInt;
       
   233     s: string[15];
       
   234 begin
       
   235 //TODO in sdl13 this overrides some values (A and B) change indices to some other values at the back perhaps?
       
   236 KeyNames[1]:= 'mousel';
       
   237 KeyNames[2]:= 'mousem';
       
   238 KeyNames[3]:= 'mouser';
       
   239 KeyNames[4]:= 'wheelup';
       
   240 KeyNames[5]:= 'wheeldown';
       
   241 
       
   242 for i:= 6 to cKeyMaxIndex do
       
   243     begin
       
   244 {$IFDEF SDL13}
       
   245     s:= shortstring(SDL_GetScancodeName(i));
       
   246 {$ELSE}
       
   247     s:= shortstring(sdl_getkeyname(i));
       
   248 {$ENDIF}
       
   249     WriteToConsole(IntToStr(i) + ': ' + s + ' ' + IntToStr(cKeyMaxIndex));
       
   250     if s = 'unknown key' then KeyNames[i]:= ''
       
   251     else 
       
   252         begin
       
   253         for t:= 1 to Length(s) do
       
   254             if s[t] = ' ' then
       
   255                 s[t]:= '_';
       
   256         KeyNames[i]:= LowerCase(s)
       
   257         end;
       
   258     end;
       
   259 
       
   260 quitKeyCode:= KeyNameToCode('q');
       
   261 
       
   262 // get the size of keyboard array
       
   263 SDL_GetKeyState(@k);
       
   264 
       
   265 // Controller(s)
       
   266 for j:= 0 to Pred(ControllerNumControllers) do
       
   267     begin
       
   268     for i:= 0 to Pred(ControllerNumAxes[j]) do
       
   269         begin
       
   270         keynames[k + 0]:= 'j' + IntToStr(j) + 'a' + IntToStr(i) + 'u';
       
   271         keynames[k + 1]:= 'j' + IntToStr(j) + 'a' + IntToStr(i) + 'd';
       
   272         inc(k, 2);
       
   273         end;
       
   274     for i:= 0 to Pred(ControllerNumHats[j]) do
       
   275         begin
       
   276         keynames[k + 0]:= 'j' + IntToStr(j) + 'h' + IntToStr(i) + 'u';
       
   277         keynames[k + 1]:= 'j' + IntToStr(j) + 'h' + IntToStr(i) + 'r';
       
   278         keynames[k + 2]:= 'j' + IntToStr(j) + 'h' + IntToStr(i) + 'd';
       
   279         keynames[k + 3]:= 'j' + IntToStr(j) + 'h' + IntToStr(i) + 'l';
       
   280         inc(k, 4);
       
   281         end;
       
   282     for i:= 0 to Pred(ControllerNumButtons[j]) do
       
   283         begin
       
   284         keynames[k]:= 'j' + IntToStr(j) + 'b' + IntToStr(i);
       
   285         inc(k, 1);
       
   286         end;
       
   287     end;
       
   288 
       
   289 DefaultBinds[KeyNameToCode('escape')]:= 'quit';
       
   290 DefaultBinds[KeyNameToCode('grave')]:= 'history';
       
   291 DefaultBinds[KeyNameToCode('delete')]:= 'rotmask';
       
   292 
       
   293 //numpad
       
   294 //DefaultBinds[265]:= '+volup';
       
   295 //DefaultBinds[256]:= '+voldown';
       
   296 
       
   297 DefaultBinds[KeyNameToCode('0')]:= '+volup';
       
   298 DefaultBinds[KeyNameToCode('9')]:= '+voldown';
       
   299 DefaultBinds[KeyNameToCode('c')]:= 'capture';
       
   300 DefaultBinds[KeyNameToCode('h')]:= 'findhh';
       
   301 DefaultBinds[KeyNameToCode('p')]:= 'pause';
       
   302 DefaultBinds[KeyNameToCode('s')]:= '+speedup';
       
   303 DefaultBinds[KeyNameToCode('t')]:= 'chat';
       
   304 DefaultBinds[KeyNameToCode('y')]:= 'confirm';
       
   305 
       
   306 DefaultBinds[KeyNameToCode('mousem')]:= 'zoomreset';
       
   307 DefaultBinds[KeyNameToCode('wheelup')]:= 'zoomout';
       
   308 DefaultBinds[KeyNameToCode('wheeldown')]:= 'zoomin';
       
   309 
       
   310 DefaultBinds[KeyNameToCode('f12')]:= 'fullscr';
       
   311 
       
   312 
       
   313 DefaultBinds[KeyNameToCode('mousel')]:= '/put';
       
   314 DefaultBinds[KeyNameToCode('mouser')]:= 'ammomenu';
       
   315 DefaultBinds[KeyNameToCode('backspace')]:= 'hjump';
       
   316 DefaultBinds[KeyNameToCode('tab')]:= 'switch';
       
   317 DefaultBinds[KeyNameToCode('return')]:= 'ljump';
       
   318 DefaultBinds[KeyNameToCode('space')]:= '+attack';
       
   319 DefaultBinds[KeyNameToCode('up')]:= '+up';
       
   320 DefaultBinds[KeyNameToCode('down')]:= '+down';
       
   321 DefaultBinds[KeyNameToCode('left')]:= '+left';
       
   322 DefaultBinds[KeyNameToCode('right')]:= '+right';
       
   323 DefaultBinds[KeyNameToCode('left_shift')]:= '+precise';
       
   324 
       
   325 for i:= 1 to 10 do DefaultBinds[KeyNameToCode('f'+IntToStr(i))]:= 'slot '+IntToStr(i);
       
   326 for i:= 1 to 5  do DefaultBinds[KeyNameToCode(IntToStr(i))]:= 'timer '+IntToStr(i);
       
   327 
       
   328 SetDefaultBinds();
       
   329 end;
       
   330 
       
   331 procedure SetBinds(var binds: TBinds);
       
   332 begin
       
   333 {$IFDEF MOBILE}
       
   334     binds:= binds; // avoid hint
       
   335     CurrentBinds:= DefaultBinds;
       
   336 {$ELSE}
       
   337     CurrentBinds:= binds;
       
   338 {$ENDIF}
       
   339 end;
       
   340 
       
   341 procedure SetDefaultBinds;
       
   342 begin
       
   343     CurrentBinds:= DefaultBinds;
       
   344 end;
       
   345 
       
   346 procedure FreezeEnterKey;
       
   347 begin
       
   348     tkbd[3]:= 1;
       
   349     tkbd[13]:= 1;
       
   350     tkbd[27]:= 1;
       
   351     tkbd[271]:= 1;
       
   352 end;
       
   353 
       
   354 var Controller: array [0..5] of PSDL_Joystick;
       
   355 
       
   356 procedure ControllerInit;
       
   357 var i, j: Integer;
       
   358 begin
       
   359 ControllerEnabled:= 0;
       
   360 {$IFDEF MOBILE}
       
   361 exit; // joystick subsystem disabled on iPhone
       
   362 {$ENDIF}
       
   363 
       
   364 SDL_InitSubSystem(SDL_INIT_JOYSTICK);
       
   365 ControllerNumControllers:= SDL_NumJoysticks();
       
   366 
       
   367 if ControllerNumControllers > 6 then
       
   368     ControllerNumControllers:= 6;
       
   369 
       
   370 WriteLnToConsole('Number of game controllers: ' + IntToStr(ControllerNumControllers));
       
   371 
       
   372 if ControllerNumControllers > 0 then
       
   373     begin
       
   374     for j:= 0 to pred(ControllerNumControllers) do
       
   375         begin
       
   376         WriteLnToConsole('Using game controller: ' + SDL_JoystickName(j));
       
   377         Controller[j]:= SDL_JoystickOpen(j);
       
   378         if Controller[j] = nil then
       
   379             WriteLnToConsole('* Failed to open game controller!')
       
   380         else
       
   381             begin
       
   382             ControllerNumAxes[j]:= SDL_JoystickNumAxes(Controller[j]);
       
   383             //ControllerNumBalls[j]:= SDL_JoystickNumBalls(Controller[j]);
       
   384             ControllerNumHats[j]:= SDL_JoystickNumHats(Controller[j]);
       
   385             ControllerNumButtons[j]:= SDL_JoystickNumButtons(Controller[j]);
       
   386             WriteLnToConsole('* Number of axes: ' + IntToStr(ControllerNumAxes[j]));
       
   387             //WriteLnToConsole('* Number of balls: ' + IntToStr(ControllerNumBalls[j]));
       
   388             WriteLnToConsole('* Number of hats: ' + IntToStr(ControllerNumHats[j]));
       
   389             WriteLnToConsole('* Number of buttons: ' + IntToStr(ControllerNumButtons[j]));
       
   390             ControllerEnabled:= 1;
       
   391 
       
   392             if ControllerNumAxes[j] > 20 then
       
   393                 ControllerNumAxes[j]:= 20;
       
   394             //if ControllerNumBalls[j] > 20 then ControllerNumBalls[j]:= 20;
       
   395             
       
   396             if ControllerNumHats[j] > 20 then
       
   397                 ControllerNumHats[j]:= 20;
       
   398                 
       
   399             if ControllerNumButtons[j] > 20 then
       
   400                 ControllerNumButtons[j]:= 20;
       
   401 
       
   402             // reset all buttons/axes
       
   403             for i:= 0 to pred(ControllerNumAxes[j]) do
       
   404                 ControllerAxes[j][i]:= 0;
       
   405             (*for i:= 0 to pred(ControllerNumBalls[j]) do
       
   406                 begin
       
   407                 ControllerBalls[j][i][0]:= 0;
       
   408                 ControllerBalls[j][i][1]:= 0;
       
   409                 end;*)
       
   410             for i:= 0 to pred(ControllerNumHats[j]) do
       
   411                 ControllerHats[j][i]:= SDL_HAT_CENTERED;
       
   412             for i:= 0 to pred(ControllerNumButtons[j]) do
       
   413                 ControllerButtons[j][i]:= 0;
       
   414             end;
       
   415         end;
       
   416     // enable event generation/controller updating
       
   417     SDL_JoystickEventState(1);
       
   418     end
       
   419 else
       
   420     WriteLnToConsole('Not using any game controller');
       
   421 end;
       
   422 
       
   423 procedure ControllerClose;
       
   424 var j: Integer;
       
   425 begin
       
   426     if ControllerEnabled > 0 then
       
   427         for j:= 0 to pred(ControllerNumControllers) do
       
   428             SDL_JoystickClose(Controller[j]);
       
   429 end;
       
   430 
       
   431 procedure ControllerAxisEvent(joy, axis: Byte; value: Integer);
       
   432 begin
       
   433     ControllerAxes[joy][axis]:= value;
       
   434 end;
       
   435 
       
   436 procedure ControllerHatEvent(joy, hat, value: Byte);
       
   437 begin
       
   438     ControllerHats[joy][hat]:= value;
       
   439 end;
       
   440 
       
   441 procedure ControllerButtonEvent(joy, button: Byte; pressed: Boolean);
       
   442 begin
       
   443     if pressed then
       
   444         ControllerButtons[joy][button]:= 1
       
   445     else
       
   446         ControllerButtons[joy][button]:= 0;
       
   447 end;
       
   448 
       
   449 procedure initModule;
       
   450 begin
       
   451     wheelUp:= false;
       
   452     wheelDown:= false;
       
   453 {$IFDEF HWLIBRARY}
       
   454     // this function is called by HW_allKeysUp so be careful
       
   455 
       
   456     // mouse emulation
       
   457     leftClick:= false;
       
   458     middleClick:= false;
       
   459     rightClick:= false;
       
   460 
       
   461     // arrow key emulation
       
   462     upKey:= false;
       
   463     downKey:= false;
       
   464     rightKey:= false;
       
   465     leftKey:= false;
       
   466     preciseKey:= false;
       
   467 
       
   468     // action key emulation
       
   469     backspaceKey:= false;
       
   470     spaceKey:= false;
       
   471     enterKey:= false;
       
   472     tabKey:= false;
       
   473 
       
   474     // other key emulation
       
   475     chatAction:= false;
       
   476     pauseAction:= false;
       
   477 {$ENDIF}
       
   478 end;
       
   479 
       
   480 procedure freeModule;
       
   481 begin
       
   482 
       
   483 end;
       
   484 
       
   485 end.