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