[USER32] Add support for navigating a group of radio buttons using a keyboard.
[reactos.git] / win32ss / user / user32 / windows / input.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
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 of the License, or
8 * (at your option) 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 this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /*
20 * PROJECT: ReactOS user32.dll
21 * FILE: win32ss/user/user32/windows/input.c
22 * PURPOSE: Input
23 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
24 * UPDATE HISTORY:
25 * 09-05-2001 CSH Created
26 */
27
28 #include <user32.h>
29
30 #include <strsafe.h>
31
32 WINE_DEFAULT_DEBUG_CHANNEL(user32);
33
34 /*
35 * @implemented
36 */
37 BOOL
38 WINAPI
39 DragDetect(
40 HWND hWnd,
41 POINT pt)
42 {
43 return NtUserDragDetect(hWnd, pt);
44 #if 0
45 MSG msg;
46 RECT rect;
47 POINT tmp;
48 ULONG dx = GetSystemMetrics(SM_CXDRAG);
49 ULONG dy = GetSystemMetrics(SM_CYDRAG);
50
51 rect.left = pt.x - dx;
52 rect.right = pt.x + dx;
53 rect.top = pt.y - dy;
54 rect.bottom = pt.y + dy;
55
56 SetCapture(hWnd);
57
58 for (;;)
59 {
60 while (
61 PeekMessageW(&msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE) ||
62 PeekMessageW(&msg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)
63 )
64 {
65 if (msg.message == WM_LBUTTONUP)
66 {
67 ReleaseCapture();
68 return FALSE;
69 }
70 if (msg.message == WM_MOUSEMOVE)
71 {
72 tmp.x = LOWORD(msg.lParam);
73 tmp.y = HIWORD(msg.lParam);
74 if (!PtInRect(&rect, tmp))
75 {
76 ReleaseCapture();
77 return TRUE;
78 }
79 }
80 if (msg.message == WM_KEYDOWN)
81 {
82 if (msg.wParam == VK_ESCAPE)
83 {
84 ReleaseCapture();
85 return TRUE;
86 }
87 }
88 }
89 WaitMessage();
90 }
91 return 0;
92 #endif
93 }
94
95 /*
96 * @implemented
97 */
98 BOOL WINAPI
99 EnableWindow(HWND hWnd, BOOL bEnable)
100 {
101 return NtUserxEnableWindow(hWnd, bEnable);
102 }
103
104 /*
105 * @implemented
106 */
107 SHORT
108 WINAPI
109 DECLSPEC_HOTPATCH
110 GetAsyncKeyState(int vKey)
111 {
112 if (vKey < 0 || vKey > 256)
113 return 0;
114 return (SHORT)NtUserGetAsyncKeyState((DWORD)vKey);
115 }
116
117
118 /*
119 * @implemented
120 */
121 HKL WINAPI
122 GetKeyboardLayout(DWORD idThread)
123 {
124 return NtUserxGetKeyboardLayout(idThread);
125 }
126
127
128 /*
129 * @implemented
130 */
131 UINT WINAPI
132 GetKBCodePage(VOID)
133 {
134 return GetOEMCP();
135 }
136
137
138 /*
139 * @implemented
140 */
141 int WINAPI
142 GetKeyNameTextA(LONG lParam,
143 LPSTR lpString,
144 int nSize)
145 {
146 LPWSTR pwszBuf;
147 UINT cchBuf = 0;
148 int iRet = 0;
149 BOOL defChar = FALSE;
150
151 pwszBuf = HeapAlloc(GetProcessHeap(), 0, nSize * sizeof(WCHAR));
152 if (!pwszBuf)
153 return 0;
154
155 cchBuf = NtUserGetKeyNameText(lParam, pwszBuf, nSize);
156
157 iRet = WideCharToMultiByte(CP_ACP, 0,
158 pwszBuf, cchBuf,
159 lpString, nSize, ".", &defChar); // FIXME: do we need defChar?
160 lpString[iRet] = 0;
161 HeapFree(GetProcessHeap(), 0, pwszBuf);
162
163 return iRet;
164 }
165
166 /*
167 * @implemented
168 */
169 int WINAPI
170 GetKeyNameTextW(LONG lParam,
171 LPWSTR lpString,
172 int nSize)
173 {
174 return NtUserGetKeyNameText(lParam, lpString, nSize);
175 }
176
177 /*
178 * @implemented
179 */
180 SHORT
181 WINAPI
182 DECLSPEC_HOTPATCH
183 GetKeyState(int nVirtKey)
184 {
185 return (SHORT)NtUserGetKeyState((DWORD)nVirtKey);
186 }
187
188 /*
189 * @implemented
190 */
191 BOOL WINAPI
192 GetKeyboardLayoutNameA(LPSTR pwszKLID)
193 {
194 WCHAR buf[KL_NAMELENGTH];
195
196 if (!GetKeyboardLayoutNameW(buf))
197 return FALSE;
198
199 if (!WideCharToMultiByte(CP_ACP, 0, buf, -1, pwszKLID, KL_NAMELENGTH, NULL, NULL))
200 return FALSE;
201
202 return TRUE;
203 }
204
205 /*
206 * @implemented
207 */
208 BOOL WINAPI
209 GetKeyboardLayoutNameW(LPWSTR pwszKLID)
210 {
211 return NtUserGetKeyboardLayoutName(pwszKLID);
212 }
213
214 /*
215 * @implemented
216 */
217 int WINAPI
218 GetKeyboardType(int nTypeFlag)
219 {
220 return NtUserxGetKeyboardType(nTypeFlag);
221 }
222
223 /*
224 * @implemented
225 */
226 BOOL WINAPI
227 GetLastInputInfo(PLASTINPUTINFO plii)
228 {
229 TRACE("%p\n", plii);
230
231 if (plii->cbSize != sizeof (*plii))
232 {
233 SetLastError(ERROR_INVALID_PARAMETER);
234 return FALSE;
235 }
236
237 plii->dwTime = gpsi->dwLastRITEventTickCount;
238 return TRUE;
239 }
240
241 /*
242 * @implemented
243 */
244 HKL WINAPI
245 LoadKeyboardLayoutA(LPCSTR pszKLID,
246 UINT Flags)
247 {
248 WCHAR wszKLID[16];
249
250 if (!MultiByteToWideChar(CP_ACP, 0, pszKLID, -1,
251 wszKLID, sizeof(wszKLID)/sizeof(wszKLID[0])))
252 {
253 return FALSE;
254 }
255
256 return LoadKeyboardLayoutW(wszKLID, Flags);
257 }
258
259 /*
260 * @implemented
261 */
262 HKL WINAPI
263 LoadKeyboardLayoutW(LPCWSTR pwszKLID,
264 UINT Flags)
265 {
266 DWORD dwhkl, dwType, dwSize;
267 UNICODE_STRING ustrKbdName;
268 UNICODE_STRING ustrKLID;
269 WCHAR wszRegKey[256] = L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\";
270 WCHAR wszLayoutId[10], wszNewKLID[10];
271 HKEY hKey;
272
273 /* LOWORD of dwhkl is Locale Identifier */
274 dwhkl = LOWORD(wcstoul(pwszKLID, NULL, 16));
275
276 if (Flags & KLF_SUBSTITUTE_OK)
277 {
278 /* Check substitutes key */
279 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Substitutes", 0,
280 KEY_READ, &hKey) == ERROR_SUCCESS)
281 {
282 dwSize = sizeof(wszNewKLID);
283 if (RegQueryValueExW(hKey, pwszKLID, NULL, &dwType, (LPBYTE)wszNewKLID, &dwSize) == ERROR_SUCCESS)
284 {
285 /* Use new KLID value */
286 pwszKLID = wszNewKLID;
287 }
288
289 /* Close the key now */
290 RegCloseKey(hKey);
291 }
292 }
293
294 /* Append KLID at the end of registry key */
295 StringCbCatW(wszRegKey, sizeof(wszRegKey), pwszKLID);
296
297 /* Open layout registry key for read */
298 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegKey, 0,
299 KEY_READ, &hKey) == ERROR_SUCCESS)
300 {
301 dwSize = sizeof(wszLayoutId);
302 if (RegQueryValueExW(hKey, L"Layout Id", NULL, &dwType, (LPBYTE)wszLayoutId, &dwSize) == ERROR_SUCCESS)
303 {
304 /* If Layout Id is specified, use this value | f000 as HIWORD */
305 /* FIXME: Microsoft Office expects this value to be something specific
306 * for Japanese and Korean Windows with an IME the value is 0xe001
307 * We should probably check to see if an IME exists and if so then
308 * set this word properly.
309 */
310 dwhkl |= (0xf000 | wcstol(wszLayoutId, NULL, 16)) << 16;
311 }
312
313 /* Close the key now */
314 RegCloseKey(hKey);
315 }
316 else
317 {
318 ERR("Could not find keyboard layout %S.\n", pwszKLID);
319 return NULL;
320 }
321
322 /* If Layout Id is not given HIWORD == LOWORD (for dwhkl) */
323 if (!HIWORD(dwhkl))
324 dwhkl |= dwhkl << 16;
325
326 ZeroMemory(&ustrKbdName, sizeof(ustrKbdName));
327 RtlInitUnicodeString(&ustrKLID, pwszKLID);
328 return NtUserLoadKeyboardLayoutEx(NULL, 0, &ustrKbdName,
329 NULL, &ustrKLID,
330 dwhkl, Flags);
331 }
332
333 /*
334 * @implemented
335 */
336 UINT WINAPI
337 MapVirtualKeyA(UINT uCode,
338 UINT uMapType)
339 {
340 return MapVirtualKeyExA(uCode, uMapType, GetKeyboardLayout(0));
341 }
342
343 /*
344 * @implemented
345 */
346 UINT WINAPI
347 MapVirtualKeyExA(UINT uCode,
348 UINT uMapType,
349 HKL dwhkl)
350 {
351 return MapVirtualKeyExW(uCode, uMapType, dwhkl);
352 }
353
354
355 /*
356 * @implemented
357 */
358 UINT WINAPI
359 MapVirtualKeyExW(UINT uCode,
360 UINT uMapType,
361 HKL dwhkl)
362 {
363 return NtUserMapVirtualKeyEx(uCode, uMapType, 0, dwhkl);
364 }
365
366
367 /*
368 * @implemented
369 */
370 UINT WINAPI
371 MapVirtualKeyW(UINT uCode,
372 UINT uMapType)
373 {
374 return MapVirtualKeyExW(uCode, uMapType, GetKeyboardLayout(0));
375 }
376
377
378 /*
379 * @implemented
380 */
381 DWORD WINAPI
382 OemKeyScan(WORD wOemChar)
383 {
384 WCHAR p;
385 SHORT Vk;
386 UINT Scan;
387
388 MultiByteToWideChar(CP_OEMCP, 0, (PCSTR)&wOemChar, 1, &p, 1);
389 Vk = VkKeyScanW(p);
390 Scan = MapVirtualKeyW((Vk & 0x00ff), 0);
391 if (!Scan) return -1;
392 /*
393 Page 450-1, MS W2k SuperBible by SAMS. Return, low word has the
394 scan code and high word has the shift state.
395 */
396 return ((Vk & 0xff00) << 8) | Scan;
397 }
398
399
400 /*
401 * @implemented
402 */
403 BOOL WINAPI
404 SetDoubleClickTime(UINT uInterval)
405 {
406 return (BOOL)NtUserSystemParametersInfo(SPI_SETDOUBLECLICKTIME,
407 uInterval,
408 NULL,
409 0);
410 }
411
412
413 /*
414 * @implemented
415 */
416 BOOL
417 WINAPI
418 SwapMouseButton(
419 BOOL fSwap)
420 {
421 return NtUserxSwapMouseButton(fSwap);
422 }
423
424
425 /*
426 * @implemented
427 */
428 int WINAPI
429 ToAscii(UINT uVirtKey,
430 UINT uScanCode,
431 CONST BYTE *lpKeyState,
432 LPWORD lpChar,
433 UINT uFlags)
434 {
435 return ToAsciiEx(uVirtKey, uScanCode, lpKeyState, lpChar, uFlags, 0);
436 }
437
438
439 /*
440 * @implemented
441 */
442 int WINAPI
443 ToAsciiEx(UINT uVirtKey,
444 UINT uScanCode,
445 CONST BYTE *lpKeyState,
446 LPWORD lpChar,
447 UINT uFlags,
448 HKL dwhkl)
449 {
450 WCHAR UniChars[2];
451 int Ret, CharCount;
452
453 Ret = ToUnicodeEx(uVirtKey, uScanCode, lpKeyState, UniChars, 2, uFlags, dwhkl);
454 CharCount = (Ret < 0 ? 1 : Ret);
455 WideCharToMultiByte(CP_ACP, 0, UniChars, CharCount, (LPSTR)lpChar, 2, NULL, NULL);
456
457 return Ret;
458 }
459
460
461 /*
462 * @implemented
463 */
464 int WINAPI
465 ToUnicode(UINT wVirtKey,
466 UINT wScanCode,
467 CONST BYTE *lpKeyState,
468 LPWSTR pwszBuff,
469 int cchBuff,
470 UINT wFlags)
471 {
472 return ToUnicodeEx(wVirtKey, wScanCode, lpKeyState, pwszBuff, cchBuff,
473 wFlags, 0);
474 }
475
476
477 /*
478 * @implemented
479 */
480 int WINAPI
481 ToUnicodeEx(UINT wVirtKey,
482 UINT wScanCode,
483 CONST BYTE *lpKeyState,
484 LPWSTR pwszBuff,
485 int cchBuff,
486 UINT wFlags,
487 HKL dwhkl)
488 {
489 return NtUserToUnicodeEx(wVirtKey, wScanCode, (PBYTE)lpKeyState, pwszBuff, cchBuff,
490 wFlags, dwhkl);
491 }
492
493
494
495 /*
496 * @implemented
497 */
498 SHORT WINAPI
499 VkKeyScanA(CHAR ch)
500 {
501 WCHAR wChar;
502
503 if (IsDBCSLeadByte(ch))
504 return -1;
505
506 MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wChar, 1);
507 return VkKeyScanW(wChar);
508 }
509
510
511 /*
512 * @implemented
513 */
514 SHORT WINAPI
515 VkKeyScanExA(CHAR ch,
516 HKL dwhkl)
517 {
518 WCHAR wChar;
519
520 if (IsDBCSLeadByte(ch))
521 return -1;
522
523 MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wChar, 1);
524 return VkKeyScanExW(wChar, dwhkl);
525 }
526
527
528 /*
529 * @implemented
530 */
531 SHORT WINAPI
532 VkKeyScanExW(WCHAR ch,
533 HKL dwhkl)
534 {
535 return (SHORT)NtUserVkKeyScanEx(ch, dwhkl, TRUE);
536 }
537
538
539 /*
540 * @implemented
541 */
542 SHORT WINAPI
543 VkKeyScanW(WCHAR ch)
544 {
545 return (SHORT)NtUserVkKeyScanEx(ch, 0, FALSE);
546 }
547
548
549 /*
550 * @implemented
551 */
552 VOID
553 WINAPI
554 keybd_event(
555 BYTE bVk,
556 BYTE bScan,
557 DWORD dwFlags,
558 ULONG_PTR dwExtraInfo)
559 {
560 INPUT Input;
561
562 Input.type = INPUT_KEYBOARD;
563 Input.ki.wVk = bVk;
564 Input.ki.wScan = bScan;
565 Input.ki.dwFlags = dwFlags;
566 Input.ki.time = 0;
567 Input.ki.dwExtraInfo = dwExtraInfo;
568
569 NtUserSendInput(1, &Input, sizeof(INPUT));
570 }
571
572
573 /*
574 * @implemented
575 */
576 VOID
577 WINAPI
578 mouse_event(
579 DWORD dwFlags,
580 DWORD dx,
581 DWORD dy,
582 DWORD dwData,
583 ULONG_PTR dwExtraInfo)
584 {
585 INPUT Input;
586
587 Input.type = INPUT_MOUSE;
588 Input.mi.dx = dx;
589 Input.mi.dy = dy;
590 Input.mi.mouseData = dwData;
591 Input.mi.dwFlags = dwFlags;
592 Input.mi.time = 0;
593 Input.mi.dwExtraInfo = dwExtraInfo;
594
595 NtUserSendInput(1, &Input, sizeof(INPUT));
596 }
597
598 /* EOF */