forked from AuroraMiddleware/gtk
f6b4585c98
2007-01-19 Tor Lillqvist <tml@novell.com> Build Wintab support always on Windows. Don't require the Wintab SDK. * configure.in: Drop the --with-wintab option. Drop the HAVE_WINTAB feature test macro and Automake variable. * acconfig.h * config.h.win32.in: Drop HAVE_WINTAB. * gdk/win32/gdkevents-win32.c * gdk/win32/gdkinput.c * gdk/win32/gdkinput-win32.h * gdk/win32/gdkinput-win32.c * gdk/win32/gdkmain-win32.c: Make HAVE_WINTAB ifdef blocks unconditional. * gdk/win32/gdkinput-win32.c (_gdk_input_wintab_init_check): Try to load wintab32.dll dynamically here. If it is found look up the handful Wintab functions we use. (rest of file): Use these function pointers instead of calling the functions from wntab32x.lib. The code in wntab32x.lib did the same thing anyway: tried to load wintab32.dll, and looked up the addresses of the actual functions from it. * gdk/Makefile.am * gdk/win32/Makefile.am: Drop the libwntab32x hacks. * gdk/win32/wintab.h * gdk/win32/pktdef.h: New files. Copied from the Wintab SDK. Copyright blurb says: "The text and information contained in this file may be freely used, copied, or distributed without compensation or licensing restrictions." * README.win32: Update a bit. Remove the text about the Wintab SDK. svn path=/trunk/; revision=17186
1265 lines
38 KiB
C
1265 lines
38 KiB
C
/* GDK - The GIMP Drawing Kit
|
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
|
* Copyright (C) 1998-2007 Tor Lillqvist
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
/*
|
|
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
|
|
* file for a list of people on the GTK+ Team. See the ChangeLog
|
|
* files for a list of changes. These files are distributed with
|
|
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
|
|
#include "gdk.h"
|
|
#include "gdkinput.h"
|
|
#include "gdkinternals.h"
|
|
#include "gdkprivate-win32.h"
|
|
#include "gdkinput-win32.h"
|
|
|
|
#define PACKETDATA (PK_CONTEXT | PK_CURSOR | PK_BUTTONS | PK_X | PK_Y | PK_NORMAL_PRESSURE | PK_ORIENTATION)
|
|
#define PACKETMODE (PK_BUTTONS)
|
|
#include <pktdef.h>
|
|
|
|
#define DEBUG_WINTAB 1 /* Verbose debug messages enabled */
|
|
|
|
#define PROXIMITY_OUT_DELAY 200 /* In milliseconds, see set_ignore_core */
|
|
|
|
#define TWOPI (2.*G_PI)
|
|
|
|
/* Forward declarations */
|
|
|
|
static GdkDevicePrivate *gdk_input_find_dev_from_ctx (HCTX hctx,
|
|
UINT id);
|
|
static GList *wintab_contexts = NULL;
|
|
|
|
static GdkWindow *wintab_window = NULL;
|
|
|
|
static GdkWindow *x_grab_window = NULL; /* Window that currently holds
|
|
* the extended inputs grab
|
|
*/
|
|
static GdkEventMask x_grab_mask;
|
|
static gboolean x_grab_owner_events;
|
|
|
|
typedef UINT (WINAPI *t_WTInfoA) (UINT a, UINT b, LPVOID c);
|
|
typedef BOOL (WINAPI *t_WTEnable) (HCTX a, BOOL b);
|
|
typedef HCTX (WINAPI *t_WTOpenA) (HWND a, LPLOGCONTEXTA b, BOOL c);
|
|
typedef BOOL (WINAPI *t_WTOverlap) (HCTX a, BOOL b);
|
|
typedef BOOL (WINAPI *t_WTPacket) (HCTX a, UINT b, LPVOID c);
|
|
typedef int (WINAPI *t_WTQueueSizeSet) (HCTX a, int b);
|
|
|
|
static t_WTInfoA p_WTInfoA;
|
|
static t_WTEnable p_WTEnable;
|
|
static t_WTOpenA p_WTOpenA;
|
|
static t_WTOverlap p_WTOverlap;
|
|
static t_WTPacket p_WTPacket;
|
|
static t_WTQueueSizeSet p_WTQueueSizeSet;
|
|
|
|
static GdkDevicePrivate *
|
|
gdk_input_find_dev_from_ctx (HCTX hctx,
|
|
UINT cursor)
|
|
{
|
|
GList *tmp_list = _gdk_input_devices;
|
|
GdkDevicePrivate *gdkdev;
|
|
|
|
while (tmp_list)
|
|
{
|
|
gdkdev = (GdkDevicePrivate *) (tmp_list->data);
|
|
if (gdkdev->hctx == hctx && gdkdev->cursor == cursor)
|
|
return gdkdev;
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#if DEBUG_WINTAB
|
|
|
|
static void
|
|
print_lc(LOGCONTEXT *lc)
|
|
{
|
|
g_print ("lcName = %s\n", lc->lcName);
|
|
g_print ("lcOptions =");
|
|
if (lc->lcOptions & CXO_SYSTEM) g_print (" CXO_SYSTEM");
|
|
if (lc->lcOptions & CXO_PEN) g_print (" CXO_PEN");
|
|
if (lc->lcOptions & CXO_MESSAGES) g_print (" CXO_MESSAGES");
|
|
if (lc->lcOptions & CXO_MARGIN) g_print (" CXO_MARGIN");
|
|
if (lc->lcOptions & CXO_MGNINSIDE) g_print (" CXO_MGNINSIDE");
|
|
if (lc->lcOptions & CXO_CSRMESSAGES) g_print (" CXO_CSRMESSAGES");
|
|
g_print ("\n");
|
|
g_print ("lcStatus =");
|
|
if (lc->lcStatus & CXS_DISABLED) g_print (" CXS_DISABLED");
|
|
if (lc->lcStatus & CXS_OBSCURED) g_print (" CXS_OBSCURED");
|
|
if (lc->lcStatus & CXS_ONTOP) g_print (" CXS_ONTOP");
|
|
g_print ("\n");
|
|
g_print ("lcLocks =");
|
|
if (lc->lcLocks & CXL_INSIZE) g_print (" CXL_INSIZE");
|
|
if (lc->lcLocks & CXL_INASPECT) g_print (" CXL_INASPECT");
|
|
if (lc->lcLocks & CXL_SENSITIVITY) g_print (" CXL_SENSITIVITY");
|
|
if (lc->lcLocks & CXL_MARGIN) g_print (" CXL_MARGIN");
|
|
g_print ("\n");
|
|
g_print ("lcMsgBase = %#x, lcDevice = %#x, lcPktRate = %d\n",
|
|
lc->lcMsgBase, lc->lcDevice, lc->lcPktRate);
|
|
g_print ("lcPktData =");
|
|
if (lc->lcPktData & PK_CONTEXT) g_print (" PK_CONTEXT");
|
|
if (lc->lcPktData & PK_STATUS) g_print (" PK_STATUS");
|
|
if (lc->lcPktData & PK_TIME) g_print (" PK_TIME");
|
|
if (lc->lcPktData & PK_CHANGED) g_print (" PK_CHANGED");
|
|
if (lc->lcPktData & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
|
|
if (lc->lcPktData & PK_CURSOR) g_print (" PK_CURSOR");
|
|
if (lc->lcPktData & PK_BUTTONS) g_print (" PK_BUTTONS");
|
|
if (lc->lcPktData & PK_X) g_print (" PK_X");
|
|
if (lc->lcPktData & PK_Y) g_print (" PK_Y");
|
|
if (lc->lcPktData & PK_Z) g_print (" PK_Z");
|
|
if (lc->lcPktData & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
|
|
if (lc->lcPktData & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
|
|
if (lc->lcPktData & PK_ORIENTATION) g_print (" PK_ORIENTATION");
|
|
if (lc->lcPktData & PK_ROTATION) g_print (" PK_ROTATION");
|
|
g_print ("\n");
|
|
g_print ("lcPktMode =");
|
|
if (lc->lcPktMode & PK_CONTEXT) g_print (" PK_CONTEXT");
|
|
if (lc->lcPktMode & PK_STATUS) g_print (" PK_STATUS");
|
|
if (lc->lcPktMode & PK_TIME) g_print (" PK_TIME");
|
|
if (lc->lcPktMode & PK_CHANGED) g_print (" PK_CHANGED");
|
|
if (lc->lcPktMode & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
|
|
if (lc->lcPktMode & PK_CURSOR) g_print (" PK_CURSOR");
|
|
if (lc->lcPktMode & PK_BUTTONS) g_print (" PK_BUTTONS");
|
|
if (lc->lcPktMode & PK_X) g_print (" PK_X");
|
|
if (lc->lcPktMode & PK_Y) g_print (" PK_Y");
|
|
if (lc->lcPktMode & PK_Z) g_print (" PK_Z");
|
|
if (lc->lcPktMode & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
|
|
if (lc->lcPktMode & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
|
|
if (lc->lcPktMode & PK_ORIENTATION) g_print (" PK_ORIENTATION");
|
|
if (lc->lcPktMode & PK_ROTATION) g_print (" PK_ROTATION");
|
|
g_print ("\n");
|
|
g_print ("lcMoveMask =");
|
|
if (lc->lcMoveMask & PK_CONTEXT) g_print (" PK_CONTEXT");
|
|
if (lc->lcMoveMask & PK_STATUS) g_print (" PK_STATUS");
|
|
if (lc->lcMoveMask & PK_TIME) g_print (" PK_TIME");
|
|
if (lc->lcMoveMask & PK_CHANGED) g_print (" PK_CHANGED");
|
|
if (lc->lcMoveMask & PK_SERIAL_NUMBER) g_print (" PK_SERIAL_NUMBER");
|
|
if (lc->lcMoveMask & PK_CURSOR) g_print (" PK_CURSOR");
|
|
if (lc->lcMoveMask & PK_BUTTONS) g_print (" PK_BUTTONS");
|
|
if (lc->lcMoveMask & PK_X) g_print (" PK_X");
|
|
if (lc->lcMoveMask & PK_Y) g_print (" PK_Y");
|
|
if (lc->lcMoveMask & PK_Z) g_print (" PK_Z");
|
|
if (lc->lcMoveMask & PK_NORMAL_PRESSURE) g_print (" PK_NORMAL_PRESSURE");
|
|
if (lc->lcMoveMask & PK_TANGENT_PRESSURE) g_print (" PK_TANGENT_PRESSURE");
|
|
if (lc->lcMoveMask & PK_ORIENTATION) g_print (" PK_ORIENTATION");
|
|
if (lc->lcMoveMask & PK_ROTATION) g_print (" PK_ROTATION");
|
|
g_print ("\n");
|
|
g_print ("lcBtnDnMask = %#x, lcBtnUpMask = %#x\n",
|
|
(guint) lc->lcBtnDnMask, (guint) lc->lcBtnUpMask);
|
|
g_print ("lcInOrgX = %ld, lcInOrgY = %ld, lcInOrgZ = %ld\n",
|
|
lc->lcInOrgX, lc->lcInOrgY, lc->lcInOrgZ);
|
|
g_print ("lcInExtX = %ld, lcInExtY = %ld, lcInExtZ = %ld\n",
|
|
lc->lcInExtX, lc->lcInExtY, lc->lcInExtZ);
|
|
g_print ("lcOutOrgX = %ld, lcOutOrgY = %ld, lcOutOrgZ = %ld\n",
|
|
lc->lcOutOrgX, lc->lcOutOrgY, lc->lcOutOrgZ);
|
|
g_print ("lcOutExtX = %ld, lcOutExtY = %ld, lcOutExtZ = %ld\n",
|
|
lc->lcOutExtX, lc->lcOutExtY, lc->lcOutExtZ);
|
|
g_print ("lcSensX = %g, lcSensY = %g, lcSensZ = %g\n",
|
|
lc->lcSensX / 65536., lc->lcSensY / 65536., lc->lcSensZ / 65536.);
|
|
g_print ("lcSysMode = %d\n", lc->lcSysMode);
|
|
g_print ("lcSysOrgX = %d, lcSysOrgY = %d\n",
|
|
lc->lcSysOrgX, lc->lcSysOrgY);
|
|
g_print ("lcSysExtX = %d, lcSysExtY = %d\n",
|
|
lc->lcSysExtX, lc->lcSysExtY);
|
|
g_print ("lcSysSensX = %g, lcSysSensY = %g\n",
|
|
lc->lcSysSensX / 65536., lc->lcSysSensY / 65536.);
|
|
}
|
|
|
|
#endif
|
|
|
|
void
|
|
_gdk_input_wintab_init_check (void)
|
|
{
|
|
static gboolean wintab_initialized = FALSE;
|
|
GdkDevicePrivate *gdkdev;
|
|
GdkWindowAttr wa;
|
|
WORD specversion;
|
|
HCTX *hctx;
|
|
UINT ndevices, ncursors, ncsrtypes, firstcsr, hardware;
|
|
BOOL active;
|
|
AXIS axis_x, axis_y, axis_npressure, axis_or[3];
|
|
int i, k;
|
|
int devix, cursorix;
|
|
char devname[100], csrname[100];
|
|
BOOL defcontext_done;
|
|
HMODULE wintab32;
|
|
|
|
if (wintab_initialized)
|
|
return;
|
|
|
|
wintab_initialized = TRUE;
|
|
|
|
wintab_contexts = NULL;
|
|
|
|
if (_gdk_input_ignore_wintab)
|
|
return;
|
|
|
|
if ((wintab32 = LoadLibrary ("wintab32.dll")) == NULL)
|
|
return;
|
|
|
|
if ((p_WTInfoA = (t_WTInfoA) GetProcAddress (wintab32, "WTInfoA")) == NULL)
|
|
return;
|
|
if ((p_WTEnable = (t_WTEnable) GetProcAddress (wintab32, "WTEnable")) == NULL)
|
|
return;
|
|
if ((p_WTOpenA = (t_WTOpenA) GetProcAddress (wintab32, "WTOpenA")) == NULL)
|
|
return;
|
|
if ((p_WTOverlap = (t_WTOverlap) GetProcAddress (wintab32, "WTOverlap")) == NULL)
|
|
return;
|
|
if ((p_WTPacket = (t_WTPacket) GetProcAddress (wintab32, "WTPacket")) == NULL)
|
|
return;
|
|
if ((p_WTQueueSizeSet = (t_WTQueueSizeSet) GetProcAddress (wintab32, "WTQueueSizeSet")) == NULL)
|
|
return;
|
|
|
|
if (!(*p_WTInfoA) (0, 0, NULL))
|
|
return;
|
|
|
|
(*p_WTInfoA) (WTI_INTERFACE, IFC_SPECVERSION, &specversion);
|
|
GDK_NOTE (INPUT, g_print ("Wintab interface version %d.%d\n",
|
|
HIBYTE (specversion), LOBYTE (specversion)));
|
|
(*p_WTInfoA) (WTI_INTERFACE, IFC_NDEVICES, &ndevices);
|
|
(*p_WTInfoA) (WTI_INTERFACE, IFC_NCURSORS, &ncursors);
|
|
#if DEBUG_WINTAB
|
|
GDK_NOTE (INPUT, g_print ("NDEVICES: %d, NCURSORS: %d\n",
|
|
ndevices, ncursors));
|
|
#endif
|
|
/* Create a dummy window to receive wintab events */
|
|
wa.wclass = GDK_INPUT_OUTPUT;
|
|
wa.event_mask = GDK_ALL_EVENTS_MASK;
|
|
wa.width = 2;
|
|
wa.height = 2;
|
|
wa.x = -100;
|
|
wa.y = -100;
|
|
wa.window_type = GDK_WINDOW_TOPLEVEL;
|
|
if ((wintab_window = gdk_window_new (NULL, &wa, GDK_WA_X|GDK_WA_Y)) == NULL)
|
|
{
|
|
g_warning ("gdk_input_wintab_init: gdk_window_new failed");
|
|
return;
|
|
}
|
|
g_object_ref (wintab_window);
|
|
|
|
for (devix = 0; devix < ndevices; devix++)
|
|
{
|
|
LOGCONTEXT lc;
|
|
|
|
/* We open the Wintab device (hmm, what if there are several?) as a
|
|
* system pointing device, i.e. it controls the normal Windows
|
|
* cursor. This seems much more natural.
|
|
*/
|
|
|
|
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_NAME, devname);
|
|
|
|
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_NCSRTYPES, &ncsrtypes);
|
|
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_FIRSTCSR, &firstcsr);
|
|
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_HARDWARE, &hardware);
|
|
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_X, &axis_x);
|
|
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_Y, &axis_y);
|
|
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_NPRESSURE, &axis_npressure);
|
|
(*p_WTInfoA) (WTI_DEVICES + devix, DVC_ORIENTATION, axis_or);
|
|
|
|
defcontext_done = FALSE;
|
|
if (HIBYTE (specversion) > 1 || LOBYTE (specversion) >= 1)
|
|
{
|
|
/* Try to get device-specific default context */
|
|
/* Some drivers, e.g. Aiptek, don't provide this info */
|
|
if ((*p_WTInfoA) (WTI_DSCTXS + devix, 0, &lc) > 0)
|
|
defcontext_done = TRUE;
|
|
#if DEBUG_WINTAB
|
|
if (defcontext_done)
|
|
GDK_NOTE (INPUT, (g_print("Using device-specific default context\n")));
|
|
else
|
|
GDK_NOTE (INPUT, (g_print("Note: Driver did not provide device specific default context info despite claiming to support version 1.1\n")));
|
|
#endif
|
|
}
|
|
|
|
if (!defcontext_done)
|
|
(*p_WTInfoA) (WTI_DEFSYSCTX, 0, &lc);
|
|
#if DEBUG_WINTAB
|
|
GDK_NOTE (INPUT, (g_print("Default context:\n"), print_lc(&lc)));
|
|
#endif
|
|
lc.lcOptions |= CXO_MESSAGES;
|
|
lc.lcStatus = 0;
|
|
lc.lcMsgBase = WT_DEFBASE;
|
|
lc.lcPktRate = 50;
|
|
lc.lcPktData = PACKETDATA;
|
|
lc.lcPktMode = PACKETMODE;
|
|
lc.lcMoveMask = PACKETDATA;
|
|
lc.lcBtnUpMask = lc.lcBtnDnMask = ~0;
|
|
lc.lcOutOrgX = axis_x.axMin;
|
|
lc.lcOutOrgY = axis_y.axMin;
|
|
lc.lcOutExtX = axis_x.axMax - axis_x.axMin;
|
|
lc.lcOutExtY = axis_y.axMax - axis_y.axMin;
|
|
lc.lcOutExtY = -lc.lcOutExtY; /* We want Y growing downward */
|
|
#if DEBUG_WINTAB
|
|
GDK_NOTE (INPUT, (g_print("context for device %d:\n", devix),
|
|
print_lc(&lc)));
|
|
#endif
|
|
hctx = g_new (HCTX, 1);
|
|
if ((*hctx = (*p_WTOpenA) (GDK_WINDOW_HWND (wintab_window), &lc, TRUE)) == NULL)
|
|
{
|
|
g_warning ("gdk_input_wintab_init: WTOpen failed");
|
|
return;
|
|
}
|
|
GDK_NOTE (INPUT, g_print ("opened Wintab device %d %p\n",
|
|
devix, *hctx));
|
|
|
|
wintab_contexts = g_list_append (wintab_contexts, hctx);
|
|
#if 0
|
|
(*p_WTEnable) (*hctx, TRUE);
|
|
#endif
|
|
(*p_WTOverlap) (*hctx, TRUE);
|
|
|
|
#if DEBUG_WINTAB
|
|
GDK_NOTE (INPUT, (g_print("context for device %d after WTOpen:\n", devix),
|
|
print_lc(&lc)));
|
|
#endif
|
|
/* Increase packet queue size to reduce the risk of lost packets.
|
|
* According to the specs, if the function fails we must try again
|
|
* with a smaller queue size.
|
|
*/
|
|
GDK_NOTE (INPUT, g_print("Attempting to increase queue size\n"));
|
|
for (i = 128; i >= 1; i >>= 1)
|
|
{
|
|
if ((*p_WTQueueSizeSet) (*hctx, i))
|
|
{
|
|
GDK_NOTE (INPUT, g_print("Queue size set to %d\n", i));
|
|
break;
|
|
}
|
|
}
|
|
if (!i)
|
|
GDK_NOTE (INPUT, g_print("Whoops, no queue size could be set\n"));
|
|
for (cursorix = firstcsr; cursorix < firstcsr + ncsrtypes; cursorix++)
|
|
{
|
|
active = FALSE;
|
|
(*p_WTInfoA) (WTI_CURSORS + cursorix, CSR_ACTIVE, &active);
|
|
if (!active)
|
|
continue;
|
|
gdkdev = g_object_new (GDK_TYPE_DEVICE, NULL);
|
|
(*p_WTInfoA) (WTI_CURSORS + cursorix, CSR_NAME, csrname);
|
|
gdkdev->info.name = g_strconcat (devname, " ", csrname, NULL);
|
|
gdkdev->info.source = GDK_SOURCE_PEN;
|
|
gdkdev->info.mode = GDK_MODE_SCREEN;
|
|
gdkdev->info.has_cursor = TRUE;
|
|
gdkdev->hctx = *hctx;
|
|
gdkdev->cursor = cursorix;
|
|
(*p_WTInfoA) (WTI_CURSORS + cursorix, CSR_PKTDATA, &gdkdev->pktdata);
|
|
gdkdev->info.num_axes = 0;
|
|
if (gdkdev->pktdata & PK_X)
|
|
gdkdev->info.num_axes++;
|
|
if (gdkdev->pktdata & PK_Y)
|
|
gdkdev->info.num_axes++;
|
|
if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
|
|
gdkdev->info.num_axes++;
|
|
/* The wintab driver for the Wacom ArtPad II reports
|
|
* PK_ORIENTATION in CSR_PKTDATA, but the tablet doesn't
|
|
* actually sense tilt. Catch this by noticing that the
|
|
* orientation axis's azimuth resolution is zero.
|
|
*/
|
|
if ((gdkdev->pktdata & PK_ORIENTATION)
|
|
&& axis_or[0].axResolution == 0)
|
|
gdkdev->pktdata &= ~PK_ORIENTATION;
|
|
|
|
if (gdkdev->pktdata & PK_ORIENTATION)
|
|
gdkdev->info.num_axes += 2; /* x and y tilt */
|
|
(*p_WTInfoA) (WTI_CURSORS + cursorix, CSR_NPBTNMARKS, &gdkdev->npbtnmarks);
|
|
gdkdev->info.axes = g_new (GdkDeviceAxis, gdkdev->info.num_axes);
|
|
gdkdev->axes = g_new (GdkAxisInfo, gdkdev->info.num_axes);
|
|
gdkdev->last_axis_data = g_new (gint, gdkdev->info.num_axes);
|
|
|
|
k = 0;
|
|
if (gdkdev->pktdata & PK_X)
|
|
{
|
|
gdkdev->axes[k].xresolution =
|
|
gdkdev->axes[k].resolution = axis_x.axResolution / 65535.;
|
|
gdkdev->axes[k].xmin_value =
|
|
gdkdev->axes[k].min_value = axis_x.axMin;
|
|
gdkdev->axes[k].xmax_value =
|
|
gdkdev->axes[k].max_value = axis_x.axMax;
|
|
gdkdev->info.axes[k].use = GDK_AXIS_X;
|
|
gdkdev->info.axes[k].min = axis_x.axMin;
|
|
gdkdev->info.axes[k].max = axis_x.axMax;
|
|
k++;
|
|
}
|
|
if (gdkdev->pktdata & PK_Y)
|
|
{
|
|
gdkdev->axes[k].xresolution =
|
|
gdkdev->axes[k].resolution = axis_y.axResolution / 65535.;
|
|
gdkdev->axes[k].xmin_value =
|
|
gdkdev->axes[k].min_value = axis_y.axMin;
|
|
gdkdev->axes[k].xmax_value =
|
|
gdkdev->axes[k].max_value = axis_y.axMax;
|
|
gdkdev->info.axes[k].use = GDK_AXIS_Y;
|
|
gdkdev->info.axes[k].min = axis_y.axMin;
|
|
gdkdev->info.axes[k].max = axis_y.axMax;
|
|
k++;
|
|
}
|
|
if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
|
|
{
|
|
gdkdev->axes[k].xresolution =
|
|
gdkdev->axes[k].resolution = axis_npressure.axResolution / 65535.;
|
|
gdkdev->axes[k].xmin_value =
|
|
gdkdev->axes[k].min_value = axis_npressure.axMin;
|
|
gdkdev->axes[k].xmax_value =
|
|
gdkdev->axes[k].max_value = axis_npressure.axMax;
|
|
gdkdev->info.axes[k].use = GDK_AXIS_PRESSURE;
|
|
/* GIMP seems to expect values in the range 0-1 */
|
|
gdkdev->info.axes[k].min = 0.0; /*axis_npressure.axMin;*/
|
|
gdkdev->info.axes[k].max = 1.0; /*axis_npressure.axMax;*/
|
|
k++;
|
|
}
|
|
if (gdkdev->pktdata & PK_ORIENTATION)
|
|
{
|
|
GdkAxisUse axis;
|
|
|
|
gdkdev->orientation_axes[0] = axis_or[0];
|
|
gdkdev->orientation_axes[1] = axis_or[1];
|
|
for (axis = GDK_AXIS_XTILT; axis <= GDK_AXIS_YTILT; axis++)
|
|
{
|
|
/* Wintab gives us aximuth and altitude, which
|
|
* we convert to x and y tilt in the -1000..1000 range
|
|
*/
|
|
gdkdev->axes[k].xresolution =
|
|
gdkdev->axes[k].resolution = 1000;
|
|
gdkdev->axes[k].xmin_value =
|
|
gdkdev->axes[k].min_value = -1000;
|
|
gdkdev->axes[k].xmax_value =
|
|
gdkdev->axes[k].max_value = 1000;
|
|
gdkdev->info.axes[k].use = axis;
|
|
gdkdev->info.axes[k].min = -1000;
|
|
gdkdev->info.axes[k].max = 1000;
|
|
k++;
|
|
}
|
|
}
|
|
gdkdev->info.num_keys = 0;
|
|
gdkdev->info.keys = NULL;
|
|
GDK_NOTE (INPUT, g_print ("device: (%d) %s axes: %d\n",
|
|
cursorix,
|
|
gdkdev->info.name,
|
|
gdkdev->info.num_axes));
|
|
for (i = 0; i < gdkdev->info.num_axes; i++)
|
|
GDK_NOTE (INPUT, g_print ("... axis %d: %d--%d@%d (%d--%d@%d)\n",
|
|
i,
|
|
gdkdev->axes[i].xmin_value,
|
|
gdkdev->axes[i].xmax_value,
|
|
gdkdev->axes[i].xresolution,
|
|
gdkdev->axes[i].min_value,
|
|
gdkdev->axes[i].max_value,
|
|
gdkdev->axes[i].resolution));
|
|
_gdk_input_devices = g_list_append (_gdk_input_devices,
|
|
gdkdev);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
decode_tilt (gint *axis_data,
|
|
AXIS *axes,
|
|
PACKET *packet)
|
|
{
|
|
/* As I don't have a tilt-sensing tablet,
|
|
* I cannot test this code.
|
|
*/
|
|
|
|
double az, el;
|
|
|
|
az = TWOPI * packet->pkOrientation.orAzimuth /
|
|
(axes[0].axResolution / 65536.);
|
|
el = TWOPI * packet->pkOrientation.orAltitude /
|
|
(axes[1].axResolution / 65536.);
|
|
|
|
/* X tilt */
|
|
axis_data[0] = cos (az) * cos (el) * 1000;
|
|
/* Y tilt */
|
|
axis_data[1] = sin (az) * cos (el) * 1000;
|
|
}
|
|
|
|
static void
|
|
gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev,
|
|
GdkInputWindow *input_window,
|
|
gint *axis_data,
|
|
gdouble *axis_out,
|
|
gdouble *x_out,
|
|
gdouble *y_out)
|
|
{
|
|
GdkWindowImplWin32 *impl, *root_impl;
|
|
|
|
int i;
|
|
int x_axis = 0;
|
|
int y_axis = 0;
|
|
|
|
double device_width, device_height;
|
|
double x_offset, y_offset, x_scale, y_scale;
|
|
|
|
impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (input_window->window)->impl);
|
|
|
|
for (i=0; i<gdkdev->info.num_axes; i++)
|
|
{
|
|
switch (gdkdev->info.axes[i].use)
|
|
{
|
|
case GDK_AXIS_X:
|
|
x_axis = i;
|
|
break;
|
|
case GDK_AXIS_Y:
|
|
y_axis = i;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
device_width = gdkdev->axes[x_axis].max_value -
|
|
gdkdev->axes[x_axis].min_value;
|
|
device_height = gdkdev->axes[y_axis].max_value -
|
|
gdkdev->axes[y_axis].min_value;
|
|
|
|
if (gdkdev->info.mode == GDK_MODE_SCREEN)
|
|
{
|
|
root_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (_gdk_root)->impl);
|
|
x_scale = root_impl->width / device_width;
|
|
y_scale = root_impl->height / device_height;
|
|
|
|
x_offset = - input_window->root_x;
|
|
y_offset = - input_window->root_y;
|
|
}
|
|
else /* GDK_MODE_WINDOW */
|
|
{
|
|
double device_aspect = (device_height*gdkdev->axes[y_axis].resolution) /
|
|
(device_width*gdkdev->axes[x_axis].resolution);
|
|
|
|
if (device_aspect * impl->width >= impl->height)
|
|
{
|
|
/* device taller than window */
|
|
x_scale = impl->width / device_width;
|
|
y_scale = (x_scale * gdkdev->axes[x_axis].resolution)
|
|
/ gdkdev->axes[y_axis].resolution;
|
|
|
|
x_offset = 0;
|
|
y_offset = -(device_height * y_scale -
|
|
impl->height)/2;
|
|
}
|
|
else
|
|
{
|
|
/* window taller than device */
|
|
y_scale = impl->height / device_height;
|
|
x_scale = (y_scale * gdkdev->axes[y_axis].resolution)
|
|
/ gdkdev->axes[x_axis].resolution;
|
|
|
|
y_offset = 0;
|
|
x_offset = - (device_width * x_scale - impl->width)/2;
|
|
}
|
|
}
|
|
|
|
for (i=0; i<gdkdev->info.num_axes; i++)
|
|
{
|
|
switch (gdkdev->info.axes[i].use)
|
|
{
|
|
case GDK_AXIS_X:
|
|
axis_out[i] = x_offset + x_scale*axis_data[x_axis];
|
|
if (x_out)
|
|
*x_out = axis_out[i];
|
|
break;
|
|
case GDK_AXIS_Y:
|
|
axis_out[i] = y_offset + y_scale*axis_data[y_axis];
|
|
if (y_out)
|
|
*y_out = axis_out[i];
|
|
break;
|
|
default:
|
|
axis_out[i] =
|
|
(gdkdev->info.axes[i].max * (axis_data[i] - gdkdev->axes[i].min_value) +
|
|
gdkdev->info.axes[i].min * (gdkdev->axes[i].max_value - axis_data[i])) /
|
|
(gdkdev->axes[i].max_value - gdkdev->axes[i].min_value);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
gdk_input_get_root_relative_geometry (HWND w,
|
|
int *x_ret,
|
|
int *y_ret)
|
|
{
|
|
RECT rect;
|
|
|
|
GetWindowRect (w, &rect);
|
|
|
|
if (x_ret)
|
|
*x_ret = rect.left + _gdk_offset_x;
|
|
if (y_ret)
|
|
*y_ret = rect.top + _gdk_offset_y;
|
|
}
|
|
|
|
void
|
|
_gdk_input_configure_event (GdkWindow *window)
|
|
{
|
|
GdkInputWindow *input_window;
|
|
int root_x, root_y;
|
|
|
|
input_window = _gdk_input_window_find (window);
|
|
g_return_if_fail (window != NULL);
|
|
|
|
gdk_input_get_root_relative_geometry (GDK_WINDOW_HWND (window),
|
|
&root_x, &root_y);
|
|
|
|
input_window->root_x = root_x;
|
|
input_window->root_y = root_y;
|
|
}
|
|
|
|
void
|
|
_gdk_input_enter_event (GdkWindow *window)
|
|
{
|
|
GdkInputWindow *input_window;
|
|
int root_x, root_y;
|
|
|
|
input_window = _gdk_input_window_find (window);
|
|
g_return_if_fail (window != NULL);
|
|
|
|
gdk_input_get_root_relative_geometry (GDK_WINDOW_HWND (window), &root_x, &root_y);
|
|
|
|
input_window->root_x = root_x;
|
|
input_window->root_y = root_y;
|
|
}
|
|
|
|
/*
|
|
* Get the currently active keyboard modifiers (ignoring the mouse buttons)
|
|
* We could use gdk_window_get_pointer but that function does a lot of other
|
|
* expensive things besides getting the modifiers. This code is somewhat based
|
|
* on build_pointer_event_state from gdkevents-win32.c
|
|
*/
|
|
static guint
|
|
get_modifier_key_state (void)
|
|
{
|
|
guint state;
|
|
|
|
state = 0;
|
|
/* High-order bit is up/down, low order bit is toggled/untoggled */
|
|
if (GetKeyState (VK_CONTROL) < 0)
|
|
state |= GDK_CONTROL_MASK;
|
|
if (GetKeyState (VK_SHIFT) < 0)
|
|
state |= GDK_SHIFT_MASK;
|
|
if (GetKeyState (VK_MENU) < 0)
|
|
state |= GDK_MOD1_MASK;
|
|
if (GetKeyState (VK_CAPITAL) & 0x1)
|
|
state |= GDK_LOCK_MASK;
|
|
|
|
return state;
|
|
}
|
|
|
|
static guint ignore_core_timer = 0;
|
|
|
|
static gboolean
|
|
ignore_core_timefunc (gpointer data)
|
|
{
|
|
/* The delay has passed */
|
|
_gdk_input_ignore_core = FALSE;
|
|
ignore_core_timer = 0;
|
|
|
|
return FALSE; /* remove timeout */
|
|
}
|
|
|
|
/*
|
|
* Set or unset the _gdk_input_ignore_core variable that tells GDK
|
|
* to ignore events for the core pointer when the tablet is in proximity
|
|
* The unsetting is delayed slightly so that if a tablet event arrives
|
|
* just after proximity out, it does not cause a core pointer event
|
|
* which e.g. causes GIMP to switch tools.
|
|
*/
|
|
static void
|
|
set_ignore_core (gboolean ignore)
|
|
{
|
|
if (ignore)
|
|
{
|
|
_gdk_input_ignore_core = TRUE;
|
|
/* Remove any pending clear */
|
|
if (ignore_core_timer)
|
|
{
|
|
g_source_remove (ignore_core_timer);
|
|
ignore_core_timer = 0;
|
|
}
|
|
}
|
|
else
|
|
if (!ignore_core_timer)
|
|
ignore_core_timer = gdk_threads_add_timeout (PROXIMITY_OUT_DELAY,
|
|
ignore_core_timefunc, NULL);
|
|
}
|
|
|
|
gboolean
|
|
_gdk_input_other_event (GdkEvent *event,
|
|
MSG *msg,
|
|
GdkWindow *window)
|
|
{
|
|
GdkDisplay *display;
|
|
GdkWindowObject *obj, *grab_obj;
|
|
GdkInputWindow *input_window;
|
|
GdkDevicePrivate *gdkdev = NULL;
|
|
GdkEventMask masktest;
|
|
guint key_state;
|
|
POINT pt;
|
|
|
|
PACKET packet;
|
|
gint k;
|
|
gint x, y;
|
|
|
|
if (event->any.window != wintab_window)
|
|
{
|
|
g_warning ("_gdk_input_other_event: not wintab_window?");
|
|
return FALSE;
|
|
}
|
|
|
|
window = gdk_window_at_pointer (&x, &y);
|
|
if (window == NULL)
|
|
window = _gdk_root;
|
|
|
|
g_object_ref (window);
|
|
display = gdk_drawable_get_display (window);
|
|
|
|
GDK_NOTE (EVENTS_OR_INPUT,
|
|
g_print ("gdk_input_win32_other_event: window=%p %+d%+d\n",
|
|
GDK_WINDOW_HWND (window), x, y));
|
|
|
|
if (msg->message == WT_PACKET)
|
|
{
|
|
if (!(*p_WTPacket) ((HCTX) msg->lParam, msg->wParam, &packet))
|
|
return FALSE;
|
|
}
|
|
|
|
obj = GDK_WINDOW_OBJECT (window);
|
|
|
|
switch (msg->message)
|
|
{
|
|
case WT_PACKET:
|
|
/* Don't produce any button or motion events while a window is being
|
|
* moved or resized, see bug #151090.
|
|
*/
|
|
if (_sizemove_in_progress)
|
|
{
|
|
GDK_NOTE (EVENTS_OR_INPUT, g_print ("... ignored when moving/sizing\n"));
|
|
return FALSE;
|
|
}
|
|
if (window == _gdk_root && x_grab_window == NULL)
|
|
{
|
|
GDK_NOTE (EVENTS_OR_INPUT, g_print ("... is root\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
if ((gdkdev = gdk_input_find_dev_from_ctx ((HCTX) msg->lParam,
|
|
packet.pkCursor)) == NULL)
|
|
return FALSE;
|
|
|
|
if (gdkdev->info.mode == GDK_MODE_DISABLED)
|
|
return FALSE;
|
|
|
|
k = 0;
|
|
if (gdkdev->pktdata & PK_X)
|
|
gdkdev->last_axis_data[k++] = packet.pkX;
|
|
if (gdkdev->pktdata & PK_Y)
|
|
gdkdev->last_axis_data[k++] = packet.pkY;
|
|
if (gdkdev->pktdata & PK_NORMAL_PRESSURE)
|
|
gdkdev->last_axis_data[k++] = packet.pkNormalPressure;
|
|
if (gdkdev->pktdata & PK_ORIENTATION)
|
|
{
|
|
decode_tilt (gdkdev->last_axis_data + k,
|
|
gdkdev->orientation_axes, &packet);
|
|
k += 2;
|
|
}
|
|
|
|
g_assert (k == gdkdev->info.num_axes);
|
|
|
|
if (HIWORD (packet.pkButtons) != TBN_NONE)
|
|
{
|
|
/* Gdk buttons are numbered 1.. */
|
|
event->button.button = 1 + LOWORD (packet.pkButtons);
|
|
|
|
if (HIWORD (packet.pkButtons) == TBN_UP)
|
|
{
|
|
event->any.type = GDK_BUTTON_RELEASE;
|
|
masktest = GDK_BUTTON_RELEASE_MASK;
|
|
gdkdev->button_state &= ~(1 << LOWORD (packet.pkButtons));
|
|
}
|
|
else
|
|
{
|
|
event->any.type = GDK_BUTTON_PRESS;
|
|
masktest = GDK_BUTTON_PRESS_MASK;
|
|
gdkdev->button_state |= 1 << LOWORD (packet.pkButtons);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
event->any.type = GDK_MOTION_NOTIFY;
|
|
masktest = GDK_POINTER_MOTION_MASK;
|
|
if (gdkdev->button_state & (1 << 0))
|
|
masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK;
|
|
if (gdkdev->button_state & (1 << 1))
|
|
masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON2_MOTION_MASK;
|
|
if (gdkdev->button_state & (1 << 2))
|
|
masktest |= GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK;
|
|
}
|
|
|
|
/* See if input is grabbed */
|
|
/* FIXME: x_grab_owner_events should probably be handled somehow */
|
|
if (x_grab_window != NULL)
|
|
{
|
|
grab_obj = GDK_WINDOW_OBJECT (x_grab_window);
|
|
if (!GDK_WINDOW_IMPL_WIN32 (grab_obj->impl)->extension_events_selected
|
|
|| !(grab_obj->extension_events & masktest)
|
|
|| !(x_grab_mask && masktest))
|
|
{
|
|
GDK_NOTE (EVENTS_OR_INPUT,
|
|
g_print ("... grabber doesn't want it\n"));
|
|
return FALSE;
|
|
}
|
|
GDK_NOTE (EVENTS_OR_INPUT, g_print ("... to grabber\n"));
|
|
|
|
g_object_ref(x_grab_window);
|
|
g_object_unref(window);
|
|
window = x_grab_window;
|
|
obj = grab_obj;
|
|
}
|
|
/* Now we can check if the window wants the event, and
|
|
* propagate if necessary.
|
|
*/
|
|
loop:
|
|
if (!GDK_WINDOW_IMPL_WIN32 (obj->impl)->extension_events_selected
|
|
|| !(obj->extension_events & masktest))
|
|
{
|
|
GDK_NOTE (EVENTS_OR_INPUT, g_print ("... not selected\n"));
|
|
|
|
if (obj->parent == GDK_WINDOW_OBJECT (_gdk_root))
|
|
return FALSE;
|
|
|
|
/* It is not good to propagate the extended events up to the parent
|
|
* if this window wants normal (not extended) motion/button events */
|
|
if (obj->event_mask & masktest)
|
|
{
|
|
GDK_NOTE (EVENTS_OR_INPUT,
|
|
g_print ("... wants ordinary event, ignoring this\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
pt.x = x;
|
|
pt.y = y;
|
|
ClientToScreen (GDK_WINDOW_HWND (window), &pt);
|
|
g_object_unref (window);
|
|
window = (GdkWindow *) obj->parent;
|
|
obj = GDK_WINDOW_OBJECT (window);
|
|
g_object_ref (window);
|
|
ScreenToClient (GDK_WINDOW_HWND (window), &pt);
|
|
x = pt.x;
|
|
y = pt.y;
|
|
GDK_NOTE (EVENTS_OR_INPUT, g_print ("... propagating to %p %+d%+d\n",
|
|
GDK_WINDOW_HWND (window), x, y));
|
|
goto loop;
|
|
}
|
|
|
|
input_window = _gdk_input_window_find (window);
|
|
|
|
g_assert (input_window != NULL);
|
|
|
|
if (gdkdev->info.mode == GDK_MODE_WINDOW
|
|
&& input_window->mode == GDK_EXTENSION_EVENTS_CURSOR)
|
|
return FALSE;
|
|
|
|
event->any.window = window;
|
|
key_state = get_modifier_key_state ();
|
|
if (event->any.type == GDK_BUTTON_PRESS
|
|
|| event->any.type == GDK_BUTTON_RELEASE)
|
|
{
|
|
event->button.time = _gdk_win32_get_next_tick (msg->time);
|
|
event->button.device = &gdkdev->info;
|
|
|
|
event->button.axes = g_new(gdouble, gdkdev->info.num_axes);
|
|
|
|
gdk_input_translate_coordinates (gdkdev, input_window,
|
|
gdkdev->last_axis_data,
|
|
event->button.axes,
|
|
&event->button.x,
|
|
&event->button.y);
|
|
|
|
/* Also calculate root coordinates. Note that input_window->root_x
|
|
is in GDK root coordinates. */
|
|
event->button.x_root = event->button.x + input_window->root_x;
|
|
event->button.y_root = event->button.y + input_window->root_y;
|
|
|
|
event->button.state = ((gdkdev->button_state << 8)
|
|
& (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
|
|
| GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
|
|
| GDK_BUTTON5_MASK))
|
|
| key_state;
|
|
GDK_NOTE (EVENTS_OR_INPUT,
|
|
g_print ("WINTAB button %s:%d %g,%g\n",
|
|
(event->button.type == GDK_BUTTON_PRESS ?
|
|
"press" : "release"),
|
|
event->button.button,
|
|
event->button.x, event->button.y));
|
|
}
|
|
else
|
|
{
|
|
event->motion.time = _gdk_win32_get_next_tick (msg->time);
|
|
event->motion.is_hint = FALSE;
|
|
event->motion.device = &gdkdev->info;
|
|
|
|
event->motion.axes = g_new(gdouble, gdkdev->info.num_axes);
|
|
|
|
gdk_input_translate_coordinates (gdkdev, input_window,
|
|
gdkdev->last_axis_data,
|
|
event->motion.axes,
|
|
&event->motion.x,
|
|
&event->motion.y);
|
|
|
|
/* Also calculate root coordinates. Note that input_window->root_x
|
|
is in GDK root coordinates. */
|
|
event->motion.x_root = event->motion.x + input_window->root_x;
|
|
event->motion.y_root = event->motion.y + input_window->root_y;
|
|
|
|
event->motion.state = ((gdkdev->button_state << 8)
|
|
& (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
|
|
| GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
|
|
| GDK_BUTTON5_MASK))
|
|
| key_state;
|
|
|
|
GDK_NOTE (EVENTS_OR_INPUT,
|
|
g_print ("WINTAB motion: %g,%g\n",
|
|
event->motion.x, event->motion.y));
|
|
|
|
/* Check for missing release or press events for the normal
|
|
* pressure button. At least on my ArtPadII I sometimes miss a
|
|
* release event?
|
|
*/
|
|
if ((gdkdev->pktdata & PK_NORMAL_PRESSURE
|
|
&& (event->motion.state & GDK_BUTTON1_MASK)
|
|
&& packet.pkNormalPressure <= MAX (0, (gint) gdkdev->npbtnmarks[0] - 2))
|
|
|| (gdkdev->pktdata & PK_NORMAL_PRESSURE
|
|
&& !(event->motion.state & GDK_BUTTON1_MASK)
|
|
&& packet.pkNormalPressure > gdkdev->npbtnmarks[1] + 2))
|
|
{
|
|
GdkEvent *event2 = gdk_event_copy (event);
|
|
if (event->motion.state & GDK_BUTTON1_MASK)
|
|
{
|
|
event2->button.type = GDK_BUTTON_RELEASE;
|
|
gdkdev->button_state &= ~1;
|
|
}
|
|
else
|
|
{
|
|
event2->button.type = GDK_BUTTON_PRESS;
|
|
gdkdev->button_state |= 1;
|
|
}
|
|
event2->button.state = ((gdkdev->button_state << 8)
|
|
& (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
|
|
| GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
|
|
| GDK_BUTTON5_MASK))
|
|
| key_state;
|
|
event2->button.button = 1;
|
|
GDK_NOTE (EVENTS_OR_INPUT,
|
|
g_print ("WINTAB synthesized button %s: %d %g,%gg\n",
|
|
(event2->button.type == GDK_BUTTON_PRESS ?
|
|
"press" : "release"),
|
|
event2->button.button,
|
|
event2->button.x,
|
|
event2->button.y));
|
|
_gdk_event_queue_append (display, event2);
|
|
}
|
|
}
|
|
return TRUE;
|
|
|
|
case WT_PROXIMITY:
|
|
if (LOWORD (msg->lParam) == 0)
|
|
{
|
|
event->proximity.type = GDK_PROXIMITY_OUT;
|
|
set_ignore_core (FALSE);
|
|
}
|
|
else
|
|
{
|
|
event->proximity.type = GDK_PROXIMITY_IN;
|
|
set_ignore_core (TRUE);
|
|
}
|
|
event->proximity.time = _gdk_win32_get_next_tick (msg->time);
|
|
event->proximity.device = &gdkdev->info;
|
|
|
|
GDK_NOTE (EVENTS_OR_INPUT,
|
|
g_print ("WINTAB proximity %s\n",
|
|
(event->proximity.type == GDK_PROXIMITY_IN ?
|
|
"in" : "out")));
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
gboolean
|
|
_gdk_input_enable_window (GdkWindow *window,
|
|
GdkDevicePrivate *gdkdev)
|
|
{
|
|
GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
|
|
|
|
impl->extension_events_selected = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
_gdk_input_disable_window (GdkWindow *window,
|
|
GdkDevicePrivate *gdkdev)
|
|
{
|
|
GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
|
|
|
|
impl->extension_events_selected = FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gint
|
|
_gdk_input_grab_pointer (GdkWindow *window,
|
|
gint owner_events,
|
|
GdkEventMask event_mask,
|
|
GdkWindow *confine_to,
|
|
guint32 time)
|
|
{
|
|
GdkInputWindow *input_window, *new_window;
|
|
gboolean need_ungrab;
|
|
GdkDevicePrivate *gdkdev;
|
|
GList *tmp_list;
|
|
|
|
tmp_list = _gdk_input_windows;
|
|
new_window = NULL;
|
|
need_ungrab = FALSE;
|
|
|
|
GDK_NOTE (INPUT, g_print ("gdk_input_win32_grab_pointer: %p %d %p\n",
|
|
GDK_WINDOW_HWND (window),
|
|
owner_events,
|
|
(confine_to ? GDK_WINDOW_HWND (confine_to) : 0)));
|
|
|
|
while (tmp_list)
|
|
{
|
|
input_window = (GdkInputWindow *)tmp_list->data;
|
|
|
|
if (input_window->window == window)
|
|
new_window = input_window;
|
|
else if (input_window->grabbed)
|
|
{
|
|
input_window->grabbed = FALSE;
|
|
need_ungrab = TRUE;
|
|
}
|
|
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
|
|
if (new_window)
|
|
{
|
|
new_window->grabbed = TRUE;
|
|
x_grab_window = window;
|
|
x_grab_mask = event_mask;
|
|
x_grab_owner_events = owner_events;
|
|
|
|
/* FIXME: Do we need to handle confine_to and time? */
|
|
|
|
tmp_list = _gdk_input_devices;
|
|
while (tmp_list)
|
|
{
|
|
gdkdev = (GdkDevicePrivate *)tmp_list->data;
|
|
if (!GDK_IS_CORE (gdkdev) && gdkdev->hctx)
|
|
{
|
|
#if 0
|
|
/* XXX */
|
|
gdk_input_common_find_events (window, gdkdev,
|
|
event_mask,
|
|
event_classes, &num_classes);
|
|
|
|
result = XGrabDevice( GDK_DISPLAY(), gdkdev->xdevice,
|
|
GDK_WINDOW_XWINDOW (window),
|
|
owner_events, num_classes, event_classes,
|
|
GrabModeAsync, GrabModeAsync, time);
|
|
|
|
/* FIXME: if failure occurs on something other than the first
|
|
device, things will be badly inconsistent */
|
|
if (result != Success)
|
|
return result;
|
|
#endif
|
|
}
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
x_grab_window = NULL;
|
|
tmp_list = _gdk_input_devices;
|
|
while (tmp_list)
|
|
{
|
|
gdkdev = (GdkDevicePrivate *)tmp_list->data;
|
|
if (!GDK_IS_CORE (gdkdev) && gdkdev->hctx &&
|
|
((gdkdev->button_state != 0) || need_ungrab))
|
|
{
|
|
#if 0
|
|
/* XXX */
|
|
XUngrabDevice (gdk_display, gdkdev->xdevice, time);
|
|
#endif
|
|
gdkdev->button_state = 0;
|
|
}
|
|
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
}
|
|
|
|
return GDK_GRAB_SUCCESS;
|
|
}
|
|
|
|
void
|
|
_gdk_input_ungrab_pointer (guint32 time)
|
|
{
|
|
GdkInputWindow *input_window;
|
|
GdkDevicePrivate *gdkdev;
|
|
GList *tmp_list;
|
|
|
|
GDK_NOTE (INPUT, g_print ("gdk_input_win32_ungrab_pointer\n"));
|
|
|
|
tmp_list = _gdk_input_windows;
|
|
while (tmp_list)
|
|
{
|
|
input_window = (GdkInputWindow *)tmp_list->data;
|
|
if (input_window->grabbed)
|
|
break;
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
|
|
if (tmp_list) /* we found a grabbed window */
|
|
{
|
|
input_window->grabbed = FALSE;
|
|
|
|
tmp_list = _gdk_input_devices;
|
|
while (tmp_list)
|
|
{
|
|
gdkdev = (GdkDevicePrivate *)tmp_list->data;
|
|
#if 0
|
|
/* XXX */
|
|
if (!GDK_IS_CORE (gdkdev) && gdkdev->xdevice)
|
|
XUngrabDevice (gdk_display, gdkdev->xdevice, time);
|
|
#endif
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
}
|
|
x_grab_window = NULL;
|
|
}
|
|
|
|
gboolean
|
|
_gdk_device_get_history (GdkDevice *device,
|
|
GdkWindow *window,
|
|
guint32 start,
|
|
guint32 stop,
|
|
GdkTimeCoord ***events,
|
|
gint *n_events)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
gdk_device_get_state (GdkDevice *device,
|
|
GdkWindow *window,
|
|
gdouble *axes,
|
|
GdkModifierType *mask)
|
|
{
|
|
g_return_if_fail (device != NULL);
|
|
g_return_if_fail (GDK_IS_WINDOW (window));
|
|
|
|
if (GDK_IS_CORE (device))
|
|
{
|
|
gint x_int, y_int;
|
|
|
|
gdk_window_get_pointer (window, &x_int, &y_int, mask);
|
|
|
|
if (axes)
|
|
{
|
|
axes[0] = x_int;
|
|
axes[1] = y_int;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GdkDevicePrivate *gdkdev;
|
|
GdkInputWindow *input_window;
|
|
|
|
gdkdev = (GdkDevicePrivate *)device;
|
|
/* For now just use the last known button and axis state of the device.
|
|
* Since graphical tablets send an insane amount of motion events each
|
|
* second, the info should be fairly up to date */
|
|
if (mask)
|
|
{
|
|
gdk_window_get_pointer (window, NULL, NULL, mask);
|
|
*mask &= 0xFF; /* Mask away core pointer buttons */
|
|
*mask |= ((gdkdev->button_state << 8)
|
|
& (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK
|
|
| GDK_BUTTON3_MASK | GDK_BUTTON4_MASK
|
|
| GDK_BUTTON5_MASK));
|
|
}
|
|
input_window = _gdk_input_window_find (window);
|
|
g_return_if_fail (input_window != NULL);
|
|
/* For some reason, input_window is sometimes NULL when I use The GIMP 2
|
|
* (bug #141543?). Avoid crashing if debugging is disabled. */
|
|
if (axes && gdkdev->last_axis_data && input_window)
|
|
gdk_input_translate_coordinates (gdkdev, input_window,
|
|
gdkdev->last_axis_data,
|
|
axes, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
void
|
|
_gdk_input_set_tablet_active (void)
|
|
{
|
|
GList *tmp_list;
|
|
HCTX *hctx;
|
|
|
|
/* Bring the contexts to the top of the overlap order when one of the
|
|
* application's windows is activated */
|
|
|
|
if (!wintab_contexts)
|
|
return; /* No tablet devices found, or Wintab not initialized yet */
|
|
|
|
GDK_NOTE (INPUT, g_print ("_gdk_input_set_tablet_active: "
|
|
"Bringing Wintab contexts to the top of the overlap order\n"));
|
|
|
|
tmp_list = wintab_contexts;
|
|
while (tmp_list)
|
|
{
|
|
hctx = (HCTX *) (tmp_list->data);
|
|
(*p_WTOverlap) (*hctx, TRUE);
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
}
|
|
|
|
void
|
|
_gdk_input_init (GdkDisplay *display)
|
|
{
|
|
_gdk_input_ignore_core = FALSE;
|
|
_gdk_input_devices = NULL;
|
|
|
|
_gdk_init_input_core (display);
|
|
#ifdef WINTAB_NO_LAZY_INIT
|
|
/* Normally, Wintab is only initialized when the application performs
|
|
* an action that requires it, such as enabling extended input events
|
|
* for a window or enumerating the devices.
|
|
*/
|
|
_gdk_input_wintab_init_check ();
|
|
#endif /* WINTAB_NO_LAZY_INIT */
|
|
|
|
_gdk_input_devices = g_list_append (_gdk_input_devices, display->core_pointer);
|
|
}
|
|
|