Merge pull request #5039 from CEikermann/patch-1
[vuplus_xbmc] / xbmc / input / KeyboardStat.cpp
1 /*
2  *      Copyright (C) 2007-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
21 // C++ Implementation: CKeyboard
22
23 // Comment OUT, if not really debugging!!!:
24 //#define DEBUG_KEYBOARD_GETCHAR
25
26 #include "KeyboardStat.h"
27 #include "KeyboardLayoutConfiguration.h"
28 #include "windowing/XBMC_events.h"
29 #include "utils/TimeUtils.h"
30 #include "input/XBMC_keytable.h"
31 #include "input/XBMC_vkeys.h"
32 #include "peripherals/Peripherals.h"
33 #include "peripherals/devices/PeripheralHID.h"
34
35 using namespace std;
36 using namespace PERIPHERALS;
37
38 CKeyboardStat g_Keyboard;
39
40 CKeyboardStat::CKeyboardStat()
41 {
42   memset(&m_lastKeysym, 0, sizeof(m_lastKeysym));
43   m_lastKeyTime = 0;
44 }
45
46 CKeyboardStat::~CKeyboardStat()
47 {
48 }
49
50 void CKeyboardStat::Initialize()
51 {
52 }
53
54 bool CKeyboardStat::LookupSymAndUnicodePeripherals(XBMC_keysym &keysym, uint8_t *key, char *unicode)
55 {
56   vector<CPeripheral *> hidDevices;
57   if (g_peripherals.GetPeripheralsWithFeature(hidDevices, FEATURE_HID))
58   {
59     for (unsigned int iDevicePtr = 0; iDevicePtr < hidDevices.size(); iDevicePtr++)
60     {
61       CPeripheralHID *hidDevice = (CPeripheralHID *) hidDevices.at(iDevicePtr);
62       if (hidDevice && hidDevice->LookupSymAndUnicode(keysym, key, unicode))
63         return true;
64     }
65   }
66   return false;
67 }
68
69 const CKey CKeyboardStat::ProcessKeyDown(XBMC_keysym& keysym)
70 { uint8_t vkey;
71   wchar_t unicode;
72   char ascii;
73   uint32_t modifiers;
74   unsigned int held;
75   XBMCKEYTABLE keytable;
76
77   modifiers = 0;
78   if (keysym.mod & XBMCKMOD_CTRL)
79     modifiers |= CKey::MODIFIER_CTRL;
80   if (keysym.mod & XBMCKMOD_SHIFT)
81     modifiers |= CKey::MODIFIER_SHIFT;
82   if (keysym.mod & XBMCKMOD_ALT)
83     modifiers |= CKey::MODIFIER_ALT;
84   if (keysym.mod & XBMCKMOD_SUPER)
85     modifiers |= CKey::MODIFIER_SUPER;
86   if (keysym.mod & XBMCKMOD_META)
87     modifiers |= CKey::MODIFIER_META;
88
89   CLog::Log(LOGDEBUG, "Keyboard: scancode: 0x%02x, sym: 0x%04x, unicode: 0x%04x, modifier: 0x%x", keysym.scancode, keysym.sym, keysym.unicode, keysym.mod);
90
91   // The keysym.unicode is usually valid, even if it is zero. A zero
92   // unicode just means this is a non-printing keypress. The ascii and
93   // vkey will be set below.
94   unicode = keysym.unicode;
95   ascii = 0;
96   vkey = 0;
97   held = 0;
98
99   // Start by check whether any of the HID peripherals wants to translate this keypress
100   if (LookupSymAndUnicodePeripherals(keysym, &vkey, &ascii))
101   {
102     CLog::Log(LOGDEBUG, "%s - keypress translated by a HID peripheral", __FUNCTION__);
103   }
104
105   // Continue by trying to match both the sym and unicode. This will identify
106   // the majority of keypresses
107   else if (KeyTableLookupSymAndUnicode(keysym.sym, keysym.unicode, &keytable))
108   {
109     vkey = keytable.vkey;
110     ascii = keytable.ascii;
111   }
112
113   // If we failed to match the sym and unicode try just the unicode. This
114   // will match keys like \ that are on different keys on regional keyboards.
115   else if (KeyTableLookupUnicode(keysym.unicode, &keytable))
116   {
117     vkey = keytable.vkey;
118     ascii = keytable.ascii;
119   }
120
121   // If there is still no match try the sym
122   else if (KeyTableLookupSym(keysym.sym, &keytable))
123   {
124     vkey = keytable.vkey;
125
126     // Occasionally we get non-printing keys that have a non-zero value in
127     // the keysym.unicode. Check for this here and replace any rogue unicode
128     // values.
129     if (keytable.unicode == 0 && unicode != 0)
130       unicode = 0;
131     else if (keysym.unicode > 32 && keysym.unicode < 128)
132       ascii = unicode & 0x7f;
133   }
134
135   // The keysym.sym is unknown ...
136   else
137   {
138     if (!vkey && !ascii)
139     {
140       if (keysym.mod & XBMCKMOD_LSHIFT) vkey = 0xa0;
141       else if (keysym.mod & XBMCKMOD_RSHIFT) vkey = 0xa1;
142       else if (keysym.mod & XBMCKMOD_LALT) vkey = 0xa4;
143       else if (keysym.mod & XBMCKMOD_RALT) vkey = 0xa5;
144       else if (keysym.mod & XBMCKMOD_LCTRL) vkey = 0xa2;
145       else if (keysym.mod & XBMCKMOD_RCTRL) vkey = 0xa3;
146       else if (keysym.unicode > 32 && keysym.unicode < 128)
147         // only TRUE ASCII! (Otherwise XBMC crashes! No unicode not even latin 1!)
148         ascii = (char)(keysym.unicode & 0xff);
149     }
150   }
151
152   // At this point update the key hold time
153   if (keysym.mod == m_lastKeysym.mod && keysym.scancode == m_lastKeysym.scancode && keysym.sym == m_lastKeysym.sym && keysym.unicode == m_lastKeysym.unicode)
154   {
155     held = CTimeUtils::GetFrameTime() - m_lastKeyTime;
156   }
157   else
158   {
159     m_lastKeysym = keysym;
160     m_lastKeyTime = CTimeUtils::GetFrameTime();
161     held = 0;
162   }
163
164   // For all shift-X keys except shift-A to shift-Z and shift-F1 to shift-F24 the
165   // shift modifier is ignored. This so that, for example, the * keypress (shift-8)
166   // is seen as <asterisk> not <asterisk mod="shift">.
167   // The A-Z keys are exempted because shift-A-Z is used for navigation in lists.
168   // The function keys are exempted because function keys have no shifted value and
169   // the Nyxboard remote uses keys like Shift-F3 for some buttons.
170   if (modifiers == CKey::MODIFIER_SHIFT)
171     if ((unicode < 'A' || unicode > 'Z') && (unicode < 'a' || unicode > 'z') && (vkey < XBMCVK_F1 || vkey > XBMCVK_F24))
172       modifiers = 0;
173
174   // Create and return a CKey
175
176   CKey key(vkey, unicode, ascii, modifiers, held);
177
178   return key;
179 }
180
181 void CKeyboardStat::ProcessKeyUp(void)
182 {
183   memset(&m_lastKeysym, 0, sizeof(m_lastKeysym));
184   m_lastKeyTime = 0;
185 }
186
187 // Return the key name given a key ID
188 // Used to make the debug log more intelligable
189 // The KeyID includes the flags for ctrl, alt etc
190
191 CStdString CKeyboardStat::GetKeyName(int KeyID)
192 { int keyid;
193   CStdString keyname;
194   XBMCKEYTABLE keytable;
195
196   keyname.clear();
197
198 // Get modifiers
199
200   if (KeyID & CKey::MODIFIER_CTRL)
201     keyname.append("ctrl-");
202   if (KeyID & CKey::MODIFIER_SHIFT)
203     keyname.append("shift-");
204   if (KeyID & CKey::MODIFIER_ALT)
205     keyname.append("alt-");
206   if (KeyID & CKey::MODIFIER_SUPER)
207     keyname.append("win-");
208   if (KeyID & CKey::MODIFIER_META)
209     keyname.append("meta-");
210
211 // Now get the key name
212
213   keyid = KeyID & 0xFF;
214   if (KeyTableLookupVKeyName(keyid, &keytable))
215     keyname.append(keytable.keyname);
216   else
217     keyname += StringUtils::Format("%i", keyid);
218   keyname += StringUtils::Format(" (0x%02x)", KeyID);
219
220   return keyname;
221 }
222
223