1 // Copyright 2009 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 #include "Core/IOS/USB/USB_KBD.h"
6 
7 #include <array>
8 #include <queue>
9 
10 #include "Common/FileUtil.h"
11 #include "Common/IniFile.h"
12 #include "Common/Logging/Log.h"
13 #include "Common/Swap.h"
14 #include "Core/ConfigManager.h"
15 #include "Core/Core.h"  // Local core functions
16 #include "Core/HW/Memmap.h"
17 #include "InputCommon/ControlReference/ControlReference.h"  // For background input check
18 
19 #ifdef _WIN32
20 #include <windows.h>
21 #endif
22 
23 namespace IOS::HLE::Device
24 {
25 namespace
26 {
27 // Crazy ugly
28 #ifdef _WIN32
29 constexpr std::array<u8, 256> s_key_codes_qwerty{
30     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31     0x2A,  // Backspace
32     0x2B,  // Tab
33     0x00, 0x00,
34     0x00,  // Clear
35     0x28,  // Return
36     0x00, 0x00,
37     0x00,  // Shift
38     0x00,  // Control
39     0x00,  // ALT
40     0x48,  // Pause
41     0x39,  // Capital
42     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
43     0x29,  // Escape
44     0x00, 0x00, 0x00, 0x00,
45     0x2C,  // Space
46     0x4B,  // Prior
47     0x4E,  // Next
48     0x4D,  // End
49     0x4A,  // Home
50     0x50,  // Left
51     0x52,  // Up
52     0x4F,  // Right
53     0x51,  // Down
54     0x00, 0x00, 0x00,
55     0x46,  // Print screen
56     0x49,  // Insert
57     0x4C,  // Delete
58     0x00,
59     // 0 -> 9
60     0x27, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61     0x00,
62     // A -> Z
63     0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13,
64     0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00,
65     // Numpad 0 -> 9
66     0x62, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61,
67     0x55,  // Multiply
68     0x57,  // Add
69     0x00,  // Separator
70     0x56,  // Subtract
71     0x63,  // Decimal
72     0x54,  // Divide
73     // F1 -> F12
74     0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
75     // F13 -> F24
76     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77     0x00, 0x00, 0x00, 0x00,
78     0x53,  // Numlock
79     0x47,  // Scroll lock
80     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
81     // Modifier keys
82     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84     0x33,  // ';'
85     0x2E,  // Plus
86     0x36,  // Comma
87     0x2D,  // Minus
88     0x37,  // Period
89     0x38,  // '/'
90     0x35,  // '~'
91     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93     0x2F,  // '['
94     0x32,  // '\'
95     0x30,  // ']'
96     0x34,  // '''
97     0x00,  //
98     0x00,  // Nothing interesting past this point.
99 };
100 
101 constexpr std::array<u8, 256> s_key_codes_azerty{
102     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103     0x2A,  // Backspace
104     0x2B,  // Tab
105     0x00, 0x00,
106     0x00,  // Clear
107     0x28,  // Return
108     0x00, 0x00,
109     0x00,  // Shift
110     0x00,  // Control
111     0x00,  // ALT
112     0x48,  // Pause
113     0x39,  // Capital
114     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
115     0x29,  // Escape
116     0x00, 0x00, 0x00, 0x00,
117     0x2C,  // Space
118     0x4B,  // Prior
119     0x4E,  // Next
120     0x4D,  // End
121     0x4A,  // Home
122     0x50,  // Left
123     0x52,  // Up
124     0x4F,  // Right
125     0x51,  // Down
126     0x00, 0x00, 0x00,
127     0x46,  // Print screen
128     0x49,  // Insert
129     0x4C,  // Delete
130     0x00,
131     // 0 -> 9
132     0x27, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133     0x00,
134     // A -> Z
135     0x14, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x33, 0x11, 0x12, 0x13,
136     0x04, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1D, 0x1B, 0x1C, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00,
137     // Numpad 0 -> 9
138     0x62, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61,
139     0x55,  // Multiply
140     0x57,  // Add
141     0x00,  // Separator
142     0x56,  // Substract
143     0x63,  // Decimal
144     0x54,  // Divide
145     // F1 -> F12
146     0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
147     // F13 -> F24
148     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
149     0x00, 0x00, 0x00, 0x00,
150     0x53,  // Numlock
151     0x47,  // Scroll lock
152     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
153     // Modifier keys
154     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
155     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
156     0x30,  // '$'
157     0x2E,  // Plus
158     0x10,  // Comma
159     0x00,  // Minus
160     0x36,  // Period
161     0x37,  // '/'
162     0x34,  // ' '
163     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
165     0x2D,  // ')'
166     0x32,  // '\'
167     0x2F,  // '^'
168     0x00,  // ' '
169     0x38,  // '!'
170     0x00,  // Nothing interesting past this point.
171 };
172 #else
173 constexpr std::array<u8, 256> s_key_codes_qwerty{};
174 
175 constexpr std::array<u8, 256> s_key_codes_azerty{};
176 #endif
177 }  // Anonymous namespace
178 
MessageData(MessageType type,u8 modifiers_,PressedKeyData pressed_keys_)179 USB_KBD::MessageData::MessageData(MessageType type, u8 modifiers_, PressedKeyData pressed_keys_)
180     : msg_type{Common::swap32(static_cast<u32>(type))}, modifiers{modifiers_}, pressed_keys{
181                                                                                    pressed_keys_}
182 {
183 }
184 
185 // TODO: support in netplay/movies.
186 
USB_KBD(Kernel & ios,const std::string & device_name)187 USB_KBD::USB_KBD(Kernel& ios, const std::string& device_name) : Device(ios, device_name)
188 {
189 }
190 
Open(const OpenRequest & request)191 IPCCommandResult USB_KBD::Open(const OpenRequest& request)
192 {
193   INFO_LOG(IOS, "USB_KBD: Open");
194   IniFile ini;
195   ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX));
196   ini.GetOrCreateSection("USB Keyboard")->Get("Layout", &m_keyboard_layout, KBD_LAYOUT_QWERTY);
197 
198   m_message_queue = {};
199   m_old_key_buffer.fill(false);
200   m_old_modifiers = 0x00;
201 
202   // m_message_queue.emplace(MessageType::KeyboardConnect, 0, PressedKeyData{});
203   return Device::Open(request);
204 }
205 
Write(const ReadWriteRequest & request)206 IPCCommandResult USB_KBD::Write(const ReadWriteRequest& request)
207 {
208   // Stubbed.
209   return GetDefaultReply(IPC_SUCCESS);
210 }
211 
IOCtl(const IOCtlRequest & request)212 IPCCommandResult USB_KBD::IOCtl(const IOCtlRequest& request)
213 {
214   if (SConfig::GetInstance().m_WiiKeyboard && !Core::WantsDeterminism() &&
215       ControlReference::GetInputGate() && !m_message_queue.empty())
216   {
217     Memory::CopyToEmu(request.buffer_out, &m_message_queue.front(), sizeof(MessageData));
218     m_message_queue.pop();
219   }
220   return GetDefaultReply(IPC_SUCCESS);
221 }
222 
IsKeyPressed(int key) const223 bool USB_KBD::IsKeyPressed(int key) const
224 {
225 #ifdef _WIN32
226   return (GetAsyncKeyState(key) & 0x8000) != 0;
227 #else
228   // TODO: do it for non-Windows platforms
229   return false;
230 #endif
231 }
232 
Update()233 void USB_KBD::Update()
234 {
235   if (!SConfig::GetInstance().m_WiiKeyboard || Core::WantsDeterminism() || !m_is_active)
236     return;
237 
238   u8 modifiers = 0x00;
239   PressedKeyData pressed_keys{0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
240   bool got_event = false;
241   size_t num_pressed_keys = 0;
242   for (size_t i = 0; i < m_old_key_buffer.size(); i++)
243   {
244     const bool key_pressed_now = IsKeyPressed(static_cast<int>(i));
245     const bool key_pressed_before = m_old_key_buffer[i];
246     u8 key_code = 0;
247 
248     if (key_pressed_now ^ key_pressed_before)
249     {
250       if (key_pressed_now)
251       {
252         switch (m_keyboard_layout)
253         {
254         case KBD_LAYOUT_QWERTY:
255           key_code = s_key_codes_qwerty[i];
256           break;
257 
258         case KBD_LAYOUT_AZERTY:
259           key_code = s_key_codes_azerty[i];
260           break;
261         }
262 
263         if (key_code == 0x00)
264           continue;
265 
266         pressed_keys[num_pressed_keys] = key_code;
267 
268         num_pressed_keys++;
269         if (num_pressed_keys == pressed_keys.size())
270           break;
271       }
272 
273       got_event = true;
274     }
275 
276     m_old_key_buffer[i] = key_pressed_now;
277   }
278 
279 #ifdef _WIN32
280   if (GetAsyncKeyState(VK_LCONTROL) & 0x8000)
281     modifiers |= 0x01;
282   if (GetAsyncKeyState(VK_LSHIFT) & 0x8000)
283     modifiers |= 0x02;
284   if (GetAsyncKeyState(VK_MENU) & 0x8000)
285     modifiers |= 0x04;
286   if (GetAsyncKeyState(VK_LWIN) & 0x8000)
287     modifiers |= 0x08;
288   if (GetAsyncKeyState(VK_RCONTROL) & 0x8000)
289     modifiers |= 0x10;
290   if (GetAsyncKeyState(VK_RSHIFT) & 0x8000)
291     modifiers |= 0x20;
292   // TODO: VK_MENU is for ALT, not for ALT GR (ALT GR seems to work though...)
293   if (GetAsyncKeyState(VK_MENU) & 0x8000)
294     modifiers |= 0x40;
295   if (GetAsyncKeyState(VK_RWIN) & 0x8000)
296     modifiers |= 0x80;
297 #else
298 // TODO: modifiers for non-Windows platforms
299 #endif
300 
301   if (modifiers ^ m_old_modifiers)
302   {
303     got_event = true;
304     m_old_modifiers = modifiers;
305   }
306 
307   if (got_event)
308     m_message_queue.emplace(MessageType::Event, modifiers, pressed_keys);
309 }
310 }  // namespace IOS::HLE::Device
311