1 /*
2  * PROJECT:     ReactOS
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * PURPOSE:     Keyboard layout testapp
5  * COPYRIGHT:   Copyright 2007 Saveliy Tretiakov
6  */
7 
8 #define UNICODE
9 #include<wchar.h>
10 #include <windows.h>
11 #include "resource.h"
12 
13 
14 
15 INT_PTR CALLBACK MainDialogProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam);
16 
17 
18 HINSTANCE hInst;
19 HWND hMainDlg;
20 
21 
22 typedef struct {
23 	WNDPROC OrigProc;
24 	WCHAR WndName[25];
25 } WND_DATA;
26 
27 DWORD WINAPI ThreadProc(LPVOID lpParam)
28 {
29 	DialogBoxParam(hInst,
30 		MAKEINTRESOURCE(IDD_MAINDIALOG),
31 		NULL,
32 		MainDialogProc,
33 		(LPARAM)NULL);
34 
35 	return 0;
36 }
37 
38 INT WINAPI WinMain(HINSTANCE hInstance,
39     HINSTANCE hPrevInstance,
40     LPSTR lpCmdLine,
41     int nCmdShow)
42 {
43 	hInst = hInstance;
44 
45 	ThreadProc(0);
46 
47 	return 0;
48 }
49 
50 int GetKlList(HKL **list)
51 {
52 	HKL *ret;
53 	int n;
54 
55 	n = GetKeyboardLayoutList(0, NULL);
56 	ret = HeapAlloc(GetProcessHeap(), 0, sizeof(HKL)*n);
57 	GetKeyboardLayoutList(n, ret);
58 	*list = ret;
59 	return n;
60 }
61 
62 void FreeKlList(HKL *list)
63 {
64 	HeapFree(GetProcessHeap(), 0, list);
65 }
66 
67 void UpdateData(HWND hDlg)
68 {
69 	WCHAR buf[KL_NAMELENGTH];
70 	WCHAR buf2[512];
71 
72 	HWND hList;
73 	HKL *klList, hKl;
74 	int n, i,j;
75 
76 	GetKeyboardLayoutName(buf);
77 	swprintf(buf2, L"Active: %s (%x)", buf, GetKeyboardLayout(0));
78 	SetWindowText(GetDlgItem(hDlg, IDC_ACTIVE), buf2);
79 
80 	hList = GetDlgItem(hDlg, IDC_LIST);
81 	SendMessage(hList, LB_RESETCONTENT, 0, 0);
82 
83 	n = GetKlList(&klList);
84 	hKl = GetKeyboardLayout(0);
85 	for(i = 0; i < n; i++)
86 	{
87 		swprintf(buf, L"%x", klList[i] );
88 		j = SendMessage(hList, LB_ADDSTRING, 0, (LPARAM) buf);
89 		SendMessage(hList, LB_SETITEMDATA, j, (LPARAM) klList[i]);
90 		if(klList[i] == hKl) SendMessage(hList, LB_SETCURSEL, j, 0);
91 	}
92 
93 	FreeKlList(klList);
94 }
95 
96 void FormatMsg(WCHAR *format, ...)
97 {
98 	WCHAR buf[255];
99 	va_list argptr;
100 	va_start(argptr, format);
101 	_vsnwprintf(buf, sizeof(buf)-1, format, argptr);
102 	MessageBox(0, buf, L"msg", 0);
103 	va_end(argptr);
104 }
105 
106 void FormatBox(HWND hWnd, DWORD Flags, WCHAR *Caption, WCHAR *Format, ...)
107 {
108 	WCHAR buf[255];
109 	va_list argptr;
110 	va_start(argptr, Format);
111 	_vsnwprintf(buf, sizeof(buf)-1, Format, argptr);
112 	MessageBox(hWnd, buf, Caption, Flags);
113 	va_end(argptr);
114 }
115 
116 LRESULT CALLBACK WndSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
117 {
118 	WND_DATA *data = (WND_DATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
119 
120 	if(uMsg == WM_INPUTLANGCHANGE)
121 	{
122 		FormatMsg(L"%s: WM_INPUTLANGCHANGE lParam=%x wParam=%x\n", data->WndName, lParam, wParam);
123 		UpdateData(hMainDlg);
124 		//Pass message to defwindowproc
125 	}
126 	else if(uMsg == WM_INPUTLANGCHANGEREQUEST)
127 	{
128 		FormatMsg(L"%s: WM_INPUTLANGCHANGEREQUEST lParam=%x wParam=%x\n", data->WndName, lParam, wParam);
129 		UpdateData(hMainDlg);
130 		//Pass message to defwindowproc
131 	}
132 
133 	return CallWindowProc(data->OrigProc, hwnd, uMsg, wParam, lParam);
134 }
135 
136 void SubclassWnd(HWND hWnd, WCHAR* Name)
137 {
138 	WND_DATA *data = HeapAlloc(GetProcessHeap(), 0, sizeof(WND_DATA));
139 	data->OrigProc = (WNDPROC)SetWindowLongPtr( hWnd, GWLP_WNDPROC, (LONG_PTR)WndSubclassProc);
140 	wcsncpy(data->WndName, Name, 25);
141 	SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)data);
142 }
143 
144 DWORD GetActivateFlags(HWND hDlg)
145 {
146 	DWORD ret = 0;
147 
148 	if(IsDlgButtonChecked(hDlg, IDC_KLF_REORDER))
149 		ret |= KLF_REORDER;
150 
151 	if(IsDlgButtonChecked(hDlg, IDC_KLF_RESET))
152 		ret |= KLF_RESET;
153 
154 	if(IsDlgButtonChecked(hDlg, IDC_KLF_SHIFTLOCK))
155 		ret |= KLF_SHIFTLOCK;
156 
157 	if(IsDlgButtonChecked(hDlg, IDC_KLF_SETFORPROCESS))
158 		ret |= KLF_SETFORPROCESS;
159 
160 	return ret;
161 }
162 
163 DWORD GetLoadFlags(HWND hDlg)
164 {
165 	DWORD ret = 0;
166 
167 	if(IsDlgButtonChecked(hDlg, IDL_KLF_ACTIVATE))
168 		ret |= KLF_ACTIVATE;
169 
170 	if(IsDlgButtonChecked(hDlg, IDL_KLF_NOTELLSHELL))
171 		ret |= KLF_NOTELLSHELL;
172 
173 	if(IsDlgButtonChecked(hDlg, IDL_KLF_REORDER))
174 		ret |= KLF_REORDER;
175 
176 	if(IsDlgButtonChecked(hDlg, IDL_KLF_REPLACELANG))
177 		ret |= KLF_REPLACELANG;
178 
179 	if(IsDlgButtonChecked(hDlg, IDL_KLF_SUBSTITUTE_OK))
180 		ret |= KLF_SUBSTITUTE_OK;
181 
182 	if(IsDlgButtonChecked(hDlg, IDL_KLF_SETFORPROCESS))
183 		ret |= KLF_SETFORPROCESS;
184 
185 	return ret;
186 }
187 
188 UINT GetDelayMilliseconds(HWND hDlg)
189 {
190 	WCHAR Buf[255];
191 	UINT ret;
192 
193 	GetWindowText(GetDlgItem(hDlg, IDC_DELAY), Buf, sizeof(Buf));
194 
195 	swscanf(Buf, L"%d", &ret);
196 
197 	return ret*1000;
198 }
199 
200 HKL GetSelectedLayout(HWND hDlg)
201 {
202 	int n;
203 	HWND hList;
204 	hList = GetDlgItem(hDlg, IDC_LIST);
205 	if((n = SendMessage(hList, LB_GETCURSEL, 0, 0)) != LB_ERR)
206 		return (HKL) SendMessage(hList, LB_GETITEMDATA, n, 0);
207 	else return INVALID_HANDLE_VALUE;
208 }
209 
210 HKL GetActivateHandle(HWND hDlg)
211 {
212 	if(IsDlgButtonChecked(hDlg, IDC_FROMLIST))
213 		return GetSelectedLayout(hDlg);
214 	else if(IsDlgButtonChecked(hDlg, IDC_HKL_NEXT))
215 		return (HKL)HKL_NEXT;
216 
217 	return (HKL)HKL_PREV;
218 }
219 
220 INT_PTR CALLBACK MainDialogProc(HWND hDlg,
221 	UINT Msg,
222 	WPARAM wParam,
223 	LPARAM lParam)
224 {
225 	HKL hKl;
226 
227 	switch (Msg)
228 	{
229 		case WM_INITDIALOG:
230 		{
231 			WCHAR Buf[255];
232 			UpdateData(hDlg);
233 			hMainDlg = hDlg;
234 
235 			SubclassWnd(GetDlgItem(hDlg, IDC_LIST), L"List");
236 			SubclassWnd(GetDlgItem(hDlg, IDC_EDIT1), L"Edit1");
237 			SubclassWnd(GetDlgItem(hDlg, IDC_KLID), L"Klid");
238 			SubclassWnd(GetDlgItem(hDlg, ID_CANCEL), L"CancelB");
239 			SubclassWnd(GetDlgItem(hDlg, IDC_ACTIVATE), L"ActivateB");
240 			SubclassWnd(GetDlgItem(hDlg, IDC_REFRESH), L"RefreshB");
241 			SubclassWnd(GetDlgItem(hDlg, IDC_UNLOAD), L"UnloadB");
242 			SubclassWnd(GetDlgItem(hDlg, IDC_LOAD), L"LoadB");
243 
244 			CheckRadioButton(hDlg, IDC_FROMLIST, IDC_FROMEDIT, IDC_FROMLIST);
245 			SetWindowText(GetDlgItem(hDlg, IDC_KLID), L"00000419");
246 
247 			swprintf(Buf, L"Current thread id: %d", GetCurrentThreadId());
248 			SetWindowText(GetDlgItem(hDlg, IDC_CURTHREAD), Buf);
249 
250 			SetWindowText(GetDlgItem(hDlg, IDC_DELAY), L"0");
251 
252 			return 0;
253 		} /* WM_INITDIALOG */
254 
255 		case WM_COMMAND:
256 		{
257 			switch(LOWORD(wParam))
258 			{
259 				case ID_CANCEL:
260 				{
261 					EndDialog(hDlg, ERROR_CANCELLED);
262 					break;
263 				}
264 
265 				case IDC_ACTIVATE:
266 				{
267 					if((hKl = GetActivateHandle(hDlg)) != INVALID_HANDLE_VALUE)
268 					{
269 						Sleep(GetDelayMilliseconds(hDlg));
270 						if(!(hKl = ActivateKeyboardLayout(hKl, GetActivateFlags(hDlg))))
271 							FormatBox(hDlg, MB_ICONERROR, L"Error",
272 								L"ActivateKeyboardLayout() failed. %d", GetLastError());
273 						else UpdateData(hDlg);
274 						//FormatBox(hDlg, 0, L"Activated", L"Prev - %x, err - %d.", hKl,
275 						// GetLastError());
276 					}
277 					else MessageBox(hDlg, L"No item selected", L"Error", MB_ICONERROR);
278 					break;
279 				}
280 
281 				case IDC_UNLOAD:
282 				{
283 					if((hKl = GetSelectedLayout(hDlg)) != INVALID_HANDLE_VALUE)
284 					{
285 						Sleep(GetDelayMilliseconds(hDlg));
286 						if(!UnloadKeyboardLayout(hKl))
287 							FormatBox(hDlg, MB_ICONERROR, L"Error",
288 								L"UnloadKeyboardLayout() failed. %d",
289 								GetLastError());
290 						else UpdateData(hDlg);
291 					}
292 					else MessageBox(hDlg,  L"No item selected", L"Error", MB_ICONERROR);
293 					break;
294 				}
295 
296 				case IDC_LOAD:
297 				{
298 					WCHAR buf[255];
299 					GetWindowText(GetDlgItem(hDlg, IDC_KLID), buf, sizeof(buf));
300 					Sleep(GetDelayMilliseconds(hDlg));
301 					if(!LoadKeyboardLayout(buf, GetLoadFlags(hDlg)))
302 						FormatBox(hDlg, MB_ICONERROR, L"Error",
303 							L"LoadKeyboardLayout() failed. %d",
304 							GetLastError());
305 					else UpdateData(hDlg);
306 					break;
307 				}
308 
309 				case IDC_REFRESH:
310 				{
311 					UpdateData(hDlg);
312 					break;
313 				}
314 
315 				case IDC_NEWTHREAD:
316 				{
317 					if(!CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL))
318 					{
319 						FormatBox(hDlg, MB_ICONERROR, L"Error!",
320 							L"Can not create thread (%d).", GetLastError());
321 					}
322 				}
323 
324 				case IDC_LIST:
325 				{
326 					if(HIWORD(wParam) == LBN_SELCHANGE)
327 					{
328 						WCHAR buf[25];
329 						if((hKl = GetSelectedLayout(hDlg)) != NULL)
330 						{
331 							swprintf(buf, L"%x", hKl);
332 							SetWindowText(GetDlgItem(hDlg, IDC_HANDLE), buf);
333 						}
334 					}
335 					break;
336 				}
337 			}
338 
339 			return TRUE;
340 		} /* WM_COMMAND */
341 
342 		case WM_INPUTLANGCHANGE:
343 		{
344 			FormatMsg(L"dlg WM_INPUTLANGCHANGE lParam=%x wParam=%x\n", lParam, wParam);
345 			return FALSE;
346 		}
347 
348 		case WM_INPUTLANGCHANGEREQUEST:
349 		{
350 			FormatMsg(L"dlg WM_INPUTLANGCHANGEREQUEST lParam=%x wParam=%x\n", lParam, wParam);
351 			UpdateData(hDlg);
352 			return FALSE;
353 		}
354 
355 		case WM_CLOSE:
356 		{
357 			EndDialog(hDlg, ERROR_CANCELLED);
358 			return TRUE;
359 		} /* WM_CLOSE */
360 
361 		default:
362 			return FALSE;
363 	}
364 }
365 
366