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