1 /*******************************************************************
2 *
3 * DESCRIPTION: consbind.cpp
4 *
5 * Ability to kind keystrokes to strings so they appear in the
6 * console when you hit the key. Initial implementation went through
7 * the WM_KEYDOWN hook so that we get debouncing and typematic action
8 * for free; subsequently added an implementation based on the KeyboadInput[]
9 * array.
10 *
11 * AUTHOR: David Malcolm
12 *
13 * HISTORY: Created 6/4/98
14 *
15 *******************************************************************/
16
17 /* Includes ********************************************************/
18 #include <ctype.h>
19
20 #include "3dc.h"
21 #include "consbind.hpp"
22
23 #if KeyBindingUses_KEY_ID
24 #include "iofocus.h"
25 #include "scstring.hpp"
26 #include "strtab.hpp"
27 #endif
28
29
30 #define UseLocalAssert Yes
31 #include "ourasert.h"
32 #include "avp_menus.h"
33
34 /* Version settings ************************************************/
35
36 /* Constants *******************************************************/
37 #if KeyBindingUses_WM_KEYDOWN
38 #define MAX_VALUE_BINDABLE_KEY (VK_DIVIDE)
39 #endif
40
41 #if KeyBindingUses_KEY_ID
42 #define MAX_VALUE_BINDABLE_KEY (MAX_NUMBER_OF_INPUT_KEYS)
43 #endif
44 /* Macros **********************************************************/
45
46 /* Imported function prototypes ************************************/
47
48 /* Imported data ***************************************************/
49 #ifdef __cplusplus
50 extern "C"
51 {
52 #endif
53 extern unsigned char KeyboardInput[];
54 extern unsigned char DebouncedKeyboardInput[];
55
56 #ifdef __cplusplus
57 };
58 #endif
59
60
61
62 /* Exported globals ************************************************/
63
64 /* Internal type definitions ***************************************/
65 typedef enum TEXTSTRING_ID TextID;
66
67 /* Internal function prototypes ************************************/
68
69 /* Internal globals ************************************************/
70
71 /* Exported function definitions ***********************************/
72 // class KeyBinding
73 // public:
74
75 // static
76 void
ParseBindCommand(ProjChar * pProjCh_ToParse)77 KeyBinding :: ParseBindCommand
78 (
79 ProjChar* pProjCh_ToParse
80 )
81 {
82 GLOBALASSERT(pProjCh_ToParse);
83
84 BindableKey theKey;
85 ProjChar* pProjCh_FollowingTheKey;
86
87 if
88 (
89 KeyBinding :: ParseBindCommand
90 (
91 theKey, // BindableKey& theKey_Out,
92 &pProjCh_FollowingTheKey, // ProjChar** ppProjCh_Out,
93 // returns where in the input string to continue processing
94
95 pProjCh_ToParse // ProjChar* pProjCh_In
96 )
97 )
98 {
99 SCString* pSCString_ToBind = new SCString(pProjCh_FollowingTheKey);
100
101 // Create the KeyBinding object:
102 KeyBinding* pNewBinding;
103 pNewBinding = new KeyBinding
104 (
105 theKey,
106 pSCString_ToBind
107 );
108
109 // Feedback:
110 {
111 SCString* pSCString_1 = new SCString("BOUND \"");
112 // LOCALISEME
113
114 SCString* pSCString_2 = new SCString("\" TO ");
115
116 SCString* pSCString_3 = MakeStringForKey
117 (
118 theKey
119 );
120
121 SCString* pSCString_Feedback = new SCString
122 (
123 pSCString_1,
124 pSCString_ToBind,
125 pSCString_2,
126 pSCString_3
127 );
128
129 pSCString_Feedback -> SendToScreen();
130
131 pSCString_Feedback -> R_Release();
132 pSCString_3 -> R_Release();
133 pSCString_2 -> R_Release();
134 pSCString_1 -> R_Release();
135 }
136
137 pSCString_ToBind -> R_Release();
138 }
139 else
140 {
141 // Can't recognise which key is to be bound to;
142 // provide an error message
143 // UNWRITTEN
144 }
145 }
146
147 // static
148 void
ParseUnbindCommand(ProjChar * pProjCh_ToParse)149 KeyBinding :: ParseUnbindCommand
150 (
151 ProjChar* pProjCh_ToParse
152 )
153 {
154 GLOBALASSERT(pProjCh_ToParse);
155
156 // Iterate through leading whitespace:
157 {
158 while
159 (
160 *pProjCh_ToParse
161 )
162 {
163 // LOCALISEME:
164 if (!isspace(*pProjCh_ToParse))
165 {
166 break;
167 }
168 pProjCh_ToParse++;
169 }
170 }
171
172 // Scan through the string, trying to find matches against strings for keys
173 // We will use the longest match:
174 {
175 OurBool bGotMatch = No;
176 unsigned int LongestMatch = 0;
177 BindableKey theKey_ToUnbind = (BindableKey)0;
178
179 for (int i=0;i<MAX_VALUE_BINDABLE_KEY; i++)
180 {
181 BindableKey theKey = (BindableKey)i;
182
183 SCString* pSCString_TestKey = MakeStringForKey(theKey);
184
185 unsigned int LengthOfTestString = pSCString_TestKey -> GetNumChars();
186
187 if (LengthOfTestString > 0)
188 {
189 if
190 (
191 0 == _strnicmp
192 (
193 pSCString_TestKey -> pProjCh(),
194 pProjCh_ToParse,
195 LengthOfTestString
196 )
197 // LOCALISEME
198 )
199 {
200 // Then we have a match; see if it's longer than
201 // what's come before...
202 if (LengthOfTestString>LongestMatch)
203 {
204 LongestMatch = LengthOfTestString;
205
206 theKey_ToUnbind = theKey;
207 bGotMatch = Yes;
208
209 }
210 }
211 }
212
213 pSCString_TestKey -> R_Release();
214 }
215
216 if (bGotMatch)
217 {
218 // Then we must get rid of all bindings with this as their key:
219 for
220 (
221 LIF<KeyBinding*> oi(&List_pKeyBindings);
222 !oi . done();
223 )
224 {
225 GLOBALASSERT(oi());
226 if ( oi() -> theKey == theKey_ToUnbind )
227 {
228 oi . delete_current();
229 }
230 else
231 {
232 oi . next();
233 }
234 }
235 }
236 }
237 }
238
239 #if 0
240 // static
241 void
242 KeyBinding :: AttemptToBind
243 (
244 SCString* pSCString_Key, // description of key
245 SCString* pSCString_ToBind // string to be bound
246 )
247 {
248 /* PRECONDITION */
249 {
250 GLOBALASSERT( pSCString_Key );
251 GLOBALASSERT( pSCString_ToBind );
252 }
253
254 /* CODE */
255 {
256 BindableKey theBindableKey_ToUse;
257
258 if
259 (
260 !bGetKeyForString
261 (
262 theBindableKey_ToUse, // BindableKey& theKey_Out,
263 pSCString_Key -> pProjCh()
264 )
265 )
266 {
267 // Can't recognise which key is to be bound to;
268 // provide an error message
269 ErrorDontRecogniseKey(pSCString_Key);
270
271 return;
272 }
273
274 // Create the KeyBinding object:
275 new KeyBinding
276 (
277 theBindableKey_ToUse,
278 pSCString_ToBind
279 );
280 }
281 }
282
283 // static
284 void
285 KeyBinding :: AttemptToUnbind
286 (
287 SCString* pSCString_Key // description of key
288 )
289 {
290 /* PRECONDITION */
291 {
292 GLOBALASSERT( pSCString_Key );
293 }
294
295 /* CODE */
296 {
297 BindableKey theBindableKey_ToUse;
298
299 if
300 (
301 !bGetKeyForString
302 (
303 theBindableKey_ToUse, // BindableKey& theKey_Out,
304 pSCString_Key -> pProjCh()
305 )
306 )
307 {
308 // Can't recognise which key is to be bound to;
309 // provide an error message
310 ErrorDontRecogniseKey(pSCString_Key);
311
312 return;
313 }
314
315 // Find and remove any bindings to that key; note the number:
316
317 // Provide feedback:
318 }
319 }
320 #endif
321
322
323 // static
324 void
UnbindAll(void)325 KeyBinding :: UnbindAll(void)
326 {
327 SCString* pSCString_Feedback = new SCString("DESTROYING ALL KEY BINDINGS");
328 // LOCALISEME
329
330 pSCString_Feedback -> SendToScreen();
331
332 pSCString_Feedback -> R_Release();
333
334 while
335 (
336 List_pKeyBindings . size() > 0
337 )
338 {
339 delete List_pKeyBindings . first_entry();
340 // The destructor for the KeyBinding will remove
341 // it from the list and hence the list will shrink.
342 }
343 }
344
345 // static
346 void
ListAllBindings(void)347 KeyBinding :: ListAllBindings(void)
348 {
349 SCString* pSCString_Feedback = new SCString("LIST OF ALL KEY BINDINGS:");
350 // LOCALISEME
351
352 pSCString_Feedback -> SendToScreen();
353
354 pSCString_Feedback -> R_Release();
355
356 for
357 (
358 CLIF<KeyBinding*> oi(&List_pKeyBindings);
359 !oi . done();
360 oi . next()
361 )
362 {
363 GLOBALASSERT(oi());
364 oi() -> ListThis();
365 }
366 }
367
368 // static
WriteToConfigFile(char * Filename)369 void KeyBinding :: WriteToConfigFile(char* Filename)
370 {
371 // overwrites the file with a batch file that'll
372 // restore current bindings
373
374 GLOBALASSERT(Filename);
375
376 FILE* pFile = OpenGameFile(Filename, FILEMODE_WRITEONLY, FILETYPE_CONFIG);
377
378 if (!pFile)
379 {
380 return;
381 // and don't destroy the bindings, since we won't
382 // restore them next time into game
383 }
384
385 fprintf(pFile,"#This file generated by AVP\n");
386 // LOCALISEME
387
388 for
389 (
390 LIF<KeyBinding*> oi(&List_pKeyBindings);
391 !oi.done();
392 oi.next()
393 )
394 {
395 SCString* pSCString_Key = MakeStringForKey
396 (
397 oi() -> theKey
398 );
399
400 fprintf
401 (
402 pFile,
403 "BIND %s %s\n",
404 pSCString_Key -> pProjCh(),
405 oi() -> pSCString_ToOutput -> pProjCh()
406 );
407
408 pSCString_Key->R_Release();
409 }
410
411 fclose(pFile);
412
413 // Destroy all the current bindings so we don't get a duplicate
414 // set next time the batch file fires:
415 {
416 while
417 (
418 List_pKeyBindings . size() > 0
419 )
420 {
421 delete List_pKeyBindings . first_entry();
422 // The destructor for the KeyBinding will remove
423 // it from the list and hence the list will shrink.
424 }
425 }
426 }
427
428
429 #if KeyBindingUses_WM_KEYDOWN
430 // static
431 void
Process_WM_KEYDOWN(WPARAM wParam)432 KeyBinding :: Process_WM_KEYDOWN
433 (
434 WPARAM wParam
435 )
436 {
437
438 // Iterate through the list, finding matches.
439 // We must process the matching objects later, in case they are bound to things
440 // which modify the list. So we built a list of pending SCString*'s.
441 // (so BIND X UNBIND X won't kill the program. I hope)
442
443 // The list of pending SCStrings has been made static to the class in an attempt to
444 // optimise this function
445
446 // Ensure it starts off empty (which it would if it was a local):
447 GLOBALASSERT( 0 == PendingList . NumEntries() );
448
449 for
450 (
451 LIF<KeyBinding*>oi(&List_pKeyBindings);
452 !oi.done();
453 oi.next()
454 )
455 {
456 // Note that the BindableKey type is type-equal to WPARAM if this function
457 // exists:
458 if
459 (
460 oi() -> theKey == wParam
461 )
462 {
463 // Add _the_string_ to the pending list (with a reference)
464 // The reference is added by the RefList template, and this ensures
465 // the string stays alive whatever that pesky user does:
466 GLOBALASSERT( oi() -> pSCString_ToOutput );
467 PendingList . AddToEnd
468 (
469 *( oi() -> pSCString_ToOutput )
470 );
471
472 if (bEcho)
473 {
474 oi() -> pSCString_ToOutput -> SendToScreen();
475 }
476 }
477 }
478
479 // Iterate through the pending list, destructively reading the
480 // "references" from the front:
481 {
482 SCString* pSCString;
483
484 // The assignment in this boolean expression is deliberate:
485 while
486 (
487 NULL != (pSCString = PendingList . GetYourFirst())
488 )
489 {
490 pSCString -> ProcessAnyCheatCodes();
491 pSCString -> R_Release();
492 }
493 }
494
495 // Ensure the pending list finishes off empty
496 // (since we're pretending it's a local variable):
497 GLOBALASSERT( 0 == PendingList . NumEntries() );
498
499 }
500 #endif
501
502 #if KeyBindingUses_KEY_ID
503 // static
504 void
Maintain(void)505 KeyBinding :: Maintain(void)
506 {
507 // Only process if we're in a running-around type of mode
508 // rather than typing at the console:
509 if
510 (
511 IOFOCUS_AcceptControls()
512 )
513 {
514 // Iterate through the list, finding matches.
515 // We must process the matching objects later, in case they are bound to things
516 // which modify the list. So we built a list of pending SCString*'s.
517 // (so BIND X UNBIND X won't kill the program. I hope)
518
519 // The list of pending SCStrings has been made static to the class in an attempt to
520 // optimise this function
521
522 // Ensure it starts off empty (which it would if it was a local):
523 GLOBALASSERT( 0 == PendingList . NumEntries() );
524
525 for
526 (
527 LIF<KeyBinding*>oi(&List_pKeyBindings);
528 !oi.done();
529 oi.next()
530 )
531 {
532 // Note that the BindableKey type is type-equal to enum KEY_ID if this function
533 // exists:
534 if
535 (
536 DebouncedKeyboardInput[ oi() -> theKey ]
537 )
538 {
539 // Add _the_string_ to the pending list (with a reference)
540 // The reference is added by the RefList template, and this ensures
541 // the string stays alive whatever that pesky user does:
542 GLOBALASSERT( oi() -> pSCString_ToOutput );
543 PendingList . AddToEnd
544 (
545 *( oi() -> pSCString_ToOutput )
546 );
547
548 if (bEcho)
549 {
550 oi() -> pSCString_ToOutput -> SendToScreen();
551 }
552 }
553 }
554
555 // Iterate through the pending list, destructively reading the
556 // "references" from the front:
557 {
558 SCString* pSCString;
559
560 // The assignment in this boolean expression is deliberate:
561 while
562 (
563 NULL != (pSCString = PendingList . GetYourFirst())
564 )
565 {
566 pSCString -> ProcessAnyCheatCodes();
567 pSCString -> R_Release();
568 }
569 }
570
571 // Ensure the pending list finishes off empty
572 // (since we're pretending it's a local variable):
573 GLOBALASSERT( 0 == PendingList . NumEntries() );
574 }
575 }
576 #endif
577
578
579 // private:
580 // Private ctor/dtor; to be called only by static fns of the class:
KeyBinding(BindableKey theKey_ToUse,SCString * pSCString_ToBind)581 KeyBinding :: KeyBinding
582 (
583 BindableKey theKey_ToUse,
584 SCString* pSCString_ToBind
585 ) : theKey(theKey_ToUse),
586 pSCString_ToOutput(pSCString_ToBind)
587 {
588 GLOBALASSERT(pSCString_ToOutput);
589
590 pSCString_ToOutput -> R_AddRef();
591
592 List_pKeyBindings . add_entry(this);
593 }
594
~KeyBinding()595 KeyBinding :: ~KeyBinding()
596 {
597 List_pKeyBindings . delete_entry(this);
598
599 pSCString_ToOutput -> R_Release();
600 }
601
602 #if 0
603 // static
604 OurBool
605 KeyBinding :: bGetKeyForString
606 (
607 BindableKey& theKey_Out,
608 const ProjChar* const pProjCh_In
609 )
610 {
611 #if KeyBindingUses_WM_KEYDOWN
612 {
613 // takes an input string and tries to figure out
614 // what the corresponding WPARAM would be...
615 // Returns truth if it manages to get a sensible value
616 // into the output area.
617
618 GLOBALASSERT( pProjCh_In );
619
620 #if 1
621 theKey_Out = pProjCh_In[0];
622 return Yes;
623 // LOCALISEME
624 #else
625
626 return No;
627 // for now
628 #endif
629 }
630 #endif
631
632 #if KeyBindingUses_KEY_ID
633 {
634 theKey_Out = KEY_NUMPADDEL;
635 return Yes;
636 // for now
637 }
638 #endif
639 }
640 #endif
641
642 // static
643 void
ErrorDontRecogniseKey(SCString * pSCString_Key)644 KeyBinding :: ErrorDontRecogniseKey( SCString* pSCString_Key )
645 {
646 GLOBALASSERT( pSCString_Key );
647
648 SCString* pSCString_1 = new SCString("UNRECOGNISED KEY: \"");
649 SCString* pSCString_2 = new SCString("\"");
650 // LOCALISEME
651
652 SCString* pSCString_Feedback = new SCString
653 (
654 pSCString_1,
655 pSCString_Key,
656 pSCString_2
657 );
658
659 pSCString_Feedback -> SendToScreen();
660
661 pSCString_Feedback -> R_Release();
662 pSCString_2 -> R_Release();
663 pSCString_1 -> R_Release();
664 }
665
666 void
ListThis(void) const667 KeyBinding :: ListThis(void) const
668 {
669 // used by ListAllBindings()
670 SCString* pSCString_1 = MakeStringForKey(theKey);
671 SCString* pSCString_2 = new SCString(" -> \"");
672 // LOCALISEME
673 SCString* pSCString_3 = new SCString("\"");
674
675 SCString* pSCString_Feedback = new SCString
676 (
677 pSCString_1,
678 pSCString_2,
679 pSCString_ToOutput,
680 pSCString_3
681 );
682
683 pSCString_Feedback -> SendToScreen();
684
685 pSCString_Feedback -> R_Release();
686 pSCString_3 -> R_Release();
687 pSCString_2 -> R_Release();
688 pSCString_1 -> R_Release();
689
690 }
691
692
GetKeyLabel(int inPhysicalKey,TextID & outTextID)693 static int GetKeyLabel(int inPhysicalKey, TextID& outTextID)
694 {
695 // takes a physical method key and attempts to find a text
696 // string to use for it, returning whether it does.
697 // If it fails, output area is untouched
698 if (inPhysicalKey>=KEY_LEFT && inPhysicalKey<=KEY_MOUSEWHEELDOWN)
699 {
700 outTextID = (enum TEXTSTRING_ID) (TEXTSTRING_KEYS_LEFT + (inPhysicalKey-KEY_LEFT));
701 return Yes;
702 }
703 else return No;
704
705 #if 0
706 switch (inPhysicalKey)
707 {
708 case KEY_UP: outTextID = TEXTSTRING_KEYS_UP; return Yes;
709 case KEY_DOWN: outTextID = TEXTSTRING_KEYS_DOWN; return Yes;
710 case KEY_LEFT: outTextID = TEXTSTRING_KEYS_LEFT; return Yes;
711 case KEY_RIGHT: outTextID = TEXTSTRING_KEYS_RIGHT; return Yes;
712 case KEY_CR: outTextID = TEXTSTRING_KEYS_RETURN; return Yes;
713 case KEY_TAB: outTextID = TEXTSTRING_KEYS_TAB; return Yes;
714 case KEY_INS: outTextID = TEXTSTRING_KEYS_INSERT; return Yes;
715 case KEY_DEL: outTextID = TEXTSTRING_KEYS_DELETE; return Yes;
716 case KEY_END: outTextID = TEXTSTRING_KEYS_END; return Yes;
717 case KEY_HOME: outTextID = TEXTSTRING_KEYS_HOME; return Yes;
718 case KEY_PAGEUP: outTextID = TEXTSTRING_KEYS_PGUP; return Yes;
719 case KEY_PAGEDOWN: outTextID = TEXTSTRING_KEYS_PGDOWN; return Yes;
720 case KEY_BACKSPACE: outTextID = TEXTSTRING_KEYS_BACKSP; return Yes;
721 case KEY_COMMA: outTextID = TEXTSTRING_KEYS_COMMA; return Yes;
722 case KEY_FSTOP: outTextID = TEXTSTRING_KEYS_PERIOD; return Yes;
723 case KEY_SPACE: outTextID = TEXTSTRING_KEYS_SPACE; return Yes;
724 case KEY_LMOUSE: outTextID = TEXTSTRING_KEYS_LMOUSE; return Yes;
725 case KEY_RMOUSE: outTextID = TEXTSTRING_KEYS_RMOUSE; return Yes;
726 case KEY_LEFTALT: outTextID = TEXTSTRING_KEYS_LALT; return Yes;
727 case KEY_RIGHTALT: outTextID = TEXTSTRING_KEYS_RALT; return Yes;
728 case KEY_LEFTCTRL: outTextID = TEXTSTRING_KEYS_LCTRL; return Yes;
729 case KEY_RIGHTCTRL: outTextID = TEXTSTRING_KEYS_RCTRL; return Yes;
730 case KEY_LEFTSHIFT: outTextID = TEXTSTRING_KEYS_LSHIFT; return Yes;
731 case KEY_RIGHTSHIFT: outTextID = TEXTSTRING_KEYS_RSHIFT; return Yes;
732 case KEY_CAPS: outTextID = TEXTSTRING_KEYS_CAPS; return Yes;
733 case KEY_NUMLOCK: outTextID = TEXTSTRING_KEYS_NUMLOCK; return Yes;
734 case KEY_SCROLLOK: outTextID = TEXTSTRING_KEYS_SCRLOCK; return Yes;
735 case KEY_NUMPAD0: outTextID = TEXTSTRING_KEYS_PAD0; return Yes;
736 case KEY_NUMPAD1: outTextID = TEXTSTRING_KEYS_PAD1; return Yes;
737 case KEY_NUMPAD2: outTextID = TEXTSTRING_KEYS_PAD2; return Yes;
738 case KEY_NUMPAD3: outTextID = TEXTSTRING_KEYS_PAD3; return Yes;
739 case KEY_NUMPAD4: outTextID = TEXTSTRING_KEYS_PAD4; return Yes;
740 case KEY_NUMPAD5: outTextID = TEXTSTRING_KEYS_PAD5; return Yes;
741 case KEY_NUMPAD6: outTextID = TEXTSTRING_KEYS_PAD6; return Yes;
742 case KEY_NUMPAD7: outTextID = TEXTSTRING_KEYS_PAD7; return Yes;
743 case KEY_NUMPAD8: outTextID = TEXTSTRING_KEYS_PAD8; return Yes;
744 case KEY_NUMPAD9: outTextID = TEXTSTRING_KEYS_PAD9; return Yes;
745 case KEY_NUMPADSUB: outTextID = TEXTSTRING_KEYS_PADSUB; return Yes;
746 case KEY_NUMPADADD: outTextID = TEXTSTRING_KEYS_PADADD; return Yes;
747 case KEY_NUMPADDEL: outTextID = TEXTSTRING_KEYS_PADDEL; return Yes;
748 default: return No;
749 }
750 #endif
751 }
752
GetMethodString(BindableKey inPhysicalKey)753 static SCString* GetMethodString(BindableKey inPhysicalKey)
754 {
755 TextID theTextID;
756
757 if
758 (
759 GetKeyLabel
760 (
761 inPhysicalKey,
762 theTextID // TextID& outTextID
763 )
764 )
765 {
766 return &StringTable :: GetSCString(theTextID);
767 }
768 else
769 {
770 ProjChar theProjChar[2];
771
772 if (inPhysicalKey >= KEY_A && inPhysicalKey <= KEY_Z)
773 {
774 theProjChar[0] = ProjChar(int(inPhysicalKey) - KEY_A + 'A');
775 }
776 else if (inPhysicalKey >= KEY_0 && inPhysicalKey <= KEY_9)
777 {
778 theProjChar[0] = ProjChar(int(inPhysicalKey) - KEY_0 + '0');
779 }
780 else
781 {
782 theProjChar[0] = 0;
783 }
784
785 theProjChar[1] = 0;
786
787 return new SCString(theProjChar);
788 }
789 }
790
791 // static
792 SCString*
MakeStringForKey(BindableKey theKey)793 KeyBinding :: MakeStringForKey
794 (
795 BindableKey theKey
796 )
797 {
798 #if KeyBindingUses_WM_KEYDOWN
799 {
800 ProjChar tempProjCh[2];
801
802 tempProjCh[0] = (ProjChar)theKey;
803 tempProjCh[1] = 0;
804 // LOCALISEME
805
806
807 return new SCString(&tempProjCh[0]);
808 }
809 #endif
810
811 #if KeyBindingUses_KEY_ID
812 {
813 return GetMethodString(theKey);
814 }
815 #endif
816 }
817
818 // static
ParseBindCommand(BindableKey & theKey_Out,ProjChar ** ppProjCh_Out,ProjChar * pProjCh_In)819 OurBool KeyBinding :: ParseBindCommand
820 (
821 BindableKey& theKey_Out,
822 ProjChar** ppProjCh_Out,
823 // returns where in the input string to continue processing
824
825 ProjChar* pProjCh_In
826 )
827 {
828 // returns Yes if it understands the binding and fills out the output
829
830 GLOBALASSERT( ppProjCh_Out );
831 GLOBALASSERT( pProjCh_In );
832
833 // Iterate through leading whitespace:
834 {
835 while
836 (
837 *pProjCh_In
838 )
839 {
840 // LOCALISEME:
841 if (!isspace(*pProjCh_In))
842 {
843 break;
844 }
845 pProjCh_In++;
846 }
847 }
848
849 // Scan through the string, trying to find matches against strings for keys
850 // We will use the longest match:
851 {
852 OurBool bGotMatch = No;
853 unsigned int LongestMatch = 0;
854
855 for (int i=0;i<MAX_VALUE_BINDABLE_KEY; i++)
856 {
857 BindableKey theKey = (BindableKey)i;
858
859 SCString* pSCString_TestKey = MakeStringForKey(theKey);
860
861 unsigned int LengthOfTestString = pSCString_TestKey -> GetNumChars();
862
863 if (LengthOfTestString > 0)
864 {
865 if
866 (
867 0 == _strnicmp
868 (
869 pSCString_TestKey -> pProjCh(),
870 pProjCh_In,
871 LengthOfTestString
872 )
873 // LOCALISEME
874 )
875 {
876 // Then we have a match; see if it's longer than
877 // what's come before...
878 if (LengthOfTestString>LongestMatch)
879 {
880 LongestMatch = LengthOfTestString;
881
882 theKey_Out = theKey;
883 *ppProjCh_Out = pProjCh_In + LengthOfTestString;
884 // Continue processing after the string
885 bGotMatch = Yes;
886
887 }
888 }
889 }
890
891 pSCString_TestKey -> R_Release();
892 }
893
894 if (bGotMatch)
895 {
896 // Strip away whitespace following the key string:
897 {
898 while (**ppProjCh_Out)
899 {
900 // LOCALISEME:
901 if (!isspace(**ppProjCh_Out))
902 {
903 break;
904 }
905 (*ppProjCh_Out)++;
906 }
907 }
908 }
909
910 return bGotMatch;
911 }
912
913 }
914
915
916
917 // private:
918 // Maintain a static list of all of objects of the class:
919 // static
920 List<KeyBinding*> KeyBinding :: List_pKeyBindings;
921
922 // static
923 RefList<SCString> KeyBinding :: PendingList;
924
925 // public:
926 // static
927 int KeyBinding :: bEcho = No;
928
CONSBIND_WriteKeyBindingsToConfigFile(void)929 void CONSBIND_WriteKeyBindingsToConfigFile(void)
930 {
931 #if !(PREDATOR_DEMO|MARINE_DEMO||ALIEN_DEMO||DEATHMATCH_DEMO)
932 KeyBinding :: WriteToConfigFile("config.cfg");
933 #endif
934 }
935
936
937 /* Internal function definitions ***********************************/
938