2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
5 Desc: Host-side part of GDI hidd. Handles windows and receives events.
23 LRESULT CALLBACK
display_callback(HWND win
, UINT msg
, WPARAM wp
, LPARAM lp
);
24 LRESULT CALLBACK
bitmap_callback(HWND win
, UINT msg
, WPARAM wp
, LPARAM lp
);
26 /* Global variables shared by all windows (theoretical) */
28 static WNDCLASS display_class_desc
=
37 (HBRUSH
)(COLOR_WINDOW
+ 1),
42 static WNDCLASS bitmap_class_desc
=
51 (HBRUSH
)(COLOR_WINDOW
+ 1),
56 static ULONG_PTR display_class
; /* Display window class */
57 static ULONG_PTR bitmap_class
; /* Bitmap window class */
58 static HWND window_active
; /* Currently active AROS window */
59 static HANDLE KbdAck
; /* Keyboard acknowledge event */
60 static HANDLE MouseAck
; /* Mouse acknowledge event */
61 static DWORD thread_id
; /* Window service thread ID */
62 static DWORD last_key
; /* Last pressed key - used to suppress autorepeat */
64 /* Virtual hardware registers */
65 static volatile struct GDI_Control gdictl
;
67 /****************************************************************************************/
69 static ULONG
SendKbdIRQ(UINT msg
, DWORD key
)
71 DKBD(printf("[GDI] Keyboard event 0x%04lX key 0x%04lX\n", msg
, key
));
74 * Lock until AROS have read the previous event.
75 * This should fix swallowing or duplicating events, which happens because
76 * of race condition between this thread and AROS:
77 * 1. We signal a keypress.
78 * 2. AROS gets a signal and wakes up. But has no time to read the event, Windows context switches.
79 * 3. We get one more keypress, send another event.
80 * 4. AROS wakes up again, reads event. Note that this is already another event (3).
81 * 5. AROS sees one more event, and reads it again. Result: first keypress lost, second duplicated.
82 * Note that this event is set to signalled state during creation.
84 * Be careful! Doing this here means AROS MUST read events and reset locks. Otherwise we'll deadlock
85 * here upon the second event. Never dispose a keyboard or mouse HIDD objects, for example. There's
86 * no need to, but who knows...
88 * In case of futrher problems a FIFO event queue needs to be implemented here.
90 WaitForSingleObject(KbdAck
, INFINITE
);
92 gdictl
.KbdEvent
= msg
;
95 return KrnCauseIRQ(gdictl
.KbdIrq
);
98 /* We have to use this weird hook technique because there's no other way to prevent "Win" keys
99 from opening theif stupid "Start menu". */
100 LRESULT CALLBACK
key_callback(int code
, WPARAM wp
, KBDLLHOOKSTRUCT
*lp
)
104 if ((code
== HC_ACTION
) && window_active
)
106 wp
&= 0xFFFFFFFB; /* This masks out difference between WM_SYSKEY* and WM_KEY* */
107 key
= (lp
->scanCode
& 0xFF) | ((lp
->flags
& LLKHF_EXTENDED
) << 8);
110 * Here we get raw keypresses, including autorepeats. We have to sort out
111 * autorepeats in some smart way.
128 return CallNextHookEx(NULL
, code
, wp
, (LPARAM
)lp
);
131 LRESULT CALLBACK
display_callback(HWND win
, UINT msg
, WPARAM wp
, LPARAM lp
)
133 struct gfx_data
*gdata
;
138 gdata
= (struct gfx_data
*)GetWindowLongPtr(win
, GWLP_USERDATA
);
142 SetCursor(gdata
->cursor
);
155 if (win
== window_active
)
157 DMSE(printf("[GDI] Mouse event 0x%04X, window 0x%p\n", msg
, win
));
159 /* Lock to prevent event loss. See SendKbdIRQ() above for explanation. */
160 WaitForSingleObject(MouseAck
, INFINITE
);
162 gdictl
.MouseEvent
= msg
;
163 gdictl
.MouseX
= GET_X_LPARAM(lp
);
164 gdictl
.MouseY
= GET_Y_LPARAM(lp
);
165 gdictl
.Buttons
= wp
& 0x0000FFFF;
166 gdictl
.WheelDelta
= wp
>> 16;
167 KrnCauseIRQ(gdictl
.MouseIrq
);
173 * This keyboard-related fragment is not used on Windows NT because keyboard hook
174 * intercepts all keyboard messages. It is left here for Windows 9x.
178 if (lp
& 0x40000000) /* Ignore autorepeats */
183 SendKbdIRQ(msg
& 0xFFFFFFFB, (lp
>> 16) & 0x000001FF);
188 DACT(printf("[GDI] WM_ACTIVATE, Window 0x%p, wParam 0x%08lX\n", win
, wp
));
189 /* In some cases Windows can activate an iconified window (for example if we minimize it
190 by clicking its button on the taskbar). We process deactivation messages regardless of
191 minimized state, but we handle activation only when it's done on a non-minimized window.
192 This behavior was discovered by trial and error, i hope it's really ok now. */
193 if ((wp
& 0x0000FFFF) != WA_INACTIVE
)
195 if (!(wp
& 0xFFFF0000))
198 gdictl
.Active
= (void *)GetWindowLongPtr(win
, GWLP_USERDATA
);
199 KrnCauseIRQ(gdictl
.GfxIrq
);
204 window_active
= NULL
;
206 /* Send WM_KEYUP in order to prevent "stuck keys" phenomena */
209 SendKbdIRQ(WM_KEYUP
, last_key
);
215 return DefWindowProc(win
, msg
, wp
, lp
);
218 LRESULT CALLBACK
bitmap_callback(HWND win
, UINT msg
, WPARAM wp
, LPARAM lp
)
222 LONG x
, y
, xsize
, ysize
;
223 struct bitmap_data
*bmdata
;
228 bmdata
= (struct bitmap_data
*)GetWindowLongPtr(win
, GWLP_USERDATA
);
229 window_dc
= BeginPaint(win
, &ps
);
232 xsize
= ps
.rcPaint
.right
- ps
.rcPaint
.left
+ 1;
233 ysize
= ps
.rcPaint
.bottom
- ps
.rcPaint
.top
+ 1;
234 BitBlt(window_dc
, x
, y
, xsize
, ysize
, bmdata
->dc
, x
, y
, SRCCOPY
);
239 return DefWindowProc(win
, msg
, wp
, lp
);
243 DWORD WINAPI
gdithread_entry(struct GDI_Control
*ctl
)
248 struct gfx_data
*gdata
;
249 struct bitmap_data
*bmdata
;
253 ctl
->KbdEvent
= 0; /* Just in case... */
256 keyhook
= SetWindowsHookEx(WH_KEYBOARD_LL
, (HOOKPROC
)key_callback
, display_class_desc
.hInstance
, 0);
260 res
= GetMessage(&msg
, NULL
, 0, 0);
261 D(printf("[GDI] GetMessage returned %ld\n", res
));
265 D(printf("[GDI] Message %lu for window 0x%p\n", msg
.message
, msg
.hwnd
));
270 gdata
= (struct gfx_data
*)msg
.wParam
;
271 DWIN(printf("[GDI] NOTY_SHOW, Display data: 0x%p\n", gdata
));
276 /* Traverse through the bitmaps list and (re)open every bitmap's window. This will
277 cause rearranging them in the correct Z-order */
278 for (bmdata
= (struct bitmap_data
*)gdata
->bitmaps
.mlh_Head
;
279 bmdata
->node
.mln_Succ
; bmdata
= (struct bitmap_data
*)bmdata
->node
.mln_Succ
)
282 /* Display window dimensions based on its size will be calculated only for the
283 first (frontmost) bitmap */
286 width
= GetSystemMetrics(SM_CXFIXEDFRAME
) * 2 + bmdata
->win_width
;
287 height
= GetSystemMetrics(SM_CYFIXEDFRAME
) * 2 + bmdata
->win_height
+ GetSystemMetrics(SM_CYCAPTION
);
289 DWIN(printf("[GDI] Display window: 0x%p\n", gdata
->fbwin
));
292 DWIN(printf("[GDI] Resizing display...\n"));
293 SetWindowPos(gdata
->fbwin
, 0, 0, 0, width
, height
, SWP_NOACTIVATE
|SWP_NOMOVE
|SWP_NOZORDER
);
297 /* Open display window if we don't have it. Try every time, for sure */
300 DWIN(printf("[GDI] Opening display...\n"));
303 * We create the window as invisible, and show it only after setting gdata pointer.
304 * Otherwise we miss activation event (since gdata is NULL)
306 gdata
->fbwin
= CreateWindow((LPCTSTR
)display_class
, TEXT("AROS Screen"), WS_OVERLAPPED
|WS_CAPTION
|WS_SYSMENU
|WS_MINIMIZEBOX
,
307 CW_USEDEFAULT
, CW_USEDEFAULT
, width
, height
, NULL
, NULL
,
308 display_class_desc
.hInstance
, NULL
);
309 DWIN(printf("[GDI] Opened display window: 0x%p\n", gdata
->fbwin
));
312 SetWindowLongPtr(gdata
->fbwin
, GWLP_USERDATA
, (LONG_PTR
)gdata
);
313 ShowWindow(gdata
->fbwin
, SW_SHOW
);
317 /* Open bitmap window only if we really have display window */
320 DWIN(printf("[GDI] Showing bitmap data 0x%p, window 0x%p\n", bmdata
, bmdata
->window
));
323 * WS_DISABLED here causes forwarding all input to the parent window (i. e. display window).
324 * In future we may need some more sophisticated input handling because current driver architecture
325 * allows further transformation to rootless mode where every screen will have its own separate window
326 * on a Windows desktop.
330 bmdata
->window
= CreateWindow((LPCTSTR
)bitmap_class
, NULL
, WS_BORDER
|WS_CHILD
|WS_CLIPSIBLINGS
|WS_DISABLED
, bmdata
->bm_left
- 1, bmdata
->bm_top
- 1, bmdata
->bm_width
+ 2, bmdata
->bm_height
+ 2,
331 gdata
->fbwin
, NULL
, display_class_desc
.hInstance
, NULL
);
332 DWIN(printf("[GDI] Opened bitmap window: 0x%p\n", bmdata
->window
));
337 SetWindowLongPtr(bmdata
->window
, GWLP_USERDATA
, (LONG_PTR
)bmdata
);
339 * We actually show the window only now, because otherwise it will pop up in front of all windows, and then
340 * immediately jump backwards, causing irritating flicker
342 SetWindowPos(bmdata
->window
, prev
, 0, 0, 0, 0, SWP_NOMOVE
|SWP_NOSIZE
|SWP_SHOWWINDOW
);
343 UpdateWindow(bmdata
->window
);
345 prev
= bmdata
->window
;
350 /* If we got no bitmaps, close the display window */
351 if ((prev
== HWND_TOP
) && gdata
->fbwin
)
353 DestroyWindow(gdata
->fbwin
);
357 ctl
->ShowDone
= TRUE
;
358 KrnCauseIRQ(ctl
->GfxIrq
);
362 DispatchMessage(&msg
);
368 /* TODO: Further cleanup (close windows etc) */
371 UnhookWindowsHookEx(keyhook
);
376 /****************************************************************************************/
378 volatile struct GDI_Control
*__declspec(dllexport
) __aros
GDI_Init(void)
394 gdictl
.MouseIrq
= irq
;
396 display_class_desc
.hInstance
= GetModuleHandle(NULL
);
397 display_class_desc
.hIcon
= LoadIcon(display_class_desc
.hInstance
, MAKEINTRESOURCE(101));
398 display_class_desc
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
399 display_class
= RegisterClass(&display_class_desc
);
400 D(printf("[GDI] Created display window class 0x%04x\n", display_class
));
404 bitmap_class_desc
.hInstance
= display_class_desc
.hInstance
;
405 bitmap_class
= RegisterClass(&bitmap_class_desc
);
406 D(printf("[GDI] Created bitmap window class 0x%04x\n", bitmap_class
));
410 KbdAck
= CreateEvent(NULL
, FALSE
, TRUE
, NULL
);
413 MouseAck
= CreateEvent(NULL
, FALSE
, TRUE
, NULL
);
416 gdictl
.ShowDone
= FALSE
;
417 gdictl
.Active
= NULL
;
419 window_active
= NULL
;
421 th
= CreateThread(NULL
, 0, (LPTHREAD_START_ROUTINE
)gdithread_entry
, (void *)&gdictl
, 0, &thread_id
);
423 D(printf("[GDI] Started thread 0x%p ID 0x%08lX\n", th
, thread_id
));
429 CloseHandle(MouseAck
);
433 UnregisterClass((LPCTSTR
)bitmap_class
, bitmap_class_desc
.hInstance
);
435 UnregisterClass((LPCTSTR
)display_class
, display_class_desc
.hInstance
);
437 KrnFreeIRQ(gdictl
.MouseIrq
);
439 KrnFreeIRQ(gdictl
.KbdIrq
);
441 KrnFreeIRQ(gdictl
.GfxIrq
);
446 void __declspec(dllexport
) __aros
GDI_Shutdown(struct GDI_Control
*ctl
)
448 PostThreadMessage(thread_id
, WM_QUIT
, 0, 0);
449 UnregisterClass((LPCTSTR
)bitmap_class
, bitmap_class_desc
.hInstance
);
450 UnregisterClass((LPCTSTR
)display_class
, display_class_desc
.hInstance
);
451 CloseHandle(MouseAck
);
453 KrnFreeIRQ(ctl
->MouseIrq
);
454 KrnFreeIRQ(ctl
->KbdIrq
);
455 KrnFreeIRQ(ctl
->GfxIrq
);
458 /* I'm too lazy to import one more .dll (kernel32). I'd better write these stubs. */
459 ULONG
__declspec(dllexport
) __aros
GDI_PutMsg(void *window
, UINT msg
, WPARAM wp
, LPARAM lp
)
462 return PostMessage(window
, msg
, wp
, lp
);
464 return PostThreadMessage(thread_id
, msg
, wp
, lp
);
467 ULONG
__declspec(dllexport
) __aros
GDI_KbdAck(void)
469 return SetEvent(KbdAck
);
472 ULONG
__declspec(dllexport
) __aros
GDI_MouseAck(void)
474 return SetEvent(MouseAck
);