From 5c1676dfe6d2f3c837a5e074117b45613fd29a72 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:30:19 +0200 Subject: Adding upstream version 2.10.34. Signed-off-by: Daniel Baumann --- modules/controller-dx-dinput.c | 1122 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1122 insertions(+) create mode 100644 modules/controller-dx-dinput.c (limited to 'modules/controller-dx-dinput.c') diff --git a/modules/controller-dx-dinput.c b/modules/controller-dx-dinput.c new file mode 100644 index 0000000..87c0eab --- /dev/null +++ b/modules/controller-dx-dinput.c @@ -0,0 +1,1122 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis + * + * controller_dx_dinput.c + * Copyright (C) 2004-2007 Sven Neumann + * Michael Natterer + * Tor Lillqvist + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* When using gcc with the February 2007 version of the DirectX SDK, + * at least, you need to fix a couple of duplicate typedefs in the + * DirectX . Unfortunately I can't include the diff here, + * both for copyright reasons, and because that would confuse the C + * lexer even if inside #if 0. + */ + +#include "config.h" + +#include +#include +#include + +#define _WIN32_WINNT 0x0501 +#include +#define DIRECTINPUT_VERSION 0x0800 +#include + +#include +#include + +#include "libgimpconfig/gimpconfig.h" +#include "libgimpmodule/gimpmodule.h" +#include "libgimpwidgets/gimpwidgets.h" + +#define GIMP_ENABLE_CONTROLLER_UNDER_CONSTRUCTION +#include "libgimpwidgets/gimpcontroller.h" + +#include "gimpinputdevicestore.h" + +#include "libgimp/libgimp-intl.h" + +enum +{ + PROP_0, + PROP_DEVICE, + PROP_DEVICE_STORE +}; + +#define NUM_EVENTS_PER_BUTTON 3 /* Button click, press and release */ +#define NUM_EVENTS_PER_AXIS 2 /* Axis decrease and increase */ +#define NUM_EVENTS_PER_SLIDER 2 /* Slider decrease and increase */ +#define NUM_EVENTS_PER_POV 3 /* POV view vector X and Y view and return */ + +#define CONTROLLER_TYPE_DX_DINPUT (controller_dx_dinput_get_type ()) +#define CONTROLLER_DX_DINPUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CONTROLLER_TYPE_DX_DINPUT, ControllerDXDInput)) +#define CONTROLLER_DX_DINPUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CONTROLLER_TYPE_DX_DINPUT, ControllerDXDInputClass)) +#define CONTROLLER_IS_DX_DINPUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CONTROLLER_TYPE_DX_DINPUT)) +#define CONTROLLER_IS_DX_DINPUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CONTROLLER_TYPE_DX_DINPUT)) + +typedef struct _DXDInputSource DXDInputSource; +typedef struct _ControllerDXDInput ControllerDXDInput; +typedef struct _ControllerDXDInputClass ControllerDXDInputClass; + +struct _DXDInputSource +{ + GSource source; + ControllerDXDInput *controller; +}; + +struct _ControllerDXDInput +{ + GimpController parent_instance; + + GimpInputDeviceStore *store; + + LPDIRECTINPUTDEVICE8W didevice8; + + HANDLE event; + + GPollFD *pollfd; + + gint num_buttons; + gint num_button_events; + + gint num_axes; + gint num_axis_events; + + gint num_sliders; + gint num_slider_events; + + gint num_povs; + gint num_pov_events; + + gint num_events; + gchar **event_names; + gchar **event_blurbs; + + DIDATAFORMAT *format; + + guchar *prevdata; + + gchar *guid; + GSource *source; + + /* Variables used by enumeration callbacks only*/ + gint bei, bi, aei, ai, sei, si, pei, pi; +}; + +struct _ControllerDXDInputClass +{ + GimpControllerClass parent_class; +}; + + +static GType controller_dx_dinput_get_type (void); + +static void dx_dinput_dispose (GObject *object); +static void dx_dinput_finalize (GObject *object); +static void dx_dinput_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void dx_dinput_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + +static gint dx_dinput_get_n_events (GimpController *controller); +static const gchar * dx_dinput_get_event_name (GimpController *controller, + gint event_id); +static const gchar * dx_dinput_get_event_blurb (GimpController *controller, + gint event_id); + +static void dx_dinput_device_changed (ControllerDXDInput *controller, + const gchar *guid); +static gboolean dx_dinput_set_device (ControllerDXDInput *controller, + const gchar *guid); + + +static const GimpModuleInfo dx_dinput_info = +{ + GIMP_MODULE_ABI_VERSION, + N_("DirectX DirectInput event controller"), + "Tor Lillqvist ", + "v0.1", + "(c) 2004-2007, released under the GPL", + "2004-2007" +}; + + +G_DEFINE_DYNAMIC_TYPE (ControllerDXDInput, controller_dx_dinput, + GIMP_TYPE_CONTROLLER) + + +G_MODULE_EXPORT const GimpModuleInfo * +gimp_module_query (GTypeModule *module) +{ + return &dx_dinput_info; +} + +G_MODULE_EXPORT gboolean +gimp_module_register (GTypeModule *module) +{ + gimp_input_device_store_register_types (module); + controller_dx_dinput_register_type (module); + + return TRUE; +} + +static void +controller_dx_dinput_class_init (ControllerDXDInputClass *klass) +{ + GimpControllerClass *controller_class = GIMP_CONTROLLER_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = dx_dinput_dispose; + object_class->finalize = dx_dinput_finalize; + object_class->get_property = dx_dinput_get_property; + object_class->set_property = dx_dinput_set_property; + + g_object_class_install_property (object_class, PROP_DEVICE, + g_param_spec_string ("device", + _("Device:"), + _("The device to read DirectInput events from."), + NULL, + GIMP_CONFIG_PARAM_FLAGS)); + g_object_class_install_property (object_class, PROP_DEVICE_STORE, + g_param_spec_object ("device-values", + NULL, NULL, + GIMP_TYPE_INPUT_DEVICE_STORE, + G_PARAM_READABLE)); + + controller_class->name = _("DirectX DirectInput"); + controller_class->help_id = "gimp-controller-directx-directinput"; + controller_class->icon_name = GIMP_ICON_CONTROLLER_LINUX_INPUT; + + controller_class->get_n_events = dx_dinput_get_n_events; + controller_class->get_event_name = dx_dinput_get_event_name; + controller_class->get_event_blurb = dx_dinput_get_event_blurb; +} + +static void +controller_dx_dinput_class_finalize (ControllerDXDInputClass *klass) +{ +} + +static void +controller_dx_dinput_init (ControllerDXDInput *controller) +{ + controller->store = gimp_input_device_store_new (); + + if (controller->store) + { + g_signal_connect_swapped (controller->store, "device-added", + G_CALLBACK (dx_dinput_device_changed), + controller); + g_signal_connect_swapped (controller->store, "device-removed", + G_CALLBACK (dx_dinput_device_changed), + controller); + } +} + +static void +dx_dinput_dispose (GObject *object) +{ + ControllerDXDInput *controller = CONTROLLER_DX_DINPUT (object); + + dx_dinput_set_device (controller, NULL); + + G_OBJECT_CLASS (controller_dx_dinput_parent_class)->dispose (object); +} + +static void +dx_dinput_finalize (GObject *object) +{ + ControllerDXDInput *controller = CONTROLLER_DX_DINPUT (object); + + if (controller->source != NULL) + { + g_source_remove_poll (controller->source, controller->pollfd); + g_source_remove (g_source_get_id (controller->source)); + g_source_unref (controller->source); + } + + if (controller->didevice8) + IDirectInputDevice8_SetEventNotification (controller->didevice8, NULL); + + if (controller->format != NULL) + { + g_free (controller->format->rgodf); + g_free (controller->format); + controller->format = NULL; + } + + g_free (controller->prevdata); + controller->prevdata = NULL; + + if (controller->event != NULL) + { + CloseHandle (controller->event); + controller->event = 0; + } + + if (controller->store) + { + g_object_unref (controller->store); + controller->store = NULL; + } + + G_OBJECT_CLASS (controller_dx_dinput_parent_class)->finalize (object); +} + +static void +dx_dinput_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + ControllerDXDInput *controller = CONTROLLER_DX_DINPUT (object); + + switch (property_id) + { + case PROP_DEVICE: + dx_dinput_set_device (controller, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +dx_dinput_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + ControllerDXDInput *controller = CONTROLLER_DX_DINPUT (object); + + switch (property_id) + { + case PROP_DEVICE: + g_value_set_string (value, controller->guid); + break; + case PROP_DEVICE_STORE: + g_value_set_object (value, controller->store); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static gint +dx_dinput_get_n_events (GimpController *controller) +{ + ControllerDXDInput *cdxdi = (ControllerDXDInput *) controller; + + return cdxdi->num_events; +} + +static const gchar * +dx_dinput_get_event_name (GimpController *controller, + gint event_id) +{ + ControllerDXDInput *cdxdi = (ControllerDXDInput *) controller; + + if (event_id < 0 || event_id >= cdxdi->num_events) + return NULL; + + return cdxdi->event_names[event_id]; +} + +static const gchar * +dx_dinput_get_event_blurb (GimpController *controller, + gint event_id) +{ + ControllerDXDInput *cdxdi = (ControllerDXDInput *) controller; + + if (event_id < 0 || event_id >= cdxdi->num_events) + return NULL; + + return cdxdi->event_blurbs[event_id]; +} + +static BOOL CALLBACK +count_objects (const DIDEVICEOBJECTINSTANCEW *doi, + void *user_data) +{ + ControllerDXDInput *controller = (ControllerDXDInput *) user_data; + HRESULT hresult; + DIPROPRANGE range; + + if (doi->dwType & DIDFT_AXIS) + { + /* Set reported range to physical range, not to give upper + * level software any false impression of higher accuracy. + */ + + range.diph.dwSize = sizeof (DIPROPRANGE); + range.diph.dwHeaderSize = sizeof (DIPROPHEADER); + range.diph.dwObj = doi->dwType; + range.diph.dwHow = DIPH_BYID; + + if (FAILED ((hresult = IDirectInputDevice8_GetProperty (controller->didevice8, + DIPROP_PHYSICALRANGE, + &range.diph)))) + g_warning ("IDirectInputDevice8::GetProperty failed: %s", + g_win32_error_message (hresult)); + else + { + if (FAILED ((hresult = IDirectInputDevice8_SetProperty (controller->didevice8, + DIPROP_RANGE, + &range.diph)))) + g_warning ("IDirectInputDevice8::SetProperty failed: %s", + g_win32_error_message (hresult)); + } + } + + if (IsEqualGUID (&doi->guidType, &GUID_Button)) + controller->num_buttons++; + else if (IsEqualGUID (&doi->guidType, &GUID_XAxis) || + IsEqualGUID (&doi->guidType, &GUID_YAxis) || + IsEqualGUID (&doi->guidType, &GUID_ZAxis) || + IsEqualGUID (&doi->guidType, &GUID_RxAxis) || + IsEqualGUID (&doi->guidType, &GUID_RyAxis) || + IsEqualGUID (&doi->guidType, &GUID_RzAxis)) + controller->num_axes++; + else if (IsEqualGUID (&doi->guidType, &GUID_Slider)) + controller->num_sliders++; + else if (IsEqualGUID (&doi->guidType, &GUID_POV)) + controller->num_povs++; + + return DIENUM_CONTINUE; +} + +static BOOL CALLBACK +name_objects (const DIDEVICEOBJECTINSTANCEW *doi, + void *user_data) +{ + ControllerDXDInput *controller = (ControllerDXDInput *) user_data; + + if (IsEqualGUID (&doi->guidType, &GUID_Button)) + { + controller->event_names[controller->bei] = g_strdup_printf ("button-%d", controller->bi); + controller->event_blurbs[controller->bei] = g_strdup_printf (_("Button %d"), controller->bi); + controller->bei++; + controller->event_names[controller->bei] = g_strdup_printf ("button-%d-press", controller->bi); + controller->event_blurbs[controller->bei] = g_strdup_printf (_("Button %d Press"), controller->bi); + controller->bei++; + controller->event_names[controller->bei] = g_strdup_printf ("button-%d-release", controller->bi); + controller->event_blurbs[controller->bei] = g_strdup_printf (_("Button %d Release"), controller->bi); + controller->bei++; + + g_assert (controller->bi < controller->num_buttons); + + controller->bi++; + } + else if (IsEqualGUID (&doi->guidType, &GUID_XAxis) || + IsEqualGUID (&doi->guidType, &GUID_YAxis) || + IsEqualGUID (&doi->guidType, &GUID_ZAxis) || + IsEqualGUID (&doi->guidType, &GUID_RxAxis) || + IsEqualGUID (&doi->guidType, &GUID_RyAxis) || + IsEqualGUID (&doi->guidType, &GUID_RzAxis)) + { + if (IsEqualGUID (&doi->guidType, &GUID_XAxis)) + { + controller->event_names[controller->aei] = g_strdup ("x-move-left"); + controller->event_blurbs[controller->aei] = g_strdup (_("X Move Left")); + controller->aei++; + controller->event_names[controller->aei] = g_strdup ("x-move-right"); + controller->event_blurbs[controller->aei] = g_strdup (_("X Move Right")); + controller->aei++; + } + else if (IsEqualGUID (&doi->guidType, &GUID_YAxis)) + { + controller->event_names[controller->aei] = g_strdup ("y-move-away"); + controller->event_blurbs[controller->aei] = g_strdup (_("Y Move Away")); + controller->aei++; + controller->event_names[controller->aei] = g_strdup ("y-move-near"); + controller->event_blurbs[controller->aei] = g_strdup (_("Y Move Near")); + controller->aei++; + } + else if (IsEqualGUID (&doi->guidType, &GUID_ZAxis)) + { + controller->event_names[controller->aei] = g_strdup ("z-move-up"); + controller->event_blurbs[controller->aei] = g_strdup (_("Z Move Up")); + controller->aei++; + controller->event_names[controller->aei] = g_strdup ("z-move-down"); + controller->event_blurbs[controller->aei] = g_strdup (_("Z Move Down")); + controller->aei++; + } + else if (IsEqualGUID (&doi->guidType, &GUID_RxAxis)) + { + controller->event_names[controller->aei] = g_strdup ("x-axis-tilt-away"); + controller->event_blurbs[controller->aei] = g_strdup (_("X Axis Tilt Away")); + controller->aei++; + controller->event_names[controller->aei] = g_strdup ("x-axis-tilt-near"); + controller->event_blurbs[controller->aei] = g_strdup (_("X Axis Tilt Near")); + controller->aei++; + } + else if (IsEqualGUID (&doi->guidType, &GUID_RyAxis)) + { + controller->event_names[controller->aei] = g_strdup ("y-axis-tilt-right"); + controller->event_blurbs[controller->aei] = g_strdup (_("Y Axis Tilt Right")); + controller->aei++; + controller->event_names[controller->aei] = g_strdup ("y-axis-tilt-left"); + controller->event_blurbs[controller->aei] = g_strdup (_("Y Axis Tilt Left")); + controller->aei++; + } + else if (IsEqualGUID (&doi->guidType, &GUID_RzAxis)) + { + controller->event_names[controller->aei] = g_strdup ("z-axis-turn-left"); + controller->event_blurbs[controller->aei] = g_strdup (_("Z Axis Turn Left")); + controller->aei++; + controller->event_names[controller->aei] = g_strdup ("z-axis-turn-right"); + controller->event_blurbs[controller->aei] = g_strdup (_("Z Axis Turn Right")); + controller->aei++; + } + + g_assert (controller->ai < controller->num_axes); + + controller->ai++; + } + else if (IsEqualGUID (&doi->guidType, &GUID_Slider)) + { + controller->event_names[controller->sei] = g_strdup_printf ("slider-%d-increase", controller->si); + controller->event_blurbs[controller->sei] = g_strdup_printf (_("Slider %d Increase"), controller->si); + controller->sei++; + controller->event_names[controller->sei] = g_strdup_printf ("slider-%d-decrease", controller->si); + controller->event_blurbs[controller->sei] = g_strdup_printf (_("Slider %d Decrease"), controller->si); + controller->sei++; + + g_assert (controller->si < controller->num_sliders); + + controller->si++; + } + else if (IsEqualGUID (&doi->guidType, &GUID_POV)) + { + controller->event_names[controller->pei] = g_strdup_printf ("pov-%d-x-view", controller->pi); + controller->event_blurbs[controller->pei] = g_strdup_printf (_("POV %d X View"), controller->pi); + controller->pei++; + controller->event_names[controller->pei] = g_strdup_printf ("pov-%d-y-view", controller->pi); + controller->event_blurbs[controller->pei] = g_strdup_printf (_("POV %d Y View"), controller->pi); + controller->pei++; + controller->event_names[controller->pei] = g_strdup_printf ("pov-%d-x-return", controller->pi); + controller->event_blurbs[controller->pei] = g_strdup_printf (_("POV %d Return"), controller->pi); + controller->pei++; + + g_assert (controller->pi < controller->num_povs); + + controller->pi++; + } + + return DIENUM_CONTINUE; +} + +static gboolean +dx_dinput_get_device_info (ControllerDXDInput *controller, + GError **error) +{ + HRESULT hresult; + + controller->num_buttons = + controller->num_axes = + controller->num_sliders = + controller->num_povs = 0; + + if (FAILED ((hresult = IDirectInputDevice8_EnumObjects (controller->didevice8, + count_objects, + controller, + DIDFT_AXIS| + DIDFT_BUTTON| + DIDFT_POV| + DIDFT_PSHBUTTON| + DIDFT_RELAXIS| + DIDFT_TGLBUTTON)))) + { + g_set_error (error, GIMP_MODULE_ERROR, GIMP_MODULE_FAILED, + "IDirectInputDevice8::EnumObjects failed: %s", + g_win32_error_message (hresult)); + return FALSE; + } + + controller->num_button_events = controller->num_buttons*NUM_EVENTS_PER_BUTTON; + controller->num_axis_events = controller->num_axes*NUM_EVENTS_PER_AXIS; + controller->num_slider_events = controller->num_sliders*NUM_EVENTS_PER_SLIDER; + controller->num_pov_events = controller->num_povs*NUM_EVENTS_PER_POV; + + controller->num_events = + controller->num_button_events + + controller->num_axis_events + + controller->num_slider_events + + controller->num_pov_events; + + controller->event_names = g_new (gchar *, controller->num_events); + controller->event_blurbs = g_new (gchar *, controller->num_events); + + controller->bi = controller->ai = controller->si = controller->pi = 0; + + controller->bei = 0; + controller->aei = controller->bei + controller->num_button_events; + controller->sei = controller->aei + controller->num_axis_events; + controller->pei = controller->sei + controller->num_slider_events; + + if (FAILED ((hresult = IDirectInputDevice8_EnumObjects (controller->didevice8, + name_objects, + controller, + DIDFT_AXIS| + DIDFT_BUTTON| + DIDFT_POV| + DIDFT_PSHBUTTON| + DIDFT_RELAXIS| + DIDFT_TGLBUTTON)))) + { + g_free (controller->event_names); + g_free (controller->event_blurbs); + + g_set_error (error, GIMP_MODULE_ERROR, GIMP_MODULE_FAILED, + "IDirectInputDevice8::EnumObjects failed: %s", + g_win32_error_message (hresult)); + return FALSE; + } + + + g_assert (controller->bei == controller->num_button_events); + g_assert (controller->aei == controller->bei + controller->num_axis_events); + g_assert (controller->sei == controller->aei + controller->num_slider_events); + g_assert (controller->pei == controller->sei + controller->num_pov_events); + + return TRUE; +} + + +static void +dx_dinput_device_changed (ControllerDXDInput *controller, + const gchar *guid) +{ + if (controller->guid && strcmp (guid, controller->guid) == 0) + { + dx_dinput_set_device (controller, guid); + g_object_notify (G_OBJECT (controller), "device"); + } +} + +static gboolean +dx_dinput_event_prepare (GSource *source, + gint *timeout) +{ + *timeout = -1; + + return FALSE; +} + +static gboolean +dx_dinput_event_check (GSource *source) +{ + DXDInputSource *input = (DXDInputSource *) source; + + if (WaitForSingleObject (input->controller->event, 0) == WAIT_OBJECT_0) + { + ResetEvent (input->controller->event); + return TRUE; + } + + return FALSE; +} + +static gboolean +dx_dinput_event_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + ControllerDXDInput * const input = ((DXDInputSource *) source)->controller; + GimpController *controller = &input->parent_instance; + const DIDATAFORMAT * const format = input->format; + const DIOBJECTDATAFORMAT *rgodf = format->rgodf; + guchar *data; + gint i; + GimpControllerEvent cevent = { 0, }; + + data = g_alloca (format->dwDataSize); + + if (FAILED (IDirectInputDevice8_GetDeviceState (input->didevice8, + format->dwDataSize, + data))) + { + return TRUE; + } + + g_object_ref (controller); + + for (i = 0; i < input->num_buttons; i++) + { + if (input->prevdata[rgodf->dwOfs] != data[rgodf->dwOfs]) + { + if (data[rgodf->dwOfs] & 0x80) + { + /* Click event, compatibility with Linux Input */ + cevent.any.type = GIMP_CONTROLLER_EVENT_TRIGGER; + cevent.any.source = controller; + cevent.any.event_id = i*NUM_EVENTS_PER_BUTTON; + gimp_controller_event (controller, &cevent); + + /* Press event */ + cevent.any.event_id = i*NUM_EVENTS_PER_BUTTON + 1; + gimp_controller_event (controller, &cevent); + } + else + { + /* Release event */ + cevent.any.type = GIMP_CONTROLLER_EVENT_TRIGGER; + cevent.any.source = controller; + cevent.any.event_id = i*NUM_EVENTS_PER_BUTTON + 2; + gimp_controller_event (controller, &cevent); + } + } + rgodf++; + } + + for (i = 0; i < input->num_axes; i++) + { + LONG *prev = (LONG *)(input->prevdata+rgodf->dwOfs); + LONG *curr = (LONG *)(data+rgodf->dwOfs); + + if (ABS (*prev - *curr) > 1) + { + cevent.any.type = GIMP_CONTROLLER_EVENT_VALUE; + cevent.any.source = controller; + cevent.any.event_id = + input->num_button_events + + i*NUM_EVENTS_PER_AXIS; + g_value_init (&cevent.value.value, G_TYPE_DOUBLE); + if (*curr - *prev < 0) + { + g_value_set_double (&cevent.value.value, *prev - *curr); + } + else + { + cevent.any.event_id++; + g_value_set_double (&cevent.value.value, *curr - *prev); + } + gimp_controller_event (controller, &cevent); + g_value_unset (&cevent.value.value); + } + else + *curr = *prev; + rgodf++; + } + + for (i = 0; i < input->num_sliders; i++) + { + LONG *prev = (LONG *)(input->prevdata+rgodf->dwOfs); + LONG *curr = (LONG *)(data+rgodf->dwOfs); + + if (ABS (*prev - *curr) > 1) + { + cevent.any.type = GIMP_CONTROLLER_EVENT_VALUE; + cevent.any.source = controller; + cevent.any.event_id = + input->num_button_events + + input->num_axis_events + + i*NUM_EVENTS_PER_SLIDER; + g_value_init (&cevent.value.value, G_TYPE_DOUBLE); + if (*curr - *prev < 0) + { + g_value_set_double (&cevent.value.value, *prev - *curr); + } + else + { + cevent.any.event_id++; + g_value_set_double (&cevent.value.value, *curr - *prev); + } + gimp_controller_event (controller, &cevent); + g_value_unset (&cevent.value.value); + } + else + *curr = *prev; + rgodf++; + } + + for (i = 0; i < input->num_povs; i++) + { + LONG prev = *((LONG *)(input->prevdata+rgodf->dwOfs)); + LONG curr = *((LONG *)(data+rgodf->dwOfs)); + double prevx, prevy; + double currx, curry; + + if (prev != curr) + { + if (prev == -1) + { + prevx = 0.; + prevy = 0.; + } + else + { + prevx = sin (prev/36000.*2.*G_PI); + prevy = cos (prev/36000.*2.*G_PI); + } + if (curr == -1) + { + currx = 0.; + curry = 0.; + } + else + { + currx = sin (curr/36000.*2.*G_PI); + curry = cos (curr/36000.*2.*G_PI); + } + + cevent.any.type = GIMP_CONTROLLER_EVENT_VALUE; + cevent.any.source = controller; + cevent.any.event_id = + input->num_button_events + + input->num_axis_events + + input->num_slider_events + + i*NUM_EVENTS_PER_POV; + g_value_init (&cevent.value.value, G_TYPE_DOUBLE); + g_value_set_double (&cevent.value.value, currx - prevx); + gimp_controller_event (controller, &cevent); + cevent.any.event_id++; + g_value_set_double (&cevent.value.value, curry - prevy); + gimp_controller_event (controller, &cevent); + g_value_unset (&cevent.value.value); + if (curr == -1) + { + cevent.any.type = GIMP_CONTROLLER_EVENT_TRIGGER; + cevent.any.event_id++; + gimp_controller_event (controller, &cevent); + } + } + rgodf++; + } + + g_assert (rgodf == format->rgodf + format->dwNumObjs); + + memmove (input->prevdata, data, format->dwDataSize); + + g_object_unref (controller); + + return TRUE; +} + +static GSourceFuncs dx_dinput_event_funcs = { + dx_dinput_event_prepare, + dx_dinput_event_check, + dx_dinput_event_dispatch, + NULL +}; + + +static void +dump_data_format (const DIDATAFORMAT *format) +{ +#ifdef GIMP_UNSTABLE + gint i; + + g_print ("dwSize: %ld\n", format->dwSize); + g_print ("dwObjSize: %ld\n", format->dwObjSize); + g_print ("dwFlags: "); + if (format->dwFlags == DIDF_ABSAXIS) + g_print ("DIDF_ABSAXIS"); + else if (format->dwFlags == DIDF_RELAXIS) + g_print ("DIDF_RELAXIS"); + else + g_print ("%#lx", format->dwFlags); + g_print ("\n"); + g_print ("dwDataSize: %ld\n", format->dwDataSize); + g_print ("dwNumObjs: %ld\n", format->dwNumObjs); + + for (i = 0; i < format->dwNumObjs; i++) + { + const DIOBJECTDATAFORMAT *oformat = (DIOBJECTDATAFORMAT *) (((char *) format->rgodf) + i*format->dwObjSize); + unsigned char *guid; + + g_print ("Object %d:\n", i); + if (oformat->pguid == NULL) + g_print (" pguid: NULL\n"); + else + { + UuidToString (oformat->pguid, &guid); + g_print (" pguid: %s\n", guid); + RpcStringFree (&guid); + } + + g_print (" dwOfs: %ld\n", oformat->dwOfs); + g_print (" dwType: "); + switch (DIDFT_GETTYPE (oformat->dwType)) + { +#define CASE(x) case DIDFT_##x: g_print ("DIDFT_"#x); break + CASE (RELAXIS); + CASE (ABSAXIS); + CASE (AXIS); + CASE (PSHBUTTON); + CASE (TGLBUTTON); + CASE (BUTTON); + CASE (POV); + CASE (COLLECTION); + CASE (NODATA); +#undef CASE + default: g_print ("%#x", DIDFT_GETTYPE (oformat->dwType)); + } + g_print (" "); + if (DIDFT_GETINSTANCE (oformat->dwType) == DIDFT_GETINSTANCE (DIDFT_ANYINSTANCE)) + g_print ("ANYINSTANCE"); + else + g_print ("#%d", DIDFT_GETINSTANCE (oformat->dwType)); +#define BIT(x) if (oformat->dwType & DIDFT_##x) g_print (" "#x) + BIT (FFACTUATOR); + BIT (FFEFFECTTRIGGER); + BIT (OUTPUT); + BIT (VENDORDEFINED); + BIT (ALIAS); + BIT (OPTIONAL); +#undef BIT + g_print ("\n"); + g_print (" dwFlags:"); + switch (oformat->dwFlags & DIDOI_ASPECTACCEL) + { + case DIDOI_ASPECTPOSITION: g_print (" DIDOI_ASPECTPOSITION"); break; + case DIDOI_ASPECTVELOCITY: g_print (" DIDOI_ASPECTVELOCITY"); break; + case DIDOI_ASPECTACCEL: g_print (" DIDOI_ASPECTACCEL"); break; + } + if (oformat->dwFlags & DIDOI_ASPECTFORCE) + g_print (" DIDOI_ASPECTFORCE"); + g_print ("\n"); + } +#endif +} + +static gboolean +dx_dinput_setup_events (ControllerDXDInput *controller, + GError **error) +{ + HRESULT hresult; + DIPROPDWORD dword; + gint i, k; + DXDInputSource *source; + + if ((controller->event = CreateEvent (NULL, TRUE, FALSE, NULL)) == NULL) + { + g_set_error (error, GIMP_MODULE_ERROR, GIMP_MODULE_FAILED, + "CreateEvent failed: %s", + g_win32_error_message (GetLastError ())); + return FALSE; + } + + controller->format = g_new (DIDATAFORMAT, 1); + controller->format->dwSize = sizeof (DIDATAFORMAT); + controller->format->dwObjSize = sizeof (DIOBJECTDATAFORMAT); + + dword.diph.dwSize = sizeof (DIPROPDWORD); + dword.diph.dwHeaderSize = sizeof (DIPROPHEADER); + dword.diph.dwObj = 0; + dword.diph.dwHow = DIPH_DEVICE; + + /* Get the axis mode so we can use the same in the format */ + if (FAILED ((hresult = IDirectInputDevice8_GetProperty (controller->didevice8, + DIPROP_AXISMODE, + &dword.diph)))) + { + g_set_error (error, GIMP_MODULE_ERROR, GIMP_MODULE_FAILED, + "IDirectInputDevice8::GetParameters failed: %s", + g_win32_error_message (hresult)); + goto fail0; + } + + controller->format->dwFlags = dword.dwData + 1; + + controller->format->dwNumObjs = + controller->num_buttons + + controller->num_axes + + controller->num_sliders + + controller->num_povs; + + controller->format->rgodf = g_new (DIOBJECTDATAFORMAT, controller->format->dwNumObjs); + + k = 0; + controller->format->dwDataSize = 0; + + for (i = 0; i < controller->num_buttons; i++) + { + controller->format->rgodf[k].pguid = NULL; + controller->format->rgodf[k].dwOfs = controller->format->dwDataSize; + controller->format->rgodf[k].dwType = DIDFT_BUTTON | DIDFT_MAKEINSTANCE (i); + controller->format->rgodf[k].dwFlags = 0; + controller->format->dwDataSize += 1; + k++; + } + + controller->format->dwDataSize = 4*((controller->format->dwDataSize + 3)/4); + + for (i = 0; i < controller->num_axes; i++) + { + controller->format->rgodf[k].pguid = NULL; + controller->format->rgodf[k].dwOfs = controller->format->dwDataSize; + controller->format->rgodf[k].dwType = DIDFT_AXIS | DIDFT_MAKEINSTANCE (i); + controller->format->rgodf[k].dwFlags = DIDOI_ASPECTPOSITION; + controller->format->dwDataSize += 4; + k++; + } + + for (i = 0; i < controller->num_sliders; i++) + { + controller->format->rgodf[k].pguid = NULL; + controller->format->rgodf[k].dwOfs = controller->format->dwDataSize; + controller->format->rgodf[k].dwType = DIDFT_AXIS | DIDFT_MAKEINSTANCE (i); + controller->format->rgodf[k].dwFlags = DIDOI_ASPECTPOSITION; + controller->format->dwDataSize += 4; + k++; + } + + for (i = 0; i < controller->num_povs; i++) + { + controller->format->rgodf[k].pguid = NULL; + controller->format->rgodf[k].dwOfs = controller->format->dwDataSize; + controller->format->rgodf[k].dwType = DIDFT_POV | DIDFT_MAKEINSTANCE (i); + controller->format->rgodf[k].dwFlags = 0; + controller->format->dwDataSize += 4; + k++; + } + + g_assert (k == controller->format->dwNumObjs); + + controller->format->dwDataSize = 4*((controller->format->dwDataSize + 3)/4); + controller->prevdata = g_malloc (controller->format->dwDataSize); + + dump_data_format (controller->format); + + if (FAILED ((hresult = IDirectInputDevice8_SetDataFormat (controller->didevice8, + controller->format)))) + { + g_set_error (error, GIMP_MODULE_ERROR, GIMP_MODULE_FAILED, + "IDirectInputDevice8::SetDataFormat failed: %s", + g_win32_error_message (hresult)); + goto fail1; + } + + if (FAILED ((hresult = IDirectInputDevice8_SetEventNotification (controller->didevice8, + controller->event)))) + { + g_set_error (error, GIMP_MODULE_ERROR, GIMP_MODULE_FAILED, + "IDirectInputDevice8::SetEventNotification failed: %s", + g_win32_error_message (hresult)); + goto fail2; + } + + if (FAILED ((hresult = IDirectInputDevice8_Acquire (controller->didevice8)))) + { + g_set_error (error, GIMP_MODULE_ERROR, GIMP_MODULE_FAILED, + "IDirectInputDevice8::Acquire failed: %s", + g_win32_error_message (hresult)); + goto fail2; + } + + if (FAILED ((hresult = IDirectInputDevice8_GetDeviceState (controller->didevice8, + controller->format->dwDataSize, + controller->prevdata)))) + { + g_set_error (error, GIMP_MODULE_ERROR, GIMP_MODULE_FAILED, + "IDirectInputDevice8::GetDeviceState failed: %s", + g_win32_error_message (hresult)); + goto fail2; + } + + source = (DXDInputSource *) g_source_new (&dx_dinput_event_funcs, + sizeof (DXDInputSource)); + source->controller = controller; + controller->source = (GSource *) source; + + controller->pollfd = g_new (GPollFD, 1); + + controller->pollfd->fd = (int) controller->event; + controller->pollfd->events = G_IO_IN; + + g_source_add_poll (&source->source, controller->pollfd); + g_source_attach (&source->source, NULL); + + return TRUE; + + fail2: + IDirectInputDevice8_SetEventNotification (controller->didevice8, NULL); + fail1: + g_free (controller->format->rgodf); + g_free (controller->format); + controller->format = NULL; + g_free (controller->prevdata); + controller->prevdata = NULL; + fail0: + CloseHandle (controller->event); + controller->event = 0; + + return FALSE; +} + +static gboolean +dx_dinput_set_device (ControllerDXDInput *controller, + const gchar *guid) +{ + GError *error = NULL; + + if (controller->guid) + g_free (controller->guid); + + controller->guid = g_strdup (guid); + + g_object_set (controller, "name", _("DirectInput Events"), NULL); + + if (controller->guid && strlen (controller->guid)) + { + if (controller->store) + controller->didevice8 = + (LPDIRECTINPUTDEVICE8W) gimp_input_device_store_get_device_file (controller->store, + controller->guid); + } + else + { + g_object_set (controller, "state", _("No device configured"), NULL); + + return FALSE; + } + + if (controller->didevice8) + { + if (!dx_dinput_get_device_info (controller, &error) || + !dx_dinput_setup_events (controller, &error)) + { + g_object_set (controller, "state", error->message, NULL); + g_error_free (error); + } + } + else if (controller->store) + { + error = gimp_input_device_store_get_error (controller->store); + + if (error) + { + g_object_set (controller, "state", error->message, NULL); + g_error_free (error); + } + else + { + g_object_set (controller, "state", _("Device not available"), NULL); + } + } + + return FALSE; +} -- cgit v1.2.3