Changed Python _getattr/_setattr methods to use const STR_String& instead of char...
[blender.git] / source / gameengine / GameLogic / SCA_KeyboardSensor.cpp
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  * Sensor for keyboard input
32  */
33 #include "SCA_KeyboardSensor.h"
34 #include "SCA_KeyboardManager.h"
35 #include "SCA_LogicManager.h"
36 #include "StringValue.h"
37 #include "SCA_IInputDevice.h"
38
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42
43 /* ------------------------------------------------------------------------- */
44 /* Native functions                                                          */
45 /* ------------------------------------------------------------------------- */
46
47 SCA_KeyboardSensor::SCA_KeyboardSensor(SCA_KeyboardManager* keybdmgr,
48                                                                            short int hotkey,
49                                                                            short int qual,
50                                                                            short int qual2,
51                                                                            bool bAllKeys,
52                                                                            const STR_String& targetProp,
53                                                                            const STR_String& toggleProp,
54                                                                            SCA_IObject* gameobj,
55                                                                            PyTypeObject* T )
56         :SCA_ISensor(gameobj,keybdmgr,T),
57          m_pKeyboardMgr(keybdmgr),
58          m_hotkey(hotkey),
59          m_qual(qual),
60          m_qual2(qual2),
61          m_bAllKeys(bAllKeys),
62          m_targetprop(targetProp),
63          m_toggleprop(toggleProp)
64 {
65         
66 //      SetDrawColor(0xff0000ff);
67         m_val=0;
68 }
69
70
71
72 SCA_KeyboardSensor::~SCA_KeyboardSensor()
73 {
74 }
75
76
77
78 CValue* SCA_KeyboardSensor::GetReplica()
79 {
80         CValue* replica = new SCA_KeyboardSensor(*this);
81         // this will copy properties and so on...
82         CValue::AddDataToReplica(replica);
83
84         return replica;
85 }
86
87
88
89 short int SCA_KeyboardSensor::GetHotkey()
90 {
91         return m_hotkey;
92 }
93
94
95
96 bool SCA_KeyboardSensor::IsPositiveTrigger()
97
98         bool result = (m_val != 0);
99
100         if (m_invert)
101                 result = !result;
102                 
103         return result;
104 }
105
106
107
108 bool SCA_KeyboardSensor::TriggerOnAllKeys()
109
110         return m_bAllKeys;
111 }
112
113
114
115 bool SCA_KeyboardSensor::Evaluate(CValue* eventval)
116 {
117         bool result    = false;
118         SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice();
119         
120         //      cerr << "SCA_KeyboardSensor::Eval event, sensing for "<< m_hotkey << " at device " << inputdev << "\n";
121
122         /* See if we need to do logging: togPropState exists and is
123      * different from 0 */
124         CValue* myparent = GetParent();
125         CValue* togPropState = myparent->GetProperty(m_toggleprop);
126         if (togPropState &&
127                 (((int)togPropState->GetNumber()) != 0) )
128         {
129                 LogKeystrokes();
130         }
131
132
133
134         /* Now see whether events must be bounced. */
135         if (m_bAllKeys)
136         {
137                 bool justactivated = false;
138                 bool justreleased = false;
139
140                 for (int i=SCA_IInputDevice::KX_BEGINKEY ; i< SCA_IInputDevice::KX_ENDKEY;i++)
141                 {
142                         const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i);
143                         if (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED)
144                         {
145                                 justactivated = true;
146                         }
147                         if (inevent.m_status == SCA_InputEvent::KX_JUSTRELEASED)
148                         {
149                                 justreleased = true;
150                         }
151                 }
152
153                 if (justactivated)
154                 {
155                         m_val=1;
156                         result = true;
157                 } else
158                 {
159                         if (justreleased)
160                         {
161                                 m_val=0;
162                                 result = true;
163                         }
164                 }
165
166
167         } else
168         {
169
170         //              cerr << "======= SCA_KeyboardSensor::Evaluate:: peeking at key status" << endl;
171                 const SCA_InputEvent & inevent = inputdev->GetEventValue(
172                         (SCA_IInputDevice::KX_EnumInputs) m_hotkey);
173         
174         //              cerr << "======= SCA_KeyboardSensor::Evaluate:: status: " << inevent.m_status << endl;
175
176                 if (inevent.m_status == SCA_InputEvent::KX_NO_INPUTSTATUS)
177                 {
178                 } else
179                 {
180                         if (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED)
181                         {
182                                 m_val=1;
183                                 result = true;
184                         } else
185                         {
186                                 if (inevent.m_status == SCA_InputEvent::KX_JUSTRELEASED)
187                                 {
188                                         m_val = 0;
189                                         result = true;
190                                 }
191                         }
192                 }
193         }
194
195         return result;
196
197 }
198
199 void SCA_KeyboardSensor::AddToTargetProp(int keyIndex)
200 {
201         if (IsPrintable(keyIndex)) {
202                 CValue* tprop = GetParent()->GetProperty(m_targetprop);
203                 
204                 if (tprop) {
205                         /* overwrite the old property */
206                         if (IsDelete(keyIndex)) {
207                                 /* strip one char, if possible */
208                                 STR_String newprop = tprop->GetText();
209                                 int oldlength = newprop.Length();
210                                 if (oldlength >= 1 ) {
211                                         newprop.SetLength(oldlength - 1);
212                                         CStringValue * newstringprop = new CStringValue(newprop, m_targetprop);
213                                         GetParent()->SetProperty(m_targetprop, newstringprop);
214                                 }                               
215                         } else {
216                                 /* append */
217                                 char pchar = ToCharacter(keyIndex, IsShifted());
218                                 STR_String newprop = tprop->GetText() + pchar;
219                                 CStringValue * newstringprop = new CStringValue(newprop, m_targetprop);                 
220                                 GetParent()->SetProperty(m_targetprop, newstringprop);
221                         }
222                 } else {
223                         if (!IsDelete(keyIndex)) {
224                                 /* Make a new property. Deletes can be ignored. */
225                                 char pchar = ToCharacter(keyIndex, IsShifted());
226                                 STR_String newprop = pchar;
227                                 CStringValue * newstringprop = new CStringValue(newprop, m_targetprop);                 
228                                 GetParent()->SetProperty(m_targetprop, newstringprop);
229                         }
230                 }
231         }
232         
233 }
234
235 /**
236  * Determine whether this character can be printed. We cannot use
237  * the library functions here, because we need to test our own
238  * keycodes. */
239 bool SCA_KeyboardSensor::IsPrintable(int keyIndex)
240 {
241         /* only print 
242          * - numerals: KX_ZEROKEY to KX_NINEKEY
243          * - alphas:   KX_AKEY to KX_ZKEY. 
244          * - specials: KX_RETKEY, KX_PADASTERKEY, KX_PADCOMMAKEY to KX_PERIODKEY,
245          *             KX_TABKEY , KX_SEMICOLONKEY to KX_RIGHTBRACKETKEY, 
246          *             KX_PAD2 to KX_PADPLUSKEY
247          * - delete and backspace: also printable in the sense that they modify 
248          *                         the string
249          * - retkey: should this be printable?
250          * - virgule: prints a space... don't know which key that's supposed
251          *   to be...
252          */
253         if ( ((keyIndex >= SCA_IInputDevice::KX_ZEROKEY) 
254                   && (keyIndex <= SCA_IInputDevice::KX_NINEKEY))
255                  || ((keyIndex >= SCA_IInputDevice::KX_AKEY) 
256                          && (keyIndex <= SCA_IInputDevice::KX_ZKEY)) 
257                  || (keyIndex == SCA_IInputDevice::KX_SPACEKEY) 
258 /*                       || (keyIndex == KX_RETKEY)  */
259                  || (keyIndex == SCA_IInputDevice::KX_PADASTERKEY) 
260                  || (keyIndex == SCA_IInputDevice::KX_TABKEY) 
261                  || ((keyIndex >= SCA_IInputDevice::KX_COMMAKEY) 
262                          && (keyIndex <= SCA_IInputDevice::KX_PERIODKEY)) 
263                  || ((keyIndex >= SCA_IInputDevice::KX_SEMICOLONKEY) 
264                          && (keyIndex <= SCA_IInputDevice::KX_RIGHTBRACKETKEY)) 
265                  || ((keyIndex >= SCA_IInputDevice::KX_PAD2) 
266                          && (keyIndex <= SCA_IInputDevice::KX_PADPLUSKEY)) 
267                  || (keyIndex == SCA_IInputDevice::KX_DELKEY)
268                  || (keyIndex == SCA_IInputDevice::KX_BACKSPACEKEY)                              
269                 )
270         {
271                 return true;
272         } else {
273                 return false;
274         }
275 }
276
277 // this code looks ugly, please use an ordinary hashtable
278
279 char SCA_KeyboardSensor::ToCharacter(int keyIndex, bool shifted)
280 {
281         /* numerals */
282         if ( (keyIndex >= SCA_IInputDevice::KX_ZEROKEY) 
283                  && (keyIndex <= SCA_IInputDevice::KX_NINEKEY) ) {
284                 if (shifted) {
285                         char numshift[] = ")!@#$%^&*(";
286                         return numshift[keyIndex - '0']; 
287                 } else {
288                         return keyIndex - SCA_IInputDevice::KX_ZEROKEY + '0'; 
289                 }
290         }
291         
292         /* letters... always lowercase... is that desirable? */
293         if ( (keyIndex >= SCA_IInputDevice::KX_AKEY) 
294                  && (keyIndex <= SCA_IInputDevice::KX_ZKEY) ) {
295                 if (shifted) {
296                         return keyIndex - SCA_IInputDevice::KX_AKEY + 'A'; 
297                 } else {
298                         return keyIndex - SCA_IInputDevice::KX_AKEY + 'a'; 
299                 }
300         }
301         
302         if (keyIndex == SCA_IInputDevice::KX_SPACEKEY) {
303                 return ' ';
304         }
305         
306 /*                       || (keyIndex == SCA_IInputDevice::KX_RETKEY)  */
307         
308         if (keyIndex == SCA_IInputDevice::KX_PADASTERKEY) {
309                 return '*';
310         }
311         
312         if (keyIndex == SCA_IInputDevice::KX_TABKEY) {
313                 return '\t';
314         }
315         
316         /* comma to period */
317         char commatoperiod[] = ",-.";
318         char commatoperiodshifted[] = "<_>";
319         if (keyIndex == SCA_IInputDevice::KX_COMMAKEY) {
320                 if (shifted) {
321                         return commatoperiodshifted[0];
322                 } else {
323                         return commatoperiod[0];
324                 }
325         }
326         if (keyIndex == SCA_IInputDevice::KX_MINUSKEY) {
327                 if (shifted) {
328                         return commatoperiodshifted[1];
329                 } else {
330                         return commatoperiod[1];
331                 }
332         }
333         if (keyIndex == SCA_IInputDevice::KX_PERIODKEY) {
334                 if (shifted) {
335                         return commatoperiodshifted[2];
336                 } else {
337                         return commatoperiod[2];
338                 }
339         }
340         
341         /* semicolon to rightbracket */
342         char semicolontorightbracket[] = ";\'` /\\=[]";
343         char semicolontorightbracketshifted[] = ":\"~ \?|+{}";
344         if ((keyIndex >= SCA_IInputDevice::KX_SEMICOLONKEY) 
345                 && (keyIndex <= SCA_IInputDevice::KX_RIGHTBRACKETKEY)) {
346                 if (shifted) {
347                         return semicolontorightbracketshifted[keyIndex - SCA_IInputDevice::KX_SEMICOLONKEY];
348                 } else {
349                         return semicolontorightbracket[keyIndex - SCA_IInputDevice::KX_SEMICOLONKEY];
350                 }
351         }
352         
353         /* keypad2 to padplus */
354         char pad2topadplus[] = "246813579. 0- +";
355         if ((keyIndex >= SCA_IInputDevice::KX_PAD2) 
356                 && (keyIndex <= SCA_IInputDevice::KX_PADPLUSKEY)) { 
357                 return pad2topadplus[keyIndex - SCA_IInputDevice::KX_PAD2];
358         }
359
360         return '!';
361 }
362         
363 /**
364  * Tests whether this is a delete key.
365  */     
366 bool SCA_KeyboardSensor::IsDelete(int keyIndex)
367 {
368         if ( (keyIndex == SCA_IInputDevice::KX_DELKEY)
369                  || (keyIndex == SCA_IInputDevice::KX_BACKSPACEKEY) ) {
370                 return true;
371         } else {
372                 return false;
373         }
374 }
375
376 /**
377  * Tests whether shift is pressed
378  */     
379 bool SCA_KeyboardSensor::IsShifted(void)
380 {
381         SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice();
382         
383         if ( (inputdev->GetEventValue(SCA_IInputDevice::KX_RIGHTSHIFTKEY).m_status 
384                   == SCA_InputEvent::KX_ACTIVE)
385                  || (inputdev->GetEventValue(SCA_IInputDevice::KX_RIGHTSHIFTKEY).m_status 
386                          == SCA_InputEvent::KX_JUSTACTIVATED)
387                  || (inputdev->GetEventValue(SCA_IInputDevice::KX_LEFTSHIFTKEY).m_status 
388                          == SCA_InputEvent::KX_ACTIVE)
389                  || (inputdev->GetEventValue(SCA_IInputDevice::KX_LEFTSHIFTKEY).m_status 
390                          == SCA_InputEvent::KX_JUSTACTIVATED)
391                 ) {
392                 return true;
393         } else {
394                 return false;
395         }       
396 }
397
398 void SCA_KeyboardSensor::LogKeystrokes(void) 
399 {
400         SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice();
401         int num = inputdev->GetNumActiveEvents();
402
403         /* weird loop, this one... */
404         if (num > 0)
405         {
406                 
407                 int index = 0;
408                 /* Check on all keys whether they were pushed. This does not
409          * untangle the ordering, so don't type too fast :) */
410                 for (int i=SCA_IInputDevice::KX_BEGINKEY ; i< SCA_IInputDevice::KX_ENDKEY;i++)
411                 {
412                         const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i);
413                         if (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED) //NO_INPUTSTATUS)
414                         {
415                                 if (index < num)
416                                 {
417                                         AddToTargetProp(i);
418                                         index++;
419                                 }
420                         }
421                 }
422         }
423 }
424
425
426 /* ------------------------------------------------------------------------- */
427 /* Python functions : specific                                               */
428 /* ------------------------------------------------------------------------- */
429
430
431 PyObject* SCA_KeyboardSensor::PySetAllMode(PyObject* self, 
432                                PyObject* args, 
433                                PyObject* kwds)
434 {
435         bool allkeys;
436
437         if (!PyArg_ParseTuple(args, "i", &allkeys))
438         {
439           return NULL;
440         }
441         
442         m_bAllKeys = allkeys;
443         Py_Return
444 }
445
446
447
448 PyObject* SCA_KeyboardSensor::sPySetAllMode(PyObject* self, 
449                                        PyObject* args, 
450                                        PyObject* kwds)
451 {
452 //      printf("sPyIsPositive\n");
453     return ((SCA_KeyboardSensor*) self)->PyIsPositive(self, args, kwds);
454 }
455
456
457 /** 1. GetKey : check which key this sensor looks at */
458 char SCA_KeyboardSensor::GetKey_doc[] = 
459 "getKey()\n"
460 "\tReturn the code of the key this sensor is listening to.\n" ;
461 PyObject* SCA_KeyboardSensor::PyGetKey(PyObject* self, PyObject* args, PyObject* kwds)
462 {
463         return PyInt_FromLong(m_hotkey);
464 }
465
466 /** 2. SetKey: change the key to look at */
467 char SCA_KeyboardSensor::SetKey_doc[] = 
468 "setKey(keycode)\n"
469 "\t- keycode: any code from GameKeys\n"
470 "\tSet the key this sensor should listen to.\n" ;
471 PyObject* SCA_KeyboardSensor::PySetKey(PyObject* self, PyObject* args, PyObject* kwds)
472 {
473         int keyCode;
474         
475         if(!PyArg_ParseTuple(args, "i", &keyCode)) {
476                 return NULL;
477         }
478
479         /* Since we have symbolic constants for this in Python, we don't guard   */
480         /* anything. It's up to the user to provide a sensible number.           */
481         m_hotkey = keyCode;
482
483         Py_Return;
484 }
485
486 /** 3. GetHold1 : set the first bucky bit */
487 char SCA_KeyboardSensor::GetHold1_doc[] = 
488 "getHold1()\n"
489 "\tReturn the code of the first key modifier to the key this \n"
490 "\tsensor is listening to.\n" ;
491 PyObject* SCA_KeyboardSensor::PyGetHold1(PyObject* self, PyObject* args, PyObject* kwds)
492 {
493         return PyInt_FromLong(m_qual);
494 }
495
496 /** 4. SetHold1: change the first bucky bit */
497 char SCA_KeyboardSensor::SetHold1_doc[] = 
498 "setHold1(keycode)\n"
499 "\t- keycode: any code from GameKeys\n"
500 "\tSet the first modifier to the key this sensor should listen to.\n" ;
501 PyObject* SCA_KeyboardSensor::PySetHold1(PyObject* self, PyObject* args, PyObject* kwds)
502 {
503         int keyCode;
504
505         if(!PyArg_ParseTuple(args, "i", &keyCode)) {
506                 return NULL;
507         }
508         
509         /* Since we have symbolic constants for this in Python, we don't guard   */
510         /* anything. It's up to the user to provide a sensible number.           */
511         m_qual = keyCode;
512
513         Py_Return;
514 }
515         
516 /** 5. GetHold2 : get the second bucky bit */
517 char SCA_KeyboardSensor::GetHold2_doc[] = 
518 "getHold2()\n"
519 "\tReturn the code of the second key modifier to the key this \n"
520 "\tsensor is listening to.\n" ;
521 PyObject* SCA_KeyboardSensor::PyGetHold2(PyObject* self, PyObject* args, PyObject* kwds)
522 {
523         return PyInt_FromLong(m_qual2);
524 }
525
526 /** 6. SetHold2: change the second bucky bit */
527 char SCA_KeyboardSensor::SetHold2_doc[] = 
528 "setHold2(keycode)\n"
529 "\t- keycode: any code from GameKeys\n"
530 "\tSet the first modifier to the key this sensor should listen to.\n" ;
531 PyObject* SCA_KeyboardSensor::PySetHold2(PyObject* self, PyObject* args, PyObject* kwds)
532 {
533         int keyCode;
534
535         if(!PyArg_ParseTuple(args, "i", &keyCode)) {
536                 return NULL;
537         }
538         
539         /* Since we have symbolic constants for this in Python, we don't guard   */
540         /* anything. It's up to the user to provide a sensible number.           */
541         m_qual2 = keyCode;
542
543         Py_Return;
544 }
545
546         
547 char SCA_KeyboardSensor::GetPressedKeys_doc[] = 
548 "getPressedKeys()\n"
549 "\tGet a list of pressed keys that have either been pressed, or just released this frame.\n" ;
550
551 PyObject* SCA_KeyboardSensor::PyGetPressedKeys(PyObject* self, PyObject* args, PyObject* kwds)
552 {
553         SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice();
554
555         int num = inputdev->GetNumJustEvents();
556         PyObject* resultlist = PyList_New(num);
557
558         if (num > 0)
559         {
560                 
561                 int index = 0;
562                 
563                 for (int i=SCA_IInputDevice::KX_BEGINKEY ; i< SCA_IInputDevice::KX_ENDKEY;i++)
564                 {
565                         const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i);
566                         if ((inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED)
567                                 || (inevent.m_status == SCA_InputEvent::KX_JUSTRELEASED))
568                         {
569                                 if (index < num)
570                                 {
571                                         PyObject* keypair = PyList_New(2);
572                                         PyList_SetItem(keypair,0,PyInt_FromLong(i));
573                                         PyList_SetItem(keypair,1,PyInt_FromLong(inevent.m_status));
574                                         PyList_SetItem(resultlist,index,keypair);
575                                         index++;
576                                 }
577                         }
578                 }       
579                 if (index>0) return resultlist;
580         }
581         
582         Py_Return;
583 }
584
585
586
587 char SCA_KeyboardSensor::GetCurrentlyPressedKeys_doc[] = 
588 "getCurrentlyPressedKeys()\n"
589 "\tGet a list of keys that are currently pressed.\n" ;
590
591 PyObject* SCA_KeyboardSensor::PyGetCurrentlyPressedKeys(PyObject* self, PyObject* args, PyObject* kwds)
592 {
593 SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice();
594
595         int num = inputdev->GetNumActiveEvents();
596         PyObject* resultlist = PyList_New(num);
597
598         if (num > 0)
599         {
600                 int index = 0;
601                 
602                 for (int i=SCA_IInputDevice::KX_BEGINKEY ; i< SCA_IInputDevice::KX_ENDKEY;i++)
603                 {
604                         const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i);
605                         if ( (inevent.m_status == SCA_InputEvent::KX_ACTIVE)
606                                  || (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED))
607                         {
608                                 if (index < num)
609                                 {
610                                         PyObject* keypair = PyList_New(2);
611                                         PyList_SetItem(keypair,0,PyInt_FromLong(i));
612                                         PyList_SetItem(keypair,1,PyInt_FromLong(inevent.m_status));
613                                         PyList_SetItem(resultlist,index,keypair);
614                                         index++;
615                                 }
616                         }
617                 }
618
619                 /* why?*/
620                 if (index > 0) return resultlist;
621         }
622
623         Py_Return;
624 }
625
626 /* ------------------------------------------------------------------------- */
627 /* Python functions : integration hooks                                      */
628 /* ------------------------------------------------------------------------- */
629
630 PyTypeObject SCA_KeyboardSensor::Type = {
631         PyObject_HEAD_INIT(&PyType_Type)
632         0,
633         "SCA_KeyboardSensor",
634         sizeof(SCA_KeyboardSensor),
635         0,
636         PyDestructor,
637         0,
638         __getattr,
639         __setattr,
640         0, //&MyPyCompare,
641         __repr,
642         0, //&cvalue_as_number,
643         0,
644         0,
645         0,
646         0
647 };
648
649 PyParentObject SCA_KeyboardSensor::Parents[] = {
650         &SCA_KeyboardSensor::Type,
651         &SCA_ISensor::Type,
652         &SCA_ILogicBrick::Type,
653         &CValue::Type,
654         NULL
655 };
656
657 PyMethodDef SCA_KeyboardSensor::Methods[] = {
658   {"getKey", (PyCFunction) SCA_KeyboardSensor::sPyGetKey, METH_VARARGS, GetKey_doc},
659   {"setKey", (PyCFunction) SCA_KeyboardSensor::sPySetKey, METH_VARARGS, SetKey_doc},
660   {"getHold1", (PyCFunction) SCA_KeyboardSensor::sPyGetHold1, METH_VARARGS, GetHold1_doc},
661   {"setHold1", (PyCFunction) SCA_KeyboardSensor::sPySetHold1, METH_VARARGS, SetHold1_doc},
662   {"getHold2", (PyCFunction) SCA_KeyboardSensor::sPyGetHold2, METH_VARARGS, GetHold2_doc},
663   {"setHold2", (PyCFunction) SCA_KeyboardSensor::sPySetHold2, METH_VARARGS, SetHold2_doc},
664 //  {"getUseAllKeys", (PyCFunction) SCA_KeyboardSensor::sPyGetUseAllKeys, METH_VARARGS, GetUseAllKeys_doc},
665 //  {"setUseAllKeys", (PyCFunction) SCA_KeyboardSensor::sPySetUseAllKeys, METH_VARARGS, SetUseAllKeys_doc},
666   {"getPressedKeys", (PyCFunction) SCA_KeyboardSensor::sPyGetPressedKeys, METH_VARARGS, GetPressedKeys_doc},
667   {"getCurrentlyPressedKeys", (PyCFunction) SCA_KeyboardSensor::sPyGetCurrentlyPressedKeys, METH_VARARGS, GetCurrentlyPressedKeys_doc},
668 //  {"getKeyEvents", (PyCFunction) SCA_KeyboardSensor::sPyGetKeyEvents, METH_VARARGS, GetKeyEvents_doc},
669   {NULL,NULL} //Sentinel
670 };
671
672 PyObject*
673 SCA_KeyboardSensor::_getattr(const STR_String& attr)
674 {
675   _getattr_up(SCA_ISensor);
676 }
677