2 * Copyright (C) 2011-2013 Team XBMC
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)
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.
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/>.
24 #include <boost/scope_exit.hpp>
28 #include <xkbcommon/xkbcommon.h>
30 #include "Application.h"
32 #include "windowing/DllXKBCommon.h"
33 #include "XKBCommonKeymap.h"
36 CXKBKeymap::CreateXKBContext(IDllXKBCommon &xkbCommonLibrary)
38 enum xkb_context_flags flags =
39 static_cast<enum xkb_context_flags>(0);
41 struct xkb_context *context = xkbCommonLibrary.xkb_context_new(flags);
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.
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 */
53 throw std::runtime_error("Failed to create xkb context");
58 /* Opens a shared memory region and parses the data in it to an
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.
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
75 CXKBKeymap::ReceiveXKBKeymapFromSharedMemory(IDllXKBCommon &xkbCommonLibrary, struct xkb_context *context, const int &fd, uint32_t size)
77 const char *keymapString = static_cast<const char *>(mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0));
78 if (keymapString == MAP_FAILED)
81 ss << "mmap: " << strerror(errno);
82 throw std::runtime_error(ss.str());
85 /* In every exit path, the keymap string memory region must be
87 BOOST_SCOPE_EXIT((keymapString)(size))
89 munmap(const_cast<void *>(static_cast<const void *>(keymapString)),
91 } BOOST_SCOPE_EXIT_END
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);
98 /* Failure to compile a keymap is a runtime error and the caller
101 throw std::runtime_error("Failed to compile 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)
109 enum xkb_keymap_compile_flags flags =
110 static_cast<enum xkb_keymap_compile_flags>(0);
112 struct xkb_rule_names names =
121 struct xkb_keymap *keymap =
122 xkbCommonLibrary.xkb_keymap_new_from_names(context, &names, flags);
125 throw std::runtime_error("Failed to compile keymap");
131 CXKBKeymap::CreateXKBStateFromKeymap(IDllXKBCommon &xkbCommonLibrary, struct xkb_keymap *keymap)
133 struct xkb_state *state = xkbCommonLibrary.xkb_state_new(keymap);
136 throw std::runtime_error("Failed to create keyboard state");
141 /* A wrapper class around an xkbcommon keymap and state tracker.
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.
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
153 CXKBKeymap::CXKBKeymap(IDllXKBCommon &xkbCommonLibrary,
154 struct xkb_keymap *keymap) :
155 m_xkbCommonLibrary(xkbCommonLibrary),
157 m_state(CreateXKBStateFromKeymap(xkbCommonLibrary,
159 m_internalLeftControlIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
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,
165 m_internalLeftAltIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
167 m_internalLeftMetaIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
169 m_internalRightControlIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
171 m_internalRightShiftIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
173 m_internalRightSuperIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
175 m_internalRightAltIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
177 m_internalRightMetaIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
179 m_internalCapsLockIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
181 m_internalNumLockIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
183 m_internalModeIndex(m_xkbCommonLibrary.xkb_keymap_mod_get_index(m_keymap,
184 XKB_LED_NAME_SCROLL))
188 CXKBKeymap::~CXKBKeymap()
190 m_xkbCommonLibrary.xkb_state_unref(m_state);
191 m_xkbCommonLibrary.xkb_keymap_unref(m_keymap);
195 CXKBKeymap::KeysymForKeycode(uint32_t code) const
197 const xkb_keysym_t *syms;
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.
205 * Codes sent generally have an offset of 8 */
206 numSyms = m_xkbCommonLibrary.xkb_state_key_get_syms(m_state, code + 8, &syms);
209 return static_cast<uint32_t>(syms[0]);
211 std::stringstream ss;
218 throw std::runtime_error(ss.str());
221 /* Gets the currently depressed, latched and locked modifiers
222 * for the keyboard */
223 uint32_t CXKBKeymap::CurrentModifiers() const
225 enum xkb_state_component components =
226 static_cast <xkb_state_component>(XKB_STATE_DEPRESSED |
229 xkb_mod_mask_t mask = m_xkbCommonLibrary.xkb_state_serialize_mods(m_state,
234 /* Updates the currently depressed, latched, locked and group
235 * modifiers for a keyboard being tracked.
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)
240 m_xkbCommonLibrary.xkb_state_update_mask(m_state, depressed, latched, locked, 0, 0, group);
243 uint32_t CXKBKeymap::ActiveXBMCModifiers() const
245 xkb_mod_mask_t mask(CurrentModifiers());
246 XBMCMod xbmcModifiers = XBMCKMOD_NONE;
250 xkb_mod_index_t xkbMod;
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 }
269 size_t modTableSize = sizeof(modTable) / sizeof(modTable[0]);
271 for (size_t i = 0; i < modTableSize; ++i)
273 if (mask & (1 << modTable[i].xkbMod))
274 xbmcModifiers = static_cast<XBMCMod>(xbmcModifiers | modTable[i].xbmcMod);
277 return static_cast<uint32_t>(xbmcModifiers);
280 uint32_t CXKBKeymap::XBMCKeysymForKeycode(uint32_t code) const
282 uint32_t sym = KeysymForKeycode(code);
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);
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);
297 if (isNavigationKey ||
303 /* Navigation keys are not in line, so we need to
305 static const struct NavigationKeySyms
309 } navigationKeySyms[] =
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 }
372 static const size_t navigationKeySymsSize = sizeof(navigationKeySyms) /
373 sizeof(navigationKeySyms[0]);
375 for (size_t i = 0; i < navigationKeySymsSize; ++i)
377 if (navigationKeySyms[i].xkb == sym)
379 sym = navigationKeySyms[i].xbmc;