2 * Copyright (C) 2007-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/>.
21 // C++ Implementation: CKeyboard
23 // Comment OUT, if not really debugging!!!:
24 //#define DEBUG_KEYBOARD_GETCHAR
26 #include "KeyboardStat.h"
27 #include "windowing/XBMC_events.h"
28 #include "input/XBMC_keytable.h"
29 #include "input/XBMC_vkeys.h"
30 #include "peripherals/Peripherals.h"
31 #include "peripherals/devices/PeripheralHID.h"
32 #include "threads/SystemClock.h"
33 #include "utils/log.h"
35 #define HOLD_THRESHOLD 250
37 using namespace PERIPHERALS
;
39 bool operator==(const XBMC_keysym
& lhs
, const XBMC_keysym
& rhs
)
41 return lhs
.mod
== rhs
.mod
&&
42 lhs
.scancode
== rhs
.scancode
&&
44 lhs
.unicode
== rhs
.unicode
;
47 CKeyboardStat::CKeyboardStat()
49 memset(&m_lastKeysym
, 0, sizeof(m_lastKeysym
));
53 CKeyboardStat::~CKeyboardStat()
57 void CKeyboardStat::Initialize()
61 bool CKeyboardStat::LookupSymAndUnicodePeripherals(XBMC_keysym
&keysym
, uint8_t *key
, char *unicode
)
63 std::vector
<CPeripheral
*> hidDevices
;
64 if (g_peripherals
.GetPeripheralsWithFeature(hidDevices
, FEATURE_HID
))
66 for (unsigned int iDevicePtr
= 0; iDevicePtr
< hidDevices
.size(); iDevicePtr
++)
68 CPeripheralHID
*hidDevice
= (CPeripheralHID
*) hidDevices
.at(iDevicePtr
);
69 if (hidDevice
&& hidDevice
->LookupSymAndUnicode(keysym
, key
, unicode
))
76 CKey
CKeyboardStat::TranslateKey(XBMC_keysym
& keysym
) const
83 XBMCKEYTABLE keytable
;
86 if (keysym
.mod
& XBMCKMOD_CTRL
)
87 modifiers
|= CKey::MODIFIER_CTRL
;
88 if (keysym
.mod
& XBMCKMOD_SHIFT
)
89 modifiers
|= CKey::MODIFIER_SHIFT
;
90 if (keysym
.mod
& XBMCKMOD_ALT
)
91 modifiers
|= CKey::MODIFIER_ALT
;
92 if (keysym
.mod
& XBMCKMOD_SUPER
)
93 modifiers
|= CKey::MODIFIER_SUPER
;
94 if (keysym
.mod
& XBMCKMOD_META
)
95 modifiers
|= CKey::MODIFIER_META
;
97 CLog::Log(LOGDEBUG
, "Keyboard: scancode: 0x%02x, sym: 0x%04x, unicode: 0x%04x, modifier: 0x%x", keysym
.scancode
, keysym
.sym
, keysym
.unicode
, keysym
.mod
);
99 // The keysym.unicode is usually valid, even if it is zero. A zero
100 // unicode just means this is a non-printing keypress. The ascii and
101 // vkey will be set below.
102 unicode
= keysym
.unicode
;
107 // Start by check whether any of the HID peripherals wants to translate this keypress
108 if (LookupSymAndUnicodePeripherals(keysym
, &vkey
, &ascii
))
110 CLog::Log(LOGDEBUG
, "%s - keypress translated by a HID peripheral", __FUNCTION__
);
113 // Continue by trying to match both the sym and unicode. This will identify
114 // the majority of keypresses
115 else if (KeyTableLookupSymAndUnicode(keysym
.sym
, keysym
.unicode
, &keytable
))
117 vkey
= keytable
.vkey
;
118 ascii
= keytable
.ascii
;
121 // If we failed to match the sym and unicode try just the unicode. This
122 // will match keys like \ that are on different keys on regional keyboards.
123 else if (KeyTableLookupUnicode(keysym
.unicode
, &keytable
))
125 vkey
= keytable
.vkey
;
126 ascii
= keytable
.ascii
;
129 // If there is still no match try the sym
130 else if (KeyTableLookupSym(keysym
.sym
, &keytable
))
132 vkey
= keytable
.vkey
;
134 // Occasionally we get non-printing keys that have a non-zero value in
135 // the keysym.unicode. Check for this here and replace any rogue unicode
137 if (keytable
.unicode
== 0 && unicode
!= 0)
139 else if (keysym
.unicode
> 32 && keysym
.unicode
< 128)
140 ascii
= unicode
& 0x7f;
143 // The keysym.sym is unknown ...
148 if (keysym
.mod
& XBMCKMOD_LSHIFT
) vkey
= 0xa0;
149 else if (keysym
.mod
& XBMCKMOD_RSHIFT
) vkey
= 0xa1;
150 else if (keysym
.mod
& XBMCKMOD_LALT
) vkey
= 0xa4;
151 else if (keysym
.mod
& XBMCKMOD_RALT
) vkey
= 0xa5;
152 else if (keysym
.mod
& XBMCKMOD_LCTRL
) vkey
= 0xa2;
153 else if (keysym
.mod
& XBMCKMOD_RCTRL
) vkey
= 0xa3;
154 else if (keysym
.unicode
> 32 && keysym
.unicode
< 128)
155 // only TRUE ASCII! (Otherwise XBMC crashes! No unicode not even latin 1!)
156 ascii
= (char)(keysym
.unicode
& 0xff);
160 if (keysym
== m_lastKeysym
)
162 held
= XbmcThreads::SystemClockMillis() - m_lastKeyTime
;
163 if (held
> HOLD_THRESHOLD
)
164 modifiers
|= CKey::MODIFIER_LONG
;
167 // For all shift-X keys except shift-A to shift-Z and shift-F1 to shift-F24 the
168 // shift modifier is ignored. This so that, for example, the * keypress (shift-8)
169 // is seen as <asterisk> not <asterisk mod="shift">.
170 // The A-Z keys are exempted because shift-A-Z is used for navigation in lists.
171 // The function keys are exempted because function keys have no shifted value and
172 // the Nyxboard remote uses keys like Shift-F3 for some buttons.
173 if (modifiers
== CKey::MODIFIER_SHIFT
)
174 if ((unicode
< 'A' || unicode
> 'Z') && (unicode
< 'a' || unicode
> 'z') && (vkey
< XBMCVK_F1
|| vkey
> XBMCVK_F24
))
177 // Create and return a CKey
179 CKey
key(vkey
, unicode
, ascii
, modifiers
, held
);
184 void CKeyboardStat::ProcessKeyDown(XBMC_keysym
& keysym
)
186 if (!(m_lastKeysym
== keysym
))
188 m_lastKeysym
= keysym
;
189 m_lastKeyTime
= XbmcThreads::SystemClockMillis();
193 void CKeyboardStat::ProcessKeyUp(void)
195 memset(&m_lastKeysym
, 0, sizeof(m_lastKeysym
));
199 // Return the key name given a key ID
200 // Used to make the debug log more intelligable
201 // The KeyID includes the flags for ctrl, alt etc
203 std::string
CKeyboardStat::GetKeyName(int KeyID
)
206 XBMCKEYTABLE keytable
;
212 if (KeyID
& CKey::MODIFIER_CTRL
)
213 keyname
.append("ctrl-");
214 if (KeyID
& CKey::MODIFIER_SHIFT
)
215 keyname
.append("shift-");
216 if (KeyID
& CKey::MODIFIER_ALT
)
217 keyname
.append("alt-");
218 if (KeyID
& CKey::MODIFIER_SUPER
)
219 keyname
.append("win-");
220 if (KeyID
& CKey::MODIFIER_META
)
221 keyname
.append("meta-");
222 if (KeyID
& CKey::MODIFIER_LONG
)
223 keyname
.append("long-");
225 // Now get the key name
227 keyid
= KeyID
& 0xFF;
228 bool VKeyFound
= KeyTableLookupVKeyName(keyid
, &keytable
);
230 keyname
.append(keytable
.keyname
);
232 keyname
+= StringUtils::Format("%i", keyid
);
234 // in case this might be an universalremote keyid
235 // we also print the possile corresponding obc code
236 // so users can easily find it in their universalremote
238 if (VKeyFound
|| keyid
> 255)
239 keyname
+= StringUtils::Format(" (0x%02x)", KeyID
);
240 else// obc keys are 255 -rawid
241 keyname
+= StringUtils::Format(" (0x%02x, obc%i)", KeyID
, 255 - KeyID
);