1 /*
2  * tkWinPointer.c --
3  *
4  *	Windows specific mouse tracking code.
5  *
6  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
7  * Copyright (c) 1998-1999 by Scriptics Corporation.
8  *
9  * See the file "license.terms" for information on usage and redistribution of
10  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
11  */
12 
13 #include "tkWinInt.h"
14 
15 /*
16  * Check for enter/leave events every MOUSE_TIMER_INTERVAL milliseconds.
17  */
18 
19 #define MOUSE_TIMER_INTERVAL 250
20 
21 /*
22  * Declarations of static variables used in this file.
23  */
24 
25 static int captured = 0;		/* 1 if mouse is currently captured. */
26 static TkWindow *keyboardWinPtr = NULL; /* Current keyboard grab window. */
27 static Tcl_TimerToken mouseTimer;	/* Handle to the latest mouse timer. */
28 static int mouseTimerSet = 0;		/* 1 if the mouse timer is active. */
29 
30 /*
31  * Forward declarations of procedures used in this file.
32  */
33 
34 static void		MouseTimerProc(ClientData clientData);
35 
36 /*
37  *----------------------------------------------------------------------
38  *
39  * TkWinGetModifierState --
40  *
41  *	Return the modifier state as of the last message.
42  *
43  * Results:
44  *	Returns the X modifier mask.
45  *
46  * Side effects:
47  *	None.
48  *
49  *----------------------------------------------------------------------
50  */
51 
52 int
TkWinGetModifierState(void)53 TkWinGetModifierState(void)
54 {
55     int state = 0;
56 
57     if (GetKeyState(VK_SHIFT) & 0x8000) {
58 	state |= ShiftMask;
59     }
60     if (GetKeyState(VK_CONTROL) & 0x8000) {
61 	state |= ControlMask;
62     }
63     if (GetKeyState(VK_MENU) & 0x8000) {
64 	state |= ALT_MASK;
65     }
66     if (GetKeyState(VK_CAPITAL) & 0x0001) {
67 	state |= LockMask;
68     }
69     if (GetKeyState(VK_NUMLOCK) & 0x0001) {
70 	state |= Mod1Mask;
71     }
72     if (GetKeyState(VK_SCROLL) & 0x0001) {
73 	state |= Mod3Mask;
74     }
75     if (GetKeyState(VK_LBUTTON) & 0x8000) {
76 	state |= Button1Mask;
77     }
78     if (GetKeyState(VK_MBUTTON) & 0x8000) {
79 	state |= Button2Mask;
80     }
81     if (GetKeyState(VK_RBUTTON) & 0x8000) {
82 	state |= Button3Mask;
83     }
84     return state;
85 }
86 
87 /*
88  *----------------------------------------------------------------------
89  *
90  * Tk_PointerEvent --
91  *
92  *	This procedure is called for each pointer-related event. It converts
93  *	the position to root coords and updates the global pointer state
94  *	machine. It also ensures that the mouse timer is scheduled.
95  *
96  * Results:
97  *	None.
98  *
99  * Side effects:
100  *	May queue events and change the grab state.
101  *
102  *----------------------------------------------------------------------
103  */
104 
105 void
Tk_PointerEvent(HWND hwnd,int x,int y)106 Tk_PointerEvent(
107     HWND hwnd,			/* Window for coords, or NULL for the root
108 				 * window. */
109     int x, int y)		/* Coords relative to hwnd, or screen if hwnd
110 				 * is NULL. */
111 {
112     POINT pos;
113     int state;
114     Tk_Window tkwin;
115 
116     pos.x = x;
117     pos.y = y;
118 
119     /*
120      * Convert client coords to root coords if we were given a window.
121      */
122 
123     if (hwnd) {
124 	ClientToScreen(hwnd, &pos);
125     }
126 
127     /*
128      * If the mouse is captured, Windows will report all pointer events to the
129      * capture window. So, we need to determine which window the mouse is
130      * really over and change the event. Note that the computed hwnd may point
131      * to a window not owned by Tk, or a toplevel decorative frame, so tkwin
132      * can be NULL.
133      */
134 
135     if (captured || hwnd == NULL) {
136 	hwnd = WindowFromPoint(pos);
137     }
138     tkwin = Tk_HWNDToWindow(hwnd);
139 
140     state = TkWinGetModifierState();
141 
142     Tk_UpdatePointer(tkwin, pos.x, pos.y, state);
143 
144     if ((captured || tkwin) && !mouseTimerSet) {
145 	mouseTimerSet = 1;
146 	mouseTimer = Tcl_CreateTimerHandler(MOUSE_TIMER_INTERVAL,
147 		MouseTimerProc, NULL);
148     }
149 }
150 
151 /*
152  *----------------------------------------------------------------------
153  *
154  * XGrabKeyboard --
155  *
156  *	Simulates a keyboard grab by setting the focus.
157  *
158  * Results:
159  *	Always returns GrabSuccess.
160  *
161  * Side effects:
162  *	Sets the keyboard focus to the specified window.
163  *
164  *----------------------------------------------------------------------
165  */
166 
167 int
XGrabKeyboard(Display * display,Window grab_window,Bool owner_events,int pointer_mode,int keyboard_mode,Time time)168 XGrabKeyboard(
169     Display *display,
170     Window grab_window,
171     Bool owner_events,
172     int pointer_mode,
173     int keyboard_mode,
174     Time time)
175 {
176     keyboardWinPtr = TkWinGetWinPtr(grab_window);
177     return GrabSuccess;
178 }
179 
180 /*
181  *----------------------------------------------------------------------
182  *
183  * XUngrabKeyboard --
184  *
185  *	Releases the simulated keyboard grab.
186  *
187  * Results:
188  *	None.
189  *
190  * Side effects:
191  *	Sets the keyboard focus back to the value before the grab.
192  *
193  *----------------------------------------------------------------------
194  */
195 
196 int
XUngrabKeyboard(Display * display,Time time)197 XUngrabKeyboard(
198     Display *display,
199     Time time)
200 {
201     keyboardWinPtr = NULL;
202     return Success;
203 }
204 
205 /*
206  *----------------------------------------------------------------------
207  *
208  * MouseTimerProc --
209  *
210  *	Check the current mouse position and look for enter/leave events.
211  *
212  * Results:
213  *	None.
214  *
215  * Side effects:
216  *	May schedule a new timer and/or generate enter/leave events.
217  *
218  *----------------------------------------------------------------------
219  */
220 
221 void
MouseTimerProc(ClientData clientData)222 MouseTimerProc(
223     ClientData clientData)
224 {
225     POINT pos;
226 
227     mouseTimerSet = 0;
228 
229     /*
230      * Get the current mouse position and window. Don't do anything if the
231      * mouse hasn't moved since the last time we looked.
232      */
233 
234     GetCursorPos(&pos);
235     Tk_PointerEvent(NULL, pos.x, pos.y);
236 }
237 
238 /*
239  *----------------------------------------------------------------------
240  *
241  * TkWinCancelMouseTimer --
242  *
243  *    If the mouse timer is set, cancel it.
244  *
245  * Results:
246  *    None.
247  *
248  * Side effects:
249  *    May cancel the mouse timer.
250  *
251  *----------------------------------------------------------------------
252  */
253 
254 void
TkWinCancelMouseTimer(void)255 TkWinCancelMouseTimer(void)
256 {
257     if (mouseTimerSet) {
258 	Tcl_DeleteTimerHandler(mouseTimer);
259 	mouseTimerSet = 0;
260     }
261 }
262 
263 /*
264  *----------------------------------------------------------------------
265  *
266  * TkGetPointerCoords --
267  *
268  *	Fetch the position of the mouse pointer.
269  *
270  * Results:
271  *	*xPtr and *yPtr are filled in with the root coordinates of the mouse
272  *	pointer for the display.
273  *
274  * Side effects:
275  *	None.
276  *
277  *----------------------------------------------------------------------
278  */
279 
280 void
TkGetPointerCoords(Tk_Window tkwin,int * xPtr,int * yPtr)281 TkGetPointerCoords(
282     Tk_Window tkwin,		/* Window that identifies screen on which
283 				 * lookup is to be done. */
284     int *xPtr, int *yPtr)	/* Store pointer coordinates here. */
285 {
286     POINT point;
287 
288     GetCursorPos(&point);
289     *xPtr = point.x;
290     *yPtr = point.y;
291 }
292 
293 /*
294  *----------------------------------------------------------------------
295  *
296  * XQueryPointer --
297  *
298  *	Check the current state of the mouse. This is not a complete
299  *	implementation of this function. It only computes the root coordinates
300  *	and the current mask.
301  *
302  * Results:
303  *	Sets root_x_return, root_y_return, and mask_return. Returns true on
304  *	success.
305  *
306  * Side effects:
307  *	None.
308  *
309  *----------------------------------------------------------------------
310  */
311 
312 Bool
XQueryPointer(Display * display,Window w,Window * root_return,Window * child_return,int * root_x_return,int * root_y_return,int * win_x_return,int * win_y_return,unsigned int * mask_return)313 XQueryPointer(
314     Display *display,
315     Window w,
316     Window *root_return,
317     Window *child_return,
318     int *root_x_return,
319     int *root_y_return,
320     int *win_x_return,
321     int *win_y_return,
322     unsigned int *mask_return)
323 {
324     display->request++;
325     TkGetPointerCoords(NULL, root_x_return, root_y_return);
326     *mask_return = TkWinGetModifierState();
327     return True;
328 }
329 
330 /*
331  *----------------------------------------------------------------------
332  *
333  * XWarpPointer --
334  *
335  *	Move pointer to new location. This is not a complete implementation of
336  *	this function.
337  *
338  * Results:
339  *	None.
340  *
341  * Side effects:
342  *	Mouse pointer changes position on screen.
343  *
344  *----------------------------------------------------------------------
345  */
346 
347 int
XWarpPointer(Display * display,Window src_w,Window dest_w,int src_x,int src_y,unsigned int src_width,unsigned int src_height,int dest_x,int dest_y)348 XWarpPointer(
349     Display *display,
350     Window src_w,
351     Window dest_w,
352     int src_x,
353     int src_y,
354     unsigned int src_width,
355     unsigned int src_height,
356     int dest_x,
357     int dest_y)
358 {
359     RECT r;
360 
361     GetWindowRect(Tk_GetHWND(dest_w), &r);
362     SetCursorPos(r.left+dest_x, r.top+dest_y);
363     return Success;
364 }
365 
366 /*
367  *----------------------------------------------------------------------
368  *
369  * XGetInputFocus --
370  *
371  *	Retrieves the current keyboard focus window.
372  *
373  * Results:
374  *	Returns the current focus window.
375  *
376  * Side effects:
377  *	None.
378  *
379  *----------------------------------------------------------------------
380  */
381 
382 int
XGetInputFocus(Display * display,Window * focus_return,int * revert_to_return)383 XGetInputFocus(
384     Display *display,
385     Window *focus_return,
386     int *revert_to_return)
387 {
388     Tk_Window tkwin = Tk_HWNDToWindow(GetFocus());
389 
390     *focus_return = tkwin ? Tk_WindowId(tkwin) : None;
391     *revert_to_return = RevertToParent;
392     display->request++;
393     return Success;
394 }
395 
396 /*
397  *----------------------------------------------------------------------
398  *
399  * XSetInputFocus --
400  *
401  *	Set the current focus window.
402  *
403  * Results:
404  *	None.
405  *
406  * Side effects:
407  *	Changes the keyboard focus and causes the selected window to
408  *	be activated.
409  *
410  *----------------------------------------------------------------------
411  */
412 
413 int
XSetInputFocus(Display * display,Window focus,int revert_to,Time time)414 XSetInputFocus(
415     Display *display,
416     Window focus,
417     int revert_to,
418     Time time)
419 {
420     display->request++;
421     if (focus != None) {
422 	SetFocus(Tk_GetHWND(focus));
423     }
424     return Success;
425 }
426 
427 /*
428  *----------------------------------------------------------------------
429  *
430  * TkpChangeFocus --
431  *
432  *	This procedure is invoked to move the system focus from one window to
433  *	another.
434  *
435  * Results:
436  *	The return value is the serial number of the command that changed the
437  *	focus. It may be needed by the caller to filter out focus change
438  *	events that were queued before the command. If the procedure doesn't
439  *	actually change the focus then it returns 0.
440  *
441  * Side effects:
442  *	The official Windows focus window changes; the application's focus
443  *	window isn't changed by this procedure.
444  *
445  *----------------------------------------------------------------------
446  */
447 
448 int
TkpChangeFocus(TkWindow * winPtr,int force)449 TkpChangeFocus(
450     TkWindow *winPtr,		/* Window that is to receive the X focus. */
451     int force)			/* Non-zero means claim the focus even if it
452 				 * didn't originally belong to topLevelPtr's
453 				 * application. */
454 {
455     TkDisplay *dispPtr = winPtr->dispPtr;
456     Window focusWindow;
457     int dummy, serial;
458     TkWindow *winPtr2;
459 
460     if (!force) {
461 	XGetInputFocus(dispPtr->display, &focusWindow, &dummy);
462 	winPtr2 = (TkWindow *) Tk_IdToWindow(dispPtr->display, focusWindow);
463 	if ((winPtr2 == NULL) || (winPtr2->mainPtr != winPtr->mainPtr)) {
464 	    return 0;
465 	}
466     }
467 
468     if (winPtr->window == None) {
469 	Tcl_Panic("ChangeXFocus got null X window");
470     }
471 
472     /*
473      * Change the foreground window so the focus window is raised to the top
474      * of the system stacking order and gets the keyboard focus.
475      */
476 
477     if (force) {
478 	TkWinSetForegroundWindow(winPtr);
479     }
480     XSetInputFocus(dispPtr->display, winPtr->window, RevertToParent,
481 	    CurrentTime);
482 
483     /*
484      * Remember the current serial number for the X server and issue a dummy
485      * server request. This marks the position at which we changed the focus,
486      * so we can distinguish FocusIn and FocusOut events on either side of the
487      * mark.
488      */
489 
490     serial = NextRequest(winPtr->display);
491     XNoOp(winPtr->display);
492     return serial;
493 }
494 
495 /*
496  *----------------------------------------------------------------------
497  *
498  * TkpSetCapture --
499  *
500  *	This function captures the mouse so that all future events will be
501  *	reported to this window, even if the mouse is outside the window. If
502  *	the specified window is NULL, then the mouse is released.
503  *
504  * Results:
505  *	None.
506  *
507  * Side effects:
508  *	Sets the capture flag and captures the mouse.
509  *
510  *----------------------------------------------------------------------
511  */
512 
513 void
TkpSetCapture(TkWindow * winPtr)514 TkpSetCapture(
515     TkWindow *winPtr)		/* Capture window, or NULL. */
516 {
517     if (winPtr) {
518 	SetCapture(Tk_GetHWND(Tk_WindowId(winPtr)));
519 	captured = 1;
520     } else {
521 	captured = 0;
522 	ReleaseCapture();
523     }
524 }
525 
526 /*
527  * Local Variables:
528  * mode: c
529  * c-basic-offset: 4
530  * fill-column: 78
531  * End:
532  */
533