]> git.mxchange.org Git - simgear.git/blob - simgear/canvas/events/KeyboardEvent.cxx
Add simple keyboard event demo application.
[simgear.git] / simgear / canvas / events / KeyboardEvent.cxx
1 // Keyboard event
2 //
3 // Copyright (C) 2014  Thomas Geymayer <tomgey@gmail.com>
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Library General Public
7 // License as published by the Free Software Foundation; either
8 // version 2 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // Library General Public License for more details.
14 //
15 // You should have received a copy of the GNU Library General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
18
19 #include "KeyboardEvent.hxx"
20 #include "utf8.h"
21
22 #include <osgGA/GUIEventAdapter>
23
24 #include <boost/version.hpp>
25 #if BOOST_VERSION >= 104800
26 # include <boost/container/flat_map.hpp>
27 # include <boost/container/flat_set.hpp>
28 #else
29 # include <map>
30 # include <set>
31 #endif
32
33 #include <iterator>
34
35 namespace simgear
36 {
37 namespace canvas
38 {
39   typedef osgGA::GUIEventAdapter EA;
40
41   // TODO check Win/Mac keycode for altgr/ISO Level3 Shift
42   const uint32_t KEY_AltGraph = 0xfe03;
43
44   //----------------------------------------------------------------------------
45   KeyboardEvent::KeyboardEvent():
46     _key(0),
47     _unmodified_key(0),
48     _repeat(false),
49     _location(DOM_KEY_LOCATION_STANDARD)
50   {
51
52   }
53
54   //----------------------------------------------------------------------------
55   KeyboardEvent::KeyboardEvent(const osgGA::GUIEventAdapter& ea):
56     DeviceEvent(ea),
57     _key(ea.getKey()),
58     _unmodified_key(ea.getUnmodifiedKey()),
59     _repeat(false),
60     _location(DOM_KEY_LOCATION_STANDARD)
61   {
62     if( ea.getEventType() == EA::KEYDOWN )
63       type = KEY_DOWN;
64     else if( ea.getEventType() == EA::KEYUP )
65       type = KEY_UP;
66 //    else
67 //      // TODO what to do with wrong event type?
68   }
69
70   //----------------------------------------------------------------------------
71   void KeyboardEvent::setKey(uint32_t key)
72   {
73     _name.clear();
74     _key = key;
75   }
76
77   //----------------------------------------------------------------------------
78   void KeyboardEvent::setUnmodifiedKey(uint32_t key)
79   {
80     _name.clear();
81     _unmodified_key = key;
82   }
83
84   //----------------------------------------------------------------------------
85   void KeyboardEvent::setRepeat(bool repeat)
86   {
87     _repeat = repeat;
88   }
89
90   //----------------------------------------------------------------------------
91   std::string KeyboardEvent::key() const
92   {
93     if( !_name.empty() )
94       return _name;
95
96     // We need to make sure only valid const char* pointers are passed. The best
97     // way is just to use string constants.
98     // Use an empty string ("") to just use the value reported by the operating
99     // system.
100     typedef std::pair<const char*, uint8_t> InternalKeyInfo;
101
102 #if BOOST_VERSION >= 104800
103     typedef boost::container::flat_map<int, InternalKeyInfo> InternalKeyMap;
104     typedef boost::container::flat_set<int> KeyList;
105 #else
106 #   warning "Use Boost >= 1.48 for faster and more memory efficient key lookup"
107     typedef std::map<int, InternalKeyInfo> InternalKeyMap;
108     typedef std::set<int> KeyList;
109 #endif
110
111     static InternalKeyMap key_map;
112     static KeyList num_pad_keys;
113
114     if( key_map.empty() )
115     {
116       const uint8_t S = DOM_KEY_LOCATION_STANDARD,
117                     L = DOM_KEY_LOCATION_LEFT,
118                     R = DOM_KEY_LOCATION_RIGHT,
119                     N = DOM_KEY_LOCATION_NUMPAD;
120
121       key_map[ EA::KEY_BackSpace    ] = std::make_pair("Backspace", S);
122       key_map[ EA::KEY_Tab          ] = std::make_pair("Tab", S);
123       key_map[ EA::KEY_Linefeed     ] = std::make_pair("Linefeed", S);
124       key_map[ EA::KEY_Clear        ] = std::make_pair("Clear", S);
125       key_map[ EA::KEY_Return       ] = std::make_pair("Enter", S);
126       key_map[ EA::KEY_Pause        ] = std::make_pair("Pause", S);
127       key_map[ EA::KEY_Scroll_Lock  ] = std::make_pair("ScrollLock", S);
128       key_map[ EA::KEY_Sys_Req      ] = std::make_pair("SystemRequest", S);
129       key_map[ EA::KEY_Escape       ] = std::make_pair("Escape", S);
130       key_map[ EA::KEY_Delete       ] = std::make_pair("Delete", S);
131
132       key_map[ EA::KEY_Home         ] = std::make_pair("Home", S);
133       key_map[ EA::KEY_Left         ] = std::make_pair("Left", S);
134       key_map[ EA::KEY_Up           ] = std::make_pair("Up", S);
135       key_map[ EA::KEY_Right        ] = std::make_pair("Right", S);
136       key_map[ EA::KEY_Down         ] = std::make_pair("Down", S);
137       key_map[ EA::KEY_Page_Up      ] = std::make_pair("PageUp", S);
138       key_map[ EA::KEY_Page_Down    ] = std::make_pair("PageDown", S);
139       key_map[ EA::KEY_End          ] = std::make_pair("End", S);
140       key_map[ EA::KEY_Begin        ] = std::make_pair("Begin", S);
141
142       key_map[ EA::KEY_Select       ] = std::make_pair("Select", S);
143       key_map[ EA::KEY_Print        ] = std::make_pair("PrintScreen", S);
144       key_map[ EA::KEY_Execute      ] = std::make_pair("Execute", S);
145       key_map[ EA::KEY_Insert       ] = std::make_pair("Insert", S);
146       key_map[ EA::KEY_Undo         ] = std::make_pair("Undo", S);
147       key_map[ EA::KEY_Redo         ] = std::make_pair("Redo", S);
148       key_map[ EA::KEY_Menu         ] = std::make_pair("ContextMenu", S);
149       key_map[ EA::KEY_Find         ] = std::make_pair("Find", S);
150       key_map[ EA::KEY_Cancel       ] = std::make_pair("Cancel", S);
151       key_map[ EA::KEY_Help         ] = std::make_pair("Help", S);
152       key_map[ EA::KEY_Break        ] = std::make_pair("Break", S);
153       key_map[ EA::KEY_Mode_switch  ] = std::make_pair("ModeChange", S);
154       key_map[ EA::KEY_Num_Lock     ] = std::make_pair("NumLock", S);
155
156       key_map[ EA::KEY_KP_Space     ] = std::make_pair(" ", N);
157       key_map[ EA::KEY_KP_Tab       ] = std::make_pair("Tab", N);
158       key_map[ EA::KEY_KP_Enter     ] = std::make_pair("Enter", N);
159       key_map[ EA::KEY_KP_F1        ] = std::make_pair("F1", N);
160       key_map[ EA::KEY_KP_F2        ] = std::make_pair("F2", N);
161       key_map[ EA::KEY_KP_F3        ] = std::make_pair("F3", N);
162       key_map[ EA::KEY_KP_F4        ] = std::make_pair("F4", N);
163       key_map[ EA::KEY_KP_Home      ] = std::make_pair("Home", N);
164       key_map[ EA::KEY_KP_Left      ] = std::make_pair("Left", N);
165       key_map[ EA::KEY_KP_Up        ] = std::make_pair("Up", N);
166       key_map[ EA::KEY_KP_Right     ] = std::make_pair("Right", N);
167       key_map[ EA::KEY_KP_Down      ] = std::make_pair("Down", N);
168       key_map[ EA::KEY_KP_Page_Up   ] = std::make_pair("PageUp", N);
169       key_map[ EA::KEY_KP_Page_Down ] = std::make_pair("PageDown", N);
170       key_map[ EA::KEY_KP_End       ] = std::make_pair("End", N);
171       key_map[ EA::KEY_KP_Begin     ] = std::make_pair("Begin", N);
172       key_map[ EA::KEY_KP_Insert    ] = std::make_pair("Insert", N);
173       key_map[ EA::KEY_KP_Delete    ] = std::make_pair("Delete", N);
174       key_map[ EA::KEY_KP_Equal     ] = std::make_pair("=", N);
175       key_map[ EA::KEY_KP_Multiply  ] = std::make_pair("*", N);
176       key_map[ EA::KEY_KP_Add       ] = std::make_pair("+", N);
177       key_map[ EA::KEY_KP_Separator ] = std::make_pair("", N);
178       key_map[ EA::KEY_KP_Subtract  ] = std::make_pair("-", N);
179       key_map[ EA::KEY_KP_Decimal   ] = std::make_pair("", N);
180       key_map[ EA::KEY_KP_Divide    ] = std::make_pair("/", N);
181
182       key_map[ EA::KEY_KP_0 ] = std::make_pair("0", N);
183       key_map[ EA::KEY_KP_1 ] = std::make_pair("1", N);
184       key_map[ EA::KEY_KP_2 ] = std::make_pair("2", N);
185       key_map[ EA::KEY_KP_3 ] = std::make_pair("3", N);
186       key_map[ EA::KEY_KP_4 ] = std::make_pair("4", N);
187       key_map[ EA::KEY_KP_5 ] = std::make_pair("5", N);
188       key_map[ EA::KEY_KP_6 ] = std::make_pair("6", N);
189       key_map[ EA::KEY_KP_7 ] = std::make_pair("7", N);
190       key_map[ EA::KEY_KP_8 ] = std::make_pair("8", N);
191       key_map[ EA::KEY_KP_9 ] = std::make_pair("9", N);
192
193       key_map[ EA::KEY_F1   ] = std::make_pair("F1", S);
194       key_map[ EA::KEY_F2   ] = std::make_pair("F2", S);
195       key_map[ EA::KEY_F3   ] = std::make_pair("F3", S);
196       key_map[ EA::KEY_F4   ] = std::make_pair("F4", S);
197       key_map[ EA::KEY_F5   ] = std::make_pair("F5", S);
198       key_map[ EA::KEY_F6   ] = std::make_pair("F6", S);
199       key_map[ EA::KEY_F7   ] = std::make_pair("F7", S);
200       key_map[ EA::KEY_F8   ] = std::make_pair("F8", S);
201       key_map[ EA::KEY_F9   ] = std::make_pair("F9", S);
202       key_map[ EA::KEY_F10  ] = std::make_pair("F10", S);
203       key_map[ EA::KEY_F11  ] = std::make_pair("F11", S);
204       key_map[ EA::KEY_F12  ] = std::make_pair("F12", S);
205       key_map[ EA::KEY_F13  ] = std::make_pair("F13", S);
206       key_map[ EA::KEY_F14  ] = std::make_pair("F14", S);
207       key_map[ EA::KEY_F15  ] = std::make_pair("F15", S);
208       key_map[ EA::KEY_F16  ] = std::make_pair("F16", S);
209       key_map[ EA::KEY_F17  ] = std::make_pair("F17", S);
210       key_map[ EA::KEY_F18  ] = std::make_pair("F18", S);
211       key_map[ EA::KEY_F19  ] = std::make_pair("F19", S);
212       key_map[ EA::KEY_F20  ] = std::make_pair("F20", S);
213       key_map[ EA::KEY_F21  ] = std::make_pair("F21", S);
214       key_map[ EA::KEY_F22  ] = std::make_pair("F22", S);
215       key_map[ EA::KEY_F23  ] = std::make_pair("F23", S);
216       key_map[ EA::KEY_F24  ] = std::make_pair("F24", S);
217       key_map[ EA::KEY_F25  ] = std::make_pair("F25", S);
218       key_map[ EA::KEY_F26  ] = std::make_pair("F26", S);
219       key_map[ EA::KEY_F27  ] = std::make_pair("F27", S);
220       key_map[ EA::KEY_F28  ] = std::make_pair("F28", S);
221       key_map[ EA::KEY_F29  ] = std::make_pair("F29", S);
222       key_map[ EA::KEY_F30  ] = std::make_pair("F30", S);
223       key_map[ EA::KEY_F31  ] = std::make_pair("F31", S);
224       key_map[ EA::KEY_F32  ] = std::make_pair("F32", S);
225       key_map[ EA::KEY_F33  ] = std::make_pair("F33", S);
226       key_map[ EA::KEY_F34  ] = std::make_pair("F34", S);
227       key_map[ EA::KEY_F35  ] = std::make_pair("F35", S);
228
229       key_map[ KEY_AltGraph       ] = std::make_pair("AltGraph", S);
230       key_map[ EA::KEY_Shift_L    ] = std::make_pair("Shift", L);
231       key_map[ EA::KEY_Shift_R    ] = std::make_pair("Shift", R);
232       key_map[ EA::KEY_Control_L  ] = std::make_pair("Control", L);
233       key_map[ EA::KEY_Control_R  ] = std::make_pair("Control", R);
234       key_map[ EA::KEY_Caps_Lock  ] = std::make_pair("CapsLock", S);
235       key_map[ EA::KEY_Shift_Lock ] = std::make_pair("ShiftLock", S);
236       key_map[ EA::KEY_Meta_L     ] = std::make_pair("Meta", L);
237       key_map[ EA::KEY_Meta_R     ] = std::make_pair("Meta", R);
238       key_map[ EA::KEY_Alt_L      ] = std::make_pair("Alt", L);
239       key_map[ EA::KEY_Alt_R      ] = std::make_pair("Alt", R);
240       key_map[ EA::KEY_Super_L    ] = std::make_pair("Super", L);
241       key_map[ EA::KEY_Super_R    ] = std::make_pair("Super", R);
242       key_map[ EA::KEY_Hyper_L    ] = std::make_pair("Hyper", L);
243       key_map[ EA::KEY_Hyper_R    ] = std::make_pair("Hyper", R);
244
245       num_pad_keys.insert(EA::KEY_KP_Home     );
246       num_pad_keys.insert(EA::KEY_KP_Left     );
247       num_pad_keys.insert(EA::KEY_KP_Up       );
248       num_pad_keys.insert(EA::KEY_KP_Right    );
249       num_pad_keys.insert(EA::KEY_KP_Down     );
250       num_pad_keys.insert(EA::KEY_KP_Page_Up  );
251       num_pad_keys.insert(EA::KEY_KP_Page_Down);
252       num_pad_keys.insert(EA::KEY_KP_End      );
253       num_pad_keys.insert(EA::KEY_KP_Begin    );
254       num_pad_keys.insert(EA::KEY_KP_Insert   );
255       num_pad_keys.insert(EA::KEY_KP_Delete   );
256     }
257
258     _location = DOM_KEY_LOCATION_STANDARD;
259
260     InternalKeyMap::const_iterator it = key_map.find(_key);
261     if( it != key_map.end())
262     {
263       _name = it->second.first;
264       _location = it->second.second;
265     }
266
267     // Empty or no mapping -> convert UTF-32 key value to UTF-8
268     if( _name.empty() )
269     {
270       if( !utf8::internal::is_code_point_valid(_key) )
271         _name = "Unidentified";
272       else
273         utf8::unchecked::append(_key, std::back_inserter(_name));
274     }
275
276     // Keys on the numpad with NumLock enabled are reported just like their
277     // equivalent keys in the standard key block. Using the unmodified key value
278     // we can detect such keys and set the location accordingly.
279     if( num_pad_keys.find(_unmodified_key) != num_pad_keys.end() )
280       _location = DOM_KEY_LOCATION_NUMPAD;
281
282     return _name;
283   }
284
285   //----------------------------------------------------------------------------
286   KeyboardEvent::DOMKeyLocation KeyboardEvent::location() const
287   {
288     key(); // ensure location is up-to-date
289     return static_cast<DOMKeyLocation>(_location);
290   }
291
292   //----------------------------------------------------------------------------
293   bool KeyboardEvent::isModifier() const
294   {
295     return (  _key >= EA::KEY_Shift_L
296            && _key <= EA::KEY_Hyper_R
297            )
298         || _key == KEY_AltGraph;
299   }
300
301 } // namespace canvas
302 } // namespace simgear