Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/input/src/core/input/KeyBinder.cc @ 1637

Last change on this file since 1637 was 1637, checked in by rgrieder, 16 years ago

Finally! The InputManager is now working like I imagined it to. And it's even easier to use it as well.
A little explanation: Every time you change something about the input distribution, it is a change of 'state' represented by the class 'InputState'.
That can be for instance: "console", "game", "gui", etc. Every state has a name and a priority which describes who comes first. Now if one state doesn't handle mouse input or instance, then the one with the next lower priority gets it. To prevent that, you can add the 'EmptyHandler' to the state with setMouseHandler.
InputState is just an abstract base class. There are two classes implementing it: SimpleInputState and ExtendedInputState. The latter allows for multiple input handlers for one single device.

Basically, what you need to know is what you see in Orxonox.cc, InGameConsole.cc and Shell.cc.

  • Property svn:eol-style set to native
File size: 18.4 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Reto Grieder
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30 @file
31 @brief Implementation of the different input handlers.
32 */
33
34#include "KeyBinder.h"
35#include <fstream>
36#include <string>
37#include "util/Convert.h"
38#include "core/Debug.h"
39#include "core/ConfigValueIncludes.h"
40#include "core/CoreIncludes.h"
41#include "InputCommands.h"
42
43namespace orxonox
44{
45    /**
46    @brief
47        Constructor that does as little as necessary.
48    */
49    KeyBinder::KeyBinder()
50        : deriveTime_(0.0f)
51    {
52        mouseRelative_[0] = 0;
53        mouseRelative_[1] = 0;
54        mousePosition_[0] = 0;
55        mousePosition_[1] = 0;
56
57        RegisterRootObject(KeyBinder);
58
59        // keys
60        std::string keyNames[] = {
61        "UNASSIGNED",
62        "ESCAPE",
63        "1", "2", "3", "4", "5", "6", "7", "8", "9", "0",
64        "MINUS", "EQUALS", "BACK", "TAB",
65        "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P",
66        "LBRACKET", "RBRACKET",
67        "RETURN", "LCONTROL",
68        "A", "S", "D", "F", "G", "H", "J", "K", "L",
69        "SEMICOLON", "APOSTROPHE", "GRAVE",
70        "LSHIFT", "BACKSLASH",
71        "Z", "X", "C", "V", "B", "N", "M",
72        "COMMA", "PERIOD", "SLASH",
73        "RSHIFT",
74        "MULTIPLY",
75        "LMENU",
76        "SPACE",
77        "CAPITAL",
78        "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10",
79        "NUMLOCK", "SCROLL",
80        "NUMPAD7", "NUMPAD8", "NUMPAD9",
81        "SUBTRACT",
82        "NUMPAD4", "NUMPAD5", "NUMPAD6",
83        "ADD",
84        "NUMPAD1", "NUMPAD2", "NUMPAD3", "NUMPAD0",
85        "DECIMAL",
86        "","",
87        "OEM_102",
88        "F11", "F12",
89        "","","","","","","","","","","",
90        "F13", "F14", "F15",
91        "","","","","","","","","","",
92        "KANA",
93        "","",
94        "ABNT_C1",
95        "","","","","",
96        "CONVERT",
97        "",
98        "NOCONVERT",
99        "",
100        "YEN",
101        "ABNT_C2",
102        "","","","","","","","","","","","","","",
103        "NUMPADEQUALS",
104        "","",
105        "PREVTRACK",
106        "AT",
107        "COLON", "UNDERLINE",
108        "KANJI",
109        "STOP",
110        "AX",
111        "UNLABELED",
112        "NEXTTRACK",
113        "","",
114        "NUMPADENTER",
115        "RCONTROL",
116        "","",
117        "MUTE",
118        "CALCULATOR",
119        "PLAYPAUSE",
120        "",
121        "MEDIASTOP",
122        "","","","","","","","","",
123        "VOLUMEDOWN",
124        "",
125        "VOLUMEUP",
126        "",
127        "WEBHOME",
128        "NUMPADCOMMA",
129        "",
130        "DIVIDE",
131        "",
132        "SYSRQ",
133        "RMENU",
134        "","","","","","","","","","","","",
135        "PAUSE",
136        "",
137        "HOME",
138        "UP",
139        "PGUP",
140        "",
141        "LEFT",
142        "",
143        "RIGHT",
144        "",
145        "END", "DOWN", "PGDOWN", "INSERT", "DELETE",
146        "","","","","","","",
147        "LWIN", "RWIN", "APPS",
148        "POWER", "SLEEP",
149        "","","",
150        "WAKE",
151        "",
152        "WEBSEARCH", "WEBFAVORITES", "WEBREFRESH", "WEBSTOP", "WEBFORWARD", "WEBBACK",
153        "MYCOMPUTER", "MAIL", "MEDIASELECT"
154        };
155        for (unsigned int i = 0; i < nKeys_s; i++)
156            keys_[i].name_ = "Key" + keyNames[i];
157
158        // mouse buttons
159        std::string mouseButtonNames[] = {
160            "MouseLeft",     "MouseRight",   "MouseMiddle",
161            "MouseButton3",  "MouseButton4", "MouseButton5",
162            "MouseButton6",  "MouseButton7",
163            "MouseWheel1Up", "MouseWheel1Down",
164            "MouseWheel2Up", "MouseWheel2Down"
165        };
166        for (unsigned int i = 0; i < nMouseButtons_s; i++)
167            mouseButtons_[i].name_ = mouseButtonNames[i];
168
169        // joy stick buttons
170        for (unsigned int i = 0; i < 32; i++)
171            joyStickButtons_[i].name_ = "JoyButton" + getConvertedValue<int, std::string>(i);
172        for (unsigned int i = 32; i < nJoyStickButtons_s; i += 4)
173        {
174            joyStickButtons_[i + 0].name_ = "JoyPOV" + convertToString((i - 32)/4 + 1) + "North";
175            joyStickButtons_[i + 1].name_ = "JoyPOV" + convertToString((i - 32)/4 + 1) + "South";
176            joyStickButtons_[i + 2].name_ = "JoyPOV" + convertToString((i - 32)/4 + 1) + "East";
177            joyStickButtons_[i + 3].name_ = "JoyPOV" + convertToString((i - 32)/4 + 1) + "West";
178        }
179
180        // half axes
181        std::string rawNames[nHalfAxes_s/2];
182        rawNames[0] = "MouseX";
183        rawNames[1] = "MouseY";
184        rawNames[2] = "Empty1";
185        rawNames[3] = "Empty2";
186        for (unsigned int i = 4; i < nHalfAxes_s/2; i++)
187            rawNames[i] = "JoyAxis" + convertToString(i - 3);
188        for (unsigned int i = 0; i < nHalfAxes_s/2; i++)
189        {
190            halfAxes_[i * 2 + 0].name_ = rawNames[i] + "Pos";
191            halfAxes_[i * 2 + 1].name_ = rawNames[i] + "Neg";
192        }
193
194        for (unsigned int i = 0; i < this->nHalfAxes_s; i++)
195            halfAxes_[i].buttonThreshold_ = buttonThreshold_;
196    }
197
198    /**
199    @brief
200        Destructor
201    */
202    KeyBinder::~KeyBinder()
203    {
204        // almost no destructors required because most of the arrays are static.
205        clearBindings(); // does some destruction work
206    }
207
208    /**
209    @brief
210        Loads the key and button bindings.
211    @return
212        True if loading succeeded.
213    */
214    void KeyBinder::loadBindings()
215    {
216        COUT(3) << "KeyBinder: Loading key bindings..." << std::endl;
217
218        clearBindings();
219
220        std::ifstream infile;
221        infile.open("keybindings.ini");
222        if (!infile)
223        {
224            ConfigFileManager::getSingleton()->setFile(CFT_Keybindings, "def_keybindings.ini");
225            ConfigFileManager::getSingleton()->save(CFT_Keybindings, "keybindings.ini");
226        }
227        else
228            infile.close();
229        ConfigFileManager::getSingleton()->setFile(CFT_Keybindings, "keybindings.ini");
230
231        // parse key bindings
232        setConfigValues();
233
234        COUT(3) << "KeyBinder: Loading key bindings done." << std::endl;
235    }
236
237    /**
238    @brief
239        Loader for the key bindings, managed by config values.
240    */
241    void KeyBinder::setConfigValues()
242    {
243        SetConfigValueGeneric(KeyBinder, analogThreshold_, 0.05f)
244            .description("Threshold for analog axes until which the state is 0.");
245        SetConfigValueGeneric(KeyBinder, mouseSensitivity_, 1.0f)
246            .description("Mouse sensitivity.");
247        SetConfigValueGeneric(KeyBinder, bDeriveMouseInput_, false)
248            .description("Whether or not to derive moues movement for the absolute value.");
249        SetConfigValueGeneric(KeyBinder, derivePeriod_, 0.05f)
250            .description("Accuracy of the mouse input deriver. The higher the more precise, but laggier.");
251        SetConfigValueGeneric(KeyBinder, mouseSensitivityDerived_, 1.0f)
252            .description("Mouse sensitivity if mouse input is derived.");
253        SetConfigValueGeneric(KeyBinder, bClipMouse_, true)
254            .description("Whether or not to clip absolute value of mouse in non derive mode.");
255
256        float oldThresh = buttonThreshold_;
257        SetConfigValueGeneric(KeyBinder, buttonThreshold_, 0.80f)
258            .description("Threshold for analog axes until which the button is not pressed.");
259        if (oldThresh != buttonThreshold_)
260            for (unsigned int i = 0; i < nHalfAxes_s; i++)
261                if (halfAxes_[i].buttonThreshold_ == oldThresh)
262                    halfAxes_[i].buttonThreshold_ = buttonThreshold_;
263
264        // keys
265        for (unsigned int i = 0; i < nKeys_s; i++)
266            readTrigger(keys_[i]);
267        // mouse buttons
268        for (unsigned int i = 0; i < nMouseButtons_s; i++)
269            readTrigger(mouseButtons_[i]);
270        // joy stick buttons
271        for (unsigned int i = 0; i < nJoyStickButtons_s; i++)
272            readTrigger(joyStickButtons_[i]);
273        // half axes
274        for (unsigned int i = 0; i < nHalfAxes_s; i++)
275            readTrigger(halfAxes_[i]);
276    }
277
278    void KeyBinder::readTrigger(Button& button)
279    {
280        // config value stuff
281        ConfigValueContainer* cont
282            = ClassIdentifier<KeyBinder>::getIdentifier()->getConfigValueContainer(button.name_);
283        if (!cont)
284        {
285            cont = new ConfigValueContainer
286                (CFT_Keybindings, ClassIdentifier<KeyBinder>::getIdentifier(), button.name_, "");
287            ClassIdentifier<KeyBinder>::getIdentifier()->addConfigValueContainer(button.name_, cont);
288        }
289        std::string old = button.bindingString_;
290        cont->getValue(&button.bindingString_);
291
292        // keybinder stuff
293        if (old != button.bindingString_)
294        {
295            // clear everything so we don't get old axis ParamCommands mixed up
296            button.clear();
297
298            // binding has changed
299            button.parse(paramCommandBuffer_);
300        }
301    }
302
303    /**
304    @brief
305        Overwrites all bindings with ""
306    */
307    void KeyBinder::clearBindings()
308    {
309        for (unsigned int i = 0; i < nKeys_s; i++)
310            keys_[i].clear();
311
312        for (unsigned int i = 0; i < nMouseButtons_s; i++)
313            mouseButtons_[i].clear();
314
315        for (unsigned int i = 0; i < nJoyStickButtons_s; i++)
316            joyStickButtons_[i].clear();
317
318        for (unsigned int i = 0; i < nHalfAxes_s; i++)
319            halfAxes_[i].clear();
320
321        for (unsigned int i = 0; i < paramCommandBuffer_.size(); i++)
322            delete paramCommandBuffer_[i];
323        paramCommandBuffer_.clear();
324    }
325
326    void KeyBinder::resetJoyStickAxes()
327    {
328        for (unsigned int i = 8; i < nHalfAxes_s; i++)
329        {
330            halfAxes_[i].absVal_ = 0.0f;
331            halfAxes_[i].relVal_ = 0.0f;
332        }
333    }
334
335    void KeyBinder::tickMouse(float dt)
336    {
337        tickDevices(0, 8);
338
339        if (bDeriveMouseInput_)
340        {
341            if (deriveTime_ > derivePeriod_)
342            {
343                //CCOUT(3) << "mouse abs: ";
344                for (int i = 0; i < 2; i++)
345                {
346                    if (mouseRelative_[i] > 0)
347                    {
348                        halfAxes_[2*i + 0].absVal_
349                            =  mouseRelative_[i] / deriveTime_ * 0.0005 * mouseSensitivityDerived_;
350                        halfAxes_[2*i + 1].absVal_ = 0.0f;
351                    }
352                    else if (mouseRelative_[i] < 0)
353                    {
354                        halfAxes_[2*i + 0].absVal_ = 0.0f;
355                        halfAxes_[2*i + 1].absVal_
356                            = -mouseRelative_[i] / deriveTime_ * 0.0005 * mouseSensitivityDerived_;
357                    }
358                    else
359                    {
360                        halfAxes_[2*i + 0].absVal_ = 0.0f;
361                        halfAxes_[2*i + 1].absVal_ = 0.0f;
362                    }
363                    //COUT(3) << mouseRelative_[i] << " | ";
364                    mouseRelative_[i] = 0;
365                    halfAxes_[2*i + 0].hasChanged_ = true;
366                    halfAxes_[2*i + 1].hasChanged_ = true;
367                }
368                deriveTime_ = 0.0f;
369                //COUT(3) << std::endl;
370            }
371            else
372                deriveTime_ += dt;
373        }
374    }
375
376    void KeyBinder::tickJoyStick(float dt, int device)
377    {
378        tickDevices(8, nHalfAxes_s);
379    }
380
381    void KeyBinder::tickInput(float dt)
382    {
383        // execute all buffered bindings (additional parameter)
384        for (unsigned int i = 0; i < paramCommandBuffer_.size(); i++)
385            paramCommandBuffer_[i]->execute();
386
387        // always reset the relative movement of the mouse
388        for (unsigned int i = 0; i < 8; i++)
389            halfAxes_[i].relVal_ = 0.0f;
390    }
391
392    void KeyBinder::tickDevices(unsigned int begin, unsigned int end)
393    {
394        for (unsigned int i = begin; i < end; i++)
395        {
396            // button mode
397            // TODO: optimize out all the half axes that don't act as a button at the moment
398            if (halfAxes_[i].hasChanged_)
399            {
400                if (!halfAxes_[i].wasDown_ && halfAxes_[i].absVal_ > halfAxes_[i].buttonThreshold_)
401                {
402                    halfAxes_[i].wasDown_ = true;
403                    if (halfAxes_[i].nCommands_[KeybindMode::OnPress])
404                        halfAxes_[i].execute(KeybindMode::OnPress);
405                }
406                else if (halfAxes_[i].wasDown_ && halfAxes_[i].absVal_ < halfAxes_[i].buttonThreshold_)
407                {
408                    halfAxes_[i].wasDown_ = false;
409                    if (halfAxes_[i].nCommands_[KeybindMode::OnRelease])
410                        halfAxes_[i].execute(KeybindMode::OnRelease);
411                }
412                halfAxes_[i].hasChanged_ = false;
413            }
414
415            if (halfAxes_[i].wasDown_)
416            {
417                if (halfAxes_[i].nCommands_[KeybindMode::OnHold])
418                    halfAxes_[i].execute(KeybindMode::OnHold);
419            }
420
421            // these are the actually useful axis bindings for analog input
422            if (halfAxes_[i].relVal_ > analogThreshold_ || halfAxes_[i].absVal_ > analogThreshold_)
423            {
424                //COUT(3) << halfAxes_[i].name_ << "\t" << halfAxes_[i].absVal_ << std::endl;
425                halfAxes_[i].execute();
426            }
427        }
428    }
429
430    void KeyBinder::keyPressed (const KeyEvent& evt)
431    { keys_[evt.key].execute(KeybindMode::OnPress); }
432
433    void KeyBinder::keyReleased(const KeyEvent& evt)
434    { keys_[evt.key].execute(KeybindMode::OnRelease); }
435
436    void KeyBinder::keyHeld    (const KeyEvent& evt)
437    { keys_[evt.key].execute(KeybindMode::OnHold); }
438
439
440    void KeyBinder::mouseButtonPressed (MouseButton::Enum id)
441    { mouseButtons_[id].execute(KeybindMode::OnPress); }
442
443    void KeyBinder::mouseButtonReleased(MouseButton::Enum id)
444    { mouseButtons_[id].execute(KeybindMode::OnRelease); }
445
446    void KeyBinder::mouseButtonHeld    (MouseButton::Enum id)
447    { mouseButtons_[id].execute(KeybindMode::OnHold); }
448
449
450    void KeyBinder::joyStickButtonPressed (unsigned int joyStickID, unsigned int button)
451    { joyStickButtons_[button].execute(KeybindMode::OnPress); }
452
453    void KeyBinder::joyStickButtonReleased(unsigned int joyStickID, unsigned int button)
454    { joyStickButtons_[button].execute(KeybindMode::OnRelease); }
455
456    void KeyBinder::joyStickButtonHeld    (unsigned int joyStickID, unsigned int button)
457    { joyStickButtons_[button].execute(KeybindMode::OnHold); }
458
459    /**
460    @brief
461        Event handler for the mouseMoved Event.
462    @param e
463        Mouse state information
464    */
465    void KeyBinder::mouseMoved(IntVector2 abs_, IntVector2 rel_, IntVector2 clippingSize)
466    {
467        // y axis of mouse input is inverted
468        int rel[] = { rel_.x, -rel_.y };
469
470        if (!bDeriveMouseInput_)
471        {
472            for (int i = 0; i < 2; i++)
473            {
474                if (rel[i])
475                {
476                    // absolute
477                    halfAxes_[2*i + 0].hasChanged_ = true;
478                    halfAxes_[2*i + 1].hasChanged_ = true;
479                    mousePosition_[i] += rel[i];
480
481                    if (bClipMouse_)
482                    {
483                        if (mousePosition_[i] > 1024)
484                            mousePosition_[i] =  1024;
485                        if (mousePosition_[i] < -1024)
486                            mousePosition_[i] = -1024;
487                    }
488
489                    if (mousePosition_[i] >= 0)
490                    {
491                        halfAxes_[2*i + 0].absVal_ =   mousePosition_[i]/1024.0f * mouseSensitivity_;
492                        halfAxes_[2*i + 1].absVal_ =  0.0f;
493                    }
494                    else
495                    {
496                        halfAxes_[2*i + 0].absVal_ =  0.0f;
497                        halfAxes_[2*i + 1].absVal_ =  -mousePosition_[i]/1024.0f * mouseSensitivity_;
498                    }
499                }
500            }
501        }
502        else
503        {
504            mouseRelative_[0] += rel[0];
505            mouseRelative_[1] += rel[1];
506        }
507
508        // relative
509        for (int i = 0; i < 2; i++)
510        {
511            if (rel[i] > 0)
512                halfAxes_[0 + 2*i].relVal_ =  ((float)rel[i])/1024 * mouseSensitivity_;
513            else
514                halfAxes_[1 + 2*i].relVal_ = -((float)rel[i])/1024 * mouseSensitivity_;
515        }
516    }
517
518    /**
519    @brief Event handler for the mouseScrolled Event.
520    @param e Mouse state information
521    */
522    void KeyBinder::mouseScrolled(int abs, int rel)
523    {
524        //COUT(3) << mouseButtons_[8].name_ << "   " << abs << " | " << rel << std::endl;
525
526        if (rel > 0)
527            for (int i = 0; i < rel/120; i++)
528                mouseButtons_[8].execute(KeybindMode::OnPress, ((float)abs)/120.0f);
529        else
530            for (int i = 0; i < -rel/120; i++)
531                mouseButtons_[9].execute(KeybindMode::OnPress, ((float)abs)/120.0f);
532    }
533
534    void KeyBinder::joyStickAxisMoved(unsigned int joyStickID, unsigned int axis, float value)
535    {
536        int i = 8 + axis * 2;
537        if (value >= 0)
538        {
539            //if (value > 10000)
540            //{ CCOUT(3) << halfAxes_[i].name_ << std::endl; }
541
542            halfAxes_[i].absVal_ = value;
543            halfAxes_[i].relVal_ = value;
544            halfAxes_[i].hasChanged_ = true;
545            if (halfAxes_[i + 1].absVal_ > 0.0f)
546            {
547                halfAxes_[i + 1].absVal_ = -0.0f;
548                halfAxes_[i + 1].relVal_ = -0.0f;
549                halfAxes_[i + 1].hasChanged_ = true;
550            }
551        }
552        else
553        {
554            //if (value < -10000)
555            //{ CCOUT(3) << halfAxes_[i + 1].name_ << std::endl; }
556
557            halfAxes_[i + 1].absVal_ = -value;
558            halfAxes_[i + 1].relVal_ = -value;
559            halfAxes_[i + 1].hasChanged_ = true;
560            if (halfAxes_[i].absVal_ > 0.0f)
561            {
562                halfAxes_[i].absVal_ = -0.0f;
563                halfAxes_[i].relVal_ = -0.0f;
564                halfAxes_[i].hasChanged_ = true;
565            }
566        }
567    }
568}
Note: See TracBrowser for help on using the repository browser.