[cosmetic] cleanup copyright headers
[vuplus_xbmc] / xbmc / input / linux / XKBCommonKeymap.cpp
1 /*
2  *      Copyright (C) 2011-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program 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
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20 #include <sstream>
21 #include <iostream>
22 #include <stdexcept>
23
24 #include <boost/scope_exit.hpp>
25
26 #include <sys/mman.h>
27
28 #include <xkbcommon/xkbcommon.h>
29
30 #include "Application.h"
31
32 #include "windowing/DllXKBCommon.h"
33 #include "XKBCommonKeymap.h"
34
35 struct xkb_context *
36 CXKBKeymap::CreateXKBContext(IDllXKBCommon &xkbCommonLibrary)
37 {
38   enum xkb_context_flags flags =
39     static_cast<enum xkb_context_flags>(0);
40
41   struct xkb_context *context = xkbCommonLibrary.xkb_context_new(flags);
42   
43   /* It is the object who wants to create an XKBKeymap and not
44    * XKBKeymap itself that owns the xkb_context. The
45    * xkb_context is merely just a detail for construction of the
46    * more interesting xkb_state and xkb_keymap objects.
47    * 
48    * Failure to create the context effectively means that that object
49    * will be unable to create a keymap or serve any useful purpose in
50    * processing key events. As such, it makes this an incomplete
51    * object and a runtime_error will be thrown */
52   if (!context)
53     throw std::runtime_error("Failed to create xkb context");
54   
55   return context;
56 }
57
58 /* Opens a shared memory region and parses the data in it to an
59  * xkbcommon keymap.
60  * 
61  * Generally a keymap is determined by the compositor by evaluating
62  * the currently available hardware and compiling a keymap
63  * most appropriate for that hardware. The compositor simply
64  * sends keycodes and modifier bits in the wire protocol. It is the
65  * client's responsibility to handle transformation of those hardware
66  * specific keycodes and modifier bits into a common keyboard
67  * representation. The compositor provides a serialized keymap
68  * in shared memory to allow clients to perform these transformations.
69  * 
70  * This function does not own the file descriptor. The fact that it
71  * is sent as a const & is a reminder of that. It must not be closed
72  * from this function.
73  */
74 struct xkb_keymap *
75 CXKBKeymap::ReceiveXKBKeymapFromSharedMemory(IDllXKBCommon &xkbCommonLibrary, struct xkb_context *context, const int &fd, uint32_t size)
76 {
77   const char *keymapString = static_cast<const char *>(mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0));
78   if (keymapString == MAP_FAILED)
79   {
80     std::stringstream ss;
81     ss << "mmap: " << strerror(errno);
82     throw std::runtime_error(ss.str());
83   }
84
85   /* In every exit path, the keymap string memory region must be
86    * unmapped */
87   BOOST_SCOPE_EXIT((keymapString)(size))
88   {
89     munmap(const_cast<void *>(static_cast<const void *>(keymapString)),
90                               size);
91   } BOOST_SCOPE_EXIT_END
92
93   enum xkb_keymap_compile_flags flags =
94     static_cast<enum xkb_keymap_compile_flags>(0);
95   struct xkb_keymap *keymap =
96     xkbCommonLibrary.xkb_keymap_new_from_string(context, keymapString, XKB_KEYMAP_FORMAT_TEXT_V1, flags);
97
98   /* Failure to compile a keymap is a runtime error and the caller
99    * should handle it */
100   if (!keymap)
101     throw std::runtime_error("Failed to compile keymap");
102
103   return keymap;
104 }
105
106 struct xkb_keymap *
107 CXKBKeymap::CreateXKBKeymapFromNames(IDllXKBCommon &xkbCommonLibrary, struct xkb_context *context, const std::string &rules, const std::string &model, const std::string &layout, const std::string &variant, const std::string &options)
108 {
109   enum xkb_keymap_compile_flags flags =
110     static_cast<enum xkb_keymap_compile_flags>(0);
111   
112   struct xkb_rule_names names =
113   {
114     rules.c_str(),
115     model.c_str(),
116     layout.c_str(),
117     variant.c_str(),
118     options.c_str()
119   };
120   
121   struct xkb_keymap *keymap =
122     xkbCommonLibrary.xkb_keymap_new_from_names(context, &names, flags);
123
124   if (!keymap)
125     throw std::runtime_error("Failed to compile keymap");
126
127   return keymap;
128 }
129
130 struct xkb_state *
131 CXKBKeymap::CreateXKBStateFromKeymap(IDllXKBCommon &xkbCommonLibrary, struct xkb_keymap *keymap)
132 {
133   struct xkb_state *state = xkbCommonLibrary.xkb_state_new(keymap);
134
135   if (!state)
136     throw std::runtime_error("Failed to create keyboard state");
137
138   return state;
139 }
140
141 /* A wrapper class around an xkbcommon keymap and state tracker.
142  * 
143  * This class knows about some common modifier combinations and keeps
144  * track of the currently pressed keys and modifiers. It also has
145  * some utility functions to transform hardware keycodes into
146  * a common representation.
147  * 
148  * Since this class is keeping track of all the pressed and depressed
149  * modifiers, IT MUST ALWAYS BE KEPT UP TO DATE WITH ANY NEWLY
150  * PRESSED MODIFIERS. Undefined behaviour will result if it is not
151  * kept up to date.
152  */
153 CXKBKeymap::CXKBKeymap(IDllXKBCommon &xkbCommonLibrary,
154                        struct xkb_keymap *keymap) :
155   m_xkbCommonLibrary(xkbCommonLibrary),
156   m_keymap(keymap),
157   m_state(CreateXKBStateFromKeymap(xkbCommonLibrary,
158                                    keymap)),
159   m_internalLeftControlIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
160                                                                          XKB_MOD_NAME_CTRL)),
161   m_internalLeftShiftIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
162                                                                        XKB_MOD_NAME_SHIFT)),
163   m_internalLeftSuperIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
164                                                                        XKB_MOD_NAME_LOGO)),
165   m_internalLeftAltIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
166                                                                      XKB_MOD_NAME_ALT)),
167   m_internalLeftMetaIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
168                                                                       "Meta")),
169   m_internalRightControlIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
170                                                                           "RControl")),
171   m_internalRightShiftIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
172                                                                         "RShift")),
173   m_internalRightSuperIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
174                                                                         "Hyper")),
175   m_internalRightAltIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
176                                                                       "AltGr")),
177   m_internalRightMetaIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
178                                                                        "Meta")),
179   m_internalCapsLockIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
180                                                                       XKB_LED_NAME_CAPS)),
181   m_internalNumLockIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
182                                                                      XKB_LED_NAME_NUM)),
183   m_internalModeIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
184                                                                   XKB_LED_NAME_SCROLL))
185 {
186 }
187
188 CXKBKeymap::~CXKBKeymap()
189 {
190   m_xkbCommonLibrary.xkb_state_unref(m_state);
191   m_xkbCommonLibrary.xkb_keymap_unref(m_keymap);
192 }
193
194 uint32_t
195 CXKBKeymap::KeysymForKeycode(uint32_t code) const
196 {
197   const xkb_keysym_t *syms;
198   uint32_t numSyms;
199
200   /* Key the keysyms for a particular keycode. Generally each
201    * keycode should only have one symbol, but if it has more than
202    * one then we're unable to just get one symbol for it, so that's
203    * a runtime_error which the client needs to handle.
204    * 
205    * Codes sent generally have an offset of 8 */
206   numSyms = m_xkbCommonLibrary.xkb_state_key_get_syms(m_state, code + 8, &syms);
207
208   if (numSyms == 1)
209     return static_cast<uint32_t>(syms[0]);
210
211   std::stringstream ss;
212   ss << "Pressed key "
213      << std::hex
214      << code
215      << std::dec
216      << " is unspported";
217
218   throw std::runtime_error(ss.str());
219 }
220
221 /* Gets the currently depressed, latched and locked modifiers
222  * for the keyboard */
223 uint32_t CXKBKeymap::CurrentModifiers() const
224 {
225   enum xkb_state_component components =
226     static_cast <xkb_state_component>(XKB_STATE_DEPRESSED |
227                                       XKB_STATE_LATCHED |
228                                       XKB_STATE_LOCKED);
229   xkb_mod_mask_t mask = m_xkbCommonLibrary.xkb_state_serialize_mods(m_state,
230                                                                     components);
231   return mask;
232 }
233
234 /* Updates the currently depressed, latched, locked and group
235  * modifiers for a keyboard being tracked.
236  * 
237  * THIS FUNCTION MUST BE CALLED WHENEVER MODIFIERS CHANGE */
238 void CXKBKeymap::UpdateMask(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group)
239 {
240   m_xkbCommonLibrary.xkb_state_update_mask(m_state, depressed, latched, locked, 0, 0, group);
241 }
242
243 uint32_t CXKBKeymap::ActiveXBMCModifiers() const
244 {
245   xkb_mod_mask_t mask(CurrentModifiers());
246   XBMCMod xbmcModifiers = XBMCKMOD_NONE;
247   
248   struct ModTable
249   {
250     xkb_mod_index_t xkbMod;
251     XBMCMod xbmcMod;
252   } modTable[] =
253   {
254     { m_internalLeftShiftIndex, XBMCKMOD_LSHIFT },
255     { m_internalRightShiftIndex, XBMCKMOD_RSHIFT },
256     { m_internalLeftShiftIndex, XBMCKMOD_LSUPER },
257     { m_internalRightSuperIndex, XBMCKMOD_RSUPER },
258     { m_internalLeftControlIndex, XBMCKMOD_LCTRL },
259     { m_internalRightControlIndex, XBMCKMOD_RCTRL },
260     { m_internalLeftAltIndex, XBMCKMOD_LALT },
261     { m_internalRightAltIndex, XBMCKMOD_RALT },
262     { m_internalLeftMetaIndex, XBMCKMOD_LMETA },
263     { m_internalRightMetaIndex, XBMCKMOD_RMETA },
264     { m_internalNumLockIndex, XBMCKMOD_NUM },
265     { m_internalCapsLockIndex, XBMCKMOD_CAPS },
266     { m_internalModeIndex, XBMCKMOD_MODE }
267   };
268
269   size_t modTableSize = sizeof(modTable) / sizeof(modTable[0]);
270
271   for (size_t i = 0; i < modTableSize; ++i)
272   {
273     if (mask & (1 << modTable[i].xkbMod))
274       xbmcModifiers = static_cast<XBMCMod>(xbmcModifiers | modTable[i].xbmcMod);
275   }
276
277   return static_cast<uint32_t>(xbmcModifiers);
278 }
279
280 uint32_t CXKBKeymap::XBMCKeysymForKeycode(uint32_t code) const
281 {
282   uint32_t sym =  KeysymForKeycode(code);
283
284   /* Strip high bits from functional keys */
285   if ((sym & ~(0xff00)) <= 0x1b)
286     sym = sym & ~(0xff00);
287   else if ((sym & ~(0xff00)) == 0xff)
288     sym = static_cast<uint32_t>(XBMCK_DELETE);
289   
290   /* We only support keys within certain ranges */
291   const bool isNavigationKey = (sym >= 0xff50 && sym <= 0xff58);
292   const bool isModifierKey = (sym >= 0xffe1 && sym <= 0xffee);
293   const bool isKeyPadKey = (sym >= 0xffb1 && sym <= 0xffb9);
294   const bool isFKey = (sym >= 0xffbe && sym <= 0xffcc);
295   const bool isMediaKey = (sym >= 0x1008ff26 && sym <= 0x1008ffa2);
296
297   if (isNavigationKey ||
298       isModifierKey ||
299       isKeyPadKey ||
300       isFKey ||
301       isMediaKey)
302   {
303     /* Navigation keys are not in line, so we need to
304      * look them up */
305     static const struct NavigationKeySyms
306     {
307       uint32_t xkb;
308       XBMCKey xbmc;
309     } navigationKeySyms[] =
310     {
311       { XKB_KEY_Home, XBMCK_HOME },
312       { XKB_KEY_Left, XBMCK_LEFT },
313       { XKB_KEY_Right, XBMCK_RIGHT },
314       { XKB_KEY_Down, XBMCK_DOWN },
315       { XKB_KEY_Up, XBMCK_UP },
316       { XKB_KEY_Page_Up, XBMCK_PAGEUP },
317       { XKB_KEY_Page_Down, XBMCK_PAGEDOWN },
318       { XKB_KEY_End, XBMCK_END },
319       { XKB_KEY_Insert, XBMCK_INSERT },
320       { XKB_KEY_KP_0, XBMCK_KP0 },
321       { XKB_KEY_KP_1, XBMCK_KP1 },
322       { XKB_KEY_KP_2, XBMCK_KP2 },
323       { XKB_KEY_KP_3, XBMCK_KP3 },
324       { XKB_KEY_KP_4, XBMCK_KP4 },
325       { XKB_KEY_KP_5, XBMCK_KP5 },
326       { XKB_KEY_KP_6, XBMCK_KP6 },
327       { XKB_KEY_KP_7, XBMCK_KP7 },
328       { XKB_KEY_KP_8, XBMCK_KP8 },
329       { XKB_KEY_KP_9, XBMCK_KP9 },
330       { XKB_KEY_KP_Decimal, XBMCK_KP_PERIOD },
331       { XKB_KEY_KP_Divide, XBMCK_KP_DIVIDE },
332       { XKB_KEY_KP_Multiply, XBMCK_KP_MULTIPLY },
333       { XKB_KEY_KP_Add, XBMCK_KP_PLUS },
334       { XKB_KEY_KP_Separator, XBMCK_KP_MINUS },
335       { XKB_KEY_KP_Equal, XBMCK_KP_EQUALS },
336       { XKB_KEY_F1, XBMCK_F1 },
337       { XKB_KEY_F2, XBMCK_F2 },
338       { XKB_KEY_F3, XBMCK_F3 },
339       { XKB_KEY_F4, XBMCK_F4 },
340       { XKB_KEY_F5, XBMCK_F5 },
341       { XKB_KEY_F6, XBMCK_F6 },
342       { XKB_KEY_F7, XBMCK_F7 },
343       { XKB_KEY_F8, XBMCK_F8 },
344       { XKB_KEY_F9, XBMCK_F9 },
345       { XKB_KEY_F10, XBMCK_F10 },
346       { XKB_KEY_F11, XBMCK_F11 },
347       { XKB_KEY_F12, XBMCK_F12 },
348       { XKB_KEY_F13, XBMCK_F13 },
349       { XKB_KEY_F14, XBMCK_F14 },
350       { XKB_KEY_F15, XBMCK_F15 },
351       { XKB_KEY_Caps_Lock, XBMCK_CAPSLOCK },
352       { XKB_KEY_Shift_Lock, XBMCK_SCROLLOCK },
353       { XKB_KEY_Shift_R, XBMCK_RSHIFT },
354       { XKB_KEY_Shift_L, XBMCK_LSHIFT },
355       { XKB_KEY_Alt_R, XBMCK_RALT },
356       { XKB_KEY_Alt_L, XBMCK_LALT },
357       { XKB_KEY_Control_R, XBMCK_RCTRL },
358       { XKB_KEY_Control_L, XBMCK_LCTRL },
359       { XKB_KEY_Meta_R, XBMCK_RMETA },
360       { XKB_KEY_Meta_L, XBMCK_LMETA },
361       { XKB_KEY_Super_R, XBMCK_RSUPER },
362       { XKB_KEY_Super_L, XBMCK_LSUPER },
363       { XKB_KEY_XF86Eject, XBMCK_EJECT },
364       { XKB_KEY_XF86AudioStop, XBMCK_STOP },
365       { XKB_KEY_XF86AudioRecord, XBMCK_RECORD },
366       { XKB_KEY_XF86AudioRewind, XBMCK_REWIND },
367       { XKB_KEY_XF86AudioPlay, XBMCK_PLAY },
368       { XKB_KEY_XF86AudioRandomPlay, XBMCK_SHUFFLE },
369       { XKB_KEY_XF86AudioForward, XBMCK_FASTFORWARD }
370     };
371   
372     static const size_t navigationKeySymsSize = sizeof(navigationKeySyms) /
373                                                 sizeof(navigationKeySyms[0]);
374
375     for (size_t i = 0; i < navigationKeySymsSize; ++i)
376     {
377       if (navigationKeySyms[i].xkb == sym)
378       {
379         sym = navigationKeySyms[i].xbmc;
380         break;
381       }
382     }
383   }
384
385   return sym;
386 }