1 | /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ |
2 | /* If you are missing that file, acquire a complete release at teeworlds.com. */ |
3 | #include "binds.h" |
4 | #include <base/system.h> |
5 | #include <engine/config.h> |
6 | #include <engine/shared/config.h> |
7 | |
8 | #include <game/client/gameclient.h> |
9 | |
10 | static const ColorRGBA gs_BindPrintColor{1.0f, 1.0f, 0.8f, 1.0f}; |
11 | |
12 | bool CBinds::CBindsSpecial::OnInput(const IInput::CEvent &Event) |
13 | { |
14 | // only handle F and composed F binds |
15 | if(((Event.m_Key >= KEY_F1 && Event.m_Key <= KEY_F12) || (Event.m_Key >= KEY_F13 && Event.m_Key <= KEY_F24)) && (Event.m_Key != KEY_F5 || !m_pClient->m_Menus.IsActive())) |
16 | { |
17 | int Mask = CBinds::GetModifierMask(pInput: Input()); |
18 | |
19 | // Look for a composed bind |
20 | bool ret = false; |
21 | if(m_pBinds->m_aapKeyBindings[Mask][Event.m_Key]) |
22 | { |
23 | m_pBinds->GetConsole()->ExecuteLineStroked(Stroke: Event.m_Flags & IInput::FLAG_PRESS, pStr: m_pBinds->m_aapKeyBindings[Mask][Event.m_Key]); |
24 | ret = true; |
25 | } |
26 | // Look for a non composed bind |
27 | if(!ret && m_pBinds->m_aapKeyBindings[0][Event.m_Key]) |
28 | { |
29 | m_pBinds->GetConsole()->ExecuteLineStroked(Stroke: Event.m_Flags & IInput::FLAG_PRESS, pStr: m_pBinds->m_aapKeyBindings[0][Event.m_Key]); |
30 | ret = true; |
31 | } |
32 | |
33 | return ret; |
34 | } |
35 | |
36 | return false; |
37 | } |
38 | |
39 | CBinds::CBinds() |
40 | { |
41 | mem_zero(block: m_aapKeyBindings, size: sizeof(m_aapKeyBindings)); |
42 | m_SpecialBinds.m_pBinds = this; |
43 | } |
44 | |
45 | CBinds::~CBinds() |
46 | { |
47 | for(int i = 0; i < KEY_LAST; i++) |
48 | for(auto &apKeyBinding : m_aapKeyBindings) |
49 | free(ptr: apKeyBinding[i]); |
50 | } |
51 | |
52 | void CBinds::Bind(int KeyId, const char *pStr, bool FreeOnly, int ModifierCombination) |
53 | { |
54 | if(KeyId < 0 || KeyId >= KEY_LAST) |
55 | return; |
56 | |
57 | if(FreeOnly && Get(KeyId, ModifierCombination)[0]) |
58 | return; |
59 | |
60 | free(ptr: m_aapKeyBindings[ModifierCombination][KeyId]); |
61 | m_aapKeyBindings[ModifierCombination][KeyId] = 0; |
62 | |
63 | // skip modifiers for +xxx binds |
64 | if(pStr[0] == '+') |
65 | ModifierCombination = 0; |
66 | |
67 | char aBuf[256]; |
68 | if(!pStr[0]) |
69 | { |
70 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "unbound %s%s (%d)" , GetKeyBindModifiersName(ModifierCombination), Input()->KeyName(Key: KeyId), KeyId); |
71 | } |
72 | else |
73 | { |
74 | int Size = str_length(str: pStr) + 1; |
75 | m_aapKeyBindings[ModifierCombination][KeyId] = (char *)malloc(size: Size); |
76 | str_copy(dst: m_aapKeyBindings[ModifierCombination][KeyId], src: pStr, dst_size: Size); |
77 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "bound %s%s (%d) = %s" , GetKeyBindModifiersName(ModifierCombination), Input()->KeyName(Key: KeyId), KeyId, m_aapKeyBindings[ModifierCombination][KeyId]); |
78 | } |
79 | Console()->Print(Level: IConsole::OUTPUT_LEVEL_ADDINFO, pFrom: "binds" , pStr: aBuf, PrintColor: gs_BindPrintColor); |
80 | } |
81 | |
82 | int CBinds::GetModifierMask(IInput *pInput) |
83 | { |
84 | int Mask = 0; |
85 | static const auto s_aModifierKeys = { |
86 | KEY_LSHIFT, |
87 | KEY_RSHIFT, |
88 | KEY_LCTRL, |
89 | KEY_RCTRL, |
90 | KEY_LALT, |
91 | KEY_RALT, |
92 | KEY_LGUI, |
93 | KEY_RGUI, |
94 | }; |
95 | for(const auto Key : s_aModifierKeys) |
96 | { |
97 | if(pInput->KeyIsPressed(Key)) |
98 | { |
99 | Mask |= GetModifierMaskOfKey(Key); |
100 | } |
101 | } |
102 | |
103 | return Mask; |
104 | } |
105 | |
106 | int CBinds::GetModifierMaskOfKey(int Key) |
107 | { |
108 | switch(Key) |
109 | { |
110 | case KEY_LSHIFT: |
111 | case KEY_RSHIFT: |
112 | return 1 << CBinds::MODIFIER_SHIFT; |
113 | case KEY_LCTRL: |
114 | case KEY_RCTRL: |
115 | return 1 << CBinds::MODIFIER_CTRL; |
116 | case KEY_LALT: |
117 | case KEY_RALT: |
118 | return 1 << CBinds::MODIFIER_ALT; |
119 | case KEY_LGUI: |
120 | case KEY_RGUI: |
121 | return 1 << CBinds::MODIFIER_GUI; |
122 | default: |
123 | return 0; |
124 | } |
125 | } |
126 | |
127 | bool CBinds::OnInput(const IInput::CEvent &Event) |
128 | { |
129 | // don't handle invalid events |
130 | if(Event.m_Key <= KEY_FIRST || Event.m_Key >= KEY_LAST) |
131 | return false; |
132 | |
133 | int Mask = GetModifierMask(pInput: Input()); |
134 | int KeyModifierMask = GetModifierMaskOfKey(Key: Event.m_Key); |
135 | Mask &= ~KeyModifierMask; |
136 | |
137 | bool ret = false; |
138 | const char *pKey = nullptr; |
139 | |
140 | if(m_aapKeyBindings[Mask][Event.m_Key]) |
141 | { |
142 | if(Event.m_Flags & IInput::FLAG_PRESS) |
143 | { |
144 | Console()->ExecuteLineStroked(Stroke: 1, pStr: m_aapKeyBindings[Mask][Event.m_Key]); |
145 | pKey = m_aapKeyBindings[Mask][Event.m_Key]; |
146 | } |
147 | // Have to check for nullptr again because the previous execute can unbind itself |
148 | if(Event.m_Flags & IInput::FLAG_RELEASE && m_aapKeyBindings[Mask][Event.m_Key]) |
149 | Console()->ExecuteLineStroked(Stroke: 0, pStr: m_aapKeyBindings[Mask][Event.m_Key]); |
150 | ret = true; |
151 | } |
152 | |
153 | if(m_aapKeyBindings[0][Event.m_Key] && !ret) |
154 | { |
155 | // When ctrl+shift are pressed (ctrl+shift binds and also the hard-coded ctrl+shift+d, ctrl+shift+g, ctrl+shift+e), ignore other +xxx binds |
156 | if(Event.m_Flags & IInput::FLAG_PRESS && Mask != ((1 << MODIFIER_CTRL) | (1 << MODIFIER_SHIFT)) && Mask != ((1 << MODIFIER_GUI) | (1 << MODIFIER_SHIFT))) |
157 | { |
158 | Console()->ExecuteLineStroked(Stroke: 1, pStr: m_aapKeyBindings[0][Event.m_Key]); |
159 | pKey = m_aapKeyBindings[Mask][Event.m_Key]; |
160 | } |
161 | // Have to check for nullptr again because the previous execute can unbind itself |
162 | if(Event.m_Flags & IInput::FLAG_RELEASE && m_aapKeyBindings[0][Event.m_Key]) |
163 | Console()->ExecuteLineStroked(Stroke: 0, pStr: m_aapKeyBindings[0][Event.m_Key]); |
164 | ret = true; |
165 | } |
166 | |
167 | if(g_Config.m_ClSubTickAiming && pKey) |
168 | { |
169 | if(str_comp(a: "+fire" , b: pKey) == 0 || str_comp(a: "+hook" , b: pKey) == 0) |
170 | { |
171 | m_MouseOnAction = true; |
172 | } |
173 | } |
174 | |
175 | return ret; |
176 | } |
177 | |
178 | void CBinds::UnbindAll() |
179 | { |
180 | for(auto &apKeyBinding : m_aapKeyBindings) |
181 | { |
182 | for(auto &pKeyBinding : apKeyBinding) |
183 | { |
184 | free(ptr: pKeyBinding); |
185 | pKeyBinding = 0; |
186 | } |
187 | } |
188 | } |
189 | |
190 | const char *CBinds::Get(int KeyId, int ModifierCombination) |
191 | { |
192 | if(KeyId > 0 && KeyId < KEY_LAST && m_aapKeyBindings[ModifierCombination][KeyId]) |
193 | return m_aapKeyBindings[ModifierCombination][KeyId]; |
194 | return "" ; |
195 | } |
196 | |
197 | void CBinds::GetKey(const char *pBindStr, char *pBuf, size_t BufSize) |
198 | { |
199 | pBuf[0] = 0; |
200 | for(int Mod = 0; Mod < MODIFIER_COMBINATION_COUNT; Mod++) |
201 | { |
202 | for(int KeyId = 0; KeyId < KEY_LAST; KeyId++) |
203 | { |
204 | const char *pBind = Get(KeyId, ModifierCombination: Mod); |
205 | if(!pBind[0]) |
206 | continue; |
207 | |
208 | if(str_comp(a: pBind, b: pBindStr) == 0) |
209 | { |
210 | if(Mod) |
211 | str_format(buffer: pBuf, buffer_size: BufSize, format: "%s+%s" , GetModifierName(Modifier: Mod), Input()->KeyName(Key: KeyId)); |
212 | else |
213 | str_copy(dst: pBuf, src: Input()->KeyName(Key: KeyId), dst_size: BufSize); |
214 | return; |
215 | } |
216 | } |
217 | } |
218 | } |
219 | |
220 | void CBinds::SetDefaults() |
221 | { |
222 | // set default key bindings |
223 | UnbindAll(); |
224 | Bind(KeyId: KEY_F1, pStr: "toggle_local_console" ); |
225 | Bind(KeyId: KEY_F2, pStr: "toggle_remote_console" ); |
226 | Bind(KeyId: KEY_TAB, pStr: "+scoreboard" ); |
227 | Bind(KeyId: KEY_EQUALS, pStr: "+statboard" ); |
228 | Bind(KeyId: KEY_F10, pStr: "screenshot" ); |
229 | |
230 | Bind(KeyId: KEY_A, pStr: "+left" ); |
231 | Bind(KeyId: KEY_D, pStr: "+right" ); |
232 | |
233 | Bind(KeyId: KEY_SPACE, pStr: "+jump" ); |
234 | Bind(KeyId: KEY_MOUSE_1, pStr: "+fire" ); |
235 | Bind(KeyId: KEY_MOUSE_2, pStr: "+hook" ); |
236 | Bind(KeyId: KEY_LSHIFT, pStr: "+emote" ); |
237 | Bind(KeyId: KEY_RETURN, pStr: "+show_chat; chat all" ); |
238 | Bind(KeyId: KEY_RIGHT, pStr: "spectate_next" ); |
239 | Bind(KeyId: KEY_LEFT, pStr: "spectate_previous" ); |
240 | Bind(KeyId: KEY_RSHIFT, pStr: "+spectate" ); |
241 | |
242 | Bind(KeyId: KEY_1, pStr: "+weapon1" ); |
243 | Bind(KeyId: KEY_2, pStr: "+weapon2" ); |
244 | Bind(KeyId: KEY_3, pStr: "+weapon3" ); |
245 | Bind(KeyId: KEY_4, pStr: "+weapon4" ); |
246 | Bind(KeyId: KEY_5, pStr: "+weapon5" ); |
247 | |
248 | Bind(KeyId: KEY_MOUSE_WHEEL_UP, pStr: "+prevweapon" ); |
249 | Bind(KeyId: KEY_MOUSE_WHEEL_DOWN, pStr: "+nextweapon" ); |
250 | |
251 | Bind(KeyId: KEY_T, pStr: "+show_chat; chat all" ); |
252 | Bind(KeyId: KEY_Y, pStr: "+show_chat; chat team" ); |
253 | Bind(KeyId: KEY_U, pStr: "+show_chat" ); |
254 | Bind(KeyId: KEY_I, pStr: "+show_chat; chat all /c " ); |
255 | |
256 | Bind(KeyId: KEY_F3, pStr: "vote yes" ); |
257 | Bind(KeyId: KEY_F4, pStr: "vote no" ); |
258 | |
259 | Bind(KeyId: KEY_K, pStr: "kill" ); |
260 | Bind(KeyId: KEY_Q, pStr: "say /pause" ); |
261 | Bind(KeyId: KEY_P, pStr: "say /pause" ); |
262 | |
263 | // DDRace |
264 | g_Config.m_ClDDRaceBindsSet = 0; |
265 | SetDDRaceBinds(false); |
266 | } |
267 | |
268 | void CBinds::OnConsoleInit() |
269 | { |
270 | ConfigManager()->RegisterCallback(pfnFunc: ConfigSaveCallback, pUserData: this); |
271 | |
272 | Console()->Register(pName: "bind" , pParams: "s[key] ?r[command]" , Flags: CFGFLAG_CLIENT, pfnFunc: ConBind, pUser: this, pHelp: "Bind key to execute a command or view keybindings" ); |
273 | Console()->Register(pName: "binds" , pParams: "?s[key]" , Flags: CFGFLAG_CLIENT, pfnFunc: ConBinds, pUser: this, pHelp: "Print command executed by this keybinding or all binds" ); |
274 | Console()->Register(pName: "unbind" , pParams: "s[key]" , Flags: CFGFLAG_CLIENT, pfnFunc: ConUnbind, pUser: this, pHelp: "Unbind key" ); |
275 | Console()->Register(pName: "unbindall" , pParams: "" , Flags: CFGFLAG_CLIENT, pfnFunc: ConUnbindAll, pUser: this, pHelp: "Unbind all keys" ); |
276 | |
277 | // default bindings |
278 | SetDefaults(); |
279 | } |
280 | |
281 | void CBinds::ConBind(IConsole::IResult *pResult, void *pUserData) |
282 | { |
283 | CBinds *pBinds = (CBinds *)pUserData; |
284 | const char *pBindStr = pResult->GetString(Index: 0); |
285 | int Modifier; |
286 | int KeyId = pBinds->GetBindSlot(pBindString: pBindStr, pModifierCombination: &Modifier); |
287 | |
288 | if(!KeyId) |
289 | { |
290 | char aBuf[256]; |
291 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "key %s not found" , pBindStr); |
292 | pBinds->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "binds" , pStr: aBuf, PrintColor: gs_BindPrintColor); |
293 | return; |
294 | } |
295 | |
296 | if(pResult->NumArguments() == 1) |
297 | { |
298 | char aBuf[256]; |
299 | const char *pKeyName = pResult->GetString(Index: 0); |
300 | |
301 | if(!pBinds->m_aapKeyBindings[Modifier][KeyId]) |
302 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s (%d) is not bound" , pKeyName, KeyId); |
303 | else |
304 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s (%d) = %s" , pKeyName, KeyId, pBinds->m_aapKeyBindings[Modifier][KeyId]); |
305 | |
306 | pBinds->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "binds" , pStr: aBuf, PrintColor: gs_BindPrintColor); |
307 | return; |
308 | } |
309 | |
310 | pBinds->Bind(KeyId, pStr: pResult->GetString(Index: 1), FreeOnly: false, ModifierCombination: Modifier); |
311 | } |
312 | |
313 | void CBinds::ConBinds(IConsole::IResult *pResult, void *pUserData) |
314 | { |
315 | CBinds *pBinds = (CBinds *)pUserData; |
316 | if(pResult->NumArguments() == 1) |
317 | { |
318 | char aBuf[256]; |
319 | const char *pKeyName = pResult->GetString(Index: 0); |
320 | |
321 | int Modifier; |
322 | int KeyId = pBinds->GetBindSlot(pBindString: pKeyName, pModifierCombination: &Modifier); |
323 | if(!KeyId) |
324 | { |
325 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "key '%s' not found" , pKeyName); |
326 | pBinds->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "binds" , pStr: aBuf, PrintColor: gs_BindPrintColor); |
327 | } |
328 | else |
329 | { |
330 | if(!pBinds->m_aapKeyBindings[Modifier][KeyId]) |
331 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s (%d) is not bound" , pKeyName, KeyId); |
332 | else |
333 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s (%d) = %s" , pKeyName, KeyId, pBinds->m_aapKeyBindings[Modifier][KeyId]); |
334 | |
335 | pBinds->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "binds" , pStr: aBuf, PrintColor: gs_BindPrintColor); |
336 | } |
337 | } |
338 | else if(pResult->NumArguments() == 0) |
339 | { |
340 | char aBuf[1024]; |
341 | for(int i = 0; i < MODIFIER_COMBINATION_COUNT; i++) |
342 | { |
343 | for(int j = 0; j < KEY_LAST; j++) |
344 | { |
345 | if(!pBinds->m_aapKeyBindings[i][j]) |
346 | continue; |
347 | |
348 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s%s (%d) = %s" , GetKeyBindModifiersName(ModifierCombination: i), pBinds->Input()->KeyName(Key: j), j, pBinds->m_aapKeyBindings[i][j]); |
349 | pBinds->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "binds" , pStr: aBuf, PrintColor: gs_BindPrintColor); |
350 | } |
351 | } |
352 | } |
353 | } |
354 | |
355 | void CBinds::ConUnbind(IConsole::IResult *pResult, void *pUserData) |
356 | { |
357 | CBinds *pBinds = (CBinds *)pUserData; |
358 | const char *pKeyName = pResult->GetString(Index: 0); |
359 | int Modifier; |
360 | int KeyId = pBinds->GetBindSlot(pBindString: pKeyName, pModifierCombination: &Modifier); |
361 | |
362 | if(!KeyId) |
363 | { |
364 | char aBuf[256]; |
365 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "key %s not found" , pKeyName); |
366 | pBinds->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "binds" , pStr: aBuf, PrintColor: gs_BindPrintColor); |
367 | return; |
368 | } |
369 | |
370 | pBinds->Bind(KeyId, pStr: "" , FreeOnly: false, ModifierCombination: Modifier); |
371 | } |
372 | |
373 | void CBinds::ConUnbindAll(IConsole::IResult *pResult, void *pUserData) |
374 | { |
375 | CBinds *pBinds = (CBinds *)pUserData; |
376 | pBinds->UnbindAll(); |
377 | } |
378 | |
379 | int CBinds::GetKeyId(const char *pKeyName) |
380 | { |
381 | // check for numeric |
382 | if(pKeyName[0] == '&') |
383 | { |
384 | int i = str_toint(str: pKeyName + 1); |
385 | if(i > 0 && i < KEY_LAST) |
386 | return i; // numeric |
387 | } |
388 | |
389 | // search for key |
390 | for(int i = 0; i < KEY_LAST; i++) |
391 | { |
392 | if(str_comp_nocase(a: pKeyName, b: Input()->KeyName(Key: i)) == 0) |
393 | return i; |
394 | } |
395 | |
396 | return 0; |
397 | } |
398 | |
399 | int CBinds::GetBindSlot(const char *pBindString, int *pModifierCombination) |
400 | { |
401 | *pModifierCombination = MODIFIER_NONE; |
402 | char aMod[32]; |
403 | aMod[0] = '\0'; |
404 | const char *pKey = str_next_token(str: pBindString, delim: "+" , buffer: aMod, buffer_size: sizeof(aMod)); |
405 | while(aMod[0] && *(pKey)) |
406 | { |
407 | if(!str_comp_nocase(a: aMod, b: "shift" )) |
408 | *pModifierCombination |= (1 << MODIFIER_SHIFT); |
409 | else if(!str_comp_nocase(a: aMod, b: "ctrl" )) |
410 | *pModifierCombination |= (1 << MODIFIER_CTRL); |
411 | else if(!str_comp_nocase(a: aMod, b: "alt" )) |
412 | *pModifierCombination |= (1 << MODIFIER_ALT); |
413 | else if(!str_comp_nocase(a: aMod, b: "gui" )) |
414 | *pModifierCombination |= (1 << MODIFIER_GUI); |
415 | else |
416 | return 0; |
417 | |
418 | if(str_find(haystack: pKey + 1, needle: "+" )) |
419 | pKey = str_next_token(str: pKey + 1, delim: "+" , buffer: aMod, buffer_size: sizeof(aMod)); |
420 | else |
421 | break; |
422 | } |
423 | return GetKeyId(pKeyName: *pModifierCombination == MODIFIER_NONE ? aMod : pKey + 1); |
424 | } |
425 | |
426 | const char *CBinds::GetModifierName(int Modifier) |
427 | { |
428 | switch(Modifier) |
429 | { |
430 | case MODIFIER_SHIFT: |
431 | return "shift" ; |
432 | case MODIFIER_CTRL: |
433 | return "ctrl" ; |
434 | case MODIFIER_ALT: |
435 | return "alt" ; |
436 | case MODIFIER_GUI: |
437 | return "gui" ; |
438 | case MODIFIER_NONE: |
439 | default: |
440 | return "" ; |
441 | } |
442 | } |
443 | |
444 | const char *CBinds::GetKeyBindModifiersName(int ModifierCombination) |
445 | { |
446 | static char aModifier[256]; |
447 | aModifier[0] = '\0'; |
448 | for(int k = 1; k < MODIFIER_COUNT; k++) |
449 | { |
450 | if(ModifierCombination & (1 << k)) |
451 | { |
452 | str_append(dst&: aModifier, src: GetModifierName(Modifier: k)); |
453 | str_append(dst&: aModifier, src: "+" ); |
454 | } |
455 | } |
456 | return aModifier; |
457 | } |
458 | |
459 | void CBinds::ConfigSaveCallback(IConfigManager *pConfigManager, void *pUserData) |
460 | { |
461 | CBinds *pSelf = (CBinds *)pUserData; |
462 | |
463 | pConfigManager->WriteLine(pLine: "unbindall" ); |
464 | for(int i = 0; i < MODIFIER_COMBINATION_COUNT; i++) |
465 | { |
466 | for(int j = 0; j < KEY_LAST; j++) |
467 | { |
468 | if(!pSelf->m_aapKeyBindings[i][j]) |
469 | continue; |
470 | |
471 | // worst case the str_escape can double the string length |
472 | int Size = str_length(str: pSelf->m_aapKeyBindings[i][j]) * 2 + 30; |
473 | char *pBuffer = (char *)malloc(size: Size); |
474 | char *pEnd = pBuffer + Size; |
475 | |
476 | str_format(buffer: pBuffer, buffer_size: Size, format: "bind %s%s \"" , GetKeyBindModifiersName(ModifierCombination: i), pSelf->Input()->KeyName(Key: j)); |
477 | // process the string. we need to escape some characters |
478 | char *pDst = pBuffer + str_length(str: pBuffer); |
479 | str_escape(dst: &pDst, src: pSelf->m_aapKeyBindings[i][j], end: pEnd); |
480 | str_append(dst: pBuffer, src: "\"" , dst_size: Size); |
481 | |
482 | pConfigManager->WriteLine(pLine: pBuffer); |
483 | free(ptr: pBuffer); |
484 | } |
485 | } |
486 | } |
487 | |
488 | // DDRace |
489 | |
490 | void CBinds::SetDDRaceBinds(bool FreeOnly) |
491 | { |
492 | if(g_Config.m_ClDDRaceBindsSet < 1) |
493 | { |
494 | Bind(KeyId: KEY_KP_PLUS, pStr: "zoom+" , FreeOnly); |
495 | Bind(KeyId: KEY_KP_MINUS, pStr: "zoom-" , FreeOnly); |
496 | Bind(KeyId: KEY_KP_MULTIPLY, pStr: "zoom" , FreeOnly); |
497 | Bind(KeyId: KEY_PAUSE, pStr: "say /pause" , FreeOnly); |
498 | Bind(KeyId: KEY_UP, pStr: "+jump" , FreeOnly); |
499 | Bind(KeyId: KEY_LEFT, pStr: "+left" , FreeOnly); |
500 | Bind(KeyId: KEY_RIGHT, pStr: "+right" , FreeOnly); |
501 | Bind(KeyId: KEY_LEFTBRACKET, pStr: "+prevweapon" , FreeOnly); |
502 | Bind(KeyId: KEY_RIGHTBRACKET, pStr: "+nextweapon" , FreeOnly); |
503 | Bind(KeyId: KEY_C, pStr: "say /rank" , FreeOnly); |
504 | Bind(KeyId: KEY_V, pStr: "say /info" , FreeOnly); |
505 | Bind(KeyId: KEY_B, pStr: "say /top5" , FreeOnly); |
506 | Bind(KeyId: KEY_S, pStr: "+showhookcoll" , FreeOnly); |
507 | Bind(KeyId: KEY_X, pStr: "toggle cl_dummy 0 1" , FreeOnly); |
508 | Bind(KeyId: KEY_H, pStr: "toggle cl_dummy_hammer 0 1" , FreeOnly); |
509 | Bind(KeyId: KEY_SLASH, pStr: "+show_chat; chat all /" , FreeOnly); |
510 | Bind(KeyId: KEY_PAGEUP, pStr: "toggle cl_overlay_entities 0 100" , FreeOnly); |
511 | Bind(KeyId: KEY_KP_0, pStr: "say /emote normal 999999" , FreeOnly); |
512 | Bind(KeyId: KEY_KP_1, pStr: "say /emote happy 999999" , FreeOnly); |
513 | Bind(KeyId: KEY_KP_2, pStr: "say /emote angry 999999" , FreeOnly); |
514 | Bind(KeyId: KEY_KP_3, pStr: "say /emote pain 999999" , FreeOnly); |
515 | Bind(KeyId: KEY_KP_4, pStr: "say /emote surprise 999999" , FreeOnly); |
516 | Bind(KeyId: KEY_KP_5, pStr: "say /emote blink 999999" , FreeOnly); |
517 | Bind(KeyId: KEY_MOUSE_3, pStr: "+spectate" , FreeOnly); |
518 | Bind(KeyId: KEY_MINUS, pStr: "spectate_previous" , FreeOnly); |
519 | Bind(KeyId: KEY_EQUALS, pStr: "spectate_next" , FreeOnly); |
520 | } |
521 | |
522 | g_Config.m_ClDDRaceBindsSet = 1; |
523 | } |
524 | |