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