1 #include "CtrlCore.h"
2 
3 #ifdef GUI_WIN
4 
5 #include <winnls.h>
6 
7 //#include "imm.h"
8 
9 namespace Upp {
10 
11 #define LLOG(x)  // DLOG(x)
12 
KEYtoK(dword chr)13 dword Ctrl::KEYtoK(dword chr) {
14 	if(chr == VK_TAB)
15 		chr = K_TAB;
16 	else
17 	if(chr == VK_SPACE)
18 		chr = K_SPACE;
19 	else
20 	if(chr == VK_RETURN)
21 		chr = K_RETURN;
22 	else
23 		chr = chr + K_DELTA;
24 	if(chr == K_ALT_KEY || chr == K_CTRL_KEY || chr == K_SHIFT_KEY)
25 		return chr;
26 	if(GetCtrl()) chr |= K_CTRL;
27 	if(GetAlt()) chr |= K_ALT;
28 	if(GetShift()) chr |= K_SHIFT;
29 	return chr;
30 }
31 
32 
33 class NilDrawFull : public NilDraw {
IsPaintingOp(const Rect & r) const34 	virtual bool IsPaintingOp(const Rect& r) const { return true; }
35 };
36 
AvoidPaintingCheck__()37 void AvoidPaintingCheck__()
38 {
39 	Ctrl::painting = false;
40 }
41 
GetKeyStateSafe(dword what)42 dword GetKeyStateSafe(dword what) {
43 	bool h = Ctrl::painting;
44 	Ctrl::painting = false;
45 	dword r = GetKeyState(what);
46 	Ctrl::painting = h;
47 	return r;
48 }
49 
GetShift()50 bool GetShift()       { return !!(GetKeyStateSafe(VK_SHIFT) & 0x8000); }
GetCtrl()51 bool GetCtrl()        { return !!(GetKeyStateSafe(VK_CONTROL) & 0x8000); }
GetAlt()52 bool GetAlt()         { return !!(GetKeyStateSafe(VK_MENU) & 0x8000); }
GetCapsLock()53 bool GetCapsLock()    { return !!(GetKeyStateSafe(VK_CAPITAL) & 1); }
GetMouseLeft()54 bool GetMouseLeft()   { return !!(GetKeyStateSafe(VK_LBUTTON) & 0x8000); }
GetMouseRight()55 bool GetMouseRight()  { return !!(GetKeyStateSafe(VK_RBUTTON) & 0x8000); }
GetMouseMiddle()56 bool GetMouseMiddle() { return !!(GetKeyStateSafe(VK_MBUTTON) & 0x8000); }
57 
58 bool PassWindowsKey(int wParam);
59 
WindowProc(UINT message,WPARAM wParam,LPARAM lParam)60 LRESULT Ctrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
61 	GuiLock __;
62 	eventid++;
63 //	LLOG("Ctrl::WindowProc(" << message << ") in " << ::Name(this) << ", focus " << (void *)::GetFocus());
64 	Ptr<Ctrl> _this = this;
65 	HWND hwnd = GetHWND();
66 	switch(message) {
67 	case WM_PALETTECHANGED:
68 		if((HWND)wParam == hwnd)
69 			break;
70 #ifndef PLATFORM_WINCE
71 	case WM_QUERYNEWPALETTE:
72 		if(!SystemDraw::AutoPalette()) break;
73 		{
74 			HDC hDC = GetDC(hwnd);
75 			HPALETTE hOldPal = SelectPalette(hDC, GetQlibPalette(), FALSE);
76 			int i = RealizePalette(hDC);
77 			SelectPalette(hDC, hOldPal, TRUE);
78 			RealizePalette(hDC);
79 			ReleaseDC(hwnd, hDC);
80 			LLOG("Realized " << i << " colors");
81 			if(i) InvalidateRect(hwnd, NULL, TRUE);
82 			return i;
83 		}
84 #endif
85 	case WM_PAINT:
86 		ASSERT_(!painting || IsPanicMode(), "WM_PAINT invoked for " + Name() + " while in Paint routine");
87 		ASSERT(hwnd);
88 		if(hwnd) {
89 			PAINTSTRUCT ps;
90 			if(IsVisible())
91 				SyncScroll();
92 			HDC dc = BeginPaint(hwnd, &ps);
93 			fullrefresh = false;
94 			if(IsVisible()) {
95 				SystemDraw draw(dc);
96 	#ifndef PLATFORM_WINCE
97 				HPALETTE hOldPal;
98 				if(draw.PaletteMode() && SystemDraw::AutoPalette()) {
99 					hOldPal = SelectPalette(dc, GetQlibPalette(), TRUE);
100 					int n = RealizePalette(dc);
101 					LLOG("In paint realized " << n << " colors");
102 				}
103 	#endif
104 				painting = true;
105 				UpdateArea(draw, Rect(ps.rcPaint));
106 				painting = false;
107 	#ifndef PLATFORM_WINCE
108 				if(draw.PaletteMode() && SystemDraw::AutoPalette())
109 					SelectPalette(dc, hOldPal, TRUE);
110 	#endif
111 			}
112 			EndPaint(hwnd, &ps);
113 
114 			UpdateDHCtrls(); // so that they are displayed withing the same WM_PAINT - looks better
115 		}
116 		return 0L;
117 #ifndef PLATFORM_WINCE
118 	case WM_NCHITTEST:
119 		CheckMouseCtrl();
120 		if(ignoremouse) return HTTRANSPARENT;
121 		break;
122 #endif
123 	case WM_LBUTTONDOWN:
124 #ifdef PLARFORM_WINCE
125 		wince_mouseleft = true;
126 #endif
127 		ClickActivateWnd();
128 		if(ignoreclick) return 0L;
129 		DoMouse(LEFTDOWN, Point((dword)lParam), 0);
130 		if(_this) PostInput();
131 		return 0L;
132 	case WM_LBUTTONUP:
133 		if(ignoreclick)
134 			EndIgnore();
135 		else
136 			DoMouse(LEFTUP, Point((dword)lParam), 0);
137 #ifdef PLATFORM_WINCE
138 		wince_mouseleft = false;
139 #endif
140 #ifdef PLATFORM_WINCE
141 		wince_mousepos = Point(-99999, -99999);
142 		if(!ignoreclick)
143 			if(_this) DoMouse(MOUSEMOVE, Point(-99999, -99999));
144 #endif
145 		if(_this) PostInput();
146 		return 0L;
147 	case WM_LBUTTONDBLCLK:
148 		ClickActivateWnd();
149 		if(ignoreclick) return 0L;
150 		DoMouse(LEFTDOUBLE, Point((dword)lParam), 0);
151 		if(_this) PostInput();
152 		return 0L;
153 	case WM_RBUTTONDOWN:
154 		ClickActivateWnd();
155 		if(ignoreclick) return 0L;
156 		DoMouse(RIGHTDOWN, Point((dword)lParam));
157 		if(_this) PostInput();
158 		return 0L;
159 	case WM_RBUTTONUP:
160 		if(ignoreclick)
161 			EndIgnore();
162 		else
163 			DoMouse(RIGHTUP, Point((dword)lParam));
164 		if(_this) PostInput();
165 		return 0L;
166 	case WM_RBUTTONDBLCLK:
167 		ClickActivateWnd();
168 		if(ignoreclick) return 0L;
169 		DoMouse(RIGHTDOUBLE, Point((dword)lParam));
170 		if(_this) PostInput();
171 		return 0L;
172 	case WM_MBUTTONDOWN:
173 		ClickActivateWnd();
174 		if(ignoreclick) return 0L;
175 		DoMouse(MIDDLEDOWN, Point((dword)lParam));
176 		if(_this) PostInput();
177 		return 0L;
178 	case WM_MBUTTONUP:
179 		if(ignoreclick)
180 			EndIgnore();
181 		else
182 			DoMouse(MIDDLEUP, Point((dword)lParam));
183 		if(_this) PostInput();
184 		return 0L;
185 	case WM_MBUTTONDBLCLK:
186 		ClickActivateWnd();
187 		if(ignoreclick) return 0L;
188 		DoMouse(MIDDLEDOUBLE, Point((dword)lParam));
189 		if(_this) PostInput();
190 		return 0L;
191 #ifndef PLATFORM_WINCE
192 	case WM_NCLBUTTONDOWN:
193 	case WM_NCRBUTTONDOWN:
194 	case WM_NCMBUTTONDOWN:
195 		ClickActivateWnd();
196 		IgnoreMouseUp();
197 		break;
198 #endif
199 	case WM_MOUSEMOVE:
200 		LLOG("WM_MOUSEMOVE: ignoreclick = " << ignoreclick);
201 		if(ignoreclick) {
202 			EndIgnore();
203 			return 0L;
204 		}
205 		if(_this)
206 			DoMouse(MOUSEMOVE, Point((dword)lParam));
207 		DoCursorShape();
208 		return 0L;
209 	case 0x20a: // WM_MOUSEWHEEL:
210 		if(ignoreclick) {
211 			EndIgnore();
212 			return 0L;
213 		}
214 		if(_this) {
215 			Point p(0, 0);
216 			::ClientToScreen(hwnd, p);
217 			DoMouse(MOUSEWHEEL, Point((dword)lParam) - p, (short)HIWORD(wParam));
218 		}
219 		if(_this) PostInput();
220 		return 0L;
221 	case WM_SETCURSOR:
222 		if((HWND)wParam == hwnd && LOWORD((dword)lParam) == HTCLIENT) {
223 			if(hCursor) SetCursor(hCursor);
224 			return TRUE;
225 		}
226 		break;
227 //	case WM_MENUCHAR:
228 //		return MAKELONG(0, MNC_SELECT);
229 	case WM_KEYDOWN:
230 	case WM_SYSKEYDOWN:
231 	case WM_CHAR:
232 		ignorekeyup = false;
233 	case WM_KEYUP:
234 	case WM_SYSKEYUP:
235 		{
236 #if 0
237 			String msgdump;
238 			switch(message)
239 			{
240 			case WM_KEYDOWN:    msgdump << "WM_KEYDOWN"; break;
241 			case WM_KEYUP:      msgdump << "WM_KEYUP"; break;
242 			case WM_SYSKEYDOWN: msgdump << "WM_SYSKEYDOWN"; break;
243 			case WM_SYSKEYUP:   msgdump << "WM_SYSKEYUP"; break;
244 			case WM_CHAR:       msgdump << "WM_CHAR"; break;
245 			}
246 			msgdump << " wParam = 0x" << FormatIntHex(wParam, 8)
247 				<< ", lParam = 0x" << FormatIntHex(lParam, 8)
248 				<< ", ignorekeyup = " << (ignorekeyup ? "true" : "false");
249 			LLOG(msgdump);
250 #endif
251 			dword keycode = 0;
252 			if(message == WM_KEYDOWN) {
253 				keycode = KEYtoK((dword)wParam);
254 				if(keycode == K_SPACE)
255 					keycode = 0;
256 			}
257 			else
258 			if(message == WM_KEYUP)
259 				keycode = KEYtoK((dword)wParam) | K_KEYUP;
260 			else
261 			if(message == WM_SYSKEYDOWN /*&& ((lParam & 0x20000000) || wParam == VK_F10)*/)
262 				keycode = KEYtoK((dword)wParam);
263 			else
264 			if(message == WM_SYSKEYUP /*&& ((lParam & 0x20000000) || wParam == VK_F10)*/)
265 				keycode = KEYtoK((dword)wParam) | K_KEYUP;
266 			else
267 			if(message == WM_CHAR && wParam != 127 && wParam > 32 || wParam == 32 && KEYtoK(VK_SPACE) == K_SPACE) {
268 #ifdef PLATFORM_WINCE
269 				keycode = wParam;
270 #else
271 				if(IsWindowUnicode(hwnd)) // TRC 04/10/17: ActiveX Unicode patch
272 					keycode = (dword)wParam;
273 				else {
274 					char b[20];
275 					::GetLocaleInfo(MAKELCID(LOWORD(GetKeyboardLayout(0)), SORT_DEFAULT),
276 					                LOCALE_IDEFAULTANSICODEPAGE, b, 20);
277 					int codepage = atoi(b);
278 					if(codepage >= 1250 && codepage <= 1258)
279 						keycode = ToUnicode((dword)wParam, codepage - 1250 + CHARSET_WIN1250);
280 					else
281 						keycode = (dword)wParam;
282 				}
283 #endif
284 			}
285 			bool b = false;
286 			if(keycode) {
287 				b = DispatchKey(keycode, LOWORD(lParam));
288 				SyncCaret();
289 				if(_this) PostInput();
290 			}
291 //			LOG("key processed = " << b);
292 			if(b || (message == WM_SYSKEYDOWN || message == WM_SYSKEYUP)
293 			&& wParam != VK_F4 && !PassWindowsKey((dword)wParam)) // 17.11.2003 Mirek -> invoke system menu
294 				return 0L;
295 			break;
296 		}
297 		break;
298 //	case WM_GETDLGCODE:
299 //		return wantfocus ? 0 : DLGC_STATIC;
300 	case WM_ERASEBKGND:
301 		return 1L;
302 	case WM_DESTROY:
303 		PreDestroy();
304 		break;
305 	case WM_NCDESTROY:
306 		if(!hwnd) break;
307 		if(HasChildDeep(mouseCtrl) || this == ~mouseCtrl) mouseCtrl = NULL;
308 		if(HasChildDeep(focusCtrl) || this == ~focusCtrl) focusCtrl = NULL;
309 		if(HasChildDeep(focusCtrlWnd) || this == ~focusCtrlWnd) {
310 			LLOG("WM_NCDESTROY: clearing focusCtrlWnd = " << UPP::Name(focusCtrlWnd));
311 			focusCtrlWnd = NULL;
312 			focusCtrl = NULL;
313 		}
314 		if(::GetFocus() == NULL) {
315 			Ctrl *owner = GetOwner();
316 			if(owner && (owner->IsForeground() || IsForeground()) && !owner->SetWantFocus())
317 				IterateFocusForward(owner, owner);
318 		}
319 		if(IsWindowUnicode(hwnd)) // TRC 04/10/17: ActiveX unicode patch
320 			DefWindowProcW(hwnd, message, wParam, lParam);
321 		else
322 			DefWindowProc(hwnd, message, wParam, lParam);
323 		hwnd = NULL;
324 		return 0L;
325 	case WM_CANCELMODE:
326 		if(this == ~captureCtrl || HasChildDeep(captureCtrl))
327 			ReleaseCtrlCapture();
328 		break;
329 	case WM_SHOWWINDOW:
330 		visible = (BOOL) wParam;
331 		StateH(SHOW);
332 		break;
333 	case WM_MOUSEACTIVATE:
334 		LLOG("WM_MOUSEACTIVATE " << Name() << ", focusCtrlWnd = " << UPP::Name(focusCtrlWnd) << ", raw = " << (void *)::GetFocus());
335 		if(!IsEnabled()) {
336 			if(lastActiveWnd && lastActiveWnd->IsEnabled()) {
337 				if(focusCtrl) { // this closes popup
338 					LLOG("WM_MOUSEACTIVATE -> ClickActivateWnd for " << UPP::Name(lastActiveWnd));
339 					lastActiveWnd->ClickActivateWnd();
340 				}
341 				else { // this makes child dialog active when clicked on disabled parent
342 					LLOG("WM_MOUSEACTIVATE -> ::SetFocus for " << UPP::Name(lastActiveWnd));
343 					::SetFocus(lastActiveWnd->GetHWND());
344 				}
345 			}
346 			else
347 				MessageBeep(MB_OK);
348 			return MA_NOACTIVATEANDEAT;
349 		}
350 		if(IsPopUp()) return MA_NOACTIVATE;
351 		break;
352 	case WM_SIZE:
353 	case WM_MOVE:
354 		if(hwnd) {
355 			Rect rect;
356 			if(activex) {
357 				WINDOWPLACEMENT wp;
358 				wp.length = sizeof(WINDOWINFO);
359 				::GetWindowPlacement(hwnd, &wp);
360 				rect = wp.rcNormalPosition;
361 			}
362 			else
363 				rect = GetScreenClient(hwnd);
364 			LLOG("WM_MOVE / WM_SIZE: screen client = " << rect);
365 			if(GetRect() != rect)
366 				SetWndRect(rect);
367 		#if WINCARET
368 			WndDestroyCaret();
369 			caretCtrl = NULL;
370 			SyncCaret();
371 		#endif
372 		}
373 		return 0L;
374 	case WM_HELP:
375 		return TRUE;
376 	case WM_ACTIVATE:
377 		LLOG("WM_ACTIVATE " << Name() << ", wParam = " << (int)wParam << ", focusCtrlWnd = " << UPP::Name(focusCtrlWnd) << ", raw = " << (void *)::GetFocus());
378 		ignorekeyup = true;
379 		break;
380 	case WM_SETFOCUS:
381 		LLOG("WM_SETFOCUS " << Name() << ", focusCtrlWnd = " << UPP::Name(focusCtrlWnd) << ", raw = " << (void *)::GetFocus());
382 		if(this != focusCtrlWnd || focusCtrl && focusCtrlWnd != focusCtrl->GetTopCtrl()) { // second condition fixes popup issue when clicking dialog parent
383 			if(IsEnabled()) {
384 				LLOG("WM_SETFOCUS -> ActivateWnd: this != focusCtrlWnd, this = "
385 					<< Name() << ", focusCtrlWnd = " << UPP::Name(focusCtrlWnd));
386 				ActivateWnd();
387 			}
388 			else {
389 				if(focusCtrlWnd && focusCtrlWnd->IsEnabled()) {
390 					if(!IsEnabled())
391 						MessageBeep(MB_OK);
392 					LLOG("WM_SETFOCUS -> ::SetFocus for " << UPP::Name(focusCtrlWnd) << ", this: " << UPP::Name(this));
393 					::SetFocus(focusCtrlWnd->GetHWND());
394 				}
395 				else
396 				if(lastActiveWnd && lastActiveWnd->IsEnabled()) {
397 					LLOG("WM_SETFOCUS -> ::SetFocus for " << UPP::Name(lastActiveWnd));
398 					::SetFocus(lastActiveWnd->GetHWND());
399 				}
400 				else {
401 					LLOG("WM_SETFOCUS - ::SetFocus(NULL)");
402 					::SetFocus(NULL);
403 				}
404 			}
405 		}
406 		LLOG("//WM_SETFOCUS " << (void *)hwnd << ", focusCtrlWnd = " << UPP::Name(focusCtrlWnd) << ", raw = " << (void *)::GetFocus());
407 		return 0L;
408 	case WM_KILLFOCUS:
409 		LLOG("WM_KILLFOCUS " << (void *)(HWND)wParam << ", this = " << UPP::Name(this) << ", focusCtrlWnd = " << UPP::Name(focusCtrlWnd) << ", raw = " << (void *)::GetFocus());
410 		LLOG("Kill " << UPP::Name(CtrlFromHWND((HWND)wParam)));
411 		if(!CtrlFromHWND((HWND)wParam)) {
412 			LLOG("WM_KILLFOCUS -> KillFocusWnd: " << UPP::Name(this));
413 			KillFocusWnd();
414 		}
415 		LLOG("//WM_KILLFOCUS " << (void *)(HWND)wParam << ", focusCtrlWnd = " << UPP::Name(focusCtrlWnd) << ", raw = " << (void *)::GetFocus());
416 		return 0L;
417 	case WM_ENABLE:
418 		if(!!wParam != enabled) {
419 			enabled = !!wParam;
420 			RefreshFrame();
421 			StateH(ENABLE);
422 		}
423 		return 0L;
424 #ifndef PLATFORM_WINCE
425 	case WM_GETMINMAXINFO:
426 		{
427 			MINMAXINFO *mmi = (MINMAXINFO *)lParam;
428 			Rect frmrc = Size(200, 200);
429 			::AdjustWindowRect(frmrc, WS_OVERLAPPEDWINDOW, FALSE);
430 //			Size msz = Ctrl::GetWorkArea().Deflated(-frmrc.left, -frmrc.top,
431 //				           frmrc.right - 200, frmrc.bottom - 200).GetSize();
432 //			Rect minr(Point(50, 50), min(msz, GetMinSize()));
433 //			Rect maxr(Point(50, 50), min(msz, GetMaxSize())); // Removed cxl&nixnixnix 2012-6-12
434 			Rect minr(Point(50, 50), GetMinSize());
435 			Rect maxr(Point(50, 50), GetMaxSize());
436 			dword style = ::GetWindowLong(hwnd, GWL_STYLE);
437 			dword exstyle = ::GetWindowLong(hwnd, GWL_EXSTYLE);
438 			AdjustWindowRectEx(minr, style, FALSE, exstyle);
439 			AdjustWindowRectEx(maxr, style, FALSE, exstyle);
440 			mmi->ptMinTrackSize = Point(minr.Size());
441 			mmi->ptMaxTrackSize = Point(maxr.Size());
442 			LLOG("WM_GETMINMAXINFO: MinTrackSize = " << Point(mmi->ptMinTrackSize) << ", MaxTrackSize = " << Point(mmi->ptMaxTrackSize));
443 			LLOG("ptMaxSize = " << Point(mmi->ptMaxSize) << ", ptMaxPosition = " << Point(mmi->ptMaxPosition));
444 		}
445 		return 0L;
446 #endif
447 /*	case WM_SETTINGCHANGE:
448 	case 0x031A: // WM_THEMECHANGED
449 		ReSkin();
450 		RefreshLayoutDeep();
451 		RefreshFrame();
452 		break;
453 */
454 /*
455     case WM_IME_COMPOSITION:
456 		HIMC himc = ImmGetContext(hwnd);
457 		if(!himc) break;
458 		CANDIDATEFORM cf;
459 		Rect r = GetScreenRect();
460 		cf.dwIndex = 0;
461 		cf.dwStyle = CFS_CANDIDATEPOS;
462 		cf.ptCurrentPos.x = r.left + caretx;
463 		cf.ptCurrentPos.y = r.top + carety + caretcy;
464 		ImmSetCandidateWindow (himc, &cf);
465 		break;
466 */
467 	}
468 	if(hwnd) {
469 #ifdef PLATFORM_WINCE
470 		return DefWindowProc(hwnd, message, wParam, lParam);
471 #else
472 		if(IsWindowUnicode(hwnd)) // TRC 04/10/17: ActiveX unicode patch
473 			return DefWindowProcW(hwnd, message, wParam, lParam);
474 		else
475 			return DefWindowProc(hwnd, message, wParam, lParam);
476 #endif
477 	}
478 	return 0L;
479 }
480 
PreDestroy()481 void Ctrl::PreDestroy() {}
482 
483 }
484 
485 #endif
486