hedgewars/uInputHandler.pas
branchios-develop
changeset 13418 ba39a1d396c0
parent 13417 236cc4cf2448
child 13464 08a3851aaf67
equal deleted inserted replaced
13416:6e8b807bda4b 13418:ba39a1d396c0
    25 procedure initModule;
    25 procedure initModule;
    26 procedure freeModule;
    26 procedure freeModule;
    27 
    27 
    28 function  KeyNameToCode(name: shortstring): LongInt; inline;
    28 function  KeyNameToCode(name: shortstring): LongInt; inline;
    29 function  KeyNameToCode(name: shortstring; Modifier: shortstring): LongInt;
    29 function  KeyNameToCode(name: shortstring; Modifier: shortstring): LongInt;
       
    30 
       
    31 function  KeyBindToCode(bind: shortstring): LongInt;
       
    32 function  KeyBindToName(bind: shortstring): shortstring;
    30 //procedure MaskModifier(var code: LongInt; modifier: LongWord);
    33 //procedure MaskModifier(var code: LongInt; modifier: LongWord);
    31 procedure MaskModifier(Modifier: shortstring; var code: LongInt);
    34 procedure MaskModifier(Modifier: shortstring; var code: LongInt);
    32 procedure ProcessMouse(event: TSDL_MouseButtonEvent; ButtonDown: boolean);
    35 procedure ProcessMouse(event: TSDL_MouseButtonEvent; ButtonDown: boolean);
    33 //procedure ProcessMouseWheel(x, y: LongInt);
    36 //procedure ProcessMouseWheel(x, y: LongInt);
    34 procedure ProcessMouseWheel(y: LongInt);
    37 procedure ProcessMouseWheel(y: LongInt);
    89     while (code <= cKeyMaxIndex) and (KeyNames[code] <> name) do inc(code);
    92     while (code <= cKeyMaxIndex) and (KeyNames[code] <> name) do inc(code);
    90 
    93 
    91     MaskModifier(Modifier, code);
    94     MaskModifier(Modifier, code);
    92     KeyNameToCode:= code;
    95     KeyNameToCode:= code;
    93 end;
    96 end;
       
    97 
       
    98 // Takes a control name (e.g. 'quit') and returns the corresponding key code,
       
    99 // if it has been bound.
       
   100 // Returns -1 if the control has not been bound.
       
   101 function KeyBindToCode(bind: shortstring): LongInt;
       
   102 var code, index: LongInt;
       
   103 begin
       
   104     index:= 0;
       
   105     while (index <= High(CurrentBinds.binds)) and (CurrentBinds.binds[index] <> bind) do inc(index);
       
   106     if index > High(CurrentBinds.binds) then
       
   107         // Return error
       
   108         KeyBindToCode:= -1
       
   109     else begin
       
   110         code:= 0;
       
   111         while (code <= High(CurrentBinds.indices)) and (CurrentBinds.indices[code] <> index) do inc(code);
       
   112         checkFails(code <= High(CurrentBinds.indices), 'binds registry inconsistency', True);
       
   113         KeyBindToCode:= code;
       
   114     end;
       
   115 end;
       
   116 
       
   117 // Takes a control name (e.g. 'quit') and returns the corresponding
       
   118 // human-readable key name from SDL.
       
   119 // FIXME: Does not work 100% for all keys yet, but at least it no
       
   120 //        longer hardcodes any key name.
       
   121 // TODO: Localize
       
   122 function KeyBindToName(bind: shortstring): shortstring;
       
   123 var code: LongInt;
       
   124     name: shortstring;
       
   125 begin
       
   126     code:= KeyBindToCode(bind);
       
   127     if code = -1 then
       
   128         KeyBindToName:= trmsg[sidUnknownKey]
       
   129     else
       
   130         begin
       
   131         name:= SDL_GetKeyName(SDL_GetKeyFromScancode(code));
       
   132         if (name = 'Escape') then
       
   133             // Let's shorten the name “Escape” for the quit menu
       
   134             KeyBindToName:= 'Esc'
       
   135         else if (length(name) <> 0) then
       
   136             KeyBindToName:= name
       
   137         else
       
   138             begin
       
   139             WriteLnToConsole('Error: KeyBindToName('+bind+') failed to find SDL key name!');
       
   140             KeyBindToName:= trmsg[sidUnknownKey];
       
   141             end;
       
   142         end;
       
   143 end;
       
   144 
    94 (*
   145 (*
    95 procedure MaskModifier(var code: LongInt; Modifier: LongWord);
   146 procedure MaskModifier(var code: LongInt; Modifier: LongWord);
    96 begin
   147 begin
    97     if(Modifier and KMOD_LSHIFT) <> 0 then code:= code or LSHIFT;
   148     if(Modifier and KMOD_LSHIFT) <> 0 then code:= code or LSHIFT;
    98     if(Modifier and KMOD_RSHIFT) <> 0 then code:= code or LSHIFT;
   149     if(Modifier and KMOD_RSHIFT) <> 0 then code:= code or LSHIFT;
   160     // on OS X it this is expected behaviour
   211     // on OS X it this is expected behaviour
   161     if tkbd[KeyNameToCode('left_meta')] or tkbd[KeyNameToCode('right_meta')] then
   212     if tkbd[KeyNameToCode('left_meta')] or tkbd[KeyNameToCode('right_meta')] then
   162 {$ELSE}
   213 {$ELSE}
   163     // on other systems use this shortcut only if the keys are not bound to any command
   214     // on other systems use this shortcut only if the keys are not bound to any command
   164     if tkbd[KeyNameToCode('left_ctrl')] or tkbd[KeyNameToCode('right_ctrl')] then
   215     if tkbd[KeyNameToCode('left_ctrl')] or tkbd[KeyNameToCode('right_ctrl')] then
   165         if ((CurrentBinds[KeyNameToCode('left_ctrl')] = '') or
   216         if ((CurrentBinds.indices[KeyNameToCode('left_ctrl')] = 0) or
   166             (CurrentBinds[KeyNameToCode('right_ctrl')] = '')) and
   217             (CurrentBinds.indices[KeyNameToCode('right_ctrl')] = 0)) and
   167             (CurrentBinds[SDLK_w] = '') then
   218             (CurrentBinds.indices[SDLK_w] = 0) then
   168 {$ENDIF}
   219 {$ENDIF}
   169         ParseCommand('forcequit', true);
   220         ParseCommand('forcequit', true);
   170     end;
   221     end;
   171 
   222 
   172 if CurrentBinds[code][0] <> #0 then
   223 if CurrentBinds.indices[code] > 0 then
   173     begin
   224     begin
   174     if (code < cKeyMaxIndex - 2) // means not mouse buttons
   225     if (code < cKeyMaxIndex - 2) // means not mouse buttons
   175         and KeyDown
   226         and KeyDown
   176         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')))
   227         and (not ((CurrentBinds.binds[CurrentBinds.indices[code]] = 'put') 
       
   228                   or (CurrentBinds.binds[CurrentBinds.indices[code]] = 'ammomenu') 
       
   229                   or (CurrentBinds.binds[CurrentBinds.indices[code]] = '+cur_u') 
       
   230                   or (CurrentBinds.binds[CurrentBinds.indices[code]] = '+cur_d') 
       
   231                   or (CurrentBinds.binds[CurrentBinds.indices[code]] = '+cur_l') 
       
   232                   or (CurrentBinds.binds[CurrentBinds.indices[code]] = '+cur_r')))
   177         and (CurrentTeam <> nil) 
   233         and (CurrentTeam <> nil) 
   178         and (not CurrentTeam^.ExtDriven) 
   234         and (not CurrentTeam^.ExtDriven) 
   179         then bShowAmmoMenu:= false;
   235         then bShowAmmoMenu:= false;
   180 
   236 
   181     if KeyDown then
   237     if KeyDown then
   182         begin
   238         begin
   183         Trusted:= Trusted and (not isPaused); //releasing keys during pause should be allowed on the other hand
   239         Trusted:= Trusted and (not isPaused); //releasing keys during pause should be allowed on the other hand
   184 
   240 
   185         if CurrentBinds[code] = 'switch' then
   241         if CurrentBinds.binds[CurrentBinds.indices[code]] = 'switch' then
   186             LocalMessage:= LocalMessage or gmSwitch
   242             LocalMessage:= LocalMessage or gmSwitch
   187         else if CurrentBinds[code] = '+precise' then
   243         else if CurrentBinds.binds[CurrentBinds.indices[code]] = '+precise' then
   188             LocalMessage:= LocalMessage or gmPrecise;
   244             LocalMessage:= LocalMessage or gmPrecise;
   189 
   245 
   190         ParseCommand(CurrentBinds[code], Trusted);
   246         ParseCommand(CurrentBinds.binds[CurrentBinds.indices[code]], Trusted);
   191         if (CurrentTeam <> nil) and (not CurrentTeam^.ExtDriven) and (ReadyTimeLeft > 1) then
   247         if (CurrentTeam <> nil) and (not CurrentTeam^.ExtDriven) and (ReadyTimeLeft > 1) then
   192             ParseCommand('gencmd R', true)
   248             ParseCommand('gencmd R', true)
   193         end
   249         end
   194     else if (CurrentBinds[code][1] = '+') then
   250     else if (CurrentBinds.binds[CurrentBinds.indices[code]][1] = '+') then
   195         begin
   251         begin
   196         if CurrentBinds[code] = '+precise' then
   252         if CurrentBinds.binds[CurrentBinds.indices[code]] = '+precise' then
   197             LocalMessage:= LocalMessage and (not gmPrecise);
   253             LocalMessage:= LocalMessage and (not gmPrecise);
   198         s:= CurrentBinds[code];
   254         s:= CurrentBinds.binds[CurrentBinds.indices[code]];
   199         s[1]:= '-';
   255         s[1]:= '-';
   200         ParseCommand(s, Trusted);
   256         ParseCommand(s, Trusted);
   201         if (CurrentTeam <> nil) and (not CurrentTeam^.ExtDriven) and (ReadyTimeLeft > 1) then
   257         if (CurrentTeam <> nil) and (not CurrentTeam^.ExtDriven) and (ReadyTimeLeft > 1) then
   202             ParseCommand('gencmd R', true)
   258             ParseCommand('gencmd R', true)
   203         end
   259         end
   204     else
   260     else
   205         begin
   261         begin
   206         if CurrentBinds[code] = 'switch' then
   262         if CurrentBinds.binds[CurrentBinds.indices[code]] = 'switch' then
   207             LocalMessage:= LocalMessage and (not gmSwitch)
   263             LocalMessage:= LocalMessage and (not gmSwitch)
   208         end
   264         end
   209     end
   265     end
   210 end;
   266 end;
   211 
   267 
   272 for t:= 0 to cKbdMaxIndex do
   328 for t:= 0 to cKbdMaxIndex do
   273     if tkbd[t] then
   329     if tkbd[t] then
   274         ProcessKey(t, False);
   330         ProcessKey(t, False);
   275 end;
   331 end;
   276 
   332 
       
   333 procedure RegisterBind(var binds: TBinds; key, value: shortstring);
       
   334 var code: LongInt;
       
   335 begin
       
   336     checkFails(binds.lastIndex < 255, 'too many binds', true);
       
   337 
       
   338     code:= KeyNameToCode(key);
       
   339 
       
   340     checkFails(code >= 0, 'unknown key', true);
       
   341 
       
   342     if binds.indices[code] > 0 then
       
   343     begin
       
   344         binds.binds[binds.indices[code]]:= value
       
   345     end
       
   346     else begin
       
   347         inc(binds.lastIndex);
       
   348         binds.indices[code]:= binds.lastIndex;
       
   349         binds.binds[binds.indices[code]]:= value
       
   350     end;
       
   351 end;
   277 
   352 
   278 procedure InitDefaultBinds;
   353 procedure InitDefaultBinds;
   279 var i: Longword;
   354 var i: Longword;
   280 begin
   355 begin
   281     DefaultBinds[KeyNameToCode('escape')]:= 'quit';
   356     RegisterBind(DefaultBinds, 'escape', 'quit');
   282     DefaultBinds[KeyNameToCode(_S'`')]:= 'history';
   357     RegisterBind(DefaultBinds, _S'`', 'history');
   283     DefaultBinds[KeyNameToCode('delete')]:= 'rotmask';
   358     RegisterBind(DefaultBinds, 'delete', 'rotmask');
       
   359     RegisterBind(DefaultBinds, 'home', 'rottags');
   284 
   360 
   285     //numpad
   361     //numpad
   286     //DefaultBinds[265]:= '+volup';
   362     //DefaultBinds[265]:= '+volup';
   287     //DefaultBinds[256]:= '+voldown';
   363     //DefaultBinds[256]:= '+voldown';
   288 
   364 
   289     DefaultBinds[KeyNameToCode(_S'0')]:= '+volup';
   365     RegisterBind(DefaultBinds, _S'0', '+volup');
   290     DefaultBinds[KeyNameToCode(_S'9')]:= '+voldown';
   366     RegisterBind(DefaultBinds, _S'9', '+voldown');
   291     DefaultBinds[KeyNameToCode(_S'8')]:= 'mute';
   367     RegisterBind(DefaultBinds, _S'8', 'mute');
   292     DefaultBinds[KeyNameToCode(_S'c')]:= 'capture';
   368     RegisterBind(DefaultBinds, _S'c', 'capture');
   293     DefaultBinds[KeyNameToCode(_S'r')]:= 'record';
   369     RegisterBind(DefaultBinds, _S'r', 'record');
   294     DefaultBinds[KeyNameToCode(_S'h')]:= 'findhh';
   370     RegisterBind(DefaultBinds, _S'h', 'findhh');
   295     DefaultBinds[KeyNameToCode(_S'p')]:= 'pause';
   371     RegisterBind(DefaultBinds, _S'p', 'pause');
   296     DefaultBinds[KeyNameToCode(_S's')]:= '+speedup';
   372     RegisterBind(DefaultBinds, _S's', '+speedup');
   297     DefaultBinds[KeyNameToCode(_S't')]:= 'chat';
   373     RegisterBind(DefaultBinds, _S't', 'chat');
   298     DefaultBinds[KeyNameToCode(_S'y')]:= 'confirm';
   374     RegisterBind(DefaultBinds, _S'y', 'confirm');
   299 
   375 
   300     DefaultBinds[KeyNameToCode('mousem')]:= 'zoomreset';
   376     RegisterBind(DefaultBinds, 'mousem', 'zoomreset');
   301     DefaultBinds[KeyNameToCode('wheelup')]:= 'zoomin';
   377     RegisterBind(DefaultBinds, 'wheelup', 'zoomin');
   302     DefaultBinds[KeyNameToCode('wheeldown')]:= 'zoomout';
   378     RegisterBind(DefaultBinds, 'wheeldown', 'zoomout');
   303 
   379 
   304     DefaultBinds[KeyNameToCode('f12')]:= 'fullscr';
   380     RegisterBind(DefaultBinds, 'f12', 'fullscr');
   305 
   381 
   306 
   382 
   307     DefaultBinds[KeyNameToCode('mousel')]:= '/put';
   383     RegisterBind(DefaultBinds, 'mousel', '/put');
   308     DefaultBinds[KeyNameToCode('mouser')]:= 'ammomenu';
   384     RegisterBind(DefaultBinds, 'mouser', 'ammomenu');
   309     DefaultBinds[KeyNameToCode('backspace')]:= 'hjump';
   385     RegisterBind(DefaultBinds, 'backspace', 'hjump');
   310     DefaultBinds[KeyNameToCode('tab')]:= 'switch';
   386     RegisterBind(DefaultBinds, 'tab', 'switch');
   311     DefaultBinds[KeyNameToCode('return')]:= 'ljump';
   387     RegisterBind(DefaultBinds, 'return', 'ljump');
   312     DefaultBinds[KeyNameToCode('space')]:= '+attack';
   388     RegisterBind(DefaultBinds, 'space', '+attack');
   313     DefaultBinds[KeyNameToCode('up')]:= '+up';
   389     RegisterBind(DefaultBinds, 'up', '+up');
   314     DefaultBinds[KeyNameToCode('down')]:= '+down';
   390     RegisterBind(DefaultBinds, 'down', '+down');
   315     DefaultBinds[KeyNameToCode('left')]:= '+left';
   391     RegisterBind(DefaultBinds, 'left', '+left');
   316     DefaultBinds[KeyNameToCode('right')]:= '+right';
   392     RegisterBind(DefaultBinds, 'right', '+right');
   317     DefaultBinds[KeyNameToCode('left_shift')]:= '+precise';
   393     RegisterBind(DefaultBinds, 'left_shift', '+precise');
   318 
   394 
   319 
   395 
   320     DefaultBinds[KeyNameToCode('j0a0u')]:= '+left';
   396     RegisterBind(DefaultBinds, 'j0a0u', '+left');
   321     DefaultBinds[KeyNameToCode('j0a0d')]:= '+right';
   397     RegisterBind(DefaultBinds, 'j0a0d', '+right');
   322     DefaultBinds[KeyNameToCode('j0a1u')]:= '+up';
   398     RegisterBind(DefaultBinds, 'j0a1u', '+up');
   323     DefaultBinds[KeyNameToCode('j0a1d')]:= '+down';
   399     RegisterBind(DefaultBinds, 'j0a1d', '+down');
   324     for i:= 1 to 10 do DefaultBinds[KeyNameToCode('f'+IntToStr(i))]:= 'slot '+char(48+i);
   400     for i:= 1 to 10 do RegisterBind(DefaultBinds, 'f'+IntToStr(i), 'slot '+char(48+i));
   325     for i:= 1 to 5  do DefaultBinds[KeyNameToCode(IntToStr(i))]:= 'timer '+IntToStr(i);
   401     for i:= 1 to 5  do RegisterBind(DefaultBinds, IntToStr(i), 'timer '+IntToStr(i));
   326 
   402 
   327     loadBinds('dbind', cPathz[ptConfig] + '/settings.ini');
   403     loadBinds('dbind', cPathz[ptConfig] + '/settings.ini');
   328 end;
   404 end;
   329 
   405 
   330 
   406 
   387 procedure SetBinds(var binds: TBinds);
   463 procedure SetBinds(var binds: TBinds);
   388 var
   464 var
   389     t: LongInt;
   465     t: LongInt;
   390 begin
   466 begin
   391     for t:= 0 to cKbdMaxIndex do
   467     for t:= 0 to cKbdMaxIndex do
   392         if (CurrentBinds[t] <> binds[t]) and tkbd[t] then
   468         if (CurrentBinds.binds[CurrentBinds.indices[t]] <> binds.binds[binds.indices[t]]) and tkbd[t] then
   393             ProcessKey(t, False);
   469             ProcessKey(t, False);
   394 
   470 
   395     CurrentBinds:= binds;
   471     CurrentBinds:= binds;
   396 end;
   472 end;
   397 {$ELSE}
   473 {$ELSE}
   577 end;
   653 end;
   578 
   654 
   579 
   655 
   580 procedure addBind(var binds: TBinds; var id: shortstring);
   656 procedure addBind(var binds: TBinds; var id: shortstring);
   581 var KeyName, Modifier, tmp: shortstring;
   657 var KeyName, Modifier, tmp: shortstring;
   582     i, b: LongInt;
   658     i, newCode, code, b: LongInt;
   583 begin
   659 begin
   584 KeyName:= '';
   660     KeyName:= '';
   585 Modifier:= '';
   661     Modifier:= '';
   586 
   662 
   587 if(Pos('mod:', id) <> 0)then
   663     if(Pos('mod:', id) <> 0)then
       
   664         begin
       
   665         tmp:= '';
       
   666         SplitBySpace(id, tmp);
       
   667         Modifier:= id;
       
   668         id:= tmp;
       
   669         end;
       
   670 
       
   671     SplitBySpace(id, KeyName);
       
   672     if KeyName[1]='"' then
       
   673         Delete(KeyName, 1, 1);
       
   674     if KeyName[byte(KeyName[0])]='"' then
       
   675         Delete(KeyName, byte(KeyName[0]), 1);
       
   676     b:= KeyNameToCode(id, Modifier);
       
   677     if b = 0 then
       
   678         OutError(errmsgUnknownVariable + ' "' + id + '"', false)
       
   679     else
   588     begin
   680     begin
   589     tmp:= '';
   681         // add bind: first check if this cmd is already bound, and remove old bind
   590     SplitBySpace(id, tmp);
   682         i:= Low(binds.binds);
   591     Modifier:= id;
   683         while (i <= High(binds.binds)) and (binds.binds[i] <> KeyName) do
   592     id:= tmp;
   684             inc(i);
   593     end;
   685 
   594 
   686         if (i <= High(binds.binds)) then
   595 SplitBySpace(id, KeyName);
   687         begin
   596 if KeyName[1]='"' then
   688             code:= Low(binds.indices);
   597     Delete(KeyName, 1, 1);
   689             while (code <= High(binds.indices)) and (binds.indices[code] <> i) do
   598 if KeyName[byte(KeyName[0])]='"' then
   690                 inc(code);
   599     Delete(KeyName, byte(KeyName[0]), 1);
   691 
   600 b:= KeyNameToCode(id, Modifier);
   692             checkFails(code <= High(binds.indices), 'binds registry inconsistency', true);
   601 if b = 0 then
   693 
   602     OutError(errmsgUnknownVariable + ' "' + id + '"', false)
   694             binds.indices[code]:= 0;
   603 else
   695             binds.binds[i]:= ''
   604     begin
   696         end;
   605     // add bind: first check if this cmd is already bound, and remove old bind
   697 
   606     i:= cKbdMaxIndex;
   698         if binds.indices[b] > 0 then
   607     repeat
   699             newCode:= binds.indices[b]
   608         dec(i)
   700         else if i >= High(binds.binds) then
   609     until (i < 0) or (binds[i] = KeyName);
   701             begin
   610     if (i >= 0) then
   702                 inc(binds.lastIndex);
   611         binds[i]:= '';
   703                 checkFails(binds.lastIndex < High(binds.binds), 'too many binds', true);
   612 
   704                 newCode:= binds.lastIndex
   613     binds[b]:= KeyName;
   705             end else
       
   706                 newCode:= i;
       
   707 
       
   708 
       
   709     binds.indices[b]:= newCode;
       
   710     binds.binds[binds.indices[b]]:= KeyName
   614     end
   711     end
   615 end;
   712 end;
   616 
   713 
   617 // Bind that isn't a team bind, but overrides defaultbinds.
   714 // Bind that isn't a team bind, but overrides defaultbinds.
   618 procedure chDefaultBind(var id: shortstring);
   715 procedure chDefaultBind(var id: shortstring);