hedgewars/uInputHandler.pas
changeset 13068 6369d148cfff
parent 13045 25a9260244f3
child 13131 f10f4bf5f84d
equal deleted inserted replaced
13067:64aba90811a2 13068:6369d148cfff
    97 
    97 
    98 // Takes a control name (e.g. 'quit') and returns the corresponding key code,
    98 // Takes a control name (e.g. 'quit') and returns the corresponding key code,
    99 // if it has been bound.
    99 // if it has been bound.
   100 // Returns -1 if the control has not been bound.
   100 // Returns -1 if the control has not been bound.
   101 function KeyBindToCode(bind: shortstring): LongInt;
   101 function KeyBindToCode(bind: shortstring): LongInt;
   102 var code: LongInt;
   102 var code, index: LongInt;
   103 begin
   103 begin
   104     code:= 0;
   104     index:= 0;
   105     while (code <= cKeyMaxIndex) and (CurrentBinds[code] <> bind) do inc(code);
   105     while (index <= High(CurrentBinds.binds)) and (CurrentBinds.binds[index] <> bind) do inc(index);
   106     if code > cKeyMaxIndex then
   106     if index > High(CurrentBinds.binds) then
   107         // Return error
   107         // Return error
   108         KeyBindToCode:= -1
   108         KeyBindToCode:= -1
   109     else
   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);
   110         KeyBindToCode:= code;
   113         KeyBindToCode:= code;
       
   114     end;
   111 end;
   115 end;
   112 
   116 
   113 // Takes a control name (e.g. 'quit') and returns the corresponding
   117 // Takes a control name (e.g. 'quit') and returns the corresponding
   114 // human-readable key name from SDL.
   118 // human-readable key name from SDL.
   115 // FIXME: Does not work 100% for all keys yet, but at least it no
   119 // FIXME: Does not work 100% for all keys yet, but at least it no
   207     // on OS X it this is expected behaviour
   211     // on OS X it this is expected behaviour
   208     if tkbd[KeyNameToCode('left_meta')] or tkbd[KeyNameToCode('right_meta')] then
   212     if tkbd[KeyNameToCode('left_meta')] or tkbd[KeyNameToCode('right_meta')] then
   209 {$ELSE}
   213 {$ELSE}
   210     // 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
   211     if tkbd[KeyNameToCode('left_ctrl')] or tkbd[KeyNameToCode('right_ctrl')] then
   215     if tkbd[KeyNameToCode('left_ctrl')] or tkbd[KeyNameToCode('right_ctrl')] then
   212         if ((CurrentBinds[KeyNameToCode('left_ctrl')] = '') or
   216         if ((CurrentBinds.indices[KeyNameToCode('left_ctrl')] = 0) or
   213             (CurrentBinds[KeyNameToCode('right_ctrl')] = '')) and
   217             (CurrentBinds.indices[KeyNameToCode('right_ctrl')] = 0)) and
   214             (CurrentBinds[SDLK_w] = '') then
   218             (CurrentBinds.indices[SDLK_w] = 0) then
   215 {$ENDIF}
   219 {$ENDIF}
   216         ParseCommand('forcequit', true);
   220         ParseCommand('forcequit', true);
   217     end;
   221     end;
   218 
   222 
   219 if CurrentBinds[code][0] <> #0 then
   223 if CurrentBinds.indices[code] > 0 then
   220     begin
   224     begin
   221     if (code < cKeyMaxIndex - 2) // means not mouse buttons
   225     if (code < cKeyMaxIndex - 2) // means not mouse buttons
   222         and KeyDown
   226         and KeyDown
   223         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')))
   224         and (CurrentTeam <> nil) 
   233         and (CurrentTeam <> nil) 
   225         and (not CurrentTeam^.ExtDriven) 
   234         and (not CurrentTeam^.ExtDriven) 
   226         then bShowAmmoMenu:= false;
   235         then bShowAmmoMenu:= false;
   227 
   236 
   228     if KeyDown then
   237     if KeyDown then
   229         begin
   238         begin
   230         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
   231 
   240 
   232         if CurrentBinds[code] = 'switch' then
   241         if CurrentBinds.binds[CurrentBinds.indices[code]] = 'switch' then
   233             LocalMessage:= LocalMessage or gmSwitch
   242             LocalMessage:= LocalMessage or gmSwitch
   234         else if CurrentBinds[code] = '+precise' then
   243         else if CurrentBinds.binds[CurrentBinds.indices[code]] = '+precise' then
   235             LocalMessage:= LocalMessage or gmPrecise;
   244             LocalMessage:= LocalMessage or gmPrecise;
   236 
   245 
   237         ParseCommand(CurrentBinds[code], Trusted);
   246         ParseCommand(CurrentBinds.binds[CurrentBinds.indices[code]], Trusted);
   238         if (CurrentTeam <> nil) and (not CurrentTeam^.ExtDriven) and (ReadyTimeLeft > 1) then
   247         if (CurrentTeam <> nil) and (not CurrentTeam^.ExtDriven) and (ReadyTimeLeft > 1) then
   239             ParseCommand('gencmd R', true)
   248             ParseCommand('gencmd R', true)
   240         end
   249         end
   241     else if (CurrentBinds[code][1] = '+') then
   250     else if (CurrentBinds.binds[CurrentBinds.indices[code]][1] = '+') then
   242         begin
   251         begin
   243         if CurrentBinds[code] = '+precise' then
   252         if CurrentBinds.binds[CurrentBinds.indices[code]] = '+precise' then
   244             LocalMessage:= LocalMessage and (not gmPrecise);
   253             LocalMessage:= LocalMessage and (not gmPrecise);
   245         s:= CurrentBinds[code];
   254         s:= CurrentBinds.binds[CurrentBinds.indices[code]];
   246         s[1]:= '-';
   255         s[1]:= '-';
   247         ParseCommand(s, Trusted);
   256         ParseCommand(s, Trusted);
   248         if (CurrentTeam <> nil) and (not CurrentTeam^.ExtDriven) and (ReadyTimeLeft > 1) then
   257         if (CurrentTeam <> nil) and (not CurrentTeam^.ExtDriven) and (ReadyTimeLeft > 1) then
   249             ParseCommand('gencmd R', true)
   258             ParseCommand('gencmd R', true)
   250         end
   259         end
   251     else
   260     else
   252         begin
   261         begin
   253         if CurrentBinds[code] = 'switch' then
   262         if CurrentBinds.binds[CurrentBinds.indices[code]] = 'switch' then
   254             LocalMessage:= LocalMessage and (not gmSwitch)
   263             LocalMessage:= LocalMessage and (not gmSwitch)
   255         end
   264         end
   256     end
   265     end
   257 end;
   266 end;
   258 
   267 
   319 for t:= 0 to cKbdMaxIndex do
   328 for t:= 0 to cKbdMaxIndex do
   320     if tkbd[t] then
   329     if tkbd[t] then
   321         ProcessKey(t, False);
   330         ProcessKey(t, False);
   322 end;
   331 end;
   323 
   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     inc(binds.lastIndex);
       
   343     binds.indices[code]:= binds.lastIndex;
       
   344     binds.binds[binds.lastIndex]:= value
       
   345 end;
   324 
   346 
   325 procedure InitDefaultBinds;
   347 procedure InitDefaultBinds;
   326 var i: Longword;
   348 var i: Longword;
   327 begin
   349 begin
   328     DefaultBinds[KeyNameToCode('escape')]:= 'quit';
   350     RegisterBind(DefaultBinds, 'escape', 'quit');
   329     DefaultBinds[KeyNameToCode(_S'`')]:= 'history';
   351     RegisterBind(DefaultBinds, _S'`', 'history');
   330     DefaultBinds[KeyNameToCode('delete')]:= 'rotmask';
   352     RegisterBind(DefaultBinds, 'delete', 'rotmask');
   331     DefaultBinds[KeyNameToCode('home')]:= 'rottags';
   353     RegisterBind(DefaultBinds, 'home', 'rottags');
   332 
   354 
   333     //numpad
   355     //numpad
   334     //DefaultBinds[265]:= '+volup';
   356     //DefaultBinds[265]:= '+volup';
   335     //DefaultBinds[256]:= '+voldown';
   357     //DefaultBinds[256]:= '+voldown';
   336 
   358 
   337     DefaultBinds[KeyNameToCode(_S'0')]:= '+volup';
   359     RegisterBind(DefaultBinds, _S'0', '+volup');
   338     DefaultBinds[KeyNameToCode(_S'9')]:= '+voldown';
   360     RegisterBind(DefaultBinds, _S'9', '+voldown');
   339     DefaultBinds[KeyNameToCode(_S'8')]:= 'mute';
   361     RegisterBind(DefaultBinds, _S'8', 'mute');
   340     DefaultBinds[KeyNameToCode(_S'c')]:= 'capture';
   362     RegisterBind(DefaultBinds, _S'c', 'capture');
   341     DefaultBinds[KeyNameToCode(_S'r')]:= 'record';
   363     RegisterBind(DefaultBinds, _S'r', 'record');
   342     DefaultBinds[KeyNameToCode(_S'h')]:= 'findhh';
   364     RegisterBind(DefaultBinds, _S'h', 'findhh');
   343     DefaultBinds[KeyNameToCode(_S'p')]:= 'pause';
   365     RegisterBind(DefaultBinds, _S'p', 'pause');
   344     DefaultBinds[KeyNameToCode(_S's')]:= '+speedup';
   366     RegisterBind(DefaultBinds, _S's', '+speedup');
   345     DefaultBinds[KeyNameToCode(_S't')]:= 'chat';
   367     RegisterBind(DefaultBinds, _S't', 'chat');
   346     DefaultBinds[KeyNameToCode(_S'y')]:= 'confirm';
   368     RegisterBind(DefaultBinds, _S'y', 'confirm');
   347 
   369 
   348     DefaultBinds[KeyNameToCode('mousem')]:= 'zoomreset';
   370     RegisterBind(DefaultBinds, 'mousem', 'zoomreset');
   349     DefaultBinds[KeyNameToCode('wheelup')]:= 'zoomin';
   371     RegisterBind(DefaultBinds, 'wheelup', 'zoomin');
   350     DefaultBinds[KeyNameToCode('wheeldown')]:= 'zoomout';
   372     RegisterBind(DefaultBinds, 'wheeldown', 'zoomout');
   351 
   373 
   352     DefaultBinds[KeyNameToCode('f12')]:= 'fullscr';
   374     RegisterBind(DefaultBinds, 'f12', 'fullscr');
   353 
   375 
   354 
   376 
   355     DefaultBinds[KeyNameToCode('mousel')]:= '/put';
   377     RegisterBind(DefaultBinds, 'mousel', '/put');
   356     DefaultBinds[KeyNameToCode('mouser')]:= 'ammomenu';
   378     RegisterBind(DefaultBinds, 'mouser', 'ammomenu');
   357     DefaultBinds[KeyNameToCode('backspace')]:= 'hjump';
   379     RegisterBind(DefaultBinds, 'backspace', 'hjump');
   358     DefaultBinds[KeyNameToCode('tab')]:= 'switch';
   380     RegisterBind(DefaultBinds, 'tab', 'switch');
   359     DefaultBinds[KeyNameToCode('return')]:= 'ljump';
   381     RegisterBind(DefaultBinds, 'return', 'ljump');
   360     DefaultBinds[KeyNameToCode('space')]:= '+attack';
   382     RegisterBind(DefaultBinds, 'space', '+attack');
   361     DefaultBinds[KeyNameToCode('up')]:= '+up';
   383     RegisterBind(DefaultBinds, 'up', '+up');
   362     DefaultBinds[KeyNameToCode('down')]:= '+down';
   384     RegisterBind(DefaultBinds, 'down', '+down');
   363     DefaultBinds[KeyNameToCode('left')]:= '+left';
   385     RegisterBind(DefaultBinds, 'left', '+left');
   364     DefaultBinds[KeyNameToCode('right')]:= '+right';
   386     RegisterBind(DefaultBinds, 'right', '+right');
   365     DefaultBinds[KeyNameToCode('left_shift')]:= '+precise';
   387     RegisterBind(DefaultBinds, 'left_shift', '+precise');
   366 
   388 
   367 
   389 
   368     DefaultBinds[KeyNameToCode('j0a0u')]:= '+left';
   390     RegisterBind(DefaultBinds, 'j0a0u', '+left');
   369     DefaultBinds[KeyNameToCode('j0a0d')]:= '+right';
   391     RegisterBind(DefaultBinds, 'j0a0d', '+right');
   370     DefaultBinds[KeyNameToCode('j0a1u')]:= '+up';
   392     RegisterBind(DefaultBinds, 'j0a1u', '+up');
   371     DefaultBinds[KeyNameToCode('j0a1d')]:= '+down';
   393     RegisterBind(DefaultBinds, 'j0a1d', '+down');
   372     for i:= 1 to 10 do DefaultBinds[KeyNameToCode('f'+IntToStr(i))]:= 'slot '+char(48+i);
   394     for i:= 1 to 10 do RegisterBind(DefaultBinds, 'f'+IntToStr(i), 'slot '+char(48+i));
   373     for i:= 1 to 5  do DefaultBinds[KeyNameToCode(IntToStr(i))]:= 'timer '+IntToStr(i);
   395     for i:= 1 to 5  do RegisterBind(DefaultBinds, IntToStr(i), 'timer '+IntToStr(i));
   374 
   396 
   375     loadBinds('dbind', cPathz[ptConfig] + '/settings.ini');
   397     loadBinds('dbind', cPathz[ptConfig] + '/settings.ini');
   376 end;
   398 end;
   377 
   399 
   378 
   400 
   435 procedure SetBinds(var binds: TBinds);
   457 procedure SetBinds(var binds: TBinds);
   436 var
   458 var
   437     t: LongInt;
   459     t: LongInt;
   438 begin
   460 begin
   439     for t:= 0 to cKbdMaxIndex do
   461     for t:= 0 to cKbdMaxIndex do
   440         if (CurrentBinds[t] <> binds[t]) and tkbd[t] then
   462         if (CurrentBinds.binds[CurrentBinds.indices[t]] <> binds.binds[binds.indices[t]]) and tkbd[t] then
   441             ProcessKey(t, False);
   463             ProcessKey(t, False);
   442 
   464 
   443     CurrentBinds:= binds;
   465     CurrentBinds:= binds;
   444 end;
   466 end;
   445 {$ELSE}
   467 {$ELSE}
   625 end;
   647 end;
   626 
   648 
   627 
   649 
   628 procedure addBind(var binds: TBinds; var id: shortstring);
   650 procedure addBind(var binds: TBinds; var id: shortstring);
   629 var KeyName, Modifier, tmp: shortstring;
   651 var KeyName, Modifier, tmp: shortstring;
   630     i, b: LongInt;
   652     i, code, b: LongInt;
   631 begin
   653 begin
   632 KeyName:= '';
   654 KeyName:= '';
   633 Modifier:= '';
   655 Modifier:= '';
   634 
   656 
   635 if(Pos('mod:', id) <> 0)then
   657 if(Pos('mod:', id) <> 0)then
   649 if b = 0 then
   671 if b = 0 then
   650     OutError(errmsgUnknownVariable + ' "' + id + '"', false)
   672     OutError(errmsgUnknownVariable + ' "' + id + '"', false)
   651 else
   673 else
   652     begin
   674     begin
   653     // add bind: first check if this cmd is already bound, and remove old bind
   675     // add bind: first check if this cmd is already bound, and remove old bind
   654     i:= cKbdMaxIndex;
   676     code:= High(binds.binds);
   655     repeat
   677     repeat
   656         dec(i)
   678         dec(code)
   657     until (i < 0) or (binds[i] = KeyName);
   679     until (code < 0) or (binds.binds[code] = KeyName);
   658     if (i >= 0) then
   680     if (code >= 0) then
   659         binds[i]:= '';
   681     begin
   660 
   682         i:= 0;
   661     binds[b]:= KeyName;
   683         while (i <= High(binds.indices)) and (binds.indices[i] <> code) do inc(i);
       
   684         checkFails(i <= High(binds.indices), 'binds registry inconsistency', true);
       
   685         binds.binds[i]:= '';
       
   686         binds.indices[code]:= 0
       
   687     end else
       
   688     begin
       
   689     inc(binds.lastIndex);
       
   690     checkFails(binds.lastIndex < High(binds.binds), 'too many binds', true);
       
   691     i:= binds.lastIndex
       
   692     end;
       
   693 
       
   694     binds.indices[b]:= i;
       
   695     binds.binds[i]:= KeyName
   662     end
   696     end
   663 end;
   697 end;
   664 
   698 
   665 // Bind that isn't a team bind, but overrides defaultbinds.
   699 // Bind that isn't a team bind, but overrides defaultbinds.
   666 procedure chDefaultBind(var id: shortstring);
   700 procedure chDefaultBind(var id: shortstring);