1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 * Copyright (C) 1998-2002 Tor Lillqvist
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
36 #include "gdkinternals.h"
37 #include "gdkprivate-win32.h"
38 #include "gdkinput-win32.h"
42 #define PACKETDATA (PK_CONTEXT | PK_CURSOR | PK_BUTTONS | PK_X | PK_Y | PK_NORMAL_PRESSURE | PK_ORIENTATION)
43 #define PACKETMODE (PK_BUTTONS)
46 #define DEBUG_WINTAB 1 /* Verbose debug messages enabled */
48 #define PROXIMITY_OUT_DELAY 200 /* In milliseconds, see set_ignore_core */
52 #if defined(HAVE_WINTAB) || defined(HAVE_WHATEVER_OTHER)
53 #define HAVE_SOME_XINPUT
56 #define TWOPI (2.*G_PI)
58 /* Forward declarations */
62 static GdkDevicePrivate *gdk_input_find_dev_from_ctx (HCTX hctx,
64 static GList *wintab_contexts = NULL;
66 static GdkWindow *wintab_window = NULL;
68 #endif /* HAVE_WINTAB */
70 #ifdef HAVE_SOME_XINPUT
72 static GdkWindow *x_grab_window = NULL; /* Window that currently holds
73 * the extended inputs grab
75 static GdkEventMask x_grab_mask;
76 static gboolean x_grab_owner_events;
78 #endif /* HAVE_SOME_XINPUT */
82 static GdkDevicePrivate *
83 gdk_input_find_dev_from_ctx (HCTX hctx,
86 GList *tmp_list = _gdk_input_devices;
87 GdkDevicePrivate *gdkdev;
91 gdkdev = (GdkDevicePrivate *) (tmp_list->data);
92 if (gdkdev->hctx == hctx && gdkdev->cursor == cursor)
94 tmp_list = tmp_list->next;
102 print_lc(LOGCONTEXT *lc)
104 g_print ("lcName = %s\n", lc->lcName);
105 g_print ("lcOptions =");
106 if (lc->lcOptions & CXO_SYSTEM) g_print (" CXO_SYSTEM");
107 if (lc->lcOptions & CXO_PEN) g_print (" CXO_PEN");
108 if (lc->lcOptions & CXO_MESSAGES) g_print (" CXO_MESSAGES");
109 if (lc->lcOptions & CXO_MARGIN) g_print (" CXO_MARGIN");
110 if (lc->lcOptions & CXO_MGNINSIDE) g_print (" CXO_MGNINSIDE");
111 if (lc->lcOptions & CXO_CSRMESSAGES) g_print (" CXO_CSRMESSAGES");
113 g_print ("lcStatus =");
114 if (lc->lcStatus & CXS_DISABLED) g_print (" CXS_DISABLED");
115 if (lc->lcStatus & CXS_OBSCURED) g_print (" CXS_OBSCURED");
116 if (lc->lcStatus & CXS_ONTOP) g_print (" CXS_ONTOP");
118 g_print ("lcLocks =");
119 if (lc->lcLocks & CXL_INSIZE) g_print (" CXL_INSIZE");
120 if (lc->lcLocks & CXL_INASPECT) g_print (" CXL_INASPECT");
121 if (lc->lcLocks & CXL_SENSITIVITY) g_print (" CXL_SENSITIVITY");
122 if (lc->lcLocks & CXL_MARGIN) g_print (" CXL_MARGIN");
124 g_print ("lcMsgBase = %#x, lcDevice = %#x, lcPktRate = %d\n",
125 lc->lcMsgBase, lc->lcDevice, lc->lcPktRate);
126 g_print ("lcPktData =");
127 if (lc->lcPktData & PK_CONTEXT) g_print (" PK_CONTEXT");
128 if (lc->lcPktData & PK_STATUS) g_print (" PK_STATUS");
129 if (lc->lcPktData & PK_TIME) g_print (" PK_TIME");
130 if (lc->lcPktData & PK_CHANGED) g_print (" PK_CHANGED");
131 if (lc->lcPktData & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
132 if (lc->lcPktData & PK_CURSOR) g_print (" PK_CURSOR");
133 if (lc->lcPktData & PK_BUTTONS) g_print (" PK_BUTTONS");
134 if (lc->lcPktData & PK_X) g_print (" PK_X");
135 if (lc->lcPktData & PK_Y) g_print (" PK_Y");
136 if (lc->lcPktData & PK_Z) g_print (" PK_Z");
137 if (lc->lcPktData & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
138 if (lc->lcPktData & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
139 if (lc->lcPktData & PK_ORIENTATION) g_print (" PK_ORIENTATION");
140 if (lc->lcPktData & PK_ROTATION) g_print (" PK_ROTATION");
142 g_print ("lcPktMode =");
143 if (lc->lcPktMode & PK_CONTEXT) g_print (" PK_CONTEXT");
144 if (lc->lcPktMode & PK_STATUS) g_print (" PK_STATUS");
145 if (lc->lcPktMode & PK_TIME) g_print (" PK_TIME");
146 if (lc->lcPktMode & PK_CHANGED) g_print (" PK_CHANGED");
147 if (lc->lcPktMode & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
148 if (lc->lcPktMode & PK_CURSOR) g_print (" PK_CURSOR");
149 if (lc->lcPktMode & PK_BUTTONS) g_print (" PK_BUTTONS");
150 if (lc->lcPktMode & PK_X) g_print (" PK_X");
151 if (lc->lcPktMode & PK_Y) g_print (" PK_Y");
152 if (lc->lcPktMode & PK_Z) g_print (" PK_Z");
153 if (lc->lcPktMode & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
154 if (lc->lcPktMode & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
155 if (lc->lcPktMode & PK_ORIENTATION) g_print (" PK_ORIENTATION");
156 if (lc->lcPktMode & PK_ROTATION) g_print (" PK_ROTATION");
158 g_print ("lcMoveMask =");
159 if (lc->lcMoveMask & PK_CONTEXT) g_print (" PK_CONTEXT");
160 if (lc->lcMoveMask & PK_STATUS) g_print (" PK_STATUS");
161 if (lc->lcMoveMask & PK_TIME) g_print (" PK_TIME");
162 if (lc->lcMoveMask & PK_CHANGED) g_print (" PK_CHANGED");
163 if (lc->lcMoveMask & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
164 if (lc->lcMoveMask & PK_CURSOR) g_print (" PK_CURSOR");
165 if (lc->lcMoveMask & PK_BUTTONS) g_print (" PK_BUTTONS");
166 if (lc->lcMoveMask & PK_X) g_print (" PK_X");
167 if (lc->lcMoveMask & PK_Y) g_print (" PK_Y");
168 if (lc->lcMoveMask & PK_Z) g_print (" PK_Z");
169 if (lc->lcMoveMask & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
170 if (lc->lcMoveMask & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
171 if (lc->lcMoveMask & PK_ORIENTATION) g_print (" PK_ORIENTATION");
172 if (lc->lcMoveMask & PK_ROTATION) g_print (" PK_ROTATION");
174 g_print ("lcBtnDnMask = %#x, lcBtnUpMask = %#x\n",
175 (guint) lc->lcBtnDnMask, (guint) lc->lcBtnUpMask);
176 g_print ("lcInOrgX = %ld, lcInOrgY = %ld, lcInOrgZ = %ld\n",
177 lc->lcInOrgX, lc->lcInOrgY, lc->lcInOrgZ);
178 g_print ("lcInExtX = %ld, lcInExtY = %ld, lcInExtZ = %ld\n",
179 lc->lcInExtX, lc->lcInExtY, lc->lcInExtZ);
180 g_print ("lcOutOrgX = %ld, lcOutOrgY = %ld, lcOutOrgZ = %ld\n",
181 lc->lcOutOrgX, lc->lcOutOrgY, lc->lcOutOrgZ);
182 g_print ("lcOutExtX = %ld, lcOutExtY = %ld, lcOutExtZ = %ld\n",
183 lc->lcOutExtX, lc->lcOutExtY, lc->lcOutExtZ);
184 g_print ("lcSensX = %g, lcSensY = %g, lcSensZ = %g\n",
185 lc->lcSensX / 65536., lc->lcSensY / 65536., lc->lcSensZ / 65536.);
186 g_print ("lcSysMode = %d\n", lc->lcSysMode);
187 g_print ("lcSysOrgX = %d, lcSysOrgY = %d\n",
188 lc->lcSysOrgX, lc->lcSysOrgY);
189 g_print ("lcSysExtX = %d, lcSysExtY = %d\n",
190 lc->lcSysExtX, lc->lcSysExtY);
191 g_print ("lcSysSensX = %g, lcSysSensY = %g\n",
192 lc->lcSysSensX / 65536., lc->lcSysSensY / 65536.);
198 _gdk_input_wintab_init_check (void)
200 static gboolean wintab_initialized = FALSE;
201 GdkDevicePrivate *gdkdev;
205 UINT ndevices, ncursors, ncsrtypes, firstcsr, hardware;
207 AXIS axis_x, axis_y, axis_npressure, axis_or[3];
210 char devname[100], csrname[100];
211 BOOL defcontext_done;
213 if (wintab_initialized)
216 wintab_initialized = TRUE;
218 wintab_contexts = NULL;
220 if (!_gdk_input_ignore_wintab &&
223 WTInfo (WTI_INTERFACE, IFC_SPECVERSION, &specversion);
224 GDK_NOTE (INPUT, g_print ("Wintab interface version %d.%d\n",
225 HIBYTE (specversion), LOBYTE (specversion)));
226 WTInfo (WTI_INTERFACE, IFC_NDEVICES, &ndevices);
227 WTInfo (WTI_INTERFACE, IFC_NCURSORS, &ncursors);
229 GDK_NOTE (INPUT, g_print ("NDEVICES: %d, NCURSORS: %d\n",
230 ndevices, ncursors));
232 /* Create a dummy window to receive wintab events */
233 wa.wclass = GDK_INPUT_OUTPUT;
234 wa.event_mask = GDK_ALL_EVENTS_MASK;
239 wa.window_type = GDK_WINDOW_TOPLEVEL;
240 if ((wintab_window = gdk_window_new (NULL, &wa, GDK_WA_X|GDK_WA_Y)) == NULL)
242 g_warning ("gdk_input_wintab_init: gdk_window_new failed");
245 g_object_ref (wintab_window);
247 for (devix = 0; devix < ndevices; devix++)
251 /* We open the Wintab device (hmm, what if there are several?) as a
252 * system pointing device, i.e. it controls the normal Windows
253 * cursor. This seems much more natural.
256 WTInfo (WTI_DEVICES + devix, DVC_NAME, devname);
258 WTInfo (WTI_DEVICES + devix, DVC_NCSRTYPES, &ncsrtypes);
259 WTInfo (WTI_DEVICES + devix, DVC_FIRSTCSR, &firstcsr);
260 WTInfo (WTI_DEVICES + devix, DVC_HARDWARE, &hardware);
261 WTInfo (WTI_DEVICES + devix, DVC_X, &axis_x);
262 WTInfo (WTI_DEVICES + devix, DVC_Y, &axis_y);
263 WTInfo (WTI_DEVICES + devix, DVC_NPRESSURE, &axis_npressure);
264 WTInfo (WTI_DEVICES + devix, DVC_ORIENTATION, axis_or);
266 defcontext_done = FALSE;
267 if (HIBYTE (specversion) > 1 || LOBYTE (specversion) >= 1)
269 /* Try to get device-specific default context */
270 /* Some drivers, e.g. Aiptek, don't provide this info */
271 if (WTInfo (WTI_DSCTXS + devix, 0, &lc) > 0)
272 defcontext_done = TRUE;
275 GDK_NOTE (INPUT, (g_print("Using device-specific default context\n")));
277 GDK_NOTE (INPUT, (g_print("Note: Driver did not provide device specific default context info despite claiming to support version 1.1\n")));
281 if (!defcontext_done)
282 WTInfo (WTI_DEFSYSCTX, 0, &lc);
284 GDK_NOTE (INPUT, (g_print("Default context:\n"), print_lc(&lc)));
286 lc.lcOptions |= CXO_MESSAGES;
288 lc.lcMsgBase = WT_DEFBASE;
290 lc.lcPktData = PACKETDATA;
291 lc.lcPktMode = PACKETMODE;
292 lc.lcMoveMask = PACKETDATA;
293 lc.lcBtnUpMask = lc.lcBtnDnMask = ~0;
294 lc.lcOutOrgX = axis_x.axMin;
295 lc.lcOutOrgY = axis_y.axMin;
296 lc.lcOutExtX = axis_x.axMax - axis_x.axMin;
297 lc.lcOutExtY = axis_y.axMax - axis_y.axMin;
298 lc.lcOutExtY = -lc.lcOutExtY; /* We want Y growing downward */
300 GDK_NOTE (INPUT, (g_print("context for device %d:\n", devix),
303 hctx = g_new (HCTX, 1);
304 if ((*hctx = WTOpen (GDK_WINDOW_HWND (wintab_window), &lc, TRUE)) == NULL)
306 g_warning ("gdk_input_wintab_init: WTOpen failed");
309 GDK_NOTE (INPUT, g_print ("opened Wintab device %d %p\n",
312 wintab_contexts = g_list_append (wintab_contexts, hctx);
314 WTEnable (*hctx, TRUE);
316 WTOverlap (*hctx, TRUE);
319 GDK_NOTE (INPUT, (g_print("context for device %d after WTOpen:\n", devix),
322 /* Increase packet queue size to reduce the risk of lost packets */
323 /* According to the specs, if the function fails we must try again */
324 /* with a smaller queue size */
325 GDK_NOTE (INPUT, g_print("Attempting to increase queue size\n"));
326 for (i = 128; i >= 1; i >>= 1)
328 if (WTQueueSizeSet(*hctx, i))
330 GDK_NOTE (INPUT, g_print("Queue size set to %d\n", i));
335 GDK_NOTE (INPUT, g_print("Whoops, no queue size could be set\n"));
336 for (cursorix = firstcsr; cursorix < firstcsr + ncsrtypes; cursorix++)
339 WTInfo (WTI_CURSORS + cursorix, CSR_ACTIVE, &active);
342 gdkdev = g_object_new (GDK_TYPE_DEVICE, NULL);
343 WTInfo (WTI_CURSORS + cursorix, CSR_NAME, csrname);
344 gdkdev->info.name = g_strconcat (devname, " ", csrname, NULL);
345 gdkdev->info.source = GDK_SOURCE_PEN;
346 gdkdev->info.mode = GDK_MODE_SCREEN;
347 gdkdev->info.has_cursor = TRUE;
348 gdkdev->hctx = *hctx;
349 gdkdev->cursor = cursorix;
350 WTInfo (WTI_CURSORS + cursorix, CSR_PKTDATA, &gdkdev->pktdata);
351 gdkdev->info.num_axes = 0;
352 if (gdkdev->pktdata & PK_X)
353 gdkdev->info.num_axes++;
354 if (gdkdev->pktdata & PK_Y)
355 gdkdev->info.num_axes++;
356 if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
357 gdkdev->info.num_axes++;
358 /* The wintab driver for the Wacom ArtPad II reports
359 * PK_ORIENTATION in CSR_PKTDATA, but the tablet doesn't
360 * actually sense tilt. Catch this by noticing that the
361 * orientation axis's azimuth resolution is zero.
363 if ((gdkdev->pktdata & PK_ORIENTATION)
364 && axis_or[0].axResolution == 0)
365 gdkdev->pktdata &= ~PK_ORIENTATION;
367 if (gdkdev->pktdata & PK_ORIENTATION)
368 gdkdev->info.num_axes += 2; /* x and y tilt */
369 WTInfo (WTI_CURSORS + cursorix, CSR_NPBTNMARKS, &gdkdev->npbtnmarks);
370 gdkdev->info.axes = g_new (GdkDeviceAxis, gdkdev->info.num_axes);
371 gdkdev->axes = g_new (GdkAxisInfo, gdkdev->info.num_axes);
372 gdkdev->last_axis_data = g_new (gint, gdkdev->info.num_axes);
375 if (gdkdev->pktdata & PK_X)
377 gdkdev->axes[k].xresolution =
378 gdkdev->axes[k].resolution = axis_x.axResolution / 65535.;
379 gdkdev->axes[k].xmin_value =
380 gdkdev->axes[k].min_value = axis_x.axMin;
381 gdkdev->axes[k].xmax_value =
382 gdkdev->axes[k].max_value = axis_x.axMax;
383 gdkdev->info.axes[k].use = GDK_AXIS_X;
384 gdkdev->info.axes[k].min = axis_x.axMin;
385 gdkdev->info.axes[k].max = axis_x.axMax;
388 if (gdkdev->pktdata & PK_Y)
390 gdkdev->axes[k].xresolution =
391 gdkdev->axes[k].resolution = axis_y.axResolution / 65535.;
392 gdkdev->axes[k].xmin_value =
393 gdkdev->axes[k].min_value = axis_y.axMin;
394 gdkdev->axes[k].xmax_value =
395 gdkdev->axes[k].max_value = axis_y.axMax;
396 gdkdev->info.axes[k].use = GDK_AXIS_Y;
397 gdkdev->info.axes[k].min = axis_y.axMin;
398 gdkdev->info.axes[k].max = axis_y.axMax;
401 if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
403 gdkdev->axes[k].xresolution =
404 gdkdev->axes[k].resolution = axis_npressure.axResolution / 65535.;
405 gdkdev->axes[k].xmin_value =
406 gdkdev->axes[k].min_value = axis_npressure.axMin;
407 gdkdev->axes[k].xmax_value =
408 gdkdev->axes[k].max_value = axis_npressure.axMax;
409 gdkdev->info.axes[k].use = GDK_AXIS_PRESSURE;
410 /* GIMP seems to expect values in the range 0-1 */
411 gdkdev->info.axes[k].min = 0.0; /*axis_npressure.axMin;*/
412 gdkdev->info.axes[k].max = 1.0; /*axis_npressure.axMax;*/
415 if (gdkdev->pktdata & PK_ORIENTATION)
419 gdkdev->orientation_axes[0] = axis_or[0];
420 gdkdev->orientation_axes[1] = axis_or[1];
421 for (axis = GDK_AXIS_XTILT; axis <= GDK_AXIS_YTILT; axis++)
423 /* Wintab gives us aximuth and altitude, which
424 * we convert to x and y tilt in the -1000..1000 range
426 gdkdev->axes[k].xresolution =
427 gdkdev->axes[k].resolution = 1000;
428 gdkdev->axes[k].xmin_value =
429 gdkdev->axes[k].min_value = -1000;
430 gdkdev->axes[k].xmax_value =
431 gdkdev->axes[k].max_value = 1000;
432 gdkdev->info.axes[k].use = axis;
433 gdkdev->info.axes[k].min = -1000;
434 gdkdev->info.axes[k].max = 1000;
438 gdkdev->info.num_keys = 0;
439 gdkdev->info.keys = NULL;
441 g_print ("device: (%d) %s axes: %d\n",
444 gdkdev->info.num_axes));
445 for (i = 0; i < gdkdev->info.num_axes; i++)
447 g_print ("... axis %d: %d--%d@%d (%d--%d@%d)\n",
449 gdkdev->axes[i].xmin_value,
450 gdkdev->axes[i].xmax_value,
451 gdkdev->axes[i].xresolution,
452 gdkdev->axes[i].min_value,
453 gdkdev->axes[i].max_value,
454 gdkdev->axes[i].resolution));
455 _gdk_input_devices = g_list_append (_gdk_input_devices,
463 decode_tilt (gint *axis_data,
467 /* As I don't have a tilt-sensing tablet,
468 * I cannot test this code.
473 az = TWOPI * packet->pkOrientation.orAzimuth /
474 (axes[0].axResolution / 65536.);
475 el = TWOPI * packet->pkOrientation.orAltitude /
476 (axes[1].axResolution / 65536.);
479 axis_data[0] = cos (az) * cos (el) * 1000;
481 axis_data[1] = sin (az) * cos (el) * 1000;
484 #endif /* HAVE_WINTAB */
487 gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev,
488 GdkInputWindow *input_window,
494 GdkWindowImplWin32 *impl, *root_impl;
500 double device_width, device_height;
501 double x_offset, y_offset, x_scale, y_scale;
503 impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (input_window->window)->impl);
505 for (i=0; i<gdkdev->info.num_axes; i++)
507 switch (gdkdev->info.axes[i].use)
520 device_width = gdkdev->axes[x_axis].max_value -
521 gdkdev->axes[x_axis].min_value;
522 device_height = gdkdev->axes[y_axis].max_value -
523 gdkdev->axes[y_axis].min_value;
525 if (gdkdev->info.mode == GDK_MODE_SCREEN)
527 root_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (_gdk_root)->impl);
528 x_scale = root_impl->width / device_width;
529 y_scale = root_impl->height / device_height;
531 x_offset = - input_window->root_x;
532 y_offset = - input_window->root_y;
534 else /* GDK_MODE_WINDOW */
536 double device_aspect = (device_height*gdkdev->axes[y_axis].resolution) /
537 (device_width*gdkdev->axes[x_axis].resolution);
539 if (device_aspect * impl->width >= impl->height)
541 /* device taller than window */
542 x_scale = impl->width / device_width;
543 y_scale = (x_scale * gdkdev->axes[x_axis].resolution)
544 / gdkdev->axes[y_axis].resolution;
547 y_offset = -(device_height * y_scale -
552 /* window taller than device */
553 y_scale = impl->height / device_height;
554 x_scale = (y_scale * gdkdev->axes[y_axis].resolution)
555 / gdkdev->axes[x_axis].resolution;
558 x_offset = - (device_width * x_scale - impl->width)/2;
562 for (i=0; i<gdkdev->info.num_axes; i++)
564 switch (gdkdev->info.axes[i].use)
567 axis_out[i] = x_offset + x_scale*axis_data[x_axis];
569 *x_out = axis_out[i];
572 axis_out[i] = y_offset + y_scale*axis_data[y_axis];
574 *y_out = axis_out[i];
578 (gdkdev->info.axes[i].max * (axis_data[i] - gdkdev->axes[i].min_value) +
579 gdkdev->info.axes[i].min * (gdkdev->axes[i].max_value - axis_data[i])) /
580 (gdkdev->axes[i].max_value - gdkdev->axes[i].min_value);
587 gdk_input_get_root_relative_geometry (HWND w,
593 GetWindowRect (w, &rect);
596 *x_ret = rect.left + _gdk_offset_x;
598 *y_ret = rect.top + _gdk_offset_y;
602 _gdk_input_configure_event (GdkWindow *window)
604 GdkInputWindow *input_window;
607 input_window = _gdk_input_window_find (window);
608 g_return_if_fail (window != NULL);
610 gdk_input_get_root_relative_geometry (GDK_WINDOW_HWND (window),
613 input_window->root_x = root_x;
614 input_window->root_y = root_y;
618 _gdk_input_enter_event (GdkWindow *window)
620 GdkInputWindow *input_window;
623 input_window = _gdk_input_window_find (window);
624 g_return_if_fail (window != NULL);
626 gdk_input_get_root_relative_geometry (GDK_WINDOW_HWND (window), &root_x, &root_y);
628 input_window->root_x = root_x;
629 input_window->root_y = root_y;
633 * Get the currently active keyboard modifiers (ignoring the mouse buttons)
634 * We could use gdk_window_get_pointer but that function does a lot of other
635 * expensive things besides getting the modifiers. This code is somewhat based
636 * on build_pointer_event_state from gdkevents-win32.c
639 get_modifier_key_state (void)
644 /* High-order bit is up/down, low order bit is toggled/untoggled */
645 if (GetKeyState (VK_CONTROL) < 0)
646 state |= GDK_CONTROL_MASK;
647 if (GetKeyState (VK_SHIFT) < 0)
648 state |= GDK_SHIFT_MASK;
649 if (GetKeyState (VK_MENU) < 0)
650 state |= GDK_MOD1_MASK;
651 if (GetKeyState (VK_CAPITAL) & 0x1)
652 state |= GDK_LOCK_MASK;
659 static guint ignore_core_timer = 0;
662 ignore_core_timefunc (gpointer data)
664 /* The delay has passed */
665 _gdk_input_ignore_core = FALSE;
666 ignore_core_timer = 0;
668 return FALSE; /* remove timeout */
672 * Set or unset the _gdk_input_ignore_core variable that tells GDK
673 * to ignore events for the core pointer when the tablet is in proximity
674 * The unsetting is delayed slightly so that if a tablet event arrives
675 * just after proximity out, it does not cause a core pointer event
676 * which e.g. causes GIMP to switch tools.
679 set_ignore_core (gboolean ignore)
683 _gdk_input_ignore_core = TRUE;
684 /* Remove any pending clear */
685 if (ignore_core_timer)
687 g_source_remove (ignore_core_timer);
688 ignore_core_timer = 0;
692 if (!ignore_core_timer)
693 ignore_core_timer = gdk_threads_add_timeout (PROXIMITY_OUT_DELAY,
694 ignore_core_timefunc, NULL);
696 #endif /* HAVE_WINTAB */
699 _gdk_input_other_event (GdkEvent *event,
705 GdkWindowObject *obj, *grab_obj;
706 GdkInputWindow *input_window;
707 GdkDevicePrivate *gdkdev = NULL;
708 GdkEventMask masktest;
716 if (event->any.window != wintab_window)
718 g_warning ("_gdk_input_other_event: not wintab_window?");
722 window = gdk_window_at_pointer (&x, &y);
726 g_object_ref (window);
727 display = gdk_drawable_get_display (window);
729 GDK_NOTE (EVENTS_OR_INPUT,
730 g_print ("gdk_input_win32_other_event: window=%p %+d%+d\n",
731 GDK_WINDOW_HWND (window), x, y));
733 if (msg->message == WT_PACKET)
735 if (!WTPacket ((HCTX) msg->lParam, msg->wParam, &packet))
739 obj = GDK_WINDOW_OBJECT (window);
741 switch (msg->message)
744 /* Don't produce any button or motion events while a window is being
745 * moved or resized, see bug #151090. */
746 if (_sizemove_in_progress)
748 GDK_NOTE (EVENTS_OR_INPUT, g_print ("... ignored when moving/sizing\n"));
751 if (window == _gdk_root && x_grab_window == NULL)
753 GDK_NOTE (EVENTS_OR_INPUT, g_print ("... is root\n"));
757 if ((gdkdev = gdk_input_find_dev_from_ctx ((HCTX) msg->lParam,
758 packet.pkCursor)) == NULL)
761 if (gdkdev->info.mode == GDK_MODE_DISABLED)
765 if (gdkdev->pktdata & PK_X)
766 gdkdev->last_axis_data[k++] = packet.pkX;
767 if (gdkdev->pktdata & PK_Y)
768 gdkdev->last_axis_data[k++] = packet.pkY;
769 if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
770 gdkdev->last_axis_data[k++] = packet.pkNormalPressure;
771 if (gdkdev->pktdata & PK_ORIENTATION)
773 decode_tilt (gdkdev->last_axis_data + k,
774 gdkdev->orientation_axes, &packet);
778 g_assert (k == gdkdev->info.num_axes);
780 if (HIWORD (packet.pkButtons) != TBN_NONE)
782 /* Gdk buttons are numbered 1.. */
783 event->button.button = 1 + LOWORD (packet.pkButtons);
785 if (HIWORD (packet.pkButtons) == TBN_UP)
787 event->any.type = GDK_BUTTON_RELEASE;
788 masktest = GDK_BUTTON_RELEASE_MASK;
789 gdkdev->button_state &= ~(1 << LOWORD (packet.pkButtons));
793 event->any.type = GDK_BUTTON_PRESS;
794 masktest = GDK_BUTTON_PRESS_MASK;
795 gdkdev->button_state |= 1 << LOWORD (packet.pkButtons);
800 event->any.type = GDK_MOTION_NOTIFY;
801 masktest = GDK_POINTER_MOTION_MASK;
802 if (gdkdev->button_state & (1 << 0))
803 masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK;
804 if (gdkdev->button_state & (1 << 1))
805 masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON2_MOTION_MASK;
806 if (gdkdev->button_state & (1 << 2))
807 masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK;
810 /* See if input is grabbed */
811 /* FIXME: x_grab_owner_events should probably be handled somehow */
812 if (x_grab_window != NULL)
814 grab_obj = GDK_WINDOW_OBJECT (x_grab_window);
815 if (!GDK_WINDOW_IMPL_WIN32 (grab_obj->impl)->extension_events_selected
816 || !(grab_obj->extension_events & masktest)
817 || !(x_grab_mask && masktest))
819 GDK_NOTE (EVENTS_OR_INPUT,
820 g_print ("... grabber doesn't want it\n"));
823 GDK_NOTE (EVENTS_OR_INPUT, g_print ("... to grabber\n"));
825 g_object_ref(x_grab_window);
826 g_object_unref(window);
827 window = x_grab_window;
830 /* Now we can check if the window wants the event, and
831 * propagate if necessary.
834 if (!GDK_WINDOW_IMPL_WIN32 (obj->impl)->extension_events_selected
835 || !(obj->extension_events & masktest))
837 GDK_NOTE (EVENTS_OR_INPUT, g_print ("... not selected\n"));
839 if (obj->parent == GDK_WINDOW_OBJECT (_gdk_root))
842 /* It is not good to propagate the extended events up to the parent
843 * if this window wants normal (not extended) motion/button events */
844 if (obj->event_mask & masktest)
846 GDK_NOTE (EVENTS_OR_INPUT,
847 g_print ("... wants ordinary event, ignoring this\n"));
853 ClientToScreen (GDK_WINDOW_HWND (window), &pt);
854 g_object_unref (window);
855 window = (GdkWindow *) obj->parent;
856 obj = GDK_WINDOW_OBJECT (window);
857 g_object_ref (window);
858 ScreenToClient (GDK_WINDOW_HWND (window), &pt);
861 GDK_NOTE (EVENTS_OR_INPUT, g_print ("... propagating to %p %+d%+d\n",
862 GDK_WINDOW_HWND (window), x, y));
866 input_window = _gdk_input_window_find (window);
868 g_assert (input_window != NULL);
870 if (gdkdev->info.mode == GDK_MODE_WINDOW
871 && input_window->mode == GDK_EXTENSION_EVENTS_CURSOR)
874 event->any.window = window;
875 key_state = get_modifier_key_state ();
876 if (event->any.type == GDK_BUTTON_PRESS
877 || event->any.type == GDK_BUTTON_RELEASE)
879 event->button.time = _gdk_win32_get_next_tick (msg->time);
880 event->button.device = &gdkdev->info;
882 event->button.axes = g_new(gdouble, gdkdev->info.num_axes);
884 gdk_input_translate_coordinates (gdkdev, input_window,
885 gdkdev->last_axis_data,
890 /* Also calculate root coordinates. Note that input_window->root_x
891 is in GDK root coordinates. */
892 event->button.x_root = event->button.x + input_window->root_x;
893 event->button.y_root = event->button.y + input_window->root_y;
895 event->button.state = ((gdkdev->button_state << 8)
896 & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
897 | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
900 GDK_NOTE (EVENTS_OR_INPUT,
901 g_print ("WINTAB button %s:%d %g,%g\n",
902 (event->button.type == GDK_BUTTON_PRESS ?
903 "press" : "release"),
904 event->button.button,
905 event->button.x, event->button.y));
909 event->motion.time = _gdk_win32_get_next_tick (msg->time);
910 event->motion.is_hint = FALSE;
911 event->motion.device = &gdkdev->info;
913 event->motion.axes = g_new(gdouble, gdkdev->info.num_axes);
915 gdk_input_translate_coordinates (gdkdev, input_window,
916 gdkdev->last_axis_data,
921 /* Also calculate root coordinates. Note that input_window->root_x
922 is in GDK root coordinates. */
923 event->motion.x_root = event->motion.x + input_window->root_x;
924 event->motion.y_root = event->motion.y + input_window->root_y;
926 event->motion.state = ((gdkdev->button_state << 8)
927 & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
928 | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
932 GDK_NOTE (EVENTS_OR_INPUT,
933 g_print ("WINTAB motion: %g,%g\n",
934 event->motion.x, event->motion.y));
936 /* Check for missing release or press events for the normal
937 * pressure button. At least on my ArtPadII I sometimes miss a
940 if ((gdkdev->pktdata & PK_NORMAL_PRESSURE
941 && (event->motion.state & GDK_BUTTON1_MASK)
942 && packet.pkNormalPressure <= MAX (0, (gint) gdkdev->npbtnmarks[0] - 2))
943 || (gdkdev->pktdata & PK_NORMAL_PRESSURE
944 && !(event->motion.state & GDK_BUTTON1_MASK)
945 && packet.pkNormalPressure > gdkdev->npbtnmarks[1] + 2))
947 GdkEvent *event2 = gdk_event_copy (event);
948 if (event->motion.state & GDK_BUTTON1_MASK)
950 event2->button.type = GDK_BUTTON_RELEASE;
951 gdkdev->button_state &= ~1;
955 event2->button.type = GDK_BUTTON_PRESS;
956 gdkdev->button_state |= 1;
958 event2->button.state = ((gdkdev->button_state << 8)
959 & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
960 | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
963 event2->button.button = 1;
964 GDK_NOTE (EVENTS_OR_INPUT,
965 g_print ("WINTAB synthesized button %s: %d %g,%gg\n",
966 (event2->button.type == GDK_BUTTON_PRESS ?
967 "press" : "release"),
968 event2->button.button,
971 _gdk_event_queue_append (display, event2);
977 if (LOWORD (msg->lParam) == 0)
979 event->proximity.type = GDK_PROXIMITY_OUT;
980 set_ignore_core (FALSE);
984 event->proximity.type = GDK_PROXIMITY_IN;
985 set_ignore_core (TRUE);
987 event->proximity.time = _gdk_win32_get_next_tick (msg->time);
988 event->proximity.device = &gdkdev->info;
990 GDK_NOTE (EVENTS_OR_INPUT,
991 g_print ("WINTAB proximity %s\n",
992 (event->proximity.type == GDK_PROXIMITY_IN ?
1001 _gdk_input_enable_window (GdkWindow *window,
1002 GdkDevicePrivate *gdkdev)
1004 #ifdef HAVE_SOME_XINPUT
1005 GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
1007 impl->extension_events_selected = TRUE;
1014 _gdk_input_disable_window (GdkWindow *window,
1015 GdkDevicePrivate *gdkdev)
1017 #ifdef HAVE_SOME_XINPUT
1018 GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
1020 impl->extension_events_selected = FALSE;
1027 _gdk_input_grab_pointer (GdkWindow *window,
1029 GdkEventMask event_mask,
1030 GdkWindow *confine_to,
1033 #ifdef HAVE_SOME_XINPUT
1034 GdkInputWindow *input_window, *new_window;
1035 gboolean need_ungrab;
1036 GdkDevicePrivate *gdkdev;
1039 tmp_list = _gdk_input_windows;
1041 need_ungrab = FALSE;
1043 GDK_NOTE (INPUT, g_print ("gdk_input_win32_grab_pointer: %p %d %p\n",
1044 GDK_WINDOW_HWND (window),
1046 (confine_to ? GDK_WINDOW_HWND (confine_to) : 0)));
1050 input_window = (GdkInputWindow *)tmp_list->data;
1052 if (input_window->window == window)
1053 new_window = input_window;
1054 else if (input_window->grabbed)
1056 input_window->grabbed = FALSE;
1060 tmp_list = tmp_list->next;
1065 new_window->grabbed = TRUE;
1066 x_grab_window = window;
1067 x_grab_mask = event_mask;
1068 x_grab_owner_events = owner_events;
1070 /* FIXME: Do we need to handle confine_to and time? */
1072 tmp_list = _gdk_input_devices;
1075 gdkdev = (GdkDevicePrivate *)tmp_list->data;
1076 if (!GDK_IS_CORE (gdkdev) && gdkdev->hctx)
1080 gdk_input_common_find_events (window, gdkdev,
1082 event_classes, &num_classes);
1084 result = XGrabDevice( GDK_DISPLAY(), gdkdev->xdevice,
1085 GDK_WINDOW_XWINDOW (window),
1086 owner_events, num_classes, event_classes,
1087 GrabModeAsync, GrabModeAsync, time);
1089 /* FIXME: if failure occurs on something other than the first
1090 device, things will be badly inconsistent */
1091 if (result != Success)
1095 tmp_list = tmp_list->next;
1100 x_grab_window = NULL;
1101 tmp_list = _gdk_input_devices;
1104 gdkdev = (GdkDevicePrivate *)tmp_list->data;
1105 if (!GDK_IS_CORE (gdkdev) && gdkdev->hctx &&
1106 ((gdkdev->button_state != 0) || need_ungrab))
1110 XUngrabDevice (gdk_display, gdkdev->xdevice, time);
1112 gdkdev->button_state = 0;
1115 tmp_list = tmp_list->next;
1120 return GDK_GRAB_SUCCESS;
1124 _gdk_input_ungrab_pointer (guint32 time)
1126 #ifdef HAVE_SOME_XINPUT
1127 GdkInputWindow *input_window;
1128 GdkDevicePrivate *gdkdev;
1131 GDK_NOTE (INPUT, g_print ("gdk_input_win32_ungrab_pointer\n"));
1133 tmp_list = _gdk_input_windows;
1136 input_window = (GdkInputWindow *)tmp_list->data;
1137 if (input_window->grabbed)
1139 tmp_list = tmp_list->next;
1142 if (tmp_list) /* we found a grabbed window */
1144 input_window->grabbed = FALSE;
1146 tmp_list = _gdk_input_devices;
1149 gdkdev = (GdkDevicePrivate *)tmp_list->data;
1152 if (!GDK_IS_CORE (gdkdev) && gdkdev->xdevice)
1153 XUngrabDevice (gdk_display, gdkdev->xdevice, time);
1155 tmp_list = tmp_list->next;
1158 x_grab_window = NULL;
1163 _gdk_device_get_history (GdkDevice *device,
1167 GdkTimeCoord ***events,
1174 gdk_device_get_state (GdkDevice *device,
1177 GdkModifierType *mask)
1179 g_return_if_fail (device != NULL);
1180 g_return_if_fail (GDK_IS_WINDOW (window));
1182 if (GDK_IS_CORE (device))
1186 gdk_window_get_pointer (window, &x_int, &y_int, mask);
1196 GdkDevicePrivate *gdkdev;
1197 GdkInputWindow *input_window;
1199 gdkdev = (GdkDevicePrivate *)device;
1200 /* For now just use the last known button and axis state of the device.
1201 * Since graphical tablets send an insane amount of motion events each
1202 * second, the info should be fairly up to date */
1205 gdk_window_get_pointer (window, NULL, NULL, mask);
1206 *mask &= 0xFF; /* Mask away core pointer buttons */
1207 *mask |= ((gdkdev->button_state << 8)
1208 & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
1209 | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
1210 | GDK_BUTTON5_MASK));
1212 input_window = _gdk_input_window_find (window);
1213 g_return_if_fail (input_window != NULL);
1214 /* For some reason, input_window is sometimes NULL when I use The GIMP 2
1215 * (bug #141543?). Avoid crashing if debugging is disabled. */
1216 if (axes && gdkdev->last_axis_data && input_window)
1217 gdk_input_translate_coordinates (gdkdev, input_window,
1218 gdkdev->last_axis_data,
1225 _gdk_input_set_tablet_active (void)
1230 /* Bring the contexts to the top of the overlap order when one of the
1231 * application's windows is activated */
1233 if (!wintab_contexts)
1234 return; /* No tablet devices found, or Wintab not initialized yet */
1236 GDK_NOTE (INPUT, g_print ("_gdk_input_set_tablet_active: "
1237 "Bringing Wintab contexts to the top of the overlap order\n"));
1239 tmp_list = wintab_contexts;
1242 hctx = (HCTX *) (tmp_list->data);
1243 WTOverlap (*hctx, TRUE);
1244 tmp_list = tmp_list->next;
1247 #endif /* HAVE_WINTAB */
1250 _gdk_input_init (GdkDisplay *display)
1252 _gdk_input_ignore_core = FALSE;
1253 _gdk_input_devices = NULL;
1255 _gdk_init_input_core (display);
1257 #ifdef WINTAB_NO_LAZY_INIT
1258 /* Normally, Wintab is only initialized when the application performs
1259 * an action that requires it, such as enabling extended input events
1260 * for a window or enumerating the devices.
1262 _gdk_input_wintab_init_check ();
1263 #endif /* WINTAB_NO_LAZY_INIT */
1264 #endif /* HAVE_WINTAB */
1266 _gdk_input_devices = g_list_append (_gdk_input_devices, display->core_pointer);