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