BGE performance, 4th round: logic
[blender.git] / source / gameengine / GameLogic / SCA_KeyboardSensor.cpp
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL 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.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  * Sensor for keyboard input
29  */
30 #include "SCA_KeyboardSensor.h"
31 #include "SCA_KeyboardManager.h"
32 #include "SCA_LogicManager.h"
33 #include "StringValue.h"
34 #include "SCA_IInputDevice.h"
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 /* ------------------------------------------------------------------------- */
41 /* Native functions                                                          */
42 /* ------------------------------------------------------------------------- */
43
44 SCA_KeyboardSensor::SCA_KeyboardSensor(SCA_KeyboardManager* keybdmgr,
45                                                                            short int hotkey,
46                                                                            short int qual,
47                                                                            short int qual2,
48                                                                            bool bAllKeys,
49                                                                            const STR_String& targetProp,
50                                                                            const STR_String& toggleProp,
51                                                                            SCA_IObject* gameobj,
52                                                                            PyTypeObject* T )
53         :SCA_ISensor(gameobj,keybdmgr,T),
54          m_pKeyboardMgr(keybdmgr),
55          m_hotkey(hotkey),
56          m_qual(qual),
57          m_qual2(qual2),
58          m_bAllKeys(bAllKeys),
59          m_targetprop(targetProp),
60          m_toggleprop(toggleProp)
61 {
62         if (hotkey == SCA_IInputDevice::KX_ESCKEY)
63                 keybdmgr->GetInputDevice()->HookEscape();
64 //      SetDrawColor(0xff0000ff);
65         Init();
66 }
67
68
69
70 SCA_KeyboardSensor::~SCA_KeyboardSensor()
71 {
72 }
73
74 void SCA_KeyboardSensor::Init()
75 {
76         // this function is used when the sensor is disconnected from all controllers
77         // by the state engine. It reinitializes the sensor as if it was just created.
78         // However, if the target key is pressed when the sensor is reactivated, it
79         // will not generated an event (see remark in Evaluate()).
80         m_val = (m_invert)?1:0;
81         m_reset = true;
82 }
83
84 CValue* SCA_KeyboardSensor::GetReplica()
85 {
86         SCA_KeyboardSensor* replica = new SCA_KeyboardSensor(*this);
87         // this will copy properties and so on...
88         replica->ProcessReplica();
89         replica->Init();
90         return replica;
91 }
92
93
94
95 short int SCA_KeyboardSensor::GetHotkey()
96 {
97         return m_hotkey;
98 }
99
100
101
102 bool SCA_KeyboardSensor::IsPositiveTrigger()
103
104         bool result = (m_val != 0);
105
106         if (m_invert)
107                 result = !result;
108                 
109         return result;
110 }
111
112
113
114 bool SCA_KeyboardSensor::TriggerOnAllKeys()
115
116         return m_bAllKeys;
117 }
118
119
120
121 bool SCA_KeyboardSensor::Evaluate()
122 {
123         bool result    = false;
124         bool reset     = m_reset && m_level;
125         bool qual          = true;
126         bool qual_change = false;
127         short int m_val_orig = m_val;
128         
129         SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice();
130         //      cerr << "SCA_KeyboardSensor::Eval event, sensing for "<< m_hotkey << " at device " << inputdev << "\n";
131
132         /* See if we need to do logging: togPropState exists and is
133      * different from 0 */
134         CValue* myparent = GetParent();
135         CValue* togPropState = myparent->GetProperty(m_toggleprop);
136         if (togPropState &&
137                 (((int)togPropState->GetNumber()) != 0) )
138         {
139                 LogKeystrokes();
140         }
141
142         m_reset = false;
143
144         /* Now see whether events must be bounced. */
145         if (m_bAllKeys)
146         {
147                 bool justactivated = false;
148                 bool justreleased = false;
149                 bool active = false;
150
151                 for (int i=SCA_IInputDevice::KX_BEGINKEY ; i<= SCA_IInputDevice::KX_ENDKEY;i++)
152                 {
153                         const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i);
154                         switch (inevent.m_status) 
155                         { 
156                         case SCA_InputEvent::KX_JUSTACTIVATED:
157                                 justactivated = true;
158                                 break;
159                         case SCA_InputEvent::KX_JUSTRELEASED:
160                                 justreleased = true;
161                                 break;
162                         case SCA_InputEvent::KX_ACTIVE:
163                                 active = true;
164                                 break;
165                         }
166                 }
167
168                 if (justactivated)
169                 {
170                         m_val=1;
171                         result = true;
172                 } else
173                 {
174                         if (justreleased)
175                         {
176                                 m_val=(active)?1:0;
177                                 result = true;
178                         } else
179                         {
180                                 if (active)
181                                 {
182                                         if (m_val == 0)
183                                         {
184                                                 m_val = 1;
185                                                 if (m_level) {
186                                                         result = true;
187                                                 }
188                                         }
189                                 } else
190                                 {
191                                         if (m_val == 1)
192                                         {
193                                                 m_val = 0;
194                                                 result = true;
195                                         }
196                                 }
197                         }
198                         if (m_tap)
199                                 // special case for tap mode: only generate event for new activation
200                                 result = false;
201                 }
202
203
204         } else
205         {
206
207         //              cerr << "======= SCA_KeyboardSensor::Evaluate:: peeking at key status" << endl;
208                 const SCA_InputEvent & inevent = inputdev->GetEventValue(
209                         (SCA_IInputDevice::KX_EnumInputs) m_hotkey);
210         
211         //              cerr << "======= SCA_KeyboardSensor::Evaluate:: status: " << inevent.m_status << endl;
212                 
213                 
214                 /* Check qualifier keys
215                  * - see if the qualifiers we request are pressed - 'qual' true/false
216                  * - see if the qualifiers we request changed their state - 'qual_change' true/false
217                  */
218                 if (m_qual > 0) {
219                         const SCA_InputEvent & qualevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) m_qual);
220                         switch(qualevent.m_status) {
221                         case SCA_InputEvent::KX_NO_INPUTSTATUS:
222                                 qual = false;
223                                 break;
224                         case SCA_InputEvent::KX_JUSTRELEASED:
225                                 qual_change = true;
226                                 qual = false;
227                                 break;
228                         case SCA_InputEvent::KX_JUSTACTIVATED:
229                                 qual_change = true;
230                         }
231                 }
232                 if (m_qual2 > 0 && qual==true) {
233                         const SCA_InputEvent & qualevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) m_qual2);
234                         /* copy of above */
235                         switch(qualevent.m_status) {
236                         case SCA_InputEvent::KX_NO_INPUTSTATUS:
237                                 qual = false;
238                                 break;
239                         case SCA_InputEvent::KX_JUSTRELEASED:
240                                 qual_change = true;
241                                 qual = false;
242                                 break;
243                         case SCA_InputEvent::KX_JUSTACTIVATED:
244                                 qual_change = true;
245                         }
246                 }
247                 /* done reading qualifiers */
248                 
249                 if (inevent.m_status == SCA_InputEvent::KX_NO_INPUTSTATUS)
250                 {
251                         if (m_val == 1)
252                         {
253                                 // this situation may occur after a scene suspend: the keyboard release 
254                                 // event was not captured, produce now the event off
255                                 m_val = 0;
256                                 result = true;
257                         }
258                 } else
259                 {
260                         if (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED)
261                         {
262                                 m_val=1;
263                                 result = true;
264                         } else
265                         {
266                                 if (inevent.m_status == SCA_InputEvent::KX_JUSTRELEASED)
267                                 {
268                                         m_val = 0;
269                                         result = true;
270                                 } else 
271                                 {
272                                         if (inevent.m_status == SCA_InputEvent::KX_ACTIVE)
273                                         {
274                                                 if (m_val == 0)
275                                                 {
276                                                         m_val = 1;
277                                                         if (m_level) 
278                                                         {
279                                                                 result = true;
280                                                         }
281                                                 }
282                                         }
283                                 }
284                         }
285                 }
286                 
287                 /* Modify the key state based on qual(s)
288                  * Tested carefuly. dont touch unless your really sure.
289                  * note, this will only change the results if key modifiers are set.
290                  *
291                  * When all modifiers and keys are positive
292                  *  - pulse true
293                  * 
294                  * When ANY of the modifiers or main key become inactive,
295                  *  - pulse false
296                  */
297                 if (qual==false) { /* one of the qualifiers are not pressed */
298                         if (m_val_orig && qual_change) { /* we were originally enabled, but a qualifier changed */
299                                 result = true;
300                         } else {
301                                 result = false;
302                         }
303                         m_val = 0; /* since one of the qualifiers is not on, set the state to false */
304                 } else {                                                /* we done have any qualifiers or they are all pressed */
305                         if (m_val && qual_change) {     /* the main key state is true and our qualifier just changed */
306                                 result = true;
307                         }
308                 }
309                 /* done with key quals */
310                 
311         }
312         
313         if (reset)
314                 // force an event
315                 result = true;
316         return result;
317
318 }
319
320 void SCA_KeyboardSensor::AddToTargetProp(int keyIndex)
321 {
322         if (IsPrintable(keyIndex)) {
323                 CValue* tprop = GetParent()->GetProperty(m_targetprop);
324                 
325                 if (tprop) {
326                         /* overwrite the old property */
327                         if (IsDelete(keyIndex)) {
328                                 /* strip one char, if possible */
329                                 STR_String newprop = tprop->GetText();
330                                 int oldlength = newprop.Length();
331                                 if (oldlength >= 1 ) {
332                                         newprop.SetLength(oldlength - 1);
333                                         CStringValue * newstringprop = new CStringValue(newprop, m_targetprop);
334                                         GetParent()->SetProperty(m_targetprop, newstringprop);
335                                         newstringprop->Release();
336                                 }                               
337                         } else {
338                                 /* append */
339                                 char pchar = ToCharacter(keyIndex, IsShifted());
340                                 STR_String newprop = tprop->GetText() + pchar;
341                                 CStringValue * newstringprop = new CStringValue(newprop, m_targetprop);                 
342                                 GetParent()->SetProperty(m_targetprop, newstringprop);
343                                 newstringprop->Release();
344                         }
345                 } else {
346                         if (!IsDelete(keyIndex)) {
347                                 /* Make a new property. Deletes can be ignored. */
348                                 char pchar = ToCharacter(keyIndex, IsShifted());
349                                 STR_String newprop = pchar;
350                                 CStringValue * newstringprop = new CStringValue(newprop, m_targetprop);                 
351                                 GetParent()->SetProperty(m_targetprop, newstringprop);
352                                 newstringprop->Release();
353                         }
354                 }
355         }
356         
357 }
358         
359 /**
360  * Tests whether shift is pressed
361  */     
362 bool SCA_KeyboardSensor::IsShifted(void)
363 {
364         SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice();
365         
366         if ( (inputdev->GetEventValue(SCA_IInputDevice::KX_RIGHTSHIFTKEY).m_status 
367                   == SCA_InputEvent::KX_ACTIVE)
368                  || (inputdev->GetEventValue(SCA_IInputDevice::KX_RIGHTSHIFTKEY).m_status 
369                          == SCA_InputEvent::KX_JUSTACTIVATED)
370                  || (inputdev->GetEventValue(SCA_IInputDevice::KX_LEFTSHIFTKEY).m_status 
371                          == SCA_InputEvent::KX_ACTIVE)
372                  || (inputdev->GetEventValue(SCA_IInputDevice::KX_LEFTSHIFTKEY).m_status 
373                          == SCA_InputEvent::KX_JUSTACTIVATED)
374                 ) {
375                 return true;
376         } else {
377                 return false;
378         }       
379 }
380
381 void SCA_KeyboardSensor::LogKeystrokes(void) 
382 {
383         SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice();
384         int num = inputdev->GetNumActiveEvents();
385
386         /* weird loop, this one... */
387         if (num > 0)
388         {
389                 
390                 int index = 0;
391                 /* Check on all keys whether they were pushed. This does not
392          * untangle the ordering, so don't type too fast :) */
393                 for (int i=SCA_IInputDevice::KX_BEGINKEY ; i<= SCA_IInputDevice::KX_ENDKEY;i++)
394                 {
395                         const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i);
396                         if (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED) //NO_INPUTSTATUS)
397                         {
398                                 if (index < num)
399                                 {
400                                         AddToTargetProp(i);
401                                         index++;
402                                 }
403                         }
404                 }
405         }
406 }
407
408
409 /* ------------------------------------------------------------------------- */
410 /* Python Functions                                                    */
411 /* ------------------------------------------------------------------------- */
412
413 //Deprecated ----->
414 /** 1. GetKey : check which key this sensor looks at */
415 const char SCA_KeyboardSensor::GetKey_doc[] = 
416 "getKey()\n"
417 "\tReturn the code of the key this sensor is listening to.\n" ;
418 PyObject* SCA_KeyboardSensor::PyGetKey()
419 {
420         ShowDeprecationWarning("getKey()", "the key property");
421         return PyInt_FromLong(m_hotkey);
422 }
423
424 /** 2. SetKey: change the key to look at */
425 const char SCA_KeyboardSensor::SetKey_doc[] = 
426 "setKey(keycode)\n"
427 "\t- keycode: any code from GameKeys\n"
428 "\tSet the key this sensor should listen to.\n" ;
429 PyObject* SCA_KeyboardSensor::PySetKey(PyObject* args)
430 {
431         ShowDeprecationWarning("setKey()", "the key property");
432         int keyCode;
433         
434         if(!PyArg_ParseTuple(args, "i:setKey", &keyCode)) {
435                 return NULL;
436         }
437
438         /* Since we have symbolic constants for this in Python, we don't guard   */
439         /* anything. It's up to the user to provide a sensible number.           */
440         m_hotkey = keyCode;
441
442         Py_RETURN_NONE;
443 }
444
445 /** 3. GetHold1 : set the first bucky bit */
446 const char SCA_KeyboardSensor::GetHold1_doc[] = 
447 "getHold1()\n"
448 "\tReturn the code of the first key modifier to the key this \n"
449 "\tsensor is listening to.\n" ;
450 PyObject* SCA_KeyboardSensor::PyGetHold1()
451 {
452         ShowDeprecationWarning("getHold1()", "the hold1 property");
453         return PyInt_FromLong(m_qual);
454 }
455
456 /** 4. SetHold1: change the first bucky bit */
457 const char SCA_KeyboardSensor::SetHold1_doc[] = 
458 "setHold1(keycode)\n"
459 "\t- keycode: any code from GameKeys\n"
460 "\tSet the first modifier to the key this sensor should listen to.\n" ;
461 PyObject* SCA_KeyboardSensor::PySetHold1(PyObject* args)
462 {
463         ShowDeprecationWarning("setHold1()", "the hold1 property");
464         int keyCode;
465
466         if(!PyArg_ParseTuple(args, "i:setHold1", &keyCode)) {
467                 return NULL;
468         }
469         
470         /* Since we have symbolic constants for this in Python, we don't guard   */
471         /* anything. It's up to the user to provide a sensible number.           */
472         m_qual = keyCode;
473
474         Py_RETURN_NONE;
475 }
476         
477 /** 5. GetHold2 : get the second bucky bit */
478 const char SCA_KeyboardSensor::GetHold2_doc[] = 
479 "getHold2()\n"
480 "\tReturn the code of the second key modifier to the key this \n"
481 "\tsensor is listening to.\n" ;
482 PyObject* SCA_KeyboardSensor::PyGetHold2()
483 {
484         ShowDeprecationWarning("getHold2()", "the hold2 property");
485         return PyInt_FromLong(m_qual2);
486 }
487
488 /** 6. SetHold2: change the second bucky bit */
489 const char SCA_KeyboardSensor::SetHold2_doc[] = 
490 "setHold2(keycode)\n"
491 "\t- keycode: any code from GameKeys\n"
492 "\tSet the first modifier to the key this sensor should listen to.\n" ;
493 PyObject* SCA_KeyboardSensor::PySetHold2(PyObject* args)
494 {
495         ShowDeprecationWarning("setHold2()", "the hold2 property");
496         int keyCode;
497
498         if(!PyArg_ParseTuple(args, "i:setHold2", &keyCode)) {
499                 return NULL;
500         }
501         
502         /* Since we have symbolic constants for this in Python, we don't guard   */
503         /* anything. It's up to the user to provide a sensible number.           */
504         m_qual2 = keyCode;
505
506         Py_RETURN_NONE;
507 }
508
509         
510 const char SCA_KeyboardSensor::GetPressedKeys_doc[] = 
511 "getPressedKeys()\n"
512 "\tGet a list of pressed keys that have either been pressed, or just released this frame.\n" ;
513
514 PyObject* SCA_KeyboardSensor::PyGetPressedKeys()
515 {
516         ShowDeprecationWarning("getPressedKeys()", "events");
517
518         SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice();
519
520         int num = inputdev->GetNumJustEvents();
521         PyObject* resultlist = PyList_New(num);
522
523         if (num > 0)
524         {
525                 
526                 int index = 0;
527                 
528                 for (int i=SCA_IInputDevice::KX_BEGINKEY ; i<= SCA_IInputDevice::KX_ENDKEY;i++)
529                 {
530                         const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i);
531                         if ((inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED)
532                                 || (inevent.m_status == SCA_InputEvent::KX_JUSTRELEASED))
533                         {
534                                 PyObject* keypair = PyList_New(2);
535                                 PyList_SET_ITEM(keypair,0,PyInt_FromLong(i));
536                                 PyList_SET_ITEM(keypair,1,PyInt_FromLong(inevent.m_status));
537                                 PyList_SET_ITEM(resultlist,index,keypair);
538                                 index++;
539                                 
540                                 if (index >= num) /* should not happen */
541                                         break; 
542                         }
543                 }
544         }
545         
546         return resultlist;
547 }
548
549
550
551 const char SCA_KeyboardSensor::GetCurrentlyPressedKeys_doc[] = 
552 "getCurrentlyPressedKeys()\n"
553 "\tGet a list of keys that are currently pressed.\n" ;
554
555 PyObject* SCA_KeyboardSensor::PyGetCurrentlyPressedKeys()
556 {
557         ShowDeprecationWarning("getCurrentlyPressedKeys()", "events");
558
559         SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice();
560
561         int num = inputdev->GetNumActiveEvents();
562         PyObject* resultlist = PyList_New(num);
563
564         if (num > 0)
565         {
566                 int index = 0;
567                 
568                 for (int i=SCA_IInputDevice::KX_BEGINKEY ; i<= SCA_IInputDevice::KX_ENDKEY;i++)
569                 {
570                         const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i);
571                         if ( (inevent.m_status == SCA_InputEvent::KX_ACTIVE)
572                                  || (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED))
573                         {
574                                 PyObject* keypair = PyList_New(2);
575                                 PyList_SET_ITEM(keypair,0,PyInt_FromLong(i));
576                                 PyList_SET_ITEM(keypair,1,PyInt_FromLong(inevent.m_status));
577                                 PyList_SET_ITEM(resultlist,index,keypair);
578                                 index++;
579                                 
580                                 if (index >= num) /* should never happen */
581                                         break;
582                         }
583                 }
584         }
585
586         return resultlist;
587 }
588
589 //<---- Deprecated
590
591 KX_PYMETHODDEF_DOC_O(SCA_KeyboardSensor, getKeyStatus,
592 "getKeyStatus(keycode)\n"
593 "\tGet the given key's status (KX_NO_INPUTSTATUS, KX_JUSTACTIVATED, KX_ACTIVE or KX_JUSTRELEASED).\n")
594 {
595         if (!PyInt_Check(value)) {
596                 PyErr_SetString(PyExc_ValueError, "sensor.getKeyStatus(int): Keyboard Sensor, expected an int");
597                 return NULL;
598         }
599         
600         int keycode = PyInt_AsLong(value);
601         
602         if ((keycode < SCA_IInputDevice::KX_BEGINKEY)
603                 || (keycode > SCA_IInputDevice::KX_ENDKEY)){
604                 PyErr_SetString(PyExc_AttributeError, "sensor.getKeyStatus(int): Keyboard Sensor, invalid keycode specified!");
605                 return NULL;
606         }
607         
608         SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice();
609         const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) keycode);
610         return PyInt_FromLong(inevent.m_status);
611 }
612
613 /* ------------------------------------------------------------------------- */
614 /* Python Integration Hooks                                            */
615 /* ------------------------------------------------------------------------- */
616
617 PyTypeObject SCA_KeyboardSensor::Type = {
618 #if (PY_VERSION_HEX >= 0x02060000)
619         PyVarObject_HEAD_INIT(NULL, 0)
620 #else
621         /* python 2.5 and below */
622         PyObject_HEAD_INIT( NULL )  /* required py macro */
623         0,                          /* ob_size */
624 #endif
625         "SCA_KeyboardSensor",
626         sizeof(PyObjectPlus_Proxy),
627         0,
628         py_base_dealloc,
629         0,
630         0,
631         0,
632         0,
633         py_base_repr,
634         0,0,0,0,0,0,
635         py_base_getattro,
636         py_base_setattro,
637         0,0,0,0,0,0,0,0,0,
638         Methods
639 };
640
641 PyParentObject SCA_KeyboardSensor::Parents[] = {
642         &SCA_KeyboardSensor::Type,
643         &SCA_ISensor::Type,
644         &SCA_ILogicBrick::Type,
645         &CValue::Type,
646         NULL
647 };
648
649 PyMethodDef SCA_KeyboardSensor::Methods[] = {
650         //Deprecated functions ------>
651         {"getKey", (PyCFunction) SCA_KeyboardSensor::sPyGetKey, METH_NOARGS, (PY_METHODCHAR)GetKey_doc},
652         {"setKey", (PyCFunction) SCA_KeyboardSensor::sPySetKey, METH_VARARGS, (PY_METHODCHAR)SetKey_doc},
653         {"getHold1", (PyCFunction) SCA_KeyboardSensor::sPyGetHold1, METH_NOARGS, (PY_METHODCHAR)GetHold1_doc},
654         {"setHold1", (PyCFunction) SCA_KeyboardSensor::sPySetHold1, METH_VARARGS, (PY_METHODCHAR)SetHold1_doc},
655         {"getHold2", (PyCFunction) SCA_KeyboardSensor::sPyGetHold2, METH_NOARGS, (PY_METHODCHAR)GetHold2_doc},
656         {"setHold2", (PyCFunction) SCA_KeyboardSensor::sPySetHold2, METH_VARARGS, (PY_METHODCHAR)SetHold2_doc},
657         {"getPressedKeys", (PyCFunction) SCA_KeyboardSensor::sPyGetPressedKeys, METH_NOARGS, (PY_METHODCHAR)GetPressedKeys_doc},
658         {"getCurrentlyPressedKeys", (PyCFunction) SCA_KeyboardSensor::sPyGetCurrentlyPressedKeys, METH_NOARGS, (PY_METHODCHAR)GetCurrentlyPressedKeys_doc},
659         //<----- Deprecated
660         KX_PYMETHODTABLE_O(SCA_KeyboardSensor, getKeyStatus),
661         {NULL,NULL} //Sentinel
662 };
663
664 PyAttributeDef SCA_KeyboardSensor::Attributes[] = {
665         KX_PYATTRIBUTE_RO_FUNCTION("events", SCA_KeyboardSensor, pyattr_get_events),
666         KX_PYATTRIBUTE_BOOL_RW("useAllKeys",SCA_KeyboardSensor,m_bAllKeys),
667         KX_PYATTRIBUTE_INT_RW("key",0,SCA_IInputDevice::KX_ENDKEY,true,SCA_KeyboardSensor,m_hotkey),
668         KX_PYATTRIBUTE_SHORT_RW("hold1",0,SCA_IInputDevice::KX_ENDKEY,true,SCA_KeyboardSensor,m_qual),
669         KX_PYATTRIBUTE_SHORT_RW("hold2",0,SCA_IInputDevice::KX_ENDKEY,true,SCA_KeyboardSensor,m_qual2),
670         KX_PYATTRIBUTE_STRING_RW("toggleProperty",0,100,false,SCA_KeyboardSensor,m_toggleprop),
671         KX_PYATTRIBUTE_STRING_RW("targetProperty",0,100,false,SCA_KeyboardSensor,m_targetprop),
672         { NULL }        //Sentinel
673 };
674
675 PyObject* SCA_KeyboardSensor::py_getattro(PyObject *attr)
676 {
677   py_getattro_up(SCA_ISensor);
678 }
679
680 PyObject* SCA_KeyboardSensor::py_getattro_dict() {
681         py_getattro_dict_up(SCA_ISensor);
682 }
683
684 int SCA_KeyboardSensor::py_setattro(PyObject *attr, PyObject *value)
685 {
686         py_setattro_up(SCA_ISensor);
687 }
688
689
690 PyObject* SCA_KeyboardSensor::pyattr_get_events(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
691 {
692         SCA_KeyboardSensor* self= static_cast<SCA_KeyboardSensor*>(self_v);
693         
694         SCA_IInputDevice* inputdev = self->m_pKeyboardMgr->GetInputDevice();
695
696         PyObject* resultlist = PyList_New(0);
697         
698         for (int i=SCA_IInputDevice::KX_BEGINKEY ; i<= SCA_IInputDevice::KX_ENDKEY;i++)
699         {
700                 const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i);
701                 if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS)
702                 {
703                         PyObject* keypair = PyList_New(2);
704                         PyList_SET_ITEM(keypair,0,PyInt_FromLong(i));
705                         PyList_SET_ITEM(keypair,1,PyInt_FromLong(inevent.m_status));
706                         PyList_Append(resultlist,keypair);
707                 }
708         }       
709         return resultlist;
710 }
711
712
713 /* Accessed from python */
714
715 // this code looks ugly, please use an ordinary hashtable
716
717 char ToCharacter(int keyIndex, bool shifted)
718 {
719         /* numerals */
720         if ( (keyIndex >= SCA_IInputDevice::KX_ZEROKEY) 
721                  && (keyIndex <= SCA_IInputDevice::KX_NINEKEY) ) {
722                 if (shifted) {
723                         char numshift[] = ")!@#$%^&*(";
724                         return numshift[keyIndex - '0']; 
725                 } else {
726                         return keyIndex - SCA_IInputDevice::KX_ZEROKEY + '0'; 
727                 }
728         }
729         
730         /* letters... always lowercase... is that desirable? */
731         if ( (keyIndex >= SCA_IInputDevice::KX_AKEY) 
732                  && (keyIndex <= SCA_IInputDevice::KX_ZKEY) ) {
733                 if (shifted) {
734                         return keyIndex - SCA_IInputDevice::KX_AKEY + 'A'; 
735                 } else {
736                         return keyIndex - SCA_IInputDevice::KX_AKEY + 'a'; 
737                 }
738         }
739         
740         if (keyIndex == SCA_IInputDevice::KX_SPACEKEY) {
741                 return ' ';
742         }
743         if (keyIndex == SCA_IInputDevice::KX_RETKEY || keyIndex == SCA_IInputDevice::KX_PADENTER) {
744                 return '\n';
745         }
746         
747         
748         if (keyIndex == SCA_IInputDevice::KX_PADASTERKEY) {
749                 return '*';
750         }
751         
752         if (keyIndex == SCA_IInputDevice::KX_TABKEY) {
753                 return '\t';
754         }
755         
756         /* comma to period */
757         char commatoperiod[] = ",-.";
758         char commatoperiodshifted[] = "<_>";
759         if (keyIndex == SCA_IInputDevice::KX_COMMAKEY) {
760                 if (shifted) {
761                         return commatoperiodshifted[0];
762                 } else {
763                         return commatoperiod[0];
764                 }
765         }
766         if (keyIndex == SCA_IInputDevice::KX_MINUSKEY) {
767                 if (shifted) {
768                         return commatoperiodshifted[1];
769                 } else {
770                         return commatoperiod[1];
771                 }
772         }
773         if (keyIndex == SCA_IInputDevice::KX_PERIODKEY) {
774                 if (shifted) {
775                         return commatoperiodshifted[2];
776                 } else {
777                         return commatoperiod[2];
778                 }
779         }
780         
781         /* semicolon to rightbracket */
782         char semicolontorightbracket[] = ";\'`/\\=[]";
783         char semicolontorightbracketshifted[] = ":\"~\?|+{}";
784         if ((keyIndex >= SCA_IInputDevice::KX_SEMICOLONKEY) 
785                 && (keyIndex <= SCA_IInputDevice::KX_RIGHTBRACKETKEY)) {
786                 if (shifted) {
787                         return semicolontorightbracketshifted[keyIndex - SCA_IInputDevice::KX_SEMICOLONKEY];
788                 } else {
789                         return semicolontorightbracket[keyIndex - SCA_IInputDevice::KX_SEMICOLONKEY];
790                 }
791         }
792         
793         /* keypad2 to padplus */
794         char pad2topadplus[] = "246813579. 0- +";
795         if ((keyIndex >= SCA_IInputDevice::KX_PAD2) 
796                 && (keyIndex <= SCA_IInputDevice::KX_PADPLUSKEY)) { 
797                 return pad2topadplus[keyIndex - SCA_IInputDevice::KX_PAD2];
798         }
799
800         return '!';
801 }
802
803
804
805 /**
806  * Determine whether this character can be printed. We cannot use
807  * the library functions here, because we need to test our own
808  * keycodes. */
809 bool IsPrintable(int keyIndex)
810 {
811         /* only print 
812          * - numerals: KX_ZEROKEY to KX_NINEKEY
813          * - alphas:   KX_AKEY to KX_ZKEY. 
814          * - specials: KX_RETKEY, KX_PADASTERKEY, KX_PADCOMMAKEY to KX_PERIODKEY,
815          *             KX_TABKEY , KX_SEMICOLONKEY to KX_RIGHTBRACKETKEY, 
816          *             KX_PAD2 to KX_PADPLUSKEY
817          * - delete and backspace: also printable in the sense that they modify 
818          *                         the string
819          * - retkey: should this be printable?
820          * - virgule: prints a space... don't know which key that's supposed
821          *   to be...
822          */
823         if ( ((keyIndex >= SCA_IInputDevice::KX_ZEROKEY) 
824                   && (keyIndex <= SCA_IInputDevice::KX_NINEKEY))
825                  || ((keyIndex >= SCA_IInputDevice::KX_AKEY) 
826                          && (keyIndex <= SCA_IInputDevice::KX_ZKEY)) 
827                  || (keyIndex == SCA_IInputDevice::KX_SPACEKEY) 
828                  || (keyIndex == SCA_IInputDevice::KX_RETKEY)
829                  || (keyIndex == SCA_IInputDevice::KX_PADENTER)
830                  || (keyIndex == SCA_IInputDevice::KX_PADASTERKEY) 
831                  || (keyIndex == SCA_IInputDevice::KX_TABKEY) 
832                  || ((keyIndex >= SCA_IInputDevice::KX_COMMAKEY) 
833                          && (keyIndex <= SCA_IInputDevice::KX_PERIODKEY)) 
834                  || ((keyIndex >= SCA_IInputDevice::KX_SEMICOLONKEY) 
835                          && (keyIndex <= SCA_IInputDevice::KX_RIGHTBRACKETKEY)) 
836                  || ((keyIndex >= SCA_IInputDevice::KX_PAD2) 
837                          && (keyIndex <= SCA_IInputDevice::KX_PADPLUSKEY)) 
838                  || (keyIndex == SCA_IInputDevice::KX_DELKEY)
839                  || (keyIndex == SCA_IInputDevice::KX_BACKSPACEKEY)
840                 )
841         {
842                 return true;
843         } else {
844                 return false;
845         }
846 }
847
848 /**
849  * Tests whether this is a delete key.
850  */     
851 bool IsDelete(int keyIndex)
852 {
853         if ( (keyIndex == SCA_IInputDevice::KX_DELKEY)
854                  || (keyIndex == SCA_IInputDevice::KX_BACKSPACEKEY) ) {
855                 return true;
856         } else {
857                 return false;
858         }
859 }