diff --git a/reactos/lib/dinput/Makefile b/reactos/lib/dinput/Makefile new file mode 100644 index 00000000000..be9c805c0ed --- /dev/null +++ b/reactos/lib/dinput/Makefile @@ -0,0 +1,9 @@ +# $Id: Makefile 11864 2004-11-29 00:15:23Z greatlrd $ + +PATH_TO_TOP = ../.. + +TARGET_TYPE = winedll + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk diff --git a/reactos/lib/dinput/Makefile.in b/reactos/lib/dinput/Makefile.in new file mode 100644 index 00000000000..1b36151b174 --- /dev/null +++ b/reactos/lib/dinput/Makefile.in @@ -0,0 +1,23 @@ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = dinput.dll +IMPORTS = ole32 user32 advapi32 kernel32 +EXTRALIBS = -ldxguid -luuid + +C_SRCS = \ + data_formats.c \ + device.c \ + dinput_main.c \ + joystick_linux.c \ + joystick_linuxinput.c \ + keyboard.c \ + mouse.c \ + regsvr.c + +RC_SRCS = version.rc + +@MAKE_DLL_RULES@ + +### Dependencies: diff --git a/reactos/lib/dinput/Makefile.ros-template b/reactos/lib/dinput/Makefile.ros-template new file mode 100644 index 00000000000..d975492e90a --- /dev/null +++ b/reactos/lib/dinput/Makefile.ros-template @@ -0,0 +1,30 @@ +# $Id: Makefile.ros-template 12238 2004-12-20 00:53:54Z greatlrd $ + +TARGET_NAME = dinput + +TARGET_BASE = $(TARGET_BASE_LIB_DINPUT) + +TARGET_OBJECTS = @C_SRCS@ + +TARGET_CFLAGS = @EXTRADEFS@ -D__REACTOS__ + +TARGET_SDKLIBS = wine.a @IMPORTS@ ole32.a wine_uuid.a ntdll.a winmm.a dxguid.a + + + +TARGET_RC_SRCS = @RC_SRCS@ +TARGET_RC_BINSRC = @RC_BINSRC@ +TARGET_RC_BINARIES = @RC_BINARIES@ + +default: all + +authors.c: +ifeq ($(HOST),mingw32-linux) + echo 'const char * const SHELL_Authors[] = { "WINE team", "ReactOS team", 0 };' > authors.c +else + echo const char * const SHELL_Authors[] = { "WINE team", "ReactOS team", 0 }; > authors.c +endif + +DEP_OBJECTS = $(TARGET_OBJECTS) + +include $(TOOLS_PATH)/depend.mk diff --git a/reactos/lib/dinput/data_formats.c b/reactos/lib/dinput/data_formats.c new file mode 100644 index 00000000000..7962a67b187 --- /dev/null +++ b/reactos/lib/dinput/data_formats.c @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2004 Robert Reif + * + * 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.1 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 + */ + +/* TODO: + * add keyboard + */ + +#include + +#include "windef.h" +#include "dinput.h" + +#define numObjects(x) (sizeof(x) / sizeof(x[0])) + +DIOBJECTDATAFORMAT dfDIJoystick[] = { + { &GUID_XAxis,DIJOFS_X,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_YAxis,DIJOFS_Y,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_ZAxis,DIJOFS_Z,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RxAxis,DIJOFS_RX,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RyAxis,DIJOFS_RY,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RzAxis,DIJOFS_RZ,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_POV,DIJOFS_POV(0),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, + { &GUID_POV,DIJOFS_POV(1),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, + { &GUID_POV,DIJOFS_POV(2),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, + { &GUID_POV,DIJOFS_POV(3),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(0),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(1),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(2),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(3),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(4),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(5),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(6),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(7),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(8),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(9),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(10),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(11),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(12),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(13),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(14),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(15),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(16),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(17),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(18),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(19),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(20),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(21),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(22),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(23),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(24),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(25),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(26),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(27),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(28),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(29),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(30),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(31),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, +}; + +const DIDATAFORMAT c_dfDIJoystick = { + sizeof(DIDATAFORMAT), + sizeof(DIOBJECTDATAFORMAT), + DIDF_ABSAXIS, + sizeof(DIJOYSTATE2), + numObjects(dfDIJoystick), + dfDIJoystick +}; + +DIOBJECTDATAFORMAT dfDIJoystick2[] = { + { &GUID_XAxis,DIJOFS_X,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_YAxis,DIJOFS_Y,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_ZAxis,DIJOFS_Z,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RxAxis,DIJOFS_RX,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RyAxis,DIJOFS_RY,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RzAxis,DIJOFS_RZ,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_POV,DIJOFS_POV(0),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, + { &GUID_POV,DIJOFS_POV(1),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, + { &GUID_POV,DIJOFS_POV(2),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, + { &GUID_POV,DIJOFS_POV(3),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(0),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(1),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(2),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(3),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(4),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(5),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(6),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(7),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(8),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(9),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(10),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(11),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(12),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(13),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(14),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(15),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(16),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(17),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(18),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(19),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(20),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(21),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(22),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(23),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(24),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(25),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(26),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(27),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(28),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(29),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(30),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(31),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(32),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(33),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(34),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(35),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(36),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(37),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(38),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(39),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(40),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(41),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(42),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(43),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(44),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(45),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(46),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(47),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(48),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(49),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(50),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(51),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(52),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(53),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(54),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(55),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(56),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(57),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(58),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(59),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(60),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(61),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(62),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(63),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(64),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(65),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(66),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(67),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(68),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(69),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(70),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(71),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(72),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(73),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(74),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(75),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(76),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(77),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(78),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(79),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(80),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(81),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(82),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(83),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(84),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(85),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(86),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(87),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(88),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(89),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(90),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(91),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(92),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(93),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(94),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(95),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(96),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(97),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(98),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(99),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(100),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(101),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(102),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(103),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(104),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(105),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(106),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(107),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(108),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(109),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(110),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(111),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(112),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(113),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(114),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(115),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(116),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(117),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(118),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(119),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(120),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(121),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(122),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(123),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(124),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(125),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(126),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(127),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { &GUID_XAxis,FIELD_OFFSET(DIJOYSTATE2,lVX),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_YAxis,FIELD_OFFSET(DIJOYSTATE2,lVY),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_ZAxis,FIELD_OFFSET(DIJOYSTATE2,lVZ),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RxAxis,FIELD_OFFSET(DIJOYSTATE2,lVRx),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RyAxis,FIELD_OFFSET(DIJOYSTATE2,lVRy),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RzAxis,FIELD_OFFSET(DIJOYSTATE2,lVRz),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglVSlider[0]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglVSlider[1]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_XAxis,FIELD_OFFSET(DIJOYSTATE2,lAX),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_YAxis,FIELD_OFFSET(DIJOYSTATE2,lAY),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_ZAxis,FIELD_OFFSET(DIJOYSTATE2,lAZ),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RxAxis,FIELD_OFFSET(DIJOYSTATE2,lARx),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RyAxis,FIELD_OFFSET(DIJOYSTATE2,lARy),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RzAxis,FIELD_OFFSET(DIJOYSTATE2,lARz),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglASlider[0]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglASlider[1]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_XAxis,FIELD_OFFSET(DIJOYSTATE2,lFX),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_YAxis,FIELD_OFFSET(DIJOYSTATE2,lFY),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_ZAxis,FIELD_OFFSET(DIJOYSTATE2,lFZ),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RxAxis,FIELD_OFFSET(DIJOYSTATE2,lFRx),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RyAxis,FIELD_OFFSET(DIJOYSTATE2,lFRy),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RzAxis,FIELD_OFFSET(DIJOYSTATE2,lFRz),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglFSlider[0]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglFSlider[1]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, +}; + +const DIDATAFORMAT c_dfDIJoystick2 = { + sizeof(DIDATAFORMAT), + sizeof(DIOBJECTDATAFORMAT), + DIDF_ABSAXIS, + sizeof(DIJOYSTATE2), + numObjects(dfDIJoystick2), + dfDIJoystick2 +}; + +DIOBJECTDATAFORMAT dfDIMouse[] = { + { &GUID_XAxis, DIMOFS_X, DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, + { &GUID_YAxis, DIMOFS_Y, DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, + { &GUID_ZAxis, DIMOFS_Z, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, + { &GUID_Button, DIMOFS_BUTTON0, DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON1, DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON2, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON3, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 } +}; + +const DIDATAFORMAT c_dfDIMouse = { + sizeof(DIDATAFORMAT), + sizeof(DIOBJECTDATAFORMAT), + DIDF_RELAXIS, + sizeof(DIMOUSESTATE), + numObjects(dfDIMouse), + dfDIMouse +}; + +DIOBJECTDATAFORMAT dfDIMouse2[] = { + { &GUID_XAxis, DIMOFS_X, DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, + { &GUID_YAxis, DIMOFS_Y, DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, + { &GUID_ZAxis, DIMOFS_Z, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, + { &GUID_Button, DIMOFS_BUTTON0, DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON1, DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON2, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON3, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON4, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON5, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON6, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON7, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 } +}; + +const DIDATAFORMAT c_dfDIMouse2 = { + sizeof(DIDATAFORMAT), + sizeof(DIOBJECTDATAFORMAT), + DIDF_RELAXIS, + sizeof(DIMOUSESTATE2), + numObjects(dfDIMouse2), + dfDIMouse2 +}; diff --git a/reactos/lib/dinput/device.c b/reactos/lib/dinput/device.c new file mode 100644 index 00000000000..1c443da51ba --- /dev/null +++ b/reactos/lib/dinput/device.c @@ -0,0 +1,884 @@ +/* DirectInput Device + * + * Copyright 1998 Marcus Meissner + * Copyright 1998,1999 Lionel Ulmer + * + * + * 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.1 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 + */ + +/* This file contains all the Device specific functions that can be used as stubs + by real device implementations. + + It also contains all the helper functions. +*/ +#include "config.h" + +#include +#include +#include "wine/debug.h" +#include "wine/unicode.h" +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "dinput.h" +#include "device_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dinput); + +/****************************************************************************** + * Various debugging tools + */ +void _dump_cooperativelevel_DI(DWORD dwFlags) { + if (TRACE_ON(dinput)) { + unsigned int i; + static const struct { + DWORD mask; + const char *name; + } flags[] = { +#define FE(x) { x, #x} + FE(DISCL_BACKGROUND), + FE(DISCL_EXCLUSIVE), + FE(DISCL_FOREGROUND), + FE(DISCL_NONEXCLUSIVE) +#undef FE + }; + for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) + if (flags[i].mask & dwFlags) + DPRINTF("%s ",flags[i].name); + DPRINTF("\n"); + } +} + +void _dump_EnumObjects_flags(DWORD dwFlags) { + if (TRACE_ON(dinput)) { + unsigned int i; + DWORD type, instance; + static const struct { + DWORD mask; + const char *name; + } flags[] = { +#define FE(x) { x, #x} + FE(DIDFT_RELAXIS), + FE(DIDFT_ABSAXIS), + FE(DIDFT_PSHBUTTON), + FE(DIDFT_TGLBUTTON), + FE(DIDFT_POV), + FE(DIDFT_COLLECTION), + FE(DIDFT_NODATA), + FE(DIDFT_FFACTUATOR), + FE(DIDFT_FFEFFECTTRIGGER), + FE(DIDFT_OUTPUT) +#undef FE + }; + type = (dwFlags & 0xFF0000FF); + instance = ((dwFlags >> 8) & 0xFFFF); + DPRINTF("Type:"); + if (type == DIDFT_ALL) { + DPRINTF(" DIDFT_ALL"); + } else { + for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) { + if (flags[i].mask & type) { + type &= ~flags[i].mask; + DPRINTF(" %s",flags[i].name); + } + } + if (type) { + DPRINTF(" (unhandled: %08lx)", type); + } + } + DPRINTF(" / Instance: "); + if (instance == ((DIDFT_ANYINSTANCE >> 8) & 0xFFFF)) { + DPRINTF("DIDFT_ANYINSTANCE"); + } else { + DPRINTF("%3ld", instance); + } + } +} + +void _dump_DIPROPHEADER(LPCDIPROPHEADER diph) { + if (TRACE_ON(dinput)) { + DPRINTF(" - dwObj = 0x%08lx\n", diph->dwObj); + DPRINTF(" - dwHow = %s\n", + ((diph->dwHow == DIPH_DEVICE) ? "DIPH_DEVICE" : + ((diph->dwHow == DIPH_BYOFFSET) ? "DIPH_BYOFFSET" : + ((diph->dwHow == DIPH_BYID)) ? "DIPH_BYID" : "unknown"))); + } +} + +void _dump_OBJECTINSTANCEA(DIDEVICEOBJECTINSTANCEA *ddoi) { + if (TRACE_ON(dinput)) { + DPRINTF(" - enumerating : %s ('%s') - %2ld - 0x%08lx - %s\n", + debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, ddoi->tszName); + } +} + +void _dump_OBJECTINSTANCEW(DIDEVICEOBJECTINSTANCEW *ddoi) { + if (TRACE_ON(dinput)) { + DPRINTF(" - enumerating : %s ('%s'), - %2ld - 0x%08lx - %s\n", + debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, debugstr_w(ddoi->tszName)); + } +} + +/* This function is a helper to convert a GUID into any possible DInput GUID out there */ +const char *_dump_dinput_GUID(const GUID *guid) { + unsigned int i; + static const struct { + const GUID *guid; + const char *name; + } guids[] = { +#define FE(x) { &x, #x} + FE(GUID_XAxis), + FE(GUID_YAxis), + FE(GUID_ZAxis), + FE(GUID_RxAxis), + FE(GUID_RyAxis), + FE(GUID_RzAxis), + FE(GUID_Slider), + FE(GUID_Button), + FE(GUID_Key), + FE(GUID_POV), + FE(GUID_Unknown), + FE(GUID_SysMouse), + FE(GUID_SysKeyboard), + FE(GUID_Joystick), + FE(GUID_ConstantForce), + FE(GUID_RampForce), + FE(GUID_Square), + FE(GUID_Sine), + FE(GUID_Triangle), + FE(GUID_SawtoothUp), + FE(GUID_SawtoothDown), + FE(GUID_Spring), + FE(GUID_Damper), + FE(GUID_Inertia), + FE(GUID_Friction), + FE(GUID_CustomForce) +#undef FE + }; + if (guid == NULL) + return "null GUID"; + for (i = 0; i < (sizeof(guids) / sizeof(guids[0])); i++) { + if (IsEqualGUID(guids[i].guid, guid)) { + return guids[i].name; + } + } + return "Unknown GUID"; +} + +void _dump_DIDATAFORMAT(const DIDATAFORMAT *df) { + unsigned int i; + + TRACE("Dumping DIDATAFORMAT structure:\n"); + TRACE(" - dwSize: %ld\n", df->dwSize); + if (df->dwSize != sizeof(DIDATAFORMAT)) { + WARN("Non-standard DIDATAFORMAT structure size (%ld instead of %d).\n", df->dwSize, sizeof(DIDATAFORMAT)); + } + TRACE(" - dwObjsize: %ld\n", df->dwObjSize); + if (df->dwObjSize != sizeof(DIOBJECTDATAFORMAT)) { + WARN("Non-standard DIOBJECTDATAFORMAT structure size (%ld instead of %d).\n", df->dwObjSize, sizeof(DIOBJECTDATAFORMAT)); + } + TRACE(" - dwFlags: 0x%08lx (", df->dwFlags); + switch (df->dwFlags) { + case DIDF_ABSAXIS: TRACE("DIDF_ABSAXIS"); break; + case DIDF_RELAXIS: TRACE("DIDF_RELAXIS"); break; + default: TRACE("unknown"); break; + } + TRACE(")\n"); + TRACE(" - dwDataSize: %ld\n", df->dwDataSize); + TRACE(" - dwNumObjs: %ld\n", df->dwNumObjs); + + for (i = 0; i < df->dwNumObjs; i++) { + TRACE(" - Object %d:\n", i); + TRACE(" * GUID: %s ('%s')\n", debugstr_guid(df->rgodf[i].pguid), _dump_dinput_GUID(df->rgodf[i].pguid)); + TRACE(" * dwOfs: %ld\n", df->rgodf[i].dwOfs); + TRACE(" * dwType: 0x%08lx\n", df->rgodf[i].dwType); + TRACE(" "); _dump_EnumObjects_flags(df->rgodf[i].dwType); TRACE("\n"); + TRACE(" * dwFlags: 0x%08lx\n", df->rgodf[i].dwFlags); + } +} + +/* Conversion between internal data buffer and external data buffer */ +void fill_DataFormat(void *out, const void *in, DataFormat *df) { + int i; + char *in_c = (char *) in; + char *out_c = (char *) out; + + if (df->dt == NULL) { + /* This means that the app uses Wine's internal data format */ + memcpy(out, in, df->internal_format_size); + } else { + for (i = 0; i < df->size; i++) { + if (df->dt[i].offset_in >= 0) { + switch (df->dt[i].size) { + case 1: + TRACE("Copying (c) to %d from %d (value %d)\n", + df->dt[i].offset_out, df->dt[i].offset_in, *((char *) (in_c + df->dt[i].offset_in))); + *((char *) (out_c + df->dt[i].offset_out)) = *((char *) (in_c + df->dt[i].offset_in)); + break; + + case 2: + TRACE("Copying (s) to %d from %d (value %d)\n", + df->dt[i].offset_out, df->dt[i].offset_in, *((short *) (in_c + df->dt[i].offset_in))); + *((short *) (out_c + df->dt[i].offset_out)) = *((short *) (in_c + df->dt[i].offset_in)); + break; + + case 4: + TRACE("Copying (i) to %d from %d (value %d)\n", + df->dt[i].offset_out, df->dt[i].offset_in, *((int *) (in_c + df->dt[i].offset_in))); + *((int *) (out_c + df->dt[i].offset_out)) = *((int *) (in_c + df->dt[i].offset_in)); + break; + + default: + memcpy((out_c + df->dt[i].offset_out), (in_c + df->dt[i].offset_in), df->dt[i].size); + break; + } + } else { + switch (df->dt[i].size) { + case 1: + TRACE("Copying (c) to %d default value %d\n", + df->dt[i].offset_out, df->dt[i].value); + *((char *) (out_c + df->dt[i].offset_out)) = (char) df->dt[i].value; + break; + + case 2: + TRACE("Copying (s) to %d default value %d\n", + df->dt[i].offset_out, df->dt[i].value); + *((short *) (out_c + df->dt[i].offset_out)) = (short) df->dt[i].value; + break; + + case 4: + TRACE("Copying (i) to %d default value %d\n", + df->dt[i].offset_out, df->dt[i].value); + *((int *) (out_c + df->dt[i].offset_out)) = (int) df->dt[i].value; + break; + + default: + memset((out_c + df->dt[i].offset_out), df->dt[i].size, 0); + break; + } + } + } + } +} + +void release_DataFormat(DataFormat * format) +{ + TRACE("Deleting DataTransform : \n"); + + HeapFree(GetProcessHeap(), 0, format->dt); +} + +DataFormat *create_DataFormat(const DIDATAFORMAT *wine_format, LPCDIDATAFORMAT asked_format, int *offset) { + DataFormat *ret; + DataTransform *dt; + unsigned int i, j; + int same = 1; + int *done; + int index = 0; + DWORD next = 0; + + ret = (DataFormat *) HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat)); + + done = (int *) HeapAlloc(GetProcessHeap(), 0, sizeof(int) * asked_format->dwNumObjs); + memset(done, 0, sizeof(int) * asked_format->dwNumObjs); + + dt = (DataTransform *) HeapAlloc(GetProcessHeap(), 0, asked_format->dwNumObjs * sizeof(DataTransform)); + + TRACE("Creating DataTransform : \n"); + + for (i = 0; i < wine_format->dwNumObjs; i++) { + offset[i] = -1; + + for (j = 0; j < asked_format->dwNumObjs; j++) { + if (done[j] == 1) + continue; + + if (/* Check if the application either requests any GUID and if not, it if matches + * the GUID of the Wine object. + */ + ((asked_format->rgodf[j].pguid == NULL) || + (IsEqualGUID(wine_format->rgodf[i].pguid, asked_format->rgodf[j].pguid))) + && + (/* Then check if it accepts any instance id, and if not, if it matches Wine's + * instance id. + */ + ((asked_format->rgodf[j].dwType & 0x00FFFF00) == DIDFT_ANYINSTANCE) || + (DIDFT_GETINSTANCE(wine_format->rgodf[i].dwType) == DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType)))) { + + done[j] = 1; + + TRACE("Matching : \n"); + TRACE(" - Asked (%d) :\n", j); + TRACE(" * GUID: %s ('%s')\n", + debugstr_guid(asked_format->rgodf[j].pguid), + _dump_dinput_GUID(asked_format->rgodf[j].pguid)); + TRACE(" * Offset: %3ld\n", asked_format->rgodf[j].dwOfs); + TRACE(" * dwType: %08lx\n", asked_format->rgodf[j].dwType); + TRACE(" "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n"); + + TRACE(" - Wine (%d) :\n", j); + TRACE(" * GUID: %s ('%s')\n", + debugstr_guid(wine_format->rgodf[j].pguid), + _dump_dinput_GUID(wine_format->rgodf[j].pguid)); + TRACE(" * Offset: %3ld\n", wine_format->rgodf[j].dwOfs); + TRACE(" * dwType: %08lx\n", wine_format->rgodf[j].dwType); + TRACE(" "); _dump_EnumObjects_flags(wine_format->rgodf[j].dwType); TRACE("\n"); + + if (wine_format->rgodf[i].dwType & DIDFT_BUTTON) + dt[index].size = sizeof(BYTE); + else + dt[index].size = sizeof(DWORD); + dt[index].offset_in = wine_format ->rgodf[i].dwOfs; + if (asked_format->rgodf[j].dwOfs < next) { + WARN("bad format: dwOfs=%ld, changing to %ld\n", asked_format->rgodf[j].dwOfs, next); + dt[index].offset_out = next; + offset[i] = next; + } else { + dt[index].offset_out = asked_format->rgodf[j].dwOfs; + offset[i] = asked_format->rgodf[j].dwOfs; + } + dt[index].value = 0; + next = next + dt[index].size; + + if (wine_format->rgodf[i].dwOfs != dt[index].offset_out) + same = 0; + + index++; + break; + } + } + + if (j == asked_format->dwNumObjs) + same = 0; + } + + TRACE("Setting to default value :\n"); + for (j = 0; j < asked_format->dwNumObjs; j++) { + if (done[j] == 0) { + TRACE(" - Asked (%d) :\n", j); + TRACE(" * GUID: %s ('%s')\n", + debugstr_guid(asked_format->rgodf[j].pguid), + _dump_dinput_GUID(asked_format->rgodf[j].pguid)); + TRACE(" * Offset: %3ld\n", asked_format->rgodf[j].dwOfs); + TRACE(" * dwType: %08lx\n", asked_format->rgodf[j].dwType); + TRACE(" "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n"); + + if (asked_format->rgodf[j].dwType & DIDFT_BUTTON) + dt[index].size = sizeof(BYTE); + else + dt[index].size = sizeof(DWORD); + dt[index].offset_in = -1; + dt[index].offset_out = asked_format->rgodf[j].dwOfs; + dt[index].value = 0; + index++; + + same = 0; + } + } + + ret->internal_format_size = wine_format->dwDataSize; + ret->size = index; + if (same) { + ret->dt = NULL; + HeapFree(GetProcessHeap(), 0, dt); + } else { + ret->dt = dt; + } + + HeapFree(GetProcessHeap(), 0, done); + + return ret; +} + +BOOL DIEnumDevicesCallbackAtoW(LPCDIDEVICEOBJECTINSTANCEA lpddi, LPVOID lpvRef) { + DIDEVICEOBJECTINSTANCEW ddtmp; + device_enumobjects_AtoWcb_data* data; + + data = (device_enumobjects_AtoWcb_data*) lpvRef; + + memset(&ddtmp, 0, sizeof(DIDEVICEINSTANCEW)); + + ddtmp.dwSize = sizeof(DIDEVICEINSTANCEW); + ddtmp.guidType = lpddi->guidType; + ddtmp.dwOfs = lpddi->dwOfs; + ddtmp.dwType = lpddi->dwType; + ddtmp.dwFlags = lpddi->dwFlags; + MultiByteToWideChar(CP_ACP, 0, lpddi->tszName, -1, ddtmp.tszName, MAX_PATH); + + if (lpddi->dwSize == sizeof(DIDEVICEINSTANCEA)) { + /** + * if dwSize < sizeof(DIDEVICEINSTANCEA of DInput version >= 5) + * force feedback and other newer datas aren't available + */ + ddtmp.dwFFMaxForce = lpddi->dwFFMaxForce; + ddtmp.dwFFForceResolution = lpddi->dwFFForceResolution; + ddtmp.wCollectionNumber = lpddi->wCollectionNumber; + ddtmp.wDesignatorIndex = lpddi->wDesignatorIndex; + ddtmp.wUsagePage = lpddi->wUsagePage; + ddtmp.wUsage = lpddi->wUsage; + ddtmp.dwDimension = lpddi->dwDimension; + ddtmp.wExponent = lpddi->wExponent; + ddtmp.wReserved = lpddi->wReserved; + } + return data->lpCallBack(&ddtmp, data->lpvRef); +} + +/****************************************************************************** + * IDirectInputDeviceA + */ + +HRESULT WINAPI IDirectInputDevice2AImpl_SetDataFormat( + LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df +) { + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + + TRACE("(this=%p,%p)\n",This,df); + + _dump_DIDATAFORMAT(df); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel( + LPDIRECTINPUTDEVICE8A iface,HWND hwnd,DWORD dwflags +) { + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags); + if (TRACE_ON(dinput)) { + TRACE(" cooperative level : "); + _dump_cooperativelevel_DI(dwflags); + } + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification( + LPDIRECTINPUTDEVICE8A iface,HANDLE hnd +) { + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + FIXME("(this=%p,0x%08lx): stub\n",This,(DWORD)hnd); + return DI_OK; +} + +ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE8A iface) +{ + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + ULONG ref; + ref = InterlockedDecrement(&(This->ref)); + if (ref == 0) + HeapFree(GetProcessHeap(),0,This); + return ref; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface( + LPDIRECTINPUTDEVICE8A iface,REFIID riid,LPVOID *ppobj +) +{ + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + + TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(&IID_IUnknown,riid)) { + IDirectInputDevice2_AddRef(iface); + *ppobj = This; + return DI_OK; + } + if (IsEqualGUID(&IID_IDirectInputDeviceA,riid)) { + IDirectInputDevice2_AddRef(iface); + *ppobj = This; + return DI_OK; + } + if (IsEqualGUID(&IID_IDirectInputDevice2A,riid)) { + IDirectInputDevice2_AddRef(iface); + *ppobj = This; + return DI_OK; + } + if (IsEqualGUID(&IID_IDirectInputDevice7A,riid)) { + IDirectInputDevice7_AddRef(iface); + *ppobj = This; + return DI_OK; + } + TRACE("Unsupported interface !\n"); + return E_FAIL; +} + +HRESULT WINAPI IDirectInputDevice2WImpl_QueryInterface( + LPDIRECTINPUTDEVICE8W iface,REFIID riid,LPVOID *ppobj +) +{ + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + + TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(&IID_IUnknown,riid)) { + IDirectInputDevice2_AddRef(iface); + *ppobj = This; + return DI_OK; + } + if (IsEqualGUID(&IID_IDirectInputDeviceW,riid)) { + IDirectInputDevice2_AddRef(iface); + *ppobj = This; + return DI_OK; + } + if (IsEqualGUID(&IID_IDirectInputDevice2W,riid)) { + IDirectInputDevice2_AddRef(iface); + *ppobj = This; + return DI_OK; + } + if (IsEqualGUID(&IID_IDirectInputDevice7W,riid)) { + IDirectInputDevice7_AddRef(iface); + *ppobj = This; + return DI_OK; + } + TRACE("Unsupported interface !\n"); + return E_FAIL; +} + +ULONG WINAPI IDirectInputDevice2AImpl_AddRef( + LPDIRECTINPUTDEVICE8A iface) +{ + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + return InterlockedIncrement(&(This->ref)); +} + +HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + FIXME("(this=%p,%p,%p,%08lx): stub!\n", iface, lpCallback, lpvRef, dwFlags); + if (TRACE_ON(dinput)) { + DPRINTF(" - flags = "); + _dump_EnumObjects_flags(dwFlags); + DPRINTF("\n"); + } + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2WImpl_EnumObjects( + LPDIRECTINPUTDEVICE8W iface, + LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + FIXME("(this=%p,%p,%p,%08lx): stub!\n", iface, lpCallback, lpvRef, dwFlags); + if (TRACE_ON(dinput)) { + DPRINTF(" - flags = "); + _dump_EnumObjects_flags(dwFlags); + DPRINTF("\n"); + } + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty( + LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPDIPROPHEADER pdiph) +{ + FIXME("(this=%p,%s,%p): stub!\n", + iface, debugstr_guid(rguid), pdiph); + + if (TRACE_ON(dinput)) + _dump_DIPROPHEADER(pdiph); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEOBJECTINSTANCEA pdidoi, + DWORD dwObj, + DWORD dwHow) +{ + FIXME("(this=%p,%p,%ld,0x%08lx): stub!\n", + iface, pdidoi, dwObj, dwHow); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2WImpl_GetObjectInfo( + LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEOBJECTINSTANCEW pdidoi, + DWORD dwObj, + DWORD dwHow) +{ + FIXME("(this=%p,%p,%ld,0x%08lx): stub!\n", + iface, pdidoi, dwObj, dwHow); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEINSTANCEA pdidi) +{ + FIXME("(this=%p,%p): stub!\n", + iface, pdidi); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2WImpl_GetDeviceInfo( + LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEINSTANCEW pdidi) +{ + FIXME("(this=%p,%p): stub!\n", + iface, pdidi); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel( + LPDIRECTINPUTDEVICE8A iface, + HWND hwndOwner, + DWORD dwFlags) +{ + FIXME("(this=%p,%p,0x%08lx): stub!\n", + iface, hwndOwner, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_Initialize( + LPDIRECTINPUTDEVICE8A iface, + HINSTANCE hinst, + DWORD dwVersion, + REFGUID rguid) +{ + FIXME("(this=%p,%p,%ld,%s): stub!\n", + iface, hinst, dwVersion, debugstr_guid(rguid)); + return DI_OK; +} + +/****************************************************************************** + * IDirectInputDevice2A + */ + +HRESULT WINAPI IDirectInputDevice2AImpl_CreateEffect( + LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPCDIEFFECT lpeff, + LPDIRECTINPUTEFFECT *ppdef, + LPUNKNOWN pUnkOuter) +{ + FIXME("(this=%p,%s,%p,%p,%p): stub!\n", + iface, debugstr_guid(rguid), lpeff, ppdef, pUnkOuter); + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMEFFECTSCALLBACKA lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + FIXME("(this=%p,%p,%p,0x%08lx): stub!\n", + iface, lpCallback, lpvRef, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2WImpl_EnumEffects( + LPDIRECTINPUTDEVICE8W iface, + LPDIENUMEFFECTSCALLBACKW lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + FIXME("(this=%p,%p,%p,0x%08lx): stub!\n", + iface, lpCallback, lpvRef, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_GetEffectInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIEFFECTINFOA lpdei, + REFGUID rguid) +{ + FIXME("(this=%p,%p,%s): stub!\n", + iface, lpdei, debugstr_guid(rguid)); + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2WImpl_GetEffectInfo( + LPDIRECTINPUTDEVICE8W iface, + LPDIEFFECTINFOW lpdei, + REFGUID rguid) +{ + FIXME("(this=%p,%p,%s): stub!\n", + iface, lpdei, debugstr_guid(rguid)); + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_GetForceFeedbackState( + LPDIRECTINPUTDEVICE8A iface, + LPDWORD pdwOut) +{ + FIXME("(this=%p,%p): stub!\n", + iface, pdwOut); + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand( + LPDIRECTINPUTDEVICE8A iface, + DWORD dwFlags) +{ + FIXME("(this=%p,0x%08lx): stub!\n", + iface, dwFlags); + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + FIXME("(this=%p,%p,%p,0x%08lx): stub!\n", + iface, lpCallback, lpvRef, dwFlags); + if (lpCallback) + lpCallback(NULL, lpvRef); + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_Escape( + LPDIRECTINPUTDEVICE8A iface, + LPDIEFFESCAPE lpDIEEsc) +{ + FIXME("(this=%p,%p): stub!\n", + iface, lpDIEEsc); + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_Poll( + LPDIRECTINPUTDEVICE8A iface) +{ + /* Because wine devices do not need to be polled, just return DI_NOEFFECT */ + return DI_NOEFFECT; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_SendDeviceData( + LPDIRECTINPUTDEVICE8A iface, + DWORD cbObjectData, + LPCDIDEVICEOBJECTDATA rgdod, + LPDWORD pdwInOut, + DWORD dwFlags) +{ + FIXME("(this=%p,0x%08lx,%p,%p,0x%08lx): stub!\n", + iface, cbObjectData, rgdod, pdwInOut, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice7AImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8A iface, + LPCSTR lpszFileName, + LPDIENUMEFFECTSINFILECALLBACK pec, + LPVOID pvRef, + DWORD dwFlags) +{ + FIXME("(%p)->(%s,%p,%p,%08lx): stub !\n", iface, lpszFileName, pec, pvRef, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice7WImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8W iface, + LPCWSTR lpszFileName, + LPDIENUMEFFECTSINFILECALLBACK pec, + LPVOID pvRef, + DWORD dwFlags) +{ + FIXME("(%p)->(%s,%p,%p,%08lx): stub !\n", iface, debugstr_w(lpszFileName), pec, pvRef, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice7AImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8A iface, + LPCSTR lpszFileName, + DWORD dwEntries, + LPDIFILEEFFECT rgDiFileEft, + DWORD dwFlags) +{ + FIXME("(%p)->(%s,%08lx,%p,%08lx): stub !\n", iface, lpszFileName, dwEntries, rgDiFileEft, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice7WImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8W iface, + LPCWSTR lpszFileName, + DWORD dwEntries, + LPDIFILEEFFECT rgDiFileEft, + DWORD dwFlags) +{ + FIXME("(%p)->(%s,%08lx,%p,%08lx): stub !\n", iface, debugstr_w(lpszFileName), dwEntries, rgDiFileEft, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice8AImpl_BuildActionMap(LPDIRECTINPUTDEVICE8A iface, + LPDIACTIONFORMATA lpdiaf, + LPCSTR lpszUserName, + DWORD dwFlags) +{ + FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, lpszUserName, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice8WImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface, + LPDIACTIONFORMATW lpdiaf, + LPCWSTR lpszUserName, + DWORD dwFlags) +{ + FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice8AImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface, + LPDIACTIONFORMATA lpdiaf, + LPCSTR lpszUserName, + DWORD dwFlags) +{ + FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, lpszUserName, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice8WImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface, + LPDIACTIONFORMATW lpdiaf, + LPCWSTR lpszUserName, + DWORD dwFlags) +{ + FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice8AImpl_GetImageInfo(LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader) +{ + FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice8WImpl_GetImageInfo(LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader) +{ + FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader); + + return DI_OK; +} diff --git a/reactos/lib/dinput/device_private.h b/reactos/lib/dinput/device_private.h new file mode 100644 index 00000000000..a044af5ef16 --- /dev/null +++ b/reactos/lib/dinput/device_private.h @@ -0,0 +1,236 @@ +/* + * Copyright 2000 Lionel Ulmer + * Copyright 2000-2001 TransGaming Technologies Inc. + * + * 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.1 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 + */ + +#ifndef __WINE_DLLS_DINPUT_DINPUTDEVICE_PRIVATE_H +#define __WINE_DLLS_DINPUT_DINPUTDEVICE_PRIVATE_H + +#include + +#include "windef.h" +#include "winbase.h" +#include "dinput.h" + +/* Device implementation */ +typedef struct IDirectInputDevice2AImpl IDirectInputDevice2AImpl; +struct IDirectInputDevice2AImpl +{ + IDirectInputDevice2AVtbl *lpVtbl; + DWORD ref; + GUID guid; +}; + +/* Routines to do DataFormat / WineFormat conversions */ +typedef struct { + int size; + int offset_in; + int offset_out; + int value; +} DataTransform; + +typedef struct { + int size; + int internal_format_size; + DataTransform *dt; +} DataFormat; +extern void fill_DataFormat(void *out, const void *in, DataFormat *df) ; +extern DataFormat *create_DataFormat(const DIDATAFORMAT *wine_format, LPCDIDATAFORMAT asked_format, int *offset) ; +extern void release_DataFormat(DataFormat *df) ; + +/* Used to fill events in the queue */ +#define GEN_EVENT(offset,data,xtime,seq) \ +{ \ + /* If queue_len > 0, queuing is requested -> TRACE the event queued */ \ + if (This->queue_len > 0) { \ + int nq; \ + TRACE(" queueing %d at offset %d (queue head %d / size %d)\n", \ + (int) (data), (int) (offset), \ + (int) (This->queue_head), (int) (This->queue_len)); \ + \ + nq = This->queue_head+1; \ + while (nq >= This->queue_len) nq -= This->queue_len; \ + if ((offset >= 0) && (nq != This->queue_tail)) { \ + This->data_queue[This->queue_head].dwOfs = offset; \ + This->data_queue[This->queue_head].dwData = data; \ + This->data_queue[This->queue_head].dwTimeStamp = xtime; \ + This->data_queue[This->queue_head].dwSequence = seq; \ + This->queue_head = nq; \ + } else \ + This->overflow = TRUE; \ + } \ +} + +/** + * Callback Data used by specific callback + * for EnumObject on 'W' interfaces + */ +typedef struct { + LPDIENUMDEVICEOBJECTSCALLBACKW lpCallBack; + LPVOID lpvRef; +} device_enumobjects_AtoWcb_data; + +extern BOOL DIEnumDevicesCallbackAtoW(LPCDIDEVICEOBJECTINSTANCEA, LPVOID); + + +/* Various debug tools */ +extern void _dump_cooperativelevel_DI(DWORD dwFlags) ; +extern void _dump_EnumObjects_flags(DWORD dwFlags) ; +extern void _dump_DIPROPHEADER(LPCDIPROPHEADER diph) ; +extern void _dump_OBJECTINSTANCEA(DIDEVICEOBJECTINSTANCEA *ddoi) ; +extern void _dump_OBJECTINSTANCEW(DIDEVICEOBJECTINSTANCEW *ddoi) ; +extern void _dump_DIDATAFORMAT(const DIDATAFORMAT *df) ; +extern const char *_dump_dinput_GUID(const GUID *guid) ; + +/* And the stubs */ +extern HRESULT WINAPI IDirectInputDevice2AImpl_SetDataFormat( + LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df ) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel( + LPDIRECTINPUTDEVICE8A iface,HWND hwnd,DWORD dwflags ) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification( + LPDIRECTINPUTDEVICE8A iface,HANDLE hnd ) ; +extern ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE8A iface) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface(LPDIRECTINPUTDEVICE8A iface,REFIID riid,LPVOID *ppobj); +extern HRESULT WINAPI IDirectInputDevice2WImpl_QueryInterface(LPDIRECTINPUTDEVICE8W iface,REFIID riid,LPVOID *ppobj); +extern ULONG WINAPI IDirectInputDevice2AImpl_AddRef( + LPDIRECTINPUTDEVICE8A iface) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, + LPVOID lpvRef, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice2WImpl_EnumObjects( + LPDIRECTINPUTDEVICE8W iface, + LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, + LPVOID lpvRef, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty( + LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPDIPROPHEADER pdiph) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEOBJECTINSTANCEA pdidoi, + DWORD dwObj, + DWORD dwHow) ; +extern HRESULT WINAPI IDirectInputDevice2WImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEOBJECTINSTANCEW pdidoi, + DWORD dwObj, + DWORD dwHow); +extern HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEINSTANCEA pdidi) ; +extern HRESULT WINAPI IDirectInputDevice2WImpl_GetDeviceInfo( + LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEINSTANCEW pdidi) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel( + LPDIRECTINPUTDEVICE8A iface, + HWND hwndOwner, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_Initialize( + LPDIRECTINPUTDEVICE8A iface, + HINSTANCE hinst, + DWORD dwVersion, + REFGUID rguid) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_CreateEffect( + LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPCDIEFFECT lpeff, + LPDIRECTINPUTEFFECT *ppdef, + LPUNKNOWN pUnkOuter) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMEFFECTSCALLBACKA lpCallback, + LPVOID lpvRef, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice2WImpl_EnumEffects( + LPDIRECTINPUTDEVICE8W iface, + LPDIENUMEFFECTSCALLBACKW lpCallback, + LPVOID lpvRef, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_GetEffectInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIEFFECTINFOA lpdei, + REFGUID rguid) ; +extern HRESULT WINAPI IDirectInputDevice2WImpl_GetEffectInfo( + LPDIRECTINPUTDEVICE8W iface, + LPDIEFFECTINFOW lpdei, + REFGUID rguid) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_GetForceFeedbackState( + LPDIRECTINPUTDEVICE8A iface, + LPDWORD pdwOut) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand( + LPDIRECTINPUTDEVICE8A iface, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, + LPVOID lpvRef, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_Escape( + LPDIRECTINPUTDEVICE8A iface, + LPDIEFFESCAPE lpDIEEsc) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_Poll( + LPDIRECTINPUTDEVICE8A iface) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_SendDeviceData( + LPDIRECTINPUTDEVICE8A iface, + DWORD cbObjectData, + LPCDIDEVICEOBJECTDATA rgdod, + LPDWORD pdwInOut, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice7AImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8A iface, + LPCSTR lpszFileName, + LPDIENUMEFFECTSINFILECALLBACK pec, + LPVOID pvRef, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice7WImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8W iface, + LPCWSTR lpszFileName, + LPDIENUMEFFECTSINFILECALLBACK pec, + LPVOID pvRef, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice7AImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8A iface, + LPCSTR lpszFileName, + DWORD dwEntries, + LPDIFILEEFFECT rgDiFileEft, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice7WImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8W iface, + LPCWSTR lpszFileName, + DWORD dwEntries, + LPDIFILEEFFECT rgDiFileEft, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice8AImpl_BuildActionMap(LPDIRECTINPUTDEVICE8A iface, + LPDIACTIONFORMATA lpdiaf, + LPCSTR lpszUserName, + DWORD dwFlags); +extern HRESULT WINAPI IDirectInputDevice8WImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface, + LPDIACTIONFORMATW lpdiaf, + LPCWSTR lpszUserName, + DWORD dwFlags); +extern HRESULT WINAPI IDirectInputDevice8AImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface, + LPDIACTIONFORMATA lpdiaf, + LPCSTR lpszUserName, + DWORD dwFlags); +extern HRESULT WINAPI IDirectInputDevice8WImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface, + LPDIACTIONFORMATW lpdiaf, + LPCWSTR lpszUserName, + DWORD dwFlags); +extern HRESULT WINAPI IDirectInputDevice8AImpl_GetImageInfo(LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader); +extern HRESULT WINAPI IDirectInputDevice8WImpl_GetImageInfo(LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader); + +#endif /* __WINE_DLLS_DINPUT_DINPUTDEVICE_PRIVATE_H */ diff --git a/reactos/lib/dinput/dinput.spec b/reactos/lib/dinput/dinput.spec new file mode 100644 index 00000000000..9a5ec99fd43 --- /dev/null +++ b/reactos/lib/dinput/dinput.spec @@ -0,0 +1,7 @@ +@ stdcall DirectInputCreateA(long long ptr ptr) +@ stdcall DirectInputCreateW(long long ptr ptr) +@ stdcall DirectInputCreateEx(long long ptr ptr ptr) +@ stdcall -private DllCanUnloadNow() DINPUT_DllCanUnloadNow +@ stdcall -private DllGetClassObject(ptr ptr ptr) DINPUT_DllGetClassObject +@ stdcall -private DllRegisterServer() DINPUT_DllRegisterServer +@ stdcall -private DllUnregisterServer() DINPUT_DllUnregisterServer diff --git a/reactos/lib/dinput/dinput_main.c b/reactos/lib/dinput/dinput_main.c new file mode 100644 index 00000000000..3bfcba05e70 --- /dev/null +++ b/reactos/lib/dinput/dinput_main.c @@ -0,0 +1,756 @@ +/* DirectInput + * + * Copyright 1998 Marcus Meissner + * Copyright 1998,1999 Lionel Ulmer + * Copyright 2000-2002 TransGaming Technologies Inc. + * + * + * 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.1 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 + */ +/* Status: + * + * - Tomb Raider 2 Demo: + * Playable using keyboard only. + * - WingCommander Prophecy Demo: + * Doesn't get Input Focus. + * + * - Fallout : works great in X and DGA mode + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include + +#define COBJMACROS + +#include "wine/debug.h" +#include "wine/unicode.h" +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winerror.h" +#include "dinput_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dinput); + +static IDirectInput7AVtbl ddi7avt; +static IDirectInput7WVtbl ddi7wvt; +static IDirectInput8AVtbl ddi8avt; +static IDirectInput8WVtbl ddi8wvt; + +/* This array will be filled a dinput.so loading */ +#define MAX_WINE_DINPUT_DEVICES 4 +static dinput_device * dinput_devices[MAX_WINE_DINPUT_DEVICES]; +static int nrof_dinput_devices = 0; + +HINSTANCE DINPUT_instance = NULL; + +BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserv) +{ + switch(reason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(inst); + DINPUT_instance = inst; + break; + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + +/* register a direct draw driver. We better not use malloc for we are in + * the ELF startup initialisation at this point. + */ +void dinput_register_device(dinput_device *device) { + int i; + + /* insert according to priority */ + for (i=0;ipref <= device->pref) { + memcpy(dinput_devices+i+1,dinput_devices+i,sizeof(dinput_devices[0])*(nrof_dinput_devices-i)); + dinput_devices[i] = device; + break; + } + } + if (i==nrof_dinput_devices) /* not found, or too low priority */ + dinput_devices[nrof_dinput_devices] = device; + + nrof_dinput_devices++; + + /* increase MAX_DDRAW_DRIVERS if the line below triggers */ + assert(nrof_dinput_devices <= MAX_WINE_DINPUT_DEVICES); +} + +/****************************************************************************** + * DirectInputCreateEx (DINPUT.@) + */ +HRESULT WINAPI DirectInputCreateEx( + HINSTANCE hinst, DWORD dwVersion, REFIID riid, LPVOID *ppDI, + LPUNKNOWN punkOuter) +{ + IDirectInputImpl* This; + + TRACE("(0x%08lx,%04lx,%s,%p,%p)\n", (DWORD)hinst,dwVersion,debugstr_guid(riid),ppDI,punkOuter); + + if (IsEqualGUID(&IID_IDirectInputA,riid) || + IsEqualGUID(&IID_IDirectInput2A,riid) || + IsEqualGUID(&IID_IDirectInput7A,riid)) { + This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); + This->lpVtbl = &ddi7avt; + This->ref = 1; + This->version = 1; + *ppDI = This; + + return DI_OK; + } + + if (IsEqualGUID(&IID_IDirectInputW,riid) || + IsEqualGUID(&IID_IDirectInput2W,riid) || + IsEqualGUID(&IID_IDirectInput7W,riid)) { + This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); + This->lpVtbl = &ddi7wvt; + This->ref = 1; + This->version = 1; + *ppDI = This; + + return DI_OK; + } + + if (IsEqualGUID(&IID_IDirectInput8A,riid)) { + This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); + This->lpVtbl = &ddi8avt; + This->ref = 1; + This->version = 8; + *ppDI = This; + + return DI_OK; + } + + if (IsEqualGUID(&IID_IDirectInput8W,riid)) { + This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); + This->lpVtbl = &ddi8wvt; + This->ref = 1; + This->version = 8; + *ppDI = This; + + return DI_OK; + } + + return DIERR_OLDDIRECTINPUTVERSION; +} + +/****************************************************************************** + * DirectInputCreateA (DINPUT.@) + */ +HRESULT WINAPI DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter) +{ + IDirectInputImpl* This; + TRACE("(0x%08lx,%04lx,%p,%p)\n", (DWORD)hinst,dwVersion,ppDI,punkOuter); + + //trace:dinput:DirectInputCreateA (0x00400000,0500,0x42bafc54,(nil)) + This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); + This->lpVtbl = &ddi7avt; + This->ref = 1; + if (dwVersion > 0x0700) { + This->version = 8; + } else { + /* We do not differientiate between version 1, 2 and 7 */ + This->version = 1; + } + *ppDI = (IDirectInputA*)This; + return 0; + +} + +/****************************************************************************** + * DirectInputCreateW (DINPUT.@) + */ +HRESULT WINAPI DirectInputCreateW(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTW *ppDI, LPUNKNOWN punkOuter) +{ + IDirectInputImpl* This; + TRACE("(0x%08lx,%04lx,%p,%p)\n", (DWORD)hinst,dwVersion,ppDI,punkOuter); + This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); + This->lpVtbl = &ddi7wvt; + This->ref = 1; + if (dwVersion >= 0x0800) { + This->version = 8; + } else { + /* We do not differientiate between version 1, 2 and 7 */ + This->version = 1; + } + *ppDI = (IDirectInputW*)This; + return 0; +} + +static char *_dump_DIDEVTYPE_value(DWORD dwDevType) { + switch (dwDevType) { + case 0: return "All devices"; + case DIDEVTYPE_MOUSE: return "DIDEVTYPE_MOUSE"; + case DIDEVTYPE_KEYBOARD: return "DIDEVTYPE_KEYBOARD"; + case DIDEVTYPE_JOYSTICK: return "DIDEVTYPE_JOYSTICK"; + case DIDEVTYPE_DEVICE: return "DIDEVTYPE_DEVICE"; + default: return "Unkown"; + } +} + +static void _dump_EnumDevices_dwFlags(DWORD dwFlags) { + if (TRACE_ON(dinput)) { + unsigned int i; + static const struct { + DWORD mask; + const char *name; + } flags[] = { +#define FE(x) { x, #x} + FE(DIEDFL_ALLDEVICES), + FE(DIEDFL_ATTACHEDONLY), + FE(DIEDFL_FORCEFEEDBACK), + FE(DIEDFL_INCLUDEALIASES), + FE(DIEDFL_INCLUDEPHANTOMS) +#undef FE + }; + if (dwFlags == 0) { + DPRINTF("DIEDFL_ALLDEVICES"); + return; + } + for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) + if (flags[i].mask & dwFlags) + DPRINTF("%s ",flags[i].name); + } +} + +/****************************************************************************** + * IDirectInputA_EnumDevices + */ +static HRESULT WINAPI IDirectInputAImpl_EnumDevices( + LPDIRECTINPUT7A iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, + LPVOID pvRef, DWORD dwFlags) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + DIDEVICEINSTANCEA devInstance; + int i, j, r; + + TRACE("(this=%p,0x%04lx '%s',%p,%p,%04lx)\n", + This, dwDevType, _dump_DIDEVTYPE_value(dwDevType), + lpCallback, pvRef, dwFlags); + + if (nrof_dinput_devices==0){ + scan_mouse(); + scan_keyboard(); + } + + TRACE(" flags: "); _dump_EnumDevices_dwFlags(dwFlags); TRACE("\n"); + + + for (i = 0; i < nrof_dinput_devices; i++) { + for (j = 0, r = -1; r != 0; j++) { + devInstance.dwSize = sizeof(devInstance); + TRACE(" - checking device %d ('%s')\n", i, dinput_devices[i]->name); + + + if ((r = dinput_devices[i]->enum_deviceA(dwDevType, dwFlags, &devInstance, This->version, j))) { + if (lpCallback(&devInstance,pvRef) == DIENUM_STOP) + return 0; + } + } + } + + return 0; +} +/****************************************************************************** + * IDirectInputW_EnumDevices + */ +static HRESULT WINAPI IDirectInputWImpl_EnumDevices( + LPDIRECTINPUT7W iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, + LPVOID pvRef, DWORD dwFlags) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + DIDEVICEINSTANCEW devInstance; + int i, j, r; + + if (nrof_dinput_devices==0){ + scan_mouse(); + scan_keyboard(); + } + + TRACE("(this=%p,0x%04lx '%s',%p,%p,%04lx)\n", + This, dwDevType, _dump_DIDEVTYPE_value(dwDevType), + lpCallback, pvRef, dwFlags); + TRACE(" flags: "); _dump_EnumDevices_dwFlags(dwFlags); TRACE("\n"); + + + for (i = 0; i < nrof_dinput_devices; i++) { + for (j = 0, r = -1; r != 0; j++) { + devInstance.dwSize = sizeof(devInstance); + TRACE(" - checking device %d ('%s')\n", i, dinput_devices[i]->name); + if ((r = dinput_devices[i]->enum_deviceW(dwDevType, dwFlags, &devInstance, This->version, j))) { + if (lpCallback(&devInstance,pvRef) == DIENUM_STOP) + return 0; + } + } + } + + return 0; +} + +static ULONG WINAPI IDirectInputAImpl_AddRef(LPDIRECTINPUT7A iface) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + return InterlockedIncrement((&This->ref)); +} + +static ULONG WINAPI IDirectInputAImpl_Release(LPDIRECTINPUT7A iface) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + ULONG ref; + ref = InterlockedDecrement(&(This->ref)); + if (ref == 0) + HeapFree(GetProcessHeap(),0,This); + return ref; +} + +static HRESULT WINAPI IDirectInputAImpl_QueryInterface(LPDIRECTINPUT7A iface, REFIID riid, LPVOID *ppobj) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + + TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(&IID_IUnknown,riid) || + IsEqualGUID(&IID_IDirectInputA,riid) || + IsEqualGUID(&IID_IDirectInput2A,riid) || + IsEqualGUID(&IID_IDirectInput7A,riid)) { + IDirectInputAImpl_AddRef(iface); + *ppobj = This; + return 0; + } + TRACE("Unsupported interface !\n"); + return E_FAIL; +} + +static HRESULT WINAPI IDirectInputWImpl_QueryInterface(LPDIRECTINPUT7W iface, REFIID riid, LPVOID *ppobj) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + + TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(&IID_IUnknown,riid) || + IsEqualGUID(&IID_IDirectInputW,riid) || + IsEqualGUID(&IID_IDirectInput2W,riid) || + IsEqualGUID(&IID_IDirectInput7W,riid)) { + IDirectInputAImpl_AddRef((LPDIRECTINPUT7A) iface); + *ppobj = This; + return 0; + } + TRACE("Unsupported interface !\n"); + return E_FAIL; +} + +static HRESULT WINAPI IDirectInputAImpl_CreateDevice( + LPDIRECTINPUT7A iface,REFGUID rguid,LPDIRECTINPUTDEVICEA* pdev, + LPUNKNOWN punk +) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + HRESULT ret_value = DIERR_DEVICENOTREG; + int i; + + TRACE("(this=%p,%s,%p,%p)\n",This,debugstr_guid(rguid),pdev,punk); + + if (nrof_dinput_devices==0){ + scan_mouse(); + scan_keyboard(); + } + + /* Loop on all the devices to see if anyone matches the given GUID */ + for (i = 0; i < nrof_dinput_devices; i++) { + HRESULT ret; + if ((ret = dinput_devices[i]->create_deviceA(This, rguid, NULL, pdev)) == DI_OK) + return DI_OK; + + if (ret == DIERR_NOINTERFACE) + ret_value = DIERR_NOINTERFACE; + } + + return ret_value; +} + +static HRESULT WINAPI IDirectInputWImpl_CreateDevice(LPDIRECTINPUT7A iface, + REFGUID rguid, LPDIRECTINPUTDEVICEW* pdev, LPUNKNOWN punk) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + HRESULT ret_value = DIERR_DEVICENOTREG; + int i; + + TRACE("(this=%p,%s,%p,%p)\n",This,debugstr_guid(rguid),pdev,punk); + + if (nrof_dinput_devices==0){ + scan_mouse(); + scan_keyboard(); + } + + /* Loop on all the devices to see if anyone matches the given GUID */ + for (i = 0; i < nrof_dinput_devices; i++) { + HRESULT ret; + if ((ret = dinput_devices[i]->create_deviceW(This, rguid, NULL, pdev)) == DI_OK) + return DI_OK; + + if (ret == DIERR_NOINTERFACE) + ret_value = DIERR_NOINTERFACE; + } + + return ret_value; +} + +static HRESULT WINAPI IDirectInputAImpl_Initialize(LPDIRECTINPUT7A iface, HINSTANCE hinst, DWORD x) { + return DIERR_ALREADYINITIALIZED; +} + +static HRESULT WINAPI IDirectInputAImpl_GetDeviceStatus(LPDIRECTINPUT7A iface, + REFGUID rguid) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + + FIXME("(%p)->(%s): stub\n",This,debugstr_guid(rguid)); + + return DI_OK; +} + +static HRESULT WINAPI IDirectInputAImpl_RunControlPanel(LPDIRECTINPUT7A iface, + HWND hwndOwner, + DWORD dwFlags) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + FIXME("(%p)->(%08lx,%08lx): stub\n",This, (DWORD) hwndOwner, dwFlags); + + return DI_OK; +} + +static HRESULT WINAPI IDirectInput2AImpl_FindDevice(LPDIRECTINPUT7A iface, REFGUID rguid, + LPCSTR pszName, LPGUID pguidInstance) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + FIXME("(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), pszName, pguidInstance); + + return DI_OK; +} + +static HRESULT WINAPI IDirectInput2WImpl_FindDevice(LPDIRECTINPUT7W iface, REFGUID rguid, + LPCWSTR pszName, LPGUID pguidInstance) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + FIXME("(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), debugstr_w(pszName), pguidInstance); + + return DI_OK; +} + +static HRESULT WINAPI IDirectInput7AImpl_CreateDeviceEx(LPDIRECTINPUT7A iface, REFGUID rguid, + REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + HRESULT ret_value = DIERR_DEVICENOTREG; + int i; + + TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter); + + if (nrof_dinput_devices==0){ + scan_mouse(); + scan_keyboard(); + } + + /* Loop on all the devices to see if anyone matches the given GUID */ + for (i = 0; i < nrof_dinput_devices; i++) { + HRESULT ret; + if ((ret = dinput_devices[i]->create_deviceA(This, rguid, riid, (LPDIRECTINPUTDEVICEA*) pvOut)) == DI_OK) + return DI_OK; + + if (ret == DIERR_NOINTERFACE) + ret_value = DIERR_NOINTERFACE; + } + + return ret_value; +} + +static HRESULT WINAPI IDirectInput7WImpl_CreateDeviceEx(LPDIRECTINPUT7W iface, REFGUID rguid, + REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + HRESULT ret_value = DIERR_DEVICENOTREG; + int i; + + TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter); + + if (nrof_dinput_devices==0){ + scan_mouse(); + scan_keyboard(); + } + + + + /* Loop on all the devices to see if anyone matches the given GUID */ + for (i = 0; i < nrof_dinput_devices; i++) { + HRESULT ret; + if ((ret = dinput_devices[i]->create_deviceW(This, rguid, riid, (LPDIRECTINPUTDEVICEW*) pvOut)) == DI_OK) + return DI_OK; + + if (ret == DIERR_NOINTERFACE) + ret_value = DIERR_NOINTERFACE; + } + + return ret_value; +} + +static HRESULT WINAPI IDirectInput8AImpl_QueryInterface(LPDIRECTINPUT8A iface, REFIID riid, LPVOID *ppobj) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + + TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(&IID_IUnknown,riid) || + IsEqualGUID(&IID_IDirectInput8A,riid)) { + IDirectInputAImpl_AddRef((LPDIRECTINPUT7A) iface); + *ppobj = This; + return 0; + } + TRACE("Unsupported interface !\n"); + return E_NOINTERFACE; +} + +static HRESULT WINAPI IDirectInput8WImpl_QueryInterface(LPDIRECTINPUT8W iface, REFIID riid, LPVOID *ppobj) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + + TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(&IID_IUnknown,riid) || + IsEqualGUID(&IID_IDirectInput8W,riid)) { + IDirectInputAImpl_AddRef((LPDIRECTINPUT7A) iface); + *ppobj = This; + return 0; + } + TRACE("Unsupported interface !\n"); + return E_NOINTERFACE; +} + +static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics( + LPDIRECTINPUT8A iface, LPCSTR ptszUserName, LPDIACTIONFORMATA lpdiActionFormat, + LPDIENUMDEVICESBYSEMANTICSCBA lpCallback, + LPVOID pvRef, DWORD dwFlags +) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + + FIXME("(this=%p,%s,%p,%p,%p,%04lx): stub\n", This, ptszUserName, lpdiActionFormat, + lpCallback, pvRef, dwFlags); + return 0; +} + +static HRESULT WINAPI IDirectInput8WImpl_EnumDevicesBySemantics( + LPDIRECTINPUT8W iface, LPCWSTR ptszUserName, LPDIACTIONFORMATW lpdiActionFormat, + LPDIENUMDEVICESBYSEMANTICSCBW lpCallback, + LPVOID pvRef, DWORD dwFlags +) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + + FIXME("(this=%p,%s,%p,%p,%p,%04lx): stub\n", This, debugstr_w(ptszUserName), lpdiActionFormat, + lpCallback, pvRef, dwFlags); + return 0; +} + +static HRESULT WINAPI IDirectInput8AImpl_ConfigureDevices( + LPDIRECTINPUT8A iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback, + LPDICONFIGUREDEVICESPARAMSA lpdiCDParams, DWORD dwFlags, LPVOID pvRefData +) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + + FIXME("(this=%p,%p,%p,%04lx,%p): stub\n", This, lpdiCallback, lpdiCDParams, + dwFlags, pvRefData); + return 0; +} + +static HRESULT WINAPI IDirectInput8WImpl_ConfigureDevices( + LPDIRECTINPUT8W iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback, + LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData +) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + + FIXME("(this=%p,%p,%p,%04lx,%p): stub\n", This, lpdiCallback, lpdiCDParams, + dwFlags, pvRefData); + return 0; +} + +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(ddi7avt.fun)) +#else +# define XCAST(fun) (void*) +#endif + +static IDirectInput7AVtbl ddi7avt = { + XCAST(QueryInterface)IDirectInputAImpl_QueryInterface, + XCAST(AddRef)IDirectInputAImpl_AddRef, + XCAST(Release)IDirectInputAImpl_Release, + XCAST(CreateDevice)IDirectInputAImpl_CreateDevice, + XCAST(EnumDevices)IDirectInputAImpl_EnumDevices, + XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus, + XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel, + XCAST(Initialize)IDirectInputAImpl_Initialize, + XCAST(FindDevice)IDirectInput2AImpl_FindDevice, + XCAST(CreateDeviceEx)IDirectInput7AImpl_CreateDeviceEx +}; + +#undef XCAST +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(ddi7wvt.fun)) +#else +# define XCAST(fun) (void*) +#endif + +static IDirectInput7WVtbl ddi7wvt = { + XCAST(QueryInterface)IDirectInputWImpl_QueryInterface, + XCAST(AddRef)IDirectInputAImpl_AddRef, + XCAST(Release)IDirectInputAImpl_Release, + XCAST(CreateDevice)IDirectInputWImpl_CreateDevice, + XCAST(EnumDevices)IDirectInputWImpl_EnumDevices, + XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus, + XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel, + XCAST(Initialize)IDirectInputAImpl_Initialize, + XCAST(FindDevice)IDirectInput2WImpl_FindDevice, + XCAST(CreateDeviceEx)IDirectInput7WImpl_CreateDeviceEx +}; +#undef XCAST + +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(ddi8avt.fun)) +#else +# define XCAST(fun) (void*) +#endif + +static IDirectInput8AVtbl ddi8avt = { + XCAST(QueryInterface)IDirectInput8AImpl_QueryInterface, + XCAST(AddRef)IDirectInputAImpl_AddRef, + XCAST(Release)IDirectInputAImpl_Release, + XCAST(CreateDevice)IDirectInputAImpl_CreateDevice, + XCAST(EnumDevices)IDirectInputAImpl_EnumDevices, + XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus, + XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel, + XCAST(Initialize)IDirectInputAImpl_Initialize, + XCAST(FindDevice)IDirectInput2AImpl_FindDevice, + XCAST(EnumDevicesBySemantics)IDirectInput8AImpl_EnumDevicesBySemantics, + XCAST(ConfigureDevices)IDirectInput8AImpl_ConfigureDevices +}; +#undef XCAST + +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(ddi8wvt.fun)) +#else +# define XCAST(fun) (void*) +#endif +static IDirectInput8WVtbl ddi8wvt = { + XCAST(QueryInterface)IDirectInput8WImpl_QueryInterface, + XCAST(AddRef)IDirectInputAImpl_AddRef, + XCAST(Release)IDirectInputAImpl_Release, + XCAST(CreateDevice)IDirectInputWImpl_CreateDevice, + XCAST(EnumDevices)IDirectInputWImpl_EnumDevices, + XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus, + XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel, + XCAST(Initialize)IDirectInputAImpl_Initialize, + XCAST(FindDevice)IDirectInput2WImpl_FindDevice, + XCAST(EnumDevicesBySemantics)IDirectInput8WImpl_EnumDevicesBySemantics, + XCAST(ConfigureDevices)IDirectInput8WImpl_ConfigureDevices +}; +#undef XCAST + +/******************************************************************************* + * DirectInput ClassFactory + */ +typedef struct +{ + /* IUnknown fields */ + IClassFactoryVtbl *lpVtbl; + DWORD ref; +} IClassFactoryImpl; + +static HRESULT WINAPI DICF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); + return E_NOINTERFACE; +} + +static ULONG WINAPI DICF_AddRef(LPCLASSFACTORY iface) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + return InterlockedIncrement(&(This->ref)); +} + +static ULONG WINAPI DICF_Release(LPCLASSFACTORY iface) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + /* static class, won't be freed */ + return InterlockedDecrement(&(This->ref)); +} + +static HRESULT WINAPI DICF_CreateInstance( + LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj +) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); + if ( IsEqualGUID( &IID_IDirectInputA, riid ) || + IsEqualGUID( &IID_IDirectInputW, riid ) || + IsEqualGUID( &IID_IDirectInput2A, riid ) || + IsEqualGUID( &IID_IDirectInput2W, riid ) || + IsEqualGUID( &IID_IDirectInput7A, riid ) || + IsEqualGUID( &IID_IDirectInput7W, riid ) || + IsEqualGUID( &IID_IDirectInput8A, riid ) || + IsEqualGUID( &IID_IDirectInput8W, riid ) ) { + /* FIXME: reuse already created dinput if present? */ + return DirectInputCreateEx(0,0,riid,ppobj,pOuter); + } + + FIXME("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); + return E_NOINTERFACE; +} + +static HRESULT WINAPI DICF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + FIXME("(%p)->(%d),stub!\n",This,dolock); + return S_OK; +} + +static IClassFactoryVtbl DICF_Vtbl = { + DICF_QueryInterface, + DICF_AddRef, + DICF_Release, + DICF_CreateInstance, + DICF_LockServer +}; +static IClassFactoryImpl DINPUT_CF = {&DICF_Vtbl, 1 }; + +/*********************************************************************** + * DllCanUnloadNow (DINPUT.@) + */ +HRESULT WINAPI DINPUT_DllCanUnloadNow(void) +{ + FIXME("(void): stub\n"); + + return S_FALSE; +} + +/*********************************************************************** + * DllGetClassObject (DINPUT.@) + */ +HRESULT WINAPI DINPUT_DllGetClassObject(REFCLSID rclsid, REFIID riid, + LPVOID *ppv) +{ + TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) { + *ppv = (LPVOID)&DINPUT_CF; + IClassFactory_AddRef((IClassFactory*)*ppv); + return S_OK; + } + + FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + return CLASS_E_CLASSNOTAVAILABLE; +} diff --git a/reactos/lib/dinput/dinput_private.h b/reactos/lib/dinput/dinput_private.h new file mode 100644 index 00000000000..ce7b54a9577 --- /dev/null +++ b/reactos/lib/dinput/dinput_private.h @@ -0,0 +1,58 @@ +/* + * Copyright 2000 Lionel Ulmer + * + * 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.1 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 + */ + +#ifndef __WINE_DLLS_DINPUT_DINPUT_PRIVATE_H +#define __WINE_DLLS_DINPUT_DINPUT_PRIVATE_H + +#include + +#include "windef.h" +#include "winbase.h" +#include "dinput.h" + +/* Implementation specification */ +typedef struct IDirectInputImpl IDirectInputImpl; +struct IDirectInputImpl +{ + LPVOID lpVtbl; + DWORD ref; + + /* Used to have an unique sequence number for all the events */ + DWORD evsequence; + + int version; +}; + +/* Function called by all devices that Wine supports */ +typedef struct dinput_device { + INT pref; + const char *name; + BOOL (*enum_deviceA)(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, int version, int id); + BOOL (*enum_deviceW)(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, int version, int id); + HRESULT (*create_deviceA)(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev); + HRESULT (*create_deviceW)(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev); +} dinput_device; + +extern void dinput_register_device(dinput_device *device); + +extern HINSTANCE DINPUT_instance; + +void scan_keyboard(); +void scan_mouse(); + +#endif /* __WINE_DLLS_DINPUT_DINPUT_PRIVATE_H */ diff --git a/reactos/lib/dinput/joystick_linux.c b/reactos/lib/dinput/joystick_linux.c new file mode 100644 index 00000000000..8b75fb06288 --- /dev/null +++ b/reactos/lib/dinput/joystick_linux.c @@ -0,0 +1,1715 @@ +/* DirectInput Joystick device + * + * Copyright 1998 Marcus Meissner + * Copyright 1998,1999 Lionel Ulmer + * Copyright 2000-2001 TransGaming Technologies Inc. + * + * 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.1 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 + */ + +/* + * To Do: + * dead zone + * force feedback + */ + +#include "config.h" +#include "wine/port.h" + +#ifdef HAVE_LINUX_22_JOYSTICK_API + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_SYS_TIME_H +# include +#endif +#include +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#include +#ifdef HAVE_SYS_ERRNO_H +# include +#endif +#ifdef HAVE_LINUX_IOCTL_H +# include +#endif +#ifdef HAVE_LINUX_JOYSTICK_H +# include +#endif +#define JOYDEV "/dev/js" + +#include "wine/debug.h" +#include "wine/unicode.h" +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" +#include "dinput.h" + +#include "dinput_private.h" +#include "device_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dinput); + +typedef struct { + LONG lMin; + LONG lMax; + LONG lDeadZone; + LONG lSaturation; +} ObjProps; + +typedef struct { + LONG lX; + LONG lY; +} POV; + +typedef struct JoystickImpl JoystickImpl; +static IDirectInputDevice8AVtbl JoystickAvt; +static IDirectInputDevice8WVtbl JoystickWvt; +struct JoystickImpl +{ + LPVOID lpVtbl; + DWORD ref; + GUID guid; + char dev[32]; + + /* The 'parent' DInput */ + IDirectInputImpl *dinput; + + /* joystick private */ + int joyfd; + DIJOYSTATE2 js; /* wine data */ + LPDIDATAFORMAT user_df; /* user defined format */ + DataFormat *transform; /* wine to user format converter */ + int *offsets; /* object offsets */ + ObjProps *props; + HANDLE hEvent; + LPDIDEVICEOBJECTDATA data_queue; + int queue_head, queue_tail, queue_len; + BOOL acquired; + char *name; + DIDEVCAPS devcaps; + LONG deadzone; + int *axis_map; + int axes; + int buttons; + POV povs[4]; + CRITICAL_SECTION crit; + BOOL overflow; +}; + +static GUID DInput_Wine_Joystick_GUID = { /* 9e573ed9-7734-11d2-8d4a-23903fb6bdf7 */ + 0x9e573ed9, + 0x7734, + 0x11d2, + {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7} +}; + +static void _dump_DIDEVCAPS(LPDIDEVCAPS lpDIDevCaps) +{ + TRACE("dwSize: %ld\n", lpDIDevCaps->dwSize); + TRACE("dwFlags: %08lx\n",lpDIDevCaps->dwFlags); + TRACE("dwDevType: %08lx %s\n", lpDIDevCaps->dwDevType, + lpDIDevCaps->dwDevType == DIDEVTYPE_DEVICE ? "DIDEVTYPE_DEVICE" : + lpDIDevCaps->dwDevType == DIDEVTYPE_DEVICE ? "DIDEVTYPE_DEVICE" : + lpDIDevCaps->dwDevType == DIDEVTYPE_MOUSE ? "DIDEVTYPE_MOUSE" : + lpDIDevCaps->dwDevType == DIDEVTYPE_KEYBOARD ? "DIDEVTYPE_KEYBOARD" : + lpDIDevCaps->dwDevType == DIDEVTYPE_JOYSTICK ? "DIDEVTYPE_JOYSTICK" : + lpDIDevCaps->dwDevType == DIDEVTYPE_HID ? "DIDEVTYPE_HID" : "UNKNOWN"); + TRACE("dwAxes: %ld\n",lpDIDevCaps->dwAxes); + TRACE("dwButtons: %ld\n",lpDIDevCaps->dwButtons); + TRACE("dwPOVs: %ld\n",lpDIDevCaps->dwPOVs); + if (lpDIDevCaps->dwSize > sizeof(DIDEVCAPS_DX3)) { + TRACE("dwFFSamplePeriod: %ld\n",lpDIDevCaps->dwFFSamplePeriod); + TRACE("dwFFMinTimeResolution: %ld\n",lpDIDevCaps->dwFFMinTimeResolution); + TRACE("dwFirmwareRevision: %ld\n",lpDIDevCaps->dwFirmwareRevision); + TRACE("dwHardwareRevision: %ld\n",lpDIDevCaps->dwHardwareRevision); + TRACE("dwFFDriverVersion: %ld\n",lpDIDevCaps->dwFFDriverVersion); + } +} + +static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, int version, int id) +{ + int fd = -1; + char dev[32]; + + if (dwFlags & DIEDFL_FORCEFEEDBACK) { + WARN("force feedback not supported\n"); + return FALSE; + } + + if ((dwDevType==0) || (GET_DIDEVICE_TYPE(dwDevType)==DIDEVTYPE_JOYSTICK)) { + /* check whether we have a joystick */ + sprintf(dev, "%s%d", JOYDEV, id); + if ((fd = open(dev,O_RDONLY)) < 0) { + WARN("open(%s,O_RDONLY) failed: %s\n", dev, strerror(errno)); + return FALSE; + } + + /* Return joystick */ + lpddi->guidInstance = DInput_Wine_Joystick_GUID; + lpddi->guidInstance.Data3 = id; + lpddi->guidProduct = DInput_Wine_Joystick_GUID; + /* we only support traditional joysticks for now */ + if (version >= 8) + lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); + else + lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); + sprintf(lpddi->tszInstanceName, "Joystick %d", id); +#if defined(JSIOCGNAME) + if (ioctl(fd,JSIOCGNAME(sizeof(lpddi->tszProductName)),lpddi->tszProductName) < 0) { + WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", dev, strerror(errno)); + strcpy(lpddi->tszProductName, "Wine Joystick"); + } +#else + strcpy(lpddi->tszProductName, "Wine Joystick"); +#endif + + lpddi->guidFFDriver = GUID_NULL; + close(fd); + TRACE("Enumerating the linux Joystick device: %s (%s)\n", dev, lpddi->tszProductName); + return TRUE; + } + + return FALSE; +} + +static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, int version, int id) +{ + int fd = -1; + char name[MAX_PATH]; + char dev[32]; + char friendly[32]; + + if (dwFlags & DIEDFL_FORCEFEEDBACK) { + WARN("force feedback not supported\n"); + return FALSE; + } + + if ((dwDevType==0) || (GET_DIDEVICE_TYPE(dwDevType)==DIDEVTYPE_JOYSTICK)) { + /* check whether we have a joystick */ + sprintf(dev, "%s%d", JOYDEV, id); + if ((fd = open(dev,O_RDONLY)) < 0) { + WARN("open(%s,O_RDONLY) failed: %s\n", dev, strerror(errno)); + return FALSE; + } + + /* Return joystick */ + lpddi->guidInstance = DInput_Wine_Joystick_GUID; + lpddi->guidInstance.Data3 = id; + lpddi->guidProduct = DInput_Wine_Joystick_GUID; + /* we only support traditional joysticks for now */ + if (version >= 8) + lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); + else + lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); + sprintf(friendly, "Joystick %d", id); + MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH); +#if defined(JSIOCGNAME) + if (ioctl(fd,JSIOCGNAME(sizeof(name)),name) < 0) { + WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", dev, strerror(errno)); + strcpy(name, "Wine Joystick"); + } +#else + strcpy(name, "Wine Joystick"); +#endif + MultiByteToWideChar(CP_ACP, 0, name, -1, lpddi->tszProductName, MAX_PATH); + lpddi->guidFFDriver = GUID_NULL; + close(fd); + TRACE("Enumerating the linux Joystick device: %s (%s)\n",dev,name); + return TRUE; + } + + return FALSE; +} + +/* + * Get a config key from either the app-specific or the default config + */ + +inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name, + char *buffer, DWORD size ) +{ + if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, buffer, &size )) + return 0; + + if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, buffer, &size )) + return 0; + + return ERROR_FILE_NOT_FOUND; +} + +/* + * Setup the dinput options. + */ + +static HRESULT setup_dinput_options(JoystickImpl * device) +{ + char buffer[MAX_PATH+1]; + HKEY hkey, appkey = 0; + DWORD len; + + buffer[MAX_PATH]='\0'; + + if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\dinput", &hkey)) hkey = 0; + + len = GetModuleFileNameA( 0, buffer, MAX_PATH ); + if (len && len < MAX_PATH) { + HKEY tmpkey; + + if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\AppDefaults", &tmpkey )) { + char appname[MAX_PATH+16]; + char *p = strrchr( buffer, '\\' ); + if (p!=NULL) { + strcpy(appname,p+1); + strcat(appname,"\\dinput"); + TRACE("appname = [%s] \n",appname); + if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0; + } + RegCloseKey( tmpkey ); + } + } + + /* get options */ + + if (!get_config_key( hkey, appkey, "DefaultDeadZone", buffer, MAX_PATH )) { + device->deadzone = atoi(buffer); + TRACE("setting default deadzone to: \"%s\" %ld\n", buffer, device->deadzone); + } + + if (!get_config_key( hkey, appkey, device->name, buffer, MAX_PATH )) { + int tokens = 0; + int axis = 0; + int pov = 0; + char *delim = ","; + char * ptr; + TRACE("\"%s\" = \"%s\"\n", device->name, buffer); + + device->axis_map = HeapAlloc(GetProcessHeap(), 0, device->axes * sizeof(int)); + if (device->axis_map == 0) + return DIERR_OUTOFMEMORY; + + if ((ptr = strtok(buffer, delim)) != NULL) { + do { + if (strcmp(ptr, "X") == 0) { + device->axis_map[tokens] = 0; + axis++; + } else if (strcmp(ptr, "Y") == 0) { + device->axis_map[tokens] = 1; + axis++; + } else if (strcmp(ptr, "Z") == 0) { + device->axis_map[tokens] = 2; + axis++; + } else if (strcmp(ptr, "Rx") == 0) { + device->axis_map[tokens] = 3; + axis++; + } else if (strcmp(ptr, "Ry") == 0) { + device->axis_map[tokens] = 4; + axis++; + } else if (strcmp(ptr, "Rz") == 0) { + device->axis_map[tokens] = 5; + axis++; + } else if (strcmp(ptr, "Slider1") == 0) { + device->axis_map[tokens] = 6; + axis++; + } else if (strcmp(ptr, "Slider2") == 0) { + device->axis_map[tokens] = 7; + axis++; + } else if (strcmp(ptr, "POV1") == 0) { + device->axis_map[tokens++] = 8; + device->axis_map[tokens] = 8; + pov++; + } else if (strcmp(ptr, "POV2") == 0) { + device->axis_map[tokens++] = 9; + device->axis_map[tokens] = 9; + pov++; + } else if (strcmp(ptr, "POV3") == 0) { + device->axis_map[tokens++] = 10; + device->axis_map[tokens] = 10; + pov++; + } else if (strcmp(ptr, "POV4") == 0) { + device->axis_map[tokens++] = 11; + device->axis_map[tokens] = 11; + pov++; + } else { + ERR("invalid joystick axis type: %s\n", ptr); + device->axis_map[tokens] = tokens; + axis++; + } + + tokens++; + } while ((ptr = strtok(NULL, delim)) != NULL); + + if (tokens != device->devcaps.dwAxes) { + ERR("not all joystick axes mapped: %d axes(%d,%d), %d arguments\n", device->axes, axis, pov,tokens); + while (tokens < device->axes) { + device->axis_map[tokens] = tokens; + tokens++; + } + } + } + + device->devcaps.dwAxes = axis; + device->devcaps.dwPOVs = pov; + } + + if (appkey) + RegCloseKey( appkey ); + + if (hkey) + RegCloseKey( hkey ); + + return DI_OK; +} + +void calculate_ids(JoystickImpl* device) +{ + int i; + int axis = 0; + int button = 0; + int pov = 0; + int axis_base; + int pov_base; + int button_base; + + /* Make two passes over the format. The first counts the number + * for each type and the second sets the id */ + for (i = 0; i < device->user_df->dwNumObjs; i++) { + if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_AXIS) + axis++; + else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_POV) + pov++; + else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_BUTTON) + button++; + } + + axis_base = 0; + pov_base = axis; + button_base = axis + pov; + + axis = 0; + button = 0; + pov = 0; + + for (i = 0; i < device->user_df->dwNumObjs; i++) { + DWORD type = 0; + if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_AXIS) { + axis++; + type = DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) | + DIDFT_MAKEINSTANCE(axis + axis_base); + TRACE("axis type = 0x%08lx\n", type); + } else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_POV) { + pov++; + type = DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) | + DIDFT_MAKEINSTANCE(pov + pov_base); + TRACE("POV type = 0x%08lx\n", type); + } else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_BUTTON) { + button++; + type = DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) | + DIDFT_MAKEINSTANCE(button + button_base); + TRACE("button type = 0x%08lx\n", type); + } + device->user_df->rgodf[i].dwType = type; + } +} + +static HRESULT alloc_device(REFGUID rguid, LPVOID jvt, IDirectInputImpl *dinput, LPDIRECTINPUTDEVICEA* pdev) +{ + DWORD i; + JoystickImpl* newDevice; + char name[MAX_PATH]; + HRESULT hr; + + newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl)); + if (newDevice == 0) { + WARN("out of memory\n"); + *pdev = 0; + return DIERR_OUTOFMEMORY; + } + + sprintf(newDevice->dev, "%s%d", JOYDEV, rguid->Data3); + + if ((newDevice->joyfd = open(newDevice->dev,O_RDONLY)) < 0) { + WARN("open(%s,O_RDONLY) failed: %s\n", newDevice->dev, strerror(errno)); + HeapFree(GetProcessHeap(), 0, newDevice); + return DIERR_DEVICENOTREG; + } + + /* get the device name */ +#if defined(JSIOCGNAME) + if (ioctl(newDevice->joyfd,JSIOCGNAME(MAX_PATH),name) < 0) { + WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", newDevice->dev, strerror(errno)); + strcpy(name, "Wine Joystick"); + } +#else + strcpy(name, "Wine Joystick"); +#endif + + /* copy the device name */ + newDevice->name = HeapAlloc(GetProcessHeap(),0,strlen(name) + 1); + strcpy(newDevice->name, name); + +#ifdef JSIOCGAXES + if (ioctl(newDevice->joyfd,JSIOCGAXES,&newDevice->axes) < 0) { + WARN("ioctl(%s,JSIOCGAXES) failed: %s, defauting to 2\n", newDevice->dev, strerror(errno)); + newDevice->axes = 2; + } +#endif +#ifdef JSIOCGBUTTONS + if (ioctl(newDevice->joyfd,JSIOCGBUTTONS,&newDevice->buttons) < 0) { + WARN("ioctl(%s,JSIOCGBUTTONS) failed: %s, defauting to 2\n", newDevice->dev, strerror(errno)); + newDevice->buttons = 2; + } +#endif + + newDevice->lpVtbl = jvt; + newDevice->ref = 1; + newDevice->dinput = dinput; + newDevice->acquired = FALSE; + newDevice->overflow = FALSE; + CopyMemory(&(newDevice->guid),rguid,sizeof(*rguid)); + + /* setup_dinput_options may change these */ + newDevice->deadzone = 5000; + newDevice->devcaps.dwButtons = newDevice->buttons; + newDevice->devcaps.dwAxes = newDevice->axes; + newDevice->devcaps.dwPOVs = 0; + + /* do any user specified configuration */ + hr = setup_dinput_options(newDevice); + if (hr != DI_OK) + goto FAILED1; + + if (newDevice->axis_map == 0) { + newDevice->axis_map = HeapAlloc(GetProcessHeap(), 0, newDevice->axes * sizeof(int)); + if (newDevice->axis_map == 0) + goto FAILED; + + for (i = 0; i < newDevice->axes; i++) + newDevice->axis_map[i] = i; + } + + /* wine uses DIJOYSTATE2 as it's internal format so copy + * the already defined format c_dfDIJoystick2 */ + newDevice->user_df = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwSize); + if (newDevice->user_df == 0) + goto FAILED; + + CopyMemory(newDevice->user_df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize); + + /* copy default objects */ + newDevice->user_df->rgodf = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwNumObjs*c_dfDIJoystick2.dwObjSize); + if (newDevice->user_df->rgodf == 0) + goto FAILED; + + CopyMemory(newDevice->user_df->rgodf,c_dfDIJoystick2.rgodf,c_dfDIJoystick2.dwNumObjs*c_dfDIJoystick2.dwObjSize); + + /* create default properties */ + newDevice->props = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwNumObjs*sizeof(ObjProps)); + if (newDevice->props == 0) + goto FAILED; + + /* initialize default properties */ + for (i = 0; i < c_dfDIJoystick2.dwNumObjs; i++) { + newDevice->props[i].lMin = 0; + newDevice->props[i].lMax = 0xffff; + newDevice->props[i].lDeadZone = newDevice->deadzone; /* % * 1000 */ + newDevice->props[i].lSaturation = 0; + } + + /* create an offsets array */ + newDevice->offsets = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,c_dfDIJoystick2.dwNumObjs*sizeof(int)); + if (newDevice->offsets == 0) + goto FAILED; + + /* create the default transform filter */ + newDevice->transform = create_DataFormat(&c_dfDIJoystick2, newDevice->user_df, newDevice->offsets); + + calculate_ids(newDevice); + + IDirectInputDevice_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->dinput); + InitializeCriticalSection(&(newDevice->crit)); + newDevice->crit.DebugInfo->Spare[1] = (DWORD)"DINPUT_Mouse"; + + newDevice->devcaps.dwSize = sizeof(newDevice->devcaps); + newDevice->devcaps.dwFlags = DIDC_ATTACHED; + newDevice->devcaps.dwDevType = DIDEVTYPE_JOYSTICK; + newDevice->devcaps.dwFFSamplePeriod = 0; + newDevice->devcaps.dwFFMinTimeResolution = 0; + newDevice->devcaps.dwFirmwareRevision = 0; + newDevice->devcaps.dwHardwareRevision = 0; + newDevice->devcaps.dwFFDriverVersion = 0; + + if (TRACE_ON(dinput)) { + _dump_DIDATAFORMAT(newDevice->user_df); + for (i = 0; i < (newDevice->axes); i++) + TRACE("axis_map[%ld] = %d\n", i, newDevice->axis_map[i]); + _dump_DIDEVCAPS(&newDevice->devcaps); + } + + *pdev = (LPDIRECTINPUTDEVICEA)newDevice; + + return DI_OK; + +FAILED: + hr = DIERR_OUTOFMEMORY; +FAILED1: + if (newDevice->axis_map) + HeapFree(GetProcessHeap(),0,newDevice->axis_map); + if (newDevice->name) + HeapFree(GetProcessHeap(),0,newDevice->name); + if (newDevice->props) + HeapFree(GetProcessHeap(),0,newDevice->props); + if (newDevice->user_df->rgodf) + HeapFree(GetProcessHeap(),0,newDevice->user_df->rgodf); + if (newDevice->user_df) + HeapFree(GetProcessHeap(),0,newDevice->user_df); + if (newDevice) + HeapFree(GetProcessHeap(),0,newDevice); + *pdev = 0; + + return hr; +} + +static BOOL IsJoystickGUID(REFGUID guid) +{ + GUID wine_joystick = DInput_Wine_Joystick_GUID; + GUID dev_guid = *guid; + + wine_joystick.Data3 = 0; + dev_guid.Data3 = 0; + + return IsEqualGUID(&wine_joystick, &dev_guid); +} + +static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev) +{ + if ((IsEqualGUID(&GUID_Joystick,rguid)) || + (IsJoystickGUID(rguid))) { + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceA,riid) || + IsEqualGUID(&IID_IDirectInputDevice2A,riid) || + IsEqualGUID(&IID_IDirectInputDevice7A,riid) || + IsEqualGUID(&IID_IDirectInputDevice8A,riid)) { + return alloc_device(rguid, &JoystickAvt, dinput, pdev); + } else { + WARN("no interface\n"); + *pdev = 0; + return DIERR_NOINTERFACE; + } + } + + WARN("invalid device GUID\n"); + *pdev = 0; + return DIERR_DEVICENOTREG; +} + +static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev) +{ + if ((IsEqualGUID(&GUID_Joystick,rguid)) || + (IsJoystickGUID(rguid))) { + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceW,riid) || + IsEqualGUID(&IID_IDirectInputDevice2W,riid) || + IsEqualGUID(&IID_IDirectInputDevice7W,riid) || + IsEqualGUID(&IID_IDirectInputDevice8W,riid)) { + return alloc_device(rguid, &JoystickWvt, dinput, (LPDIRECTINPUTDEVICEA *)pdev); + } else { + WARN("no interface\n"); + *pdev = 0; + return DIERR_NOINTERFACE; + } + } + + WARN("invalid device GUID\n"); + *pdev = 0; + return DIERR_DEVICENOTREG; +} + +static dinput_device joydev = { + 10, + "Wine Linux joystick driver", + joydev_enum_deviceA, + joydev_enum_deviceW, + joydev_create_deviceA, + joydev_create_deviceW +}; + +DECL_GLOBAL_CONSTRUCTOR(joydev_register) { dinput_register_device(&joydev); } + + + +/****************************************************************************** + * Joystick + */ +static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE8A iface) +{ + JoystickImpl *This = (JoystickImpl *)iface; + ULONG ref; + + ref = InterlockedDecrement((&This->ref)); + if (ref) + return ref; + + /* Free the device name */ + if (This->name) + HeapFree(GetProcessHeap(),0,This->name); + + /* Free the axis map */ + if (This->axis_map) + HeapFree(GetProcessHeap(),0,This->axis_map); + + /* Free the data queue */ + if (This->data_queue != NULL) + HeapFree(GetProcessHeap(),0,This->data_queue); + + /* Free the DataFormat */ + HeapFree(GetProcessHeap(), 0, This->user_df->rgodf); + HeapFree(GetProcessHeap(), 0, This->user_df); + + /* Free the properties */ + HeapFree(GetProcessHeap(), 0, This->props); + + /* Free the offsets array */ + HeapFree(GetProcessHeap(),0,This->offsets); + + /* release the data transform filter */ + release_DataFormat(This->transform); + + This->crit.DebugInfo->Spare[1] = 0; + DeleteCriticalSection(&(This->crit)); + IDirectInputDevice_Release((LPDIRECTINPUTDEVICE8A)This->dinput); + + HeapFree(GetProcessHeap(),0,This); + return 0; +} + +/****************************************************************************** + * SetDataFormat : the application can choose the format of the data + * the device driver sends back with GetDeviceState. + */ +static HRESULT WINAPI JoystickAImpl_SetDataFormat( + LPDIRECTINPUTDEVICE8A iface, + LPCDIDATAFORMAT df) +{ + JoystickImpl *This = (JoystickImpl *)iface; + unsigned int i; + LPDIDATAFORMAT new_df = 0; + LPDIOBJECTDATAFORMAT new_rgodf = 0; + ObjProps * new_props = 0; + + TRACE("(%p,%p)\n",This,df); + + if (This->acquired) { + WARN("acquired\n"); + return DIERR_ACQUIRED; + } + + if (TRACE_ON(dinput)) + _dump_DIDATAFORMAT(df); + + /* Store the new data format */ + new_df = HeapAlloc(GetProcessHeap(),0,df->dwSize); + if (new_df == 0) + goto FAILED; + + new_rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize); + if (new_rgodf == 0) + goto FAILED; + + new_props = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*sizeof(ObjProps)); + if (new_props == 0) + goto FAILED; + + HeapFree(GetProcessHeap(),0,This->user_df); + HeapFree(GetProcessHeap(),0,This->user_df->rgodf); + HeapFree(GetProcessHeap(),0,This->props); + release_DataFormat(This->transform); + + This->user_df = new_df; + CopyMemory(This->user_df, df, df->dwSize); + This->user_df->rgodf = new_rgodf; + CopyMemory(This->user_df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize); + This->props = new_props; + for (i = 0; i < df->dwNumObjs; i++) { + This->props[i].lMin = 0; + This->props[i].lMax = 0xffff; + This->props[i].lDeadZone = 1000; + This->props[i].lSaturation = 0; + } + This->transform = create_DataFormat(&c_dfDIJoystick2, This->user_df, This->offsets); + + calculate_ids(This); + + return DI_OK; + +FAILED: + WARN("out of memory\n"); + if (new_props) + HeapFree(GetProcessHeap(),0,new_props); + if (new_rgodf) + HeapFree(GetProcessHeap(),0,new_rgodf); + if (new_df) + HeapFree(GetProcessHeap(),0,new_df); + return DIERR_OUTOFMEMORY; +} + +/****************************************************************************** + * Acquire : gets exclusive control of the joystick + */ +static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(%p)\n",This); + + if (This->acquired) { + WARN("already acquired\n"); + return S_FALSE; + } + + /* open the joystick device */ + if (This->joyfd==-1) { + TRACE("opening joystick device %s\n", This->dev); + + This->joyfd=open(This->dev,O_RDONLY); + if (This->joyfd==-1) { + ERR("open(%s) failed: %s\n", This->dev, strerror(errno)); + return DIERR_NOTFOUND; + } + } + + This->acquired = TRUE; + + return DI_OK; +} + +/****************************************************************************** + * Unacquire : frees the joystick + */ +static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(%p)\n",This); + + if (!This->acquired) { + WARN("not acquired\n"); + return DIERR_NOTACQUIRED; + } + + if (This->joyfd!=-1) { + TRACE("closing joystick device\n"); + close(This->joyfd); + This->joyfd = -1; + This->acquired = FALSE; + return DI_OK; + } + + This->acquired = FALSE; + + return DI_NOEFFECT; +} + +LONG map_axis(JoystickImpl * This, short val, short index) +{ + double fval = val; + double fmin = This->props[index].lMin; + double fmax = This->props[index].lMax; + double fret; + + fret = (((fval + 32767.0) * (fmax - fmin)) / (32767.0*2.0)) + fmin; + + if (fret >= 0.0) + fret += 0.5; + else + fret -= 0.5; + + return fret; +} + +/* convert wine format offset to user format object index */ +int offset_to_object(JoystickImpl *This, int offset) +{ + int i; + + for (i = 0; i < This->user_df->dwNumObjs; i++) { + if (This->user_df->rgodf[i].dwOfs == offset) + return i; + } + + return -1; +} + +static LONG calculate_pov(JoystickImpl *This, int index) +{ + if (This->povs[index].lX < 16384) { + if (This->povs[index].lY < 16384) + This->js.rgdwPOV[index] = 31500; + else if (This->povs[index].lY > 49150) + This->js.rgdwPOV[index] = 22500; + else + This->js.rgdwPOV[index] = 27000; + } else if (This->povs[index].lX > 49150) { + if (This->povs[index].lY < 16384) + This->js.rgdwPOV[index] = 4500; + else if (This->povs[index].lY > 49150) + This->js.rgdwPOV[index] = 13500; + else + This->js.rgdwPOV[index] = 9000; + } else { + if (This->povs[index].lY < 16384) + This->js.rgdwPOV[index] = 0; + else if (This->povs[index].lY > 49150) + This->js.rgdwPOV[index] = 18000; + else + This->js.rgdwPOV[index] = -1; + } + + return This->js.rgdwPOV[index]; +} + +static void joy_polldev(JoystickImpl *This) { + struct timeval tv; + fd_set readfds; + struct js_event jse; + TRACE("(%p)\n", This); + + if (This->joyfd==-1) { + WARN("no device\n"); + return; + } + while (1) { + memset(&tv,0,sizeof(tv)); + FD_ZERO(&readfds);FD_SET(This->joyfd,&readfds); + if (1>select(This->joyfd+1,&readfds,NULL,NULL,&tv)) + return; + /* we have one event, so we can read */ + if (sizeof(jse)!=read(This->joyfd,&jse,sizeof(jse))) { + return; + } + TRACE("js_event: type 0x%x, number %d, value %d\n", + jse.type,jse.number,jse.value); + if (jse.type & JS_EVENT_BUTTON) { + int offset = This->offsets[jse.number + 12]; + int value = jse.value?0x80:0x00; + + This->js.rgbButtons[jse.number] = value; + GEN_EVENT(offset,value,jse.time,(This->dinput->evsequence)++); + } else if (jse.type & JS_EVENT_AXIS) { + int number = This->axis_map[jse.number]; /* wine format object index */ + if (number < 12) { + int offset = This->offsets[number]; + int index = offset_to_object(This, offset); + LONG value = map_axis(This, jse.value, index); + + /* FIXME do deadzone and saturation here */ + + TRACE("changing axis %d => %d\n", jse.number, number); + switch (number) { + case 0: + This->js.lX = value; + break; + case 1: + This->js.lY = value; + break; + case 2: + This->js.lZ = value; + break; + case 3: + This->js.lRx = value; + break; + case 4: + This->js.lRy = value; + break; + case 5: + This->js.lRz = value; + break; + case 6: + This->js.rglSlider[0] = value; + break; + case 7: + This->js.rglSlider[1] = value; + break; + case 8: + /* FIXME don't go off array */ + if (This->axis_map[jse.number + 1] == number) + This->povs[0].lX = value; + else if (This->axis_map[jse.number - 1] == number) + This->povs[0].lY = value; + value = calculate_pov(This, 0); + break; + case 9: + if (This->axis_map[jse.number + 1] == number) + This->povs[1].lX = value; + else if (This->axis_map[jse.number - 1] == number) + This->povs[1].lY = value; + value = calculate_pov(This, 1); + break; + case 10: + if (This->axis_map[jse.number + 1] == number) + This->povs[2].lX = value; + else if (This->axis_map[jse.number - 1] == number) + This->povs[2].lY = value; + value = calculate_pov(This, 2); + break; + case 11: + if (This->axis_map[jse.number + 1] == number) + This->povs[3].lX = value; + else if (This->axis_map[jse.number - 1] == number) + This->povs[3].lY = value; + value = calculate_pov(This, 3); + break; + } + + GEN_EVENT(offset,value,jse.time,(This->dinput->evsequence)++); + } else + WARN("axis %d not supported\n", number); + } + } +} + +/****************************************************************************** + * GetDeviceState : returns the "state" of the joystick. + * + */ +static HRESULT WINAPI JoystickAImpl_GetDeviceState( + LPDIRECTINPUTDEVICE8A iface, + DWORD len, + LPVOID ptr) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(%p,0x%08lx,%p)\n",This,len,ptr); + + if (!This->acquired) { + WARN("not acquired\n"); + return DIERR_NOTACQUIRED; + } + + /* update joystick state */ + joy_polldev(This); + + /* convert and copy data to user supplied buffer */ + fill_DataFormat(ptr, &This->js, This->transform); + + return DI_OK; +} + +/****************************************************************************** + * GetDeviceData : gets buffered input data. + */ +static HRESULT WINAPI JoystickAImpl_GetDeviceData( + LPDIRECTINPUTDEVICE8A iface, + DWORD dodsize, + LPDIDEVICEOBJECTDATA dod, + LPDWORD entries, + DWORD flags) +{ + JoystickImpl *This = (JoystickImpl *)iface; + DWORD len; + int nqtail; + HRESULT hr = DI_OK; + + TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags); + + if (!This->acquired) { + WARN("not acquired\n"); + return DIERR_NOTACQUIRED; + } + + EnterCriticalSection(&(This->crit)); + + joy_polldev(This); + + len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0) + + (This->queue_head - This->queue_tail); + if (len > *entries) + len = *entries; + + if (dod == NULL) { + if (len) + TRACE("Application discarding %ld event(s).\n", len); + + *entries = len; + nqtail = This->queue_tail + len; + while (nqtail >= This->queue_len) + nqtail -= This->queue_len; + } else { + if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3)) { + ERR("Wrong structure size !\n"); + LeaveCriticalSection(&(This->crit)); + return DIERR_INVALIDPARAM; + } + + if (len) + TRACE("Application retrieving %ld event(s).\n", len); + + *entries = 0; + nqtail = This->queue_tail; + while (len) { + DWORD span = ((This->queue_head < nqtail) ? This->queue_len : This->queue_head) - nqtail; + if (span > len) + span = len; + + /* Copy the buffered data into the application queue */ + memcpy(dod + *entries, This->data_queue + nqtail, span * dodsize); + /* Advance position */ + nqtail += span; + if (nqtail >= This->queue_len) + nqtail -= This->queue_len; + *entries += span; + len -= span; + } + } + + if (This->overflow) { + hr = DI_BUFFEROVERFLOW; + if (!(flags & DIGDD_PEEK)) { + This->overflow = FALSE; + } + } + + if (!(flags & DIGDD_PEEK)) + This->queue_tail = nqtail; + + LeaveCriticalSection(&(This->crit)); + + return hr; +} + +int find_property(JoystickImpl * This, LPCDIPROPHEADER ph) +{ + int i; + if (ph->dwHow == DIPH_BYOFFSET) { + return offset_to_object(This, ph->dwObj); + } else if (ph->dwHow == DIPH_BYID) { + for (i = 0; i < This->user_df->dwNumObjs; i++) { + if ((This->user_df->rgodf[i].dwType & 0x00ffffff) == (ph->dwObj & 0x00ffffff)) { + return i; + } + } + } + + return -1; +} + +/****************************************************************************** + * SetProperty : change input device properties + */ +static HRESULT WINAPI JoystickAImpl_SetProperty( + LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPCDIPROPHEADER ph) +{ + JoystickImpl *This = (JoystickImpl *)iface; + int i; + + TRACE("(%p,%s,%p)\n",This,debugstr_guid(rguid),ph); + + if (TRACE_ON(dinput)) + _dump_DIPROPHEADER(ph); + + if (!HIWORD(rguid)) { + switch ((DWORD)rguid) { + case (DWORD) DIPROP_BUFFERSIZE: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + TRACE("buffersize = %ld\n",pd->dwData); + if (This->data_queue) + This->data_queue = HeapReAlloc(GetProcessHeap(),0, This->data_queue, pd->dwData * sizeof(DIDEVICEOBJECTDATA)); + else + This->data_queue = HeapAlloc(GetProcessHeap(),0, pd->dwData * sizeof(DIDEVICEOBJECTDATA)); + This->queue_head = 0; + This->queue_tail = 0; + This->queue_len = pd->dwData; + break; + } + case (DWORD)DIPROP_RANGE: { + LPCDIPROPRANGE pr = (LPCDIPROPRANGE)ph; + if (ph->dwHow == DIPH_DEVICE) { + TRACE("proprange(%ld,%ld) all\n",pr->lMin,pr->lMax); + for (i = 0; i < This->user_df->dwNumObjs; i++) { + This->props[i].lMin = pr->lMin; + This->props[i].lMax = pr->lMax; + } + } else { + int obj = find_property(This, ph); + TRACE("proprange(%ld,%ld) obj=%d\n",pr->lMin,pr->lMax,obj); + if (obj >= 0) { + This->props[obj].lMin = pr->lMin; + This->props[obj].lMax = pr->lMax; + return DI_OK; + } + } + break; + } + case (DWORD)DIPROP_DEADZONE: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + if (ph->dwHow == DIPH_DEVICE) { + TRACE("deadzone(%ld) all\n",pd->dwData); + for (i = 0; i < This->user_df->dwNumObjs; i++) + This->props[i].lDeadZone = pd->dwData; + } else { + int obj = find_property(This, ph); + TRACE("deadzone(%ld) obj=%d\n",pd->dwData,obj); + if (obj >= 0) { + This->props[obj].lDeadZone = pd->dwData; + return DI_OK; + } + } + break; + } + case (DWORD)DIPROP_SATURATION: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + if (ph->dwHow == DIPH_DEVICE) { + TRACE("saturation(%ld) all\n",pd->dwData); + for (i = 0; i < This->user_df->dwNumObjs; i++) + This->props[i].lSaturation = pd->dwData; + } else { + int obj = find_property(This, ph); + TRACE("saturation(%ld) obj=%d\n",pd->dwData,obj); + if (obj >= 0) { + This->props[obj].lSaturation = pd->dwData; + return DI_OK; + } + } + break; + } + default: + FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); + break; + } + } + + return DI_OK; +} + +/****************************************************************************** + * SetEventNotification : specifies event to be sent on state change + */ +static HRESULT WINAPI JoystickAImpl_SetEventNotification( + LPDIRECTINPUTDEVICE8A iface, HANDLE hnd +) { + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd); + This->hEvent = hnd; + return DI_OK; +} + +static HRESULT WINAPI JoystickAImpl_GetCapabilities( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVCAPS lpDIDevCaps) +{ + JoystickImpl *This = (JoystickImpl *)iface; + int size; + + TRACE("%p->(%p)\n",iface,lpDIDevCaps); + + if (lpDIDevCaps == NULL) { + WARN("invalid parameter: lpDIDevCaps = NULL\n"); + return DIERR_INVALIDPARAM; + } + + size = lpDIDevCaps->dwSize; + CopyMemory(lpDIDevCaps, &This->devcaps, size); + lpDIDevCaps->dwSize = size; + + if (TRACE_ON(dinput)) + _dump_DIDEVCAPS(lpDIDevCaps); + + return DI_OK; +} + +static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(%p)\n",This); + + if (!This->acquired) { + WARN("not acquired\n"); + return DIERR_NOTACQUIRED; + } + + joy_polldev(This); + return DI_OK; +} + +/****************************************************************************** + * EnumObjects : enumerate the different buttons and axis... + */ +static HRESULT WINAPI JoystickAImpl_EnumObjects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + JoystickImpl *This = (JoystickImpl *)iface; + DIDEVICEOBJECTINSTANCEA ddoi; + BYTE i; + int user_offset; + int user_object; + + TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags); + if (TRACE_ON(dinput)) { + TRACE(" - flags = "); + _dump_EnumObjects_flags(dwFlags); + TRACE("\n"); + } + + /* Only the fields till dwFFMaxForce are relevant */ + ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce); + + /* For the joystick, do as is done in the GetCapabilities function */ + if ((dwFlags == DIDFT_ALL) || + (dwFlags & DIDFT_AXIS) || + (dwFlags & DIDFT_POV)) { + int pov[4] = { 0, 0, 0, 0 }; + int axes = 0; + int povs = 0; + + for (i = 0; i < This->axes; i++) { + int wine_obj = This->axis_map[i]; + BOOL skip = FALSE; + + switch (wine_obj) { + case 0: + ddoi.guidType = GUID_XAxis; + break; + case 1: + ddoi.guidType = GUID_YAxis; + break; + case 2: + ddoi.guidType = GUID_ZAxis; + break; + case 3: + ddoi.guidType = GUID_RxAxis; + break; + case 4: + ddoi.guidType = GUID_RyAxis; + break; + case 5: + ddoi.guidType = GUID_RzAxis; + break; + case 6: + ddoi.guidType = GUID_Slider; + break; + case 7: + ddoi.guidType = GUID_Slider; + break; + case 8: + pov[0]++; + ddoi.guidType = GUID_POV; + break; + case 9: + pov[1]++; + ddoi.guidType = GUID_POV; + break; + case 10: + pov[2]++; + ddoi.guidType = GUID_POV; + break; + case 11: + pov[3]++; + ddoi.guidType = GUID_POV; + break; + default: + ddoi.guidType = GUID_Unknown; + } + if (wine_obj < 8) { + user_offset = This->offsets[wine_obj]; /* get user offset from wine index */ + user_object = offset_to_object(This, user_offset); + + ddoi.dwType = This->user_df->rgodf[user_object].dwType & 0x00ffffff; + ddoi.dwOfs = This->user_df->rgodf[user_object].dwOfs; + sprintf(ddoi.tszName, "Axis %d", axes); + axes++; + } else { + if (pov[wine_obj - 8] < 2) { + user_offset = This->offsets[wine_obj]; /* get user offset from wine index */ + user_object = offset_to_object(This, user_offset); + + ddoi.dwType = This->user_df->rgodf[user_object].dwType & 0x00ffffff; + ddoi.dwOfs = This->user_df->rgodf[user_object].dwOfs; + sprintf(ddoi.tszName, "POV %d", povs); + povs++; + } else + skip = TRUE; + } + if (!skip) { + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) + return DI_OK; + } + } + } + + if ((dwFlags == DIDFT_ALL) || + (dwFlags & DIDFT_BUTTON)) { + + /* The DInput SDK says that GUID_Button is only for mouse buttons but well... */ + ddoi.guidType = GUID_Button; + + for (i = 0; i < This->buttons; i++) { + user_offset = This->offsets[i + 12]; /* get user offset from wine index */ + user_object = offset_to_object(This, user_offset); + ddoi.guidType = GUID_Button; + ddoi.dwType = This->user_df->rgodf[user_object].dwType & 0x00ffffff; + ddoi.dwOfs = This->user_df->rgodf[user_object].dwOfs; + sprintf(ddoi.tszName, "Button %d", i); + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; + } + } + + return DI_OK; +} + +/****************************************************************************** + * EnumObjects : enumerate the different buttons and axis... + */ +static HRESULT WINAPI JoystickWImpl_EnumObjects( + LPDIRECTINPUTDEVICE8W iface, + LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + device_enumobjects_AtoWcb_data data; + + data.lpCallBack = lpCallback; + data.lpvRef = lpvRef; + + return JoystickAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags); +} + +/****************************************************************************** + * GetProperty : get input device properties + */ +static HRESULT WINAPI JoystickAImpl_GetProperty( + LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPDIPROPHEADER pdiph) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(%p,%s,%p)\n", iface, debugstr_guid(rguid), pdiph); + + if (TRACE_ON(dinput)) + _dump_DIPROPHEADER(pdiph); + + if (!HIWORD(rguid)) { + switch ((DWORD)rguid) { + case (DWORD) DIPROP_BUFFERSIZE: { + LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; + TRACE(" return buffersize = %d\n",This->queue_len); + pd->dwData = This->queue_len; + break; + } + case (DWORD) DIPROP_RANGE: { + LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph; + int obj = find_property(This, pdiph); + /* The app is querying the current range of the axis + * return the lMin and lMax values */ + if (obj >= 0) { + pr->lMin = This->props[obj].lMin; + pr->lMax = This->props[obj].lMax; + TRACE("range(%ld, %ld) obj=%d\n", pr->lMin, pr->lMax, obj); + return DI_OK; + } + break; + } + case (DWORD) DIPROP_DEADZONE: { + LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; + int obj = find_property(This, pdiph); + if (obj >= 0) { + pd->dwData = This->props[obj].lDeadZone; + TRACE("deadzone(%ld) obj=%d\n", pd->dwData, obj); + return DI_OK; + } + break; + } + case (DWORD) DIPROP_SATURATION: { + LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; + int obj = find_property(This, pdiph); + if (obj >= 0) { + pd->dwData = This->props[obj].lSaturation; + TRACE("saturation(%ld) obj=%d\n", pd->dwData, obj); + return DI_OK; + } + break; + } + default: + FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); + break; + } + } + + return DI_OK; +} + +/****************************************************************************** + * GetObjectInfo : get object info + */ +HRESULT WINAPI JoystickAImpl_GetObjectInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEOBJECTINSTANCEA pdidoi, + DWORD dwObj, + DWORD dwHow) +{ + JoystickImpl *This = (JoystickImpl *)iface; + DIDEVICEOBJECTINSTANCEA didoiA; + unsigned int i; + + TRACE("(%p,%p,%ld,0x%08lx(%s))\n", + iface, pdidoi, dwObj, dwHow, + dwHow == DIPH_BYOFFSET ? "DIPH_BYOFFSET" : + dwHow == DIPH_BYID ? "DIPH_BYID" : + dwHow == DIPH_BYUSAGE ? "DIPH_BYUSAGE" : + "UNKNOWN"); + + if (pdidoi == NULL) { + WARN("invalid parameter: pdidoi = NULL\n"); + return DIERR_INVALIDPARAM; + } + + if ((pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCEA)) && + (pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3A))) { + WARN("invalid parameter: pdidoi->dwSize = %ld != %d or %d\n", + pdidoi->dwSize, sizeof(DIDEVICEOBJECTINSTANCEA), + sizeof(DIDEVICEOBJECTINSTANCE_DX3A)); + return DIERR_INVALIDPARAM; + } + + ZeroMemory(&didoiA, sizeof(didoiA)); + didoiA.dwSize = pdidoi->dwSize; + + switch (dwHow) { + case DIPH_BYOFFSET: { + int axis = 0; + int pov = 0; + int button = 0; + for (i = 0; i < This->user_df->dwNumObjs; i++) { + if (This->user_df->rgodf[i].dwOfs == dwObj) { + if (This->user_df->rgodf[i].pguid) + didoiA.guidType = *This->user_df->rgodf[i].pguid; + else + didoiA.guidType = GUID_NULL; + + didoiA.dwOfs = dwObj; + didoiA.dwType = This->user_df->rgodf[i].dwType; + didoiA.dwFlags = This->user_df->rgodf[i].dwFlags; + + if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_AXIS) + sprintf(didoiA.tszName, "Axis %d", axis); + else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_POV) + sprintf(didoiA.tszName, "POV %d", pov); + else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_BUTTON) + sprintf(didoiA.tszName, "Button %d", button); + + CopyMemory(pdidoi, &didoiA, pdidoi->dwSize); + return DI_OK; + } + + if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_AXIS) + axis++; + else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_POV) + pov++; + else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_BUTTON) + button++; + } + break; + } + case DIPH_BYID: + FIXME("dwHow = DIPH_BYID not implemented\n"); + break; + case DIPH_BYUSAGE: + FIXME("dwHow = DIPH_BYUSAGE not implemented\n"); + break; + default: + WARN("invalid parameter: dwHow = %08lx\n", dwHow); + return DIERR_INVALIDPARAM; + } + + CopyMemory(pdidoi, &didoiA, pdidoi->dwSize); + + return DI_OK; +} + +/****************************************************************************** + * GetDeviceInfo : get information about a device's identity + */ +HRESULT WINAPI JoystickAImpl_GetDeviceInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEINSTANCEA pdidi) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(%p,%p)\n", iface, pdidi); + + if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3A)) && + (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA))) { + WARN("invalid parameter: pdidi->dwSize = %ld != %d or %d\n", + pdidi->dwSize, sizeof(DIDEVICEINSTANCE_DX3A), + sizeof(DIDEVICEINSTANCEA)); + return DIERR_INVALIDPARAM; + } + + /* Return joystick */ + pdidi->guidInstance = GUID_Joystick; + pdidi->guidProduct = DInput_Wine_Joystick_GUID; + /* we only support traditional joysticks for now */ + if (This->dinput->version >= 8) + pdidi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); + else + pdidi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); + strcpy(pdidi->tszInstanceName, "Joystick"); + strcpy(pdidi->tszProductName, This->name); + if (pdidi->dwSize > sizeof(DIDEVICEINSTANCE_DX3A)) { + pdidi->guidFFDriver = GUID_NULL; + pdidi->wUsagePage = 0; + pdidi->wUsage = 0; + } + + return DI_OK; +} + +/****************************************************************************** + * GetDeviceInfo : get information about a device's identity + */ +HRESULT WINAPI JoystickWImpl_GetDeviceInfo( + LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEINSTANCEW pdidi) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(%p,%p)\n", iface, pdidi); + + if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3W)) && + (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW))) { + WARN("invalid parameter: pdidi->dwSize = %ld != %d or %d\n", + pdidi->dwSize, sizeof(DIDEVICEINSTANCE_DX3W), + sizeof(DIDEVICEINSTANCEW)); + return DIERR_INVALIDPARAM; + } + + /* Return joystick */ + pdidi->guidInstance = GUID_Joystick; + pdidi->guidProduct = DInput_Wine_Joystick_GUID; + /* we only support traditional joysticks for now */ + if (This->dinput->version >= 8) + pdidi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); + else + pdidi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); + MultiByteToWideChar(CP_ACP, 0, "Joystick", -1, pdidi->tszInstanceName, MAX_PATH); + MultiByteToWideChar(CP_ACP, 0, This->name, -1, pdidi->tszProductName, MAX_PATH); + if (pdidi->dwSize > sizeof(DIDEVICEINSTANCE_DX3W)) { + pdidi->guidFFDriver = GUID_NULL; + pdidi->wUsagePage = 0; + pdidi->wUsage = 0; + } + + return DI_OK; +} + +static IDirectInputDevice8AVtbl JoystickAvt = +{ + IDirectInputDevice2AImpl_QueryInterface, + IDirectInputDevice2AImpl_AddRef, + JoystickAImpl_Release, + JoystickAImpl_GetCapabilities, + JoystickAImpl_EnumObjects, + JoystickAImpl_GetProperty, + JoystickAImpl_SetProperty, + JoystickAImpl_Acquire, + JoystickAImpl_Unacquire, + JoystickAImpl_GetDeviceState, + JoystickAImpl_GetDeviceData, + JoystickAImpl_SetDataFormat, + JoystickAImpl_SetEventNotification, + IDirectInputDevice2AImpl_SetCooperativeLevel, + JoystickAImpl_GetObjectInfo, + JoystickAImpl_GetDeviceInfo, + IDirectInputDevice2AImpl_RunControlPanel, + IDirectInputDevice2AImpl_Initialize, + IDirectInputDevice2AImpl_CreateEffect, + IDirectInputDevice2AImpl_EnumEffects, + IDirectInputDevice2AImpl_GetEffectInfo, + IDirectInputDevice2AImpl_GetForceFeedbackState, + IDirectInputDevice2AImpl_SendForceFeedbackCommand, + IDirectInputDevice2AImpl_EnumCreatedEffectObjects, + IDirectInputDevice2AImpl_Escape, + JoystickAImpl_Poll, + IDirectInputDevice2AImpl_SendDeviceData, + IDirectInputDevice7AImpl_EnumEffectsInFile, + IDirectInputDevice7AImpl_WriteEffectToFile, + IDirectInputDevice8AImpl_BuildActionMap, + IDirectInputDevice8AImpl_SetActionMap, + IDirectInputDevice8AImpl_GetImageInfo +}; + +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(SysJoystickWvt.fun)) +#else +# define XCAST(fun) (void*) +#endif + +static IDirectInputDevice8WVtbl SysJoystickWvt = +{ + IDirectInputDevice2WImpl_QueryInterface, + XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, + XCAST(Release)JoystickAImpl_Release, + XCAST(GetCapabilities)JoystickAImpl_GetCapabilities, + JoystickWImpl_EnumObjects, + XCAST(GetProperty)JoystickAImpl_GetProperty, + XCAST(SetProperty)JoystickAImpl_SetProperty, + XCAST(Acquire)JoystickAImpl_Acquire, + XCAST(Unacquire)JoystickAImpl_Unacquire, + XCAST(GetDeviceState)JoystickAImpl_GetDeviceState, + XCAST(GetDeviceData)JoystickAImpl_GetDeviceData, + XCAST(SetDataFormat)JoystickAImpl_SetDataFormat, + XCAST(SetEventNotification)JoystickAImpl_SetEventNotification, + XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel, + IDirectInputDevice2WImpl_GetObjectInfo, + JoystickWImpl_GetDeviceInfo, + XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel, + XCAST(Initialize)IDirectInputDevice2AImpl_Initialize, + XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect, + IDirectInputDevice2WImpl_EnumEffects, + IDirectInputDevice2WImpl_GetEffectInfo, + XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState, + XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand, + XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects, + XCAST(Escape)IDirectInputDevice2AImpl_Escape, + XCAST(Poll)JoystickAImpl_Poll, + XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData, + IDirectInputDevice7WImpl_EnumEffectsInFile, + IDirectInputDevice7WImpl_WriteEffectToFile, + IDirectInputDevice8WImpl_BuildActionMap, + IDirectInputDevice8WImpl_SetActionMap, + IDirectInputDevice8WImpl_GetImageInfo +}; +#undef XCAST + +#endif /* HAVE_LINUX_22_JOYSTICK_API */ diff --git a/reactos/lib/dinput/joystick_linuxinput.c b/reactos/lib/dinput/joystick_linuxinput.c new file mode 100644 index 00000000000..514715b578b --- /dev/null +++ b/reactos/lib/dinput/joystick_linuxinput.c @@ -0,0 +1,1090 @@ +/* DirectInput Joystick device + * + * Copyright 1998,2000 Marcus Meissner + * Copyright 1998,1999 Lionel Ulmer + * Copyright 2000-2001 TransGaming Technologies Inc. + * + * 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.1 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 + */ + +#include "config.h" +#include "wine/port.h" + +#ifdef HAVE_LINUX_INPUT_H + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_SYS_TIME_H +# include +#endif +#include +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#include +#ifdef HAVE_SYS_ERRNO_H +# include +#endif + +#ifdef HAVE_CORRECT_LINUXINPUT_H + +#ifdef HAVE_LINUX_INPUT_H +# include +#endif + + +#define EVDEVPREFIX "/dev/input/event" + +#include "wine/debug.h" +#include "wine/unicode.h" +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "dinput.h" + +#include "dinput_private.h" +#include "device_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dinput); + +/* Wine joystick driver object instances */ +#define WINE_JOYSTICK_AXIS_BASE 0 +#define WINE_JOYSTICK_BUTTON_BASE 8 + +typedef struct JoystickImpl JoystickImpl; +static IDirectInputDevice8AVtbl JoystickAvt; +static IDirectInputDevice8WVtbl JoystickWvt; +struct JoystickImpl +{ + LPVOID lpVtbl; + DWORD ref; + GUID guid; + + + /* The 'parent' DInput */ + IDirectInputImpl *dinput; + + /* joystick private */ + /* what range and deadzone the game wants */ + LONG wantmin[ABS_MAX]; + LONG wantmax[ABS_MAX]; + LONG deadz[ABS_MAX]; + + /* autodetecting ranges per axe by following movement */ + LONG havemax[ABS_MAX]; + LONG havemin[ABS_MAX]; + + int joyfd; + + LPDIDATAFORMAT df; + HANDLE hEvent; + LPDIDEVICEOBJECTDATA data_queue; + int queue_head, queue_tail, queue_len; + BOOL overflow; + DIJOYSTATE2 js; + + /* data returned by the EVIOCGABS() ioctl */ + int axes[ABS_MAX+1][5]; + +#define AXE_ABS 0 +#define AXE_ABSMIN 1 +#define AXE_ABSMAX 2 +#define AXE_ABSFUZZ 3 +#define AXE_ABSFLAT 4 + + + /* data returned by EVIOCGBIT for EV_ABS and EV_KEY */ + BYTE absbits[(ABS_MAX+7)/8]; + BYTE keybits[(KEY_MAX+7)/8]; +}; + +/* This GUID is slightly different from the linux joystick one. Take note. */ +static GUID DInput_Wine_Joystick_GUID = { /* 9e573eda-7734-11d2-8d4a-23903fb6bdf7 */ + 0x9e573eda, + 0x7734, + 0x11d2, + {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7} +}; + +static void fake_current_js_state(JoystickImpl *ji); + +#define test_bit(arr,bit) (((BYTE*)arr)[bit>>3]&(1<<(bit&7))) + +static int joydev_have(void) +{ + int i, fd; + int havejoy = 0; + + for (i=0;i<64;i++) { + char buf[200]; + BYTE absbits[(ABS_MAX+7)/8],keybits[(KEY_MAX+7)/8]; + + sprintf(buf,EVDEVPREFIX"%d",i); + if (-1!=(fd=open(buf,O_RDONLY))) { + if (-1==ioctl(fd,EVIOCGBIT(EV_ABS,sizeof(absbits)),absbits)) { + perror("EVIOCGBIT EV_ABS"); + close(fd); + continue; + } + if (-1==ioctl(fd,EVIOCGBIT(EV_KEY,sizeof(keybits)),keybits)) { + perror("EVIOCGBIT EV_KEY"); + close(fd); + continue; + } + /* A true joystick has at least axis X and Y, and at least 1 + * button. copied from linux/drivers/input/joydev.c */ + if (test_bit(absbits,ABS_X) && test_bit(absbits,ABS_Y) && + ( test_bit(keybits,BTN_TRIGGER) || + test_bit(keybits,BTN_A) || + test_bit(keybits,BTN_1) + ) + ) { + FIXME("found a joystick at %s!\n",buf); + havejoy = 1; + } + close(fd); + } + if (havejoy || (errno==ENODEV)) + break; + } + return havejoy; +} + +static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, int version, int id) +{ + int havejoy = 0; + + if (id != 0) + return FALSE; + + if ((dwDevType != 0) && (GET_DIDEVICE_TYPE(dwDevType) != DIDEVTYPE_JOYSTICK)) + return FALSE; + + if (dwFlags & DIEDFL_FORCEFEEDBACK) + return FALSE; + + havejoy = joydev_have(); + + if (!havejoy) + return FALSE; + + TRACE("Enumerating the linuxinput Joystick device\n"); + + /* Return joystick */ + lpddi->guidInstance = GUID_Joystick; + lpddi->guidProduct = DInput_Wine_Joystick_GUID; + + lpddi->guidFFDriver = GUID_NULL; + if (version >= 8) + lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); + else + lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); + + strcpy(lpddi->tszInstanceName, "Joystick"); + /* ioctl JSIOCGNAME(len) */ + strcpy(lpddi->tszProductName, "Wine Joystick"); + return TRUE; +} + +static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, int version, int id) +{ + int havejoy = 0; + + if (id != 0) + return FALSE; + + if ((dwDevType != 0) && (GET_DIDEVICE_TYPE(dwDevType) != DIDEVTYPE_JOYSTICK)) + return FALSE; + + if (dwFlags & DIEDFL_FORCEFEEDBACK) + return FALSE; + + havejoy = joydev_have(); + + if (!havejoy) + return FALSE; + + TRACE("Enumerating the linuxinput Joystick device\n"); + + /* Return joystick */ + lpddi->guidInstance = GUID_Joystick; + lpddi->guidProduct = DInput_Wine_Joystick_GUID; + + lpddi->guidFFDriver = GUID_NULL; + lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL<<8); + + MultiByteToWideChar(CP_ACP, 0, "Joystick", -1, lpddi->tszInstanceName, MAX_PATH); + /* ioctl JSIOCGNAME(len) */ + MultiByteToWideChar(CP_ACP, 0, "Wine Joystick", -1, lpddi->tszProductName, MAX_PATH); + return TRUE; +} + +static JoystickImpl *alloc_device(REFGUID rguid, LPVOID jvt, IDirectInputImpl *dinput) +{ + JoystickImpl* newDevice; + int i; + + newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl)); + newDevice->lpVtbl = jvt; + newDevice->ref = 1; + newDevice->joyfd = -1; + newDevice->dinput = dinput; + memcpy(&(newDevice->guid),rguid,sizeof(*rguid)); + for (i=0;iwantmin[i] = -32768; + newDevice->wantmax[i] = 32767; + /* TODO: + * direct input defines a default for the deadzone somewhere; but as long + * as in map_axis the code for the dead zone is commented out its no + * problem + */ + newDevice->deadz[i] = 0; + } + fake_current_js_state(newDevice); + return newDevice; +} + +static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev) +{ + int havejoy = 0; + + havejoy = joydev_have(); + + if (!havejoy) + return DIERR_DEVICENOTREG; + + if ((IsEqualGUID(&GUID_Joystick,rguid)) || + (IsEqualGUID(&DInput_Wine_Joystick_GUID,rguid))) { + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceA,riid) || + IsEqualGUID(&IID_IDirectInputDevice2A,riid) || + IsEqualGUID(&IID_IDirectInputDevice7A,riid) || + IsEqualGUID(&IID_IDirectInputDevice8A,riid)) { + *pdev = (IDirectInputDeviceA*) alloc_device(rguid, &JoystickAvt, dinput); + TRACE("Creating a Joystick device (%p)\n", *pdev); + return DI_OK; + } else + return DIERR_NOINTERFACE; + } + + return DIERR_DEVICENOTREG; +} + + +static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev) +{ + int havejoy = 0; + + havejoy = joydev_have(); + + if (!havejoy) + return DIERR_DEVICENOTREG; + + if ((IsEqualGUID(&GUID_Joystick,rguid)) || + (IsEqualGUID(&DInput_Wine_Joystick_GUID,rguid))) { + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceW,riid) || + IsEqualGUID(&IID_IDirectInputDevice2W,riid) || + IsEqualGUID(&IID_IDirectInputDevice7W,riid) || + IsEqualGUID(&IID_IDirectInputDevice8W,riid)) { + *pdev = (IDirectInputDeviceW*) alloc_device(rguid, &JoystickWvt, dinput); + TRACE("Creating a Joystick device (%p)\n", *pdev); + return DI_OK; + } else + return DIERR_NOINTERFACE; + } + + return DIERR_DEVICENOTREG; +} + +static dinput_device joydev = { + 20, + "Wine Linux-input joystick driver", + joydev_enum_deviceA, + joydev_enum_deviceW, + joydev_create_deviceA, + joydev_create_deviceW +}; + +DECL_GLOBAL_CONSTRUCTOR(joydev_register) { dinput_register_device(&joydev); } + +/****************************************************************************** + * Joystick + */ +static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE8A iface) +{ + JoystickImpl *This = (JoystickImpl *)iface; + ULONG ref; + + ref = InterlockedDecrement(&(This->ref)); + if (ref) + return ref; + + /* Free the data queue */ + if (This->data_queue != NULL) + HeapFree(GetProcessHeap(),0,This->data_queue); + + /* Free the DataFormat */ + HeapFree(GetProcessHeap(), 0, This->df); + + HeapFree(GetProcessHeap(),0,This); + return 0; +} + +/****************************************************************************** + * SetDataFormat : the application can choose the format of the data + * the device driver sends back with GetDeviceState. + */ +static HRESULT WINAPI JoystickAImpl_SetDataFormat( + LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df +) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(this=%p,%p)\n",This,df); + + _dump_DIDATAFORMAT(df); + + /* Store the new data format */ + This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize); + memcpy(This->df, df, df->dwSize); + This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize); + memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize); + + return 0; +} + +/****************************************************************************** + * Acquire : gets exclusive control of the joystick + */ +static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) +{ + int i; + JoystickImpl *This = (JoystickImpl *)iface; + char buf[200]; + + TRACE("(this=%p)\n",This); + if (This->joyfd!=-1) + return 0; + for (i=0;i<64;i++) { + sprintf(buf,EVDEVPREFIX"%d",i); + if (-1==(This->joyfd=open(buf,O_RDONLY))) { + if (errno==ENODEV) + return DIERR_NOTFOUND; + perror(buf); + continue; + } + if ((-1!=ioctl(This->joyfd,EVIOCGBIT(EV_ABS,sizeof(This->absbits)),This->absbits)) && + (-1!=ioctl(This->joyfd,EVIOCGBIT(EV_KEY,sizeof(This->keybits)),This->keybits)) && + (test_bit(This->absbits,ABS_X) && test_bit(This->absbits,ABS_Y) && + (test_bit(This->keybits,BTN_TRIGGER)|| + test_bit(This->keybits,BTN_A) || + test_bit(This->keybits,BTN_1) + ) + ) + ) + break; + close(This->joyfd); + This->joyfd = -1; + } + if (This->joyfd==-1) + return DIERR_NOTFOUND; + + for (i=0;iabsbits,i)) { + if (-1==ioctl(This->joyfd,EVIOCGABS(i),&(This->axes[i]))) + continue; + FIXME("axe %d: cur=%d, min=%d, max=%d, fuzz=%d, flat=%d\n", + i, + This->axes[i][AXE_ABS], + This->axes[i][AXE_ABSMIN], + This->axes[i][AXE_ABSMAX], + This->axes[i][AXE_ABSFUZZ], + This->axes[i][AXE_ABSFLAT] + ); + This->havemin[i] = This->axes[i][AXE_ABSMIN]; + This->havemax[i] = This->axes[i][AXE_ABSMAX]; + } + } + MESSAGE("\n"); + + fake_current_js_state(This); + + return 0; +} + +/****************************************************************************** + * Unacquire : frees the joystick + */ +static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(this=%p)\n",This); + if (This->joyfd!=-1) { + close(This->joyfd); + This->joyfd = -1; + return DI_OK; + } + else + return DI_NOEFFECT; +} + +/* + * This maps the read value (from the input event) to a value in the + * 'wanted' range. It also autodetects the possible range of the axe and + * adapts values accordingly. + */ +static int +map_axis(JoystickImpl* This, int axis, int val) { + int xmin = This->axes[axis][AXE_ABSMIN]; + int xmax = This->axes[axis][AXE_ABSMAX]; + int hmax = This->havemax[axis]; + int hmin = This->havemin[axis]; + int wmin = This->wantmin[axis]; + int wmax = This->wantmax[axis]; + int ret; + + if (val > hmax) This->havemax[axis] = hmax = val; + if (val < hmin) This->havemin[axis] = hmin = val; + + if (xmin == xmax) return val; + + /* map the value from the hmin-hmax range into the wmin-wmax range */ + ret = (val * (wmax-wmin)) / (hmax-hmin) + wmin; + +#if 0 + /* deadzone doesn't work comfortably enough right now. needs more testing*/ + if ((ret > -deadz/2 ) && (ret < deadz/2)) { + FIXME("%d in deadzone, return mid.\n",val); + return (wmax-wmin)/2+wmin; + } +#endif + return ret; +} + +/* + * set the current state of the js device as it would be with the middle + * values on the axes + */ +static void fake_current_js_state(JoystickImpl *ji) +{ + ji->js.lX = map_axis(ji, ABS_X, ji->axes[ABS_X ][AXE_ABS]); + ji->js.lY = map_axis(ji, ABS_Y, ji->axes[ABS_Y ][AXE_ABS]); + ji->js.lZ = map_axis(ji, ABS_Z, ji->axes[ABS_Z ][AXE_ABS]); + ji->js.lRx = map_axis(ji, ABS_RX, ji->axes[ABS_RX][AXE_ABS]); + ji->js.lRy = map_axis(ji, ABS_RY, ji->axes[ABS_RY][AXE_ABS]); + ji->js.lRz = map_axis(ji, ABS_RZ, ji->axes[ABS_RZ][AXE_ABS]); +} + +static void joy_polldev(JoystickImpl *This) { + struct timeval tv; + fd_set readfds; + struct input_event ie; + + if (This->joyfd==-1) + return; + + while (1) { + memset(&tv,0,sizeof(tv)); + FD_ZERO(&readfds); + FD_SET(This->joyfd,&readfds); + + if (1>select(This->joyfd+1,&readfds,NULL,NULL,&tv)) + return; + + /* we have one event, so we can read */ + if (sizeof(ie)!=read(This->joyfd,&ie,sizeof(ie))) + return; + + TRACE("input_event: type %d, code %d, value %d\n",ie.type,ie.code,ie.value); + switch (ie.type) { + case EV_KEY: /* button */ + switch (ie.code) { + case BTN_TRIGGER: /* normal flight stick */ + case BTN_A: /* gamepad */ + case BTN_1: /* generic */ + This->js.rgbButtons[0] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(0),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_THUMB: + case BTN_B: + case BTN_2: + This->js.rgbButtons[1] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(1),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_THUMB2: + case BTN_C: + case BTN_3: + This->js.rgbButtons[2] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(2),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_TOP: + case BTN_X: + case BTN_4: + This->js.rgbButtons[3] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(3),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_TOP2: + case BTN_Y: + case BTN_5: + This->js.rgbButtons[4] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(4),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_PINKIE: + case BTN_Z: + case BTN_6: + This->js.rgbButtons[5] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(5),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_BASE: + case BTN_TL: + case BTN_7: + This->js.rgbButtons[6] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(6),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_BASE2: + case BTN_TR: + case BTN_8: + This->js.rgbButtons[7] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(7),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_BASE3: + case BTN_TL2: + case BTN_9: + This->js.rgbButtons[8] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(8),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_BASE4: + case BTN_TR2: + This->js.rgbButtons[9] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(9),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_BASE5: + case BTN_SELECT: + This->js.rgbButtons[10] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(10),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + default: + FIXME("unhandled joystick button %x, value %d\n",ie.code,ie.value); + break; + } + break; + case EV_ABS: + switch (ie.code) { + case ABS_X: + This->js.lX = map_axis(This,ABS_X,ie.value); + GEN_EVENT(DIJOFS_X,This->js.lX,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case ABS_Y: + This->js.lY = map_axis(This,ABS_Y,ie.value); + GEN_EVENT(DIJOFS_Y,This->js.lY,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case ABS_Z: + This->js.lZ = map_axis(This,ABS_Z,ie.value); + GEN_EVENT(DIJOFS_Z,This->js.lZ,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case ABS_RX: + This->js.lRx = map_axis(This,ABS_RX,ie.value); + GEN_EVENT(DIJOFS_RX,This->js.lRx,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case ABS_RY: + This->js.lRy = map_axis(This,ABS_RY,ie.value); + GEN_EVENT(DIJOFS_RY,This->js.lRy,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case ABS_RZ: + This->js.lRz = map_axis(This,ABS_RZ,ie.value); + GEN_EVENT(DIJOFS_RZ,This->js.lRz,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + default: + FIXME("unhandled joystick axe event (code %d, value %d)\n",ie.code,ie.value); + break; + } + break; + default: + FIXME("joystick cannot handle type %d event (code %d)\n",ie.type,ie.code); + break; + } + } +} + +/****************************************************************************** + * GetDeviceState : returns the "state" of the joystick. + * + */ +static HRESULT WINAPI JoystickAImpl_GetDeviceState( + LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr +) { + JoystickImpl *This = (JoystickImpl *)iface; + + joy_polldev(This); + + TRACE("(this=%p,0x%08lx,%p)\n",This,len,ptr); + if ((len != sizeof(DIJOYSTATE)) && (len != sizeof(DIJOYSTATE2))) { + FIXME("len %ld is not sizeof(DIJOYSTATE) or DIJOYSTATE2, unsupported format.\n",len); + return E_FAIL; + } + memcpy(ptr,&(This->js),len); + This->queue_head = 0; + This->queue_tail = 0; + return 0; +} + +/****************************************************************************** + * GetDeviceData : gets buffered input data. + */ +static HRESULT WINAPI JoystickAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface, + DWORD dodsize, + LPDIDEVICEOBJECTDATA dod, + LPDWORD entries, + DWORD flags +) { + JoystickImpl *This = (JoystickImpl *)iface; + + FIXME("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx),STUB!\n",This,dodsize,*entries,flags); + + joy_polldev(This); + if (flags & DIGDD_PEEK) + FIXME("DIGDD_PEEK\n"); + + if (dod == NULL) { + } else { + } + return 0; +} + +/****************************************************************************** + * SetProperty : change input device properties + */ +static HRESULT WINAPI JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPCDIPROPHEADER ph) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + FIXME("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph); + FIXME("ph.dwSize = %ld, ph.dwHeaderSize =%ld, ph.dwObj = %ld, ph.dwHow= %ld\n",ph->dwSize, ph->dwHeaderSize,ph->dwObj,ph->dwHow); + + if (!HIWORD(rguid)) { + switch ((DWORD)rguid) { + case (DWORD) DIPROP_BUFFERSIZE: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + + FIXME("buffersize = %ld\n",pd->dwData); + break; + } + case (DWORD)DIPROP_RANGE: { + LPCDIPROPRANGE pr = (LPCDIPROPRANGE)ph; + + FIXME("proprange(%ld,%ld)\n",pr->lMin,pr->lMax); + switch (ph->dwObj) { + case 0: /* X */ + case 4: /* Y */ + case 8: /* Z */ + case 12: /* Rx */ + case 16: /* Ry */ + case 20: /* Rz */ + This->wantmin[ph->dwObj/4] = pr->lMin; + This->wantmax[ph->dwObj/4] = pr->lMax; + break; + default: + FIXME("setting proprange %ld - %ld for dwObj %ld\n",pr->lMin,pr->lMax,ph->dwObj); + } + break; + } + case (DWORD)DIPROP_DEADZONE: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + + FIXME("setting deadzone(%ld)\n",pd->dwData); + This->deadz[ph->dwObj/4] = pd->dwData; + break; + } + default: + FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); + break; + } + } + fake_current_js_state(This); + return 0; +} + +/****************************************************************************** + * SetEventNotification : specifies event to be sent on state change + */ +static HRESULT WINAPI JoystickAImpl_SetEventNotification( + LPDIRECTINPUTDEVICE8A iface, HANDLE hnd +) { + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd); + This->hEvent = hnd; + return DI_OK; +} + +static HRESULT WINAPI JoystickAImpl_GetCapabilities( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVCAPS lpDIDevCaps) +{ + JoystickImpl *This = (JoystickImpl *)iface; + int xfd = This->joyfd; + int i,axes,buttons; + int wasacquired = 1; + + TRACE("%p->(%p)\n",iface,lpDIDevCaps); + if (xfd==-1) { + /* yes, games assume we return something, even if unacquired */ + JoystickAImpl_Acquire(iface); + xfd = This->joyfd; + wasacquired = 0; + } + lpDIDevCaps->dwFlags = DIDC_ATTACHED; + lpDIDevCaps->dwDevType = DIDEVTYPE_JOYSTICK; + + axes=0; + for (i=0;iabsbits,i)) axes++; + buttons=0; + for (i=0;ikeybits,i)) buttons++; + + lpDIDevCaps->dwAxes = axes; + lpDIDevCaps->dwButtons = buttons; + + if (!wasacquired) + JoystickAImpl_Unacquire(iface); + + return DI_OK; +} + +static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface) { + JoystickImpl *This = (JoystickImpl *)iface; + TRACE("(),stub!\n"); + + joy_polldev(This); + return DI_OK; +} + +/****************************************************************************** + * EnumObjects : enumerate the different buttons and axis... + */ +static HRESULT WINAPI JoystickAImpl_EnumObjects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + JoystickImpl *This = (JoystickImpl *)iface; + DIDEVICEOBJECTINSTANCEA ddoi; + int xfd = This->joyfd; + + + TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags); + if (TRACE_ON(dinput)) { + TRACE(" - flags = "); + _dump_EnumObjects_flags(dwFlags); + TRACE("\n"); + } + + if (xfd == -1) return DIERR_NOTACQUIRED; + + /* Only the fields till dwFFMaxForce are relevant */ + ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce); + + /* For the joystick, do as is done in the GetCapabilities function */ + /* FIXME: needs more items */ + if ((dwFlags == DIDFT_ALL) || + (dwFlags & DIDFT_AXIS)) { + BYTE i; + + for (i = 0; i < ABS_MAX; i++) { + if (!test_bit(This->absbits,i)) continue; + + switch (i) { + case ABS_X: + ddoi.guidType = GUID_XAxis; + ddoi.dwOfs = DIJOFS_X; + break; + case ABS_Y: + ddoi.guidType = GUID_YAxis; + ddoi.dwOfs = DIJOFS_Y; + break; + case ABS_Z: + ddoi.guidType = GUID_ZAxis; + ddoi.dwOfs = DIJOFS_Z; + break; + case ABS_RX: + ddoi.guidType = GUID_RxAxis; + ddoi.dwOfs = DIJOFS_RX; + break; + case ABS_RY: + ddoi.guidType = GUID_RyAxis; + ddoi.dwOfs = DIJOFS_RY; + break; + case ABS_RZ: + ddoi.guidType = GUID_RzAxis; + ddoi.dwOfs = DIJOFS_RZ; + break; + case ABS_THROTTLE: + ddoi.guidType = GUID_Slider; + ddoi.dwOfs = DIJOFS_SLIDER(0); + break; + default: + FIXME("unhandled abs axis %d, ignoring!\n",i); + } + ddoi.dwType = DIDFT_MAKEINSTANCE((1<keybits,i)) continue; + + switch (i) { + case BTN_TRIGGER: + case BTN_A: + case BTN_1: + ddoi.dwOfs = DIJOFS_BUTTON(0); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 0) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_THUMB: + case BTN_B: + case BTN_2: + ddoi.dwOfs = DIJOFS_BUTTON(1); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 1) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_THUMB2: + case BTN_C: + case BTN_3: + ddoi.dwOfs = DIJOFS_BUTTON(2); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 2) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_TOP: + case BTN_X: + case BTN_4: + ddoi.dwOfs = DIJOFS_BUTTON(3); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 3) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_TOP2: + case BTN_Y: + case BTN_5: + ddoi.dwOfs = DIJOFS_BUTTON(4); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 4) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_PINKIE: + case BTN_Z: + case BTN_6: + ddoi.dwOfs = DIJOFS_BUTTON(5); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 5) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_BASE: + case BTN_TL: + case BTN_7: + ddoi.dwOfs = DIJOFS_BUTTON(6); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 6) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_BASE2: + case BTN_TR: + case BTN_8: + ddoi.dwOfs = DIJOFS_BUTTON(7); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 7) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_BASE3: + case BTN_TL2: + case BTN_9: + ddoi.dwOfs = DIJOFS_BUTTON(8); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 8) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_BASE4: + case BTN_TR2: + ddoi.dwOfs = DIJOFS_BUTTON(9); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 9) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_BASE5: + case BTN_SELECT: + ddoi.dwOfs = DIJOFS_BUTTON(10); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 10) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + } + sprintf(ddoi.tszName, "%d-Button", i); + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) + return DI_OK; + } + } + + if (xfd!=This->joyfd) + close(xfd); + + return DI_OK; +} + +static HRESULT WINAPI JoystickWImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface, + LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + device_enumobjects_AtoWcb_data data; + + data.lpCallBack = lpCallback; + data.lpvRef = lpvRef; + + return JoystickAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags); +} + +/****************************************************************************** + * GetProperty : get input device properties + */ +static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPDIPROPHEADER pdiph) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(this=%p,%s,%p): stub!\n", + iface, debugstr_guid(rguid), pdiph); + + if (TRACE_ON(dinput)) + _dump_DIPROPHEADER(pdiph); + + if (!HIWORD(rguid)) { + switch ((DWORD)rguid) { + case (DWORD) DIPROP_BUFFERSIZE: { + LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; + + TRACE(" return buffersize = %d\n",This->queue_len); + pd->dwData = This->queue_len; + break; + } + + case (DWORD) DIPROP_RANGE: { + /* LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph; */ + if ((pdiph->dwHow == DIPH_BYID) && + (pdiph->dwObj & DIDFT_ABSAXIS)) { + /* The app is querying the current range of the axis : return the lMin and lMax values */ + FIXME("unimplemented axis range query.\n"); + } + + break; + } + + default: + FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); + break; + } + } + + + return DI_OK; +} + +static IDirectInputDevice8AVtbl JoystickAvt = +{ + IDirectInputDevice2AImpl_QueryInterface, + IDirectInputDevice2AImpl_AddRef, + JoystickAImpl_Release, + JoystickAImpl_GetCapabilities, + JoystickAImpl_EnumObjects, + JoystickAImpl_GetProperty, + JoystickAImpl_SetProperty, + JoystickAImpl_Acquire, + JoystickAImpl_Unacquire, + JoystickAImpl_GetDeviceState, + JoystickAImpl_GetDeviceData, + JoystickAImpl_SetDataFormat, + JoystickAImpl_SetEventNotification, + IDirectInputDevice2AImpl_SetCooperativeLevel, + IDirectInputDevice2AImpl_GetObjectInfo, + IDirectInputDevice2AImpl_GetDeviceInfo, + IDirectInputDevice2AImpl_RunControlPanel, + IDirectInputDevice2AImpl_Initialize, + IDirectInputDevice2AImpl_CreateEffect, + IDirectInputDevice2AImpl_EnumEffects, + IDirectInputDevice2AImpl_GetEffectInfo, + IDirectInputDevice2AImpl_GetForceFeedbackState, + IDirectInputDevice2AImpl_SendForceFeedbackCommand, + IDirectInputDevice2AImpl_EnumCreatedEffectObjects, + IDirectInputDevice2AImpl_Escape, + JoystickAImpl_Poll, + IDirectInputDevice2AImpl_SendDeviceData, + IDirectInputDevice7AImpl_EnumEffectsInFile, + IDirectInputDevice7AImpl_WriteEffectToFile, + IDirectInputDevice8AImpl_BuildActionMap, + IDirectInputDevice8AImpl_SetActionMap, + IDirectInputDevice8AImpl_GetImageInfo +}; + +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(JoystickWvt.fun)) +#else +# define XCAST(fun) (void*) +#endif + +static IDirectInputDevice8WVtbl JoystickWvt = +{ + IDirectInputDevice2WImpl_QueryInterface, + XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, + XCAST(Release)JoystickAImpl_Release, + XCAST(GetCapabilities)JoystickAImpl_GetCapabilities, + JoystickWImpl_EnumObjects, + XCAST(GetProperty)JoystickAImpl_GetProperty, + XCAST(SetProperty)JoystickAImpl_SetProperty, + XCAST(Acquire)JoystickAImpl_Acquire, + XCAST(Unacquire)JoystickAImpl_Unacquire, + XCAST(GetDeviceState)JoystickAImpl_GetDeviceState, + XCAST(GetDeviceData)JoystickAImpl_GetDeviceData, + XCAST(SetDataFormat)JoystickAImpl_SetDataFormat, + XCAST(SetEventNotification)JoystickAImpl_SetEventNotification, + XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel, + IDirectInputDevice2WImpl_GetObjectInfo, + IDirectInputDevice2WImpl_GetDeviceInfo, + XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel, + XCAST(Initialize)IDirectInputDevice2AImpl_Initialize, + XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect, + IDirectInputDevice2WImpl_EnumEffects, + IDirectInputDevice2WImpl_GetEffectInfo, + XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState, + XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand, + XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects, + XCAST(Escape)IDirectInputDevice2AImpl_Escape, + XCAST(Poll)JoystickAImpl_Poll, + XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData, + IDirectInputDevice7WImpl_EnumEffectsInFile, + IDirectInputDevice7WImpl_WriteEffectToFile, + IDirectInputDevice8WImpl_BuildActionMap, + IDirectInputDevice8WImpl_SetActionMap, + IDirectInputDevice8WImpl_GetImageInfo +}; +#undef XCAST + +#endif /* HAVE_LINUX_INPUT_H */ + +#endif diff --git a/reactos/lib/dinput/keyboard.c b/reactos/lib/dinput/keyboard.c new file mode 100644 index 00000000000..7110679d172 --- /dev/null +++ b/reactos/lib/dinput/keyboard.c @@ -0,0 +1,868 @@ +/* DirectInput Keyboard device + * + * Copyright 1998 Marcus Meissner + * Copyright 1998,1999 Lionel Ulmer + * Copyright 2000-2001 TransGaming Technologies Inc. + * + * 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.1 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 + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winerror.h" +#include "dinput.h" + +#include "dinput_private.h" +#include "device_private.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dinput); + +//fast fix misning from mingw headers +#ifdef __REACTOS__ +#define LLKHF_EXTENDED (KF_EXTENDED >> 8) +#define LLKHF_INJECTED 0x00000010 +//#define LLKHF_ALTDOWN (KF_ALTDOWN >> 8) +#define LLKHF_UP (KF_UP >> 8) +#endif + +static IDirectInputDevice8AVtbl SysKeyboardAvt; +static IDirectInputDevice8WVtbl SysKeyboardWvt; + +typedef struct SysKeyboardImpl SysKeyboardImpl; +struct SysKeyboardImpl +{ + LPVOID lpVtbl; + DWORD ref; + GUID guid; + + IDirectInputImpl* dinput; + + HANDLE hEvent; + /* SysKeyboardAImpl */ + int acquired; + int buffersize; /* set in 'SetProperty' */ + LPDIDEVICEOBJECTDATA buffer; /* buffer for 'GetDeviceData'. + Alloc at 'Acquire', Free at + 'Unacquire' */ + int count; /* number of objects in use in + 'buffer' */ + int start; /* 'buffer' rotates. This is the + first in use (if count > 0) */ + BOOL overflow; /* return DI_BUFFEROVERFLOW in + 'GetDeviceData' */ + CRITICAL_SECTION crit; +}; + +SysKeyboardImpl *current; /* Today's acquired device +FIXME: currently this can be only one. +Maybe this should be a linked list or st. +I don't know what the rules are for multiple acquired keyboards, +but 'DI_LOSTFOCUS' and 'DI_UNACQUIRED' exist for a reason. +*/ + +static BYTE DInputKeyState[256]; /* array for 'GetDeviceState' */ + +static CRITICAL_SECTION keyboard_crit; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &keyboard_crit, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": keyboard_crit") } +}; +static CRITICAL_SECTION keyboard_crit = { &critsect_debug, -1, 0, 0, 0, 0 }; + +static DWORD keyboard_users; + +#ifndef __REACTOS__ +static HHOOK keyboard_hook; +#endif + +#ifdef __REACTOS__ +void reactos_input_keyboard(); + +void reactos_input_keyboard() +{ + MSG msg; + BOOL fDone; + int disk_code = -1; + BOOL down; + BYTE oldDInputKeyState[256]; + int t; + + memcpy(&oldDInputKeyState,&DInputKeyState,256); + GetKeyboardState(DInputKeyState); + + for( t=0;t<255;t++) + { + if (oldDInputKeyState[t]!=DInputKeyState[t]) disk_code=t; + } + + + if (disk_code!=-1) { + if (current->buffer != NULL) + { + int n; + n = (current->start + current->count) % current->buffersize; + + current->buffer[n].dwOfs = (BYTE) disk_code; + current->buffer[n].dwData = DInputKeyState[disk_code]; + current->buffer[n].dwTimeStamp = 10; + current->buffer[n].dwSequence = current->dinput->evsequence++; + + + if (current->count == current->buffersize) + { + current->start = ++current->start % current->buffersize; + current->overflow = TRUE; + } + else + current->count++; + + } + } + + +} +#endif +#ifndef __REACTOS__ +LRESULT CALLBACK KeyboardCallback( int code, WPARAM wparam, LPARAM lparam ) +{ + TRACE("(%d,%d,%ld)\n", code, wparam, lparam); + + if (code == HC_ACTION) + { + BYTE dik_code; + BOOL down; + DWORD timestamp; + + { + KBDLLHOOKSTRUCT *hook = (KBDLLHOOKSTRUCT *)lparam; + dik_code = hook->scanCode; + if (hook->flags & LLKHF_EXTENDED) dik_code |= 0x80; + down = !(hook->flags & LLKHF_UP); + timestamp = hook->time; + } + + DInputKeyState[dik_code] = (down ? 0x80 : 0); + TRACE(" setting %02X to %02X\n", dik_code, DInputKeyState[dik_code]); + + if (current != NULL) + { + if (current->hEvent) + SetEvent(current->hEvent); + + if (current->buffer != NULL) + { + int n; + + EnterCriticalSection(&(current->crit)); + + n = (current->start + current->count) % current->buffersize; + + current->buffer[n].dwOfs = dik_code; + current->buffer[n].dwData = down ? 0x80 : 0; + current->buffer[n].dwTimeStamp = timestamp; + current->buffer[n].dwSequence = current->dinput->evsequence++; + + TRACE("Adding event at offset %d : %ld - %ld - %ld - %ld\n", n, + current->buffer[n].dwOfs, current->buffer[n].dwData, current->buffer[n].dwTimeStamp, current->buffer[n].dwSequence); + + if (current->count == current->buffersize) + { + current->start = ++current->start % current->buffersize; + current->overflow = TRUE; + } + else + current->count++; + + LeaveCriticalSection(&(current->crit)); + } + } + } + + return CallNextHookEx(keyboard_hook, code, wparam, lparam); +} +#endif + +static GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a96441 */ + 0x0ab8648a, + 0x7735, + 0x11d2, + {0x8c, 0x73, 0x71, 0xdf, 0x54, 0xa9, 0x64, 0x41} +}; + +static void fill_keyboard_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, int version) { + DWORD dwSize; + DIDEVICEINSTANCEA ddi; + + dwSize = lpddi->dwSize; + + TRACE("%ld %p\n", dwSize, lpddi); + + memset(lpddi, 0, dwSize); + memset(&ddi, 0, sizeof(ddi)); + + ddi.dwSize = dwSize; + ddi.guidInstance = GUID_SysKeyboard;/* DInput's GUID */ + ddi.guidProduct = DInput_Wine_Keyboard_GUID; /* Vendor's GUID */ + if (version >= 8) + ddi.dwDevType = DI8DEVTYPE_KEYBOARD | (DI8DEVTYPEKEYBOARD_UNKNOWN << 8); + else + ddi.dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8); + strcpy(ddi.tszInstanceName, "Keyboard"); + strcpy(ddi.tszProductName, "Wine Keyboard"); + + memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi))); +} + +static void fill_keyboard_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, int version) { + DWORD dwSize; + DIDEVICEINSTANCEW ddi; + + dwSize = lpddi->dwSize; + + TRACE("%ld %p\n", dwSize, lpddi); + + memset(lpddi, 0, dwSize); + memset(&ddi, 0, sizeof(ddi)); + + ddi.dwSize = dwSize; + ddi.guidInstance = GUID_SysKeyboard;/* DInput's GUID */ + ddi.guidProduct = DInput_Wine_Keyboard_GUID; /* Vendor's GUID */ + if (version >= 8) + ddi.dwDevType = DI8DEVTYPE_KEYBOARD | (DI8DEVTYPEKEYBOARD_UNKNOWN << 8); + else + ddi.dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8); + MultiByteToWideChar(CP_ACP, 0, "Keyboard", -1, ddi.tszInstanceName, MAX_PATH); + MultiByteToWideChar(CP_ACP, 0, "Wine Keyboard", -1, ddi.tszProductName, MAX_PATH); + + memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi))); +} + +static BOOL keyboarddev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, int version, int id) +{ + if (id != 0) + return FALSE; + + if ((dwDevType == 0) || + ((dwDevType == DIDEVTYPE_KEYBOARD) && (version < 8)) || + ((dwDevType == DI8DEVTYPE_KEYBOARD) && (version >= 8))) { + TRACE("Enumerating the Keyboard device\n"); + + fill_keyboard_dideviceinstanceA(lpddi, version); + + return TRUE; + } + + return FALSE; +} + +static BOOL keyboarddev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, int version, int id) +{ + if (id != 0) + return FALSE; + + if ((dwDevType == 0) || + ((dwDevType == DIDEVTYPE_KEYBOARD) && (version < 8)) || + ((dwDevType == DI8DEVTYPE_KEYBOARD) && (version >= 8))) { + TRACE("Enumerating the Keyboard device\n"); + + fill_keyboard_dideviceinstanceW(lpddi, version); + + return TRUE; + } + + return FALSE; +} + +static SysKeyboardImpl *alloc_device_keyboard(REFGUID rguid, LPVOID kvt, IDirectInputImpl *dinput) +{ + SysKeyboardImpl* newDevice; + newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysKeyboardImpl)); + newDevice->lpVtbl = kvt; + newDevice->ref = 1; + memcpy(&(newDevice->guid),rguid,sizeof(*rguid)); + newDevice->dinput = dinput; + +#ifndef __REACTOS__ + EnterCriticalSection(&keyboard_crit); + + if (!keyboard_users++) + keyboard_hook = SetWindowsHookExW( WH_KEYBOARD_LL, KeyboardCallback, DINPUT_instance, 0 ); + + LeaveCriticalSection(&keyboard_crit); +#endif + return newDevice; +} + + +static HRESULT keyboarddev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev) +{ + if ((IsEqualGUID(&GUID_SysKeyboard,rguid)) || /* Generic Keyboard */ + (IsEqualGUID(&DInput_Wine_Keyboard_GUID,rguid))) { /* Wine Keyboard */ + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceA,riid) || + IsEqualGUID(&IID_IDirectInputDevice2A,riid) || + IsEqualGUID(&IID_IDirectInputDevice7A,riid) || + IsEqualGUID(&IID_IDirectInputDevice8A,riid)) { + *pdev = (IDirectInputDeviceA*) alloc_device_keyboard(rguid, &SysKeyboardAvt, dinput); + TRACE("Creating a Keyboard device (%p)\n", *pdev); + return DI_OK; + } else + return DIERR_NOINTERFACE; + } + return DIERR_DEVICENOTREG; +} + +static HRESULT keyboarddev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev) +{ + if ((IsEqualGUID(&GUID_SysKeyboard,rguid)) || /* Generic Keyboard */ + (IsEqualGUID(&DInput_Wine_Keyboard_GUID,rguid))) { /* Wine Keyboard */ + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceW,riid) || + IsEqualGUID(&IID_IDirectInputDevice2W,riid) || + IsEqualGUID(&IID_IDirectInputDevice7W,riid) || + IsEqualGUID(&IID_IDirectInputDevice8W,riid)) { + *pdev = (IDirectInputDeviceW*) alloc_device_keyboard(rguid, &SysKeyboardWvt, dinput); + TRACE("Creating a Keyboard device (%p)\n", *pdev); + return DI_OK; + } else + return DIERR_NOINTERFACE; + } + return DIERR_DEVICENOTREG; +} + +dinput_device keyboarddev = { + 100, + "Wine keyboard driver", + keyboarddev_enum_deviceA, + keyboarddev_enum_deviceW, + keyboarddev_create_deviceA, + keyboarddev_create_deviceW +}; + +void scan_keyboard() +{ + dinput_register_device(&keyboarddev); +} + +DECL_GLOBAL_CONSTRUCTOR(keyboarddev_register) { dinput_register_device(&keyboarddev); } + +static ULONG WINAPI SysKeyboardAImpl_Release(LPDIRECTINPUTDEVICE8A iface) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + ULONG ref; + + ref = InterlockedDecrement(&(This->ref)); + if (ref) + return ref; + +#ifndef __REACTOS__ + EnterCriticalSection(&keyboard_crit); + if (!--keyboard_users) { + UnhookWindowsHookEx( keyboard_hook ); + keyboard_hook = 0; + } + LeaveCriticalSection(&keyboard_crit); +#endif + + /* Free the data queue */ + if (This->buffer != NULL) + HeapFree(GetProcessHeap(),0,This->buffer); + + DeleteCriticalSection(&(This->crit)); + + HeapFree(GetProcessHeap(),0,This); + return DI_OK; +} + +static HRESULT WINAPI SysKeyboardAImpl_SetProperty( + LPDIRECTINPUTDEVICE8A iface,REFGUID rguid,LPCDIPROPHEADER ph +) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + + TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph); + TRACE("(size=%ld,headersize=%ld,obj=%ld,how=%ld\n", + ph->dwSize,ph->dwHeaderSize,ph->dwObj,ph->dwHow); + if (!HIWORD(rguid)) { + switch ((DWORD)rguid) { + case (DWORD) DIPROP_BUFFERSIZE: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + + TRACE("(buffersize=%ld)\n",pd->dwData); + + if (This->acquired) + return DIERR_INVALIDPARAM; + + This->buffersize = pd->dwData; + + break; + } + default: + WARN("Unknown type %ld\n",(DWORD)rguid); + break; + } + } + return DI_OK; +} + + +static HRESULT WINAPI SysKeyboardAImpl_GetDeviceState( + LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr +) +{ + TRACE("(%p)->(%ld,%p)\n", iface, len, ptr); + +#ifdef __REACTOS__ + reactos_input_keyboard(); +#endif + + /* Note: device does not need to be acquired */ + if (len != 256) + return DIERR_INVALIDPARAM; + + MsgWaitForMultipleObjectsEx(0, NULL, 0, 0, 0); + + if (TRACE_ON(dinput)) { + int i; + for (i = 0; i < 256; i++) { + if (DInputKeyState[i] != 0x00) { + TRACE(" - %02X: %02x\n", i, DInputKeyState[i]); + } + } + } + + memcpy(ptr, DInputKeyState, 256); + return DI_OK; +} + +static HRESULT WINAPI SysKeyboardAImpl_GetDeviceData( + LPDIRECTINPUTDEVICE8A iface,DWORD dodsize,LPDIDEVICEOBJECTDATA dod, + LPDWORD entries,DWORD flags +) +{ + + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + int ret = DI_OK, i = 0; +#ifdef __REACTOS__ + reactos_input_keyboard(); +#endif + + TRACE("(this=%p,%ld,%p,%p(%ld)),0x%08lx)\n", + This,dodsize,dod,entries,entries?*entries:0,flags); + + if (This->acquired == 0) + return DIERR_NOTACQUIRED; + + if (This->buffer == NULL) + return DIERR_NOTBUFFERED; + + if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3)) + return DIERR_INVALIDPARAM; + + MsgWaitForMultipleObjectsEx(0, NULL, 0, 0, 0); + + EnterCriticalSection(&(This->crit)); + + /* Copy item at a time for the case dodsize > sizeof(buffer[n]) */ + while ((i < *entries || *entries == INFINITE) && i < This->count) + { + if (dod != NULL) + { + int n = (This->start + i) % This->buffersize; + LPDIDEVICEOBJECTDATA pd + = (LPDIDEVICEOBJECTDATA)((BYTE *)dod + dodsize * i); + pd->dwOfs = This->buffer[n].dwOfs; + pd->dwData = This->buffer[n].dwData; + pd->dwTimeStamp = This->buffer[n].dwTimeStamp; + pd->dwSequence = This->buffer[n].dwSequence; + } + i++; + } + + *entries = i; + + if (This->overflow) + ret = DI_BUFFEROVERFLOW; + + if (!(flags & DIGDD_PEEK)) + { + /* Empty buffer */ + This->count -= i; + This->start = (This->start + i) % This->buffersize; + This->overflow = FALSE; + } + + LeaveCriticalSection(&(This->crit)); + + TRACE("Returning %ld events queued\n", *entries); + + return ret; +} + +static HRESULT WINAPI SysKeyboardAImpl_EnumObjects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + DIDEVICEOBJECTINSTANCEA ddoi; + int i; + + TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags); + if (TRACE_ON(dinput)) { + TRACE(" - flags = "); + _dump_EnumObjects_flags(dwFlags); + TRACE("\n"); + } + + /* Only the fields till dwFFMaxForce are relevant */ + memset(&ddoi, 0, sizeof(ddoi)); + ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce); + + for (i = 0; i < 256; i++) { + /* Report 255 keys :-) */ + ddoi.guidType = GUID_Key; + ddoi.dwOfs = i; + ddoi.dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_BUTTON; + GetKeyNameTextA(((i & 0x7f) << 16) | ((i & 0x80) << 17), ddoi.tszName, sizeof(ddoi.tszName)); + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; + } + + return DI_OK; +} + +static HRESULT WINAPI SysKeyboardWImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface, + LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + + device_enumobjects_AtoWcb_data data; + + data.lpCallBack = lpCallback; + data.lpvRef = lpvRef; + + return SysKeyboardAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags); +} + +static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface); + +static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + + TRACE("(this=%p)\n",This); + + if (This->acquired) + return S_FALSE; + + This->acquired = 1; + + if (current != NULL) + { + FIXME("Not more than one keyboard can be acquired at the same time.\n"); + SysKeyboardAImpl_Unacquire(iface); + } + + current = This; + + if (This->buffersize > 0) + { + This->buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + This->buffersize * sizeof(*(This->buffer))); + This->start = 0; + This->count = 0; + This->overflow = FALSE; + InitializeCriticalSection(&(This->crit)); + } + else + This->buffer = NULL; + + + return DI_OK; +} + +static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + TRACE("(this=%p)\n",This); + + if (This->acquired == 0) + return DI_NOEFFECT; + + if (current == This) + current = NULL; + else + ERR("this != current\n"); + + This->acquired = 0; + + if (This->buffersize >= 0) + { + HeapFree(GetProcessHeap(), 0, This->buffer); + This->buffer = NULL; + DeleteCriticalSection(&(This->crit)); + } + + return DI_OK; +} + +static HRESULT WINAPI SysKeyboardAImpl_SetEventNotification(LPDIRECTINPUTDEVICE8A iface, + HANDLE hnd) { + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + + TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd); + + This->hEvent = hnd; + return DI_OK; +} + +/****************************************************************************** + * GetCapabilities : get the device capablitites + */ +static HRESULT WINAPI SysKeyboardAImpl_GetCapabilities( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVCAPS lpDIDevCaps) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + + TRACE("(this=%p,%p)\n",This,lpDIDevCaps); + + if (lpDIDevCaps->dwSize == sizeof(DIDEVCAPS)) { + lpDIDevCaps->dwFlags = DIDC_ATTACHED; + if (This->dinput->version >= 8) + lpDIDevCaps->dwDevType = DI8DEVTYPE_KEYBOARD | (DI8DEVTYPEKEYBOARD_UNKNOWN << 8); + else + lpDIDevCaps->dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8); + lpDIDevCaps->dwAxes = 0; + lpDIDevCaps->dwButtons = 256; + lpDIDevCaps->dwPOVs = 0; + lpDIDevCaps->dwFFSamplePeriod = 0; + lpDIDevCaps->dwFFMinTimeResolution = 0; + lpDIDevCaps->dwFirmwareRevision = 100; + lpDIDevCaps->dwHardwareRevision = 100; + lpDIDevCaps->dwFFDriverVersion = 0; + } else if (lpDIDevCaps->dwSize == sizeof(DIDEVCAPS_DX3)) { + lpDIDevCaps->dwFlags = DIDC_ATTACHED; + lpDIDevCaps->dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8); + lpDIDevCaps->dwAxes = 0; + lpDIDevCaps->dwButtons = 256; + lpDIDevCaps->dwPOVs = 0; + } else { + WARN("invalid parameter\n"); + return DIERR_INVALIDPARAM; + } + + return DI_OK; +} + +/****************************************************************************** + * GetObjectInfo : get information about a device object such as a button + * or axis + */ +static HRESULT WINAPI +SysKeyboardAImpl_GetObjectInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEOBJECTINSTANCEA pdidoi, + DWORD dwObj, + DWORD dwHow) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + DIDEVICEOBJECTINSTANCEA ddoi; + DWORD dwSize = pdidoi->dwSize; + + TRACE("(this=%p,%p,%ld,0x%08lx)\n", This, pdidoi, dwObj, dwHow); + + if (dwHow == DIPH_BYID) { + WARN(" querying by id not supported yet...\n"); + return DI_OK; + } + + memset(pdidoi, 0, dwSize); + memset(&ddoi, 0, sizeof(ddoi)); + + ddoi.dwSize = dwSize; + ddoi.guidType = GUID_Key; + ddoi.dwOfs = dwObj; + ddoi.dwType = DIDFT_MAKEINSTANCE(dwObj) | DIDFT_BUTTON; + GetKeyNameTextA(((dwObj & 0x7f) << 16) | ((dwObj & 0x80) << 17), ddoi.tszName, sizeof(ddoi.tszName)); + + /* And return our just filled device object instance structure */ + memcpy(pdidoi, &ddoi, (dwSize < sizeof(ddoi) ? dwSize : sizeof(ddoi))); + + _dump_OBJECTINSTANCEA(pdidoi); + + return DI_OK; +} + +static HRESULT WINAPI SysKeyboardWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEOBJECTINSTANCEW pdidoi, + DWORD dwObj, + DWORD dwHow) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + DIDEVICEOBJECTINSTANCEW ddoi; + DWORD dwSize = pdidoi->dwSize; + + TRACE("(this=%p,%p,%ld,0x%08lx)\n", This, pdidoi, dwObj, dwHow); + + if (dwHow == DIPH_BYID) { + WARN(" querying by id not supported yet...\n"); + return DI_OK; + } + + memset(pdidoi, 0, dwSize); + memset(&ddoi, 0, sizeof(ddoi)); + + ddoi.dwSize = dwSize; + ddoi.guidType = GUID_Key; + ddoi.dwOfs = dwObj; + ddoi.dwType = DIDFT_MAKEINSTANCE(dwObj) | DIDFT_BUTTON; + GetKeyNameTextW(((dwObj & 0x7f) << 16) | ((dwObj & 0x80) << 17), ddoi.tszName, sizeof(ddoi.tszName)); + + /* And return our just filled device object instance structure */ + memcpy(pdidoi, &ddoi, (dwSize < sizeof(ddoi) ? dwSize : sizeof(ddoi))); + + _dump_OBJECTINSTANCEW(pdidoi); + + return DI_OK; +} + +/****************************************************************************** + * GetDeviceInfo : get information about a device's identity + */ +static HRESULT WINAPI SysKeyboardAImpl_GetDeviceInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEINSTANCEA pdidi) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + TRACE("(this=%p,%p)\n", This, pdidi); + + if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)) { + WARN(" dinput3 not supporte yet...\n"); + return DI_OK; + } + + fill_keyboard_dideviceinstanceA(pdidi, This->dinput->version); + + return DI_OK; +} + +static HRESULT WINAPI SysKeyboardWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEINSTANCEW pdidi) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + TRACE("(this=%p,%p)\n", This, pdidi); + + if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW)) { + WARN(" dinput3 not supporte yet...\n"); + return DI_OK; + } + + fill_keyboard_dideviceinstanceW(pdidi, This->dinput->version); + + return DI_OK; +} + +static IDirectInputDevice8AVtbl SysKeyboardAvt = +{ + IDirectInputDevice2AImpl_QueryInterface, + IDirectInputDevice2AImpl_AddRef, + SysKeyboardAImpl_Release, + SysKeyboardAImpl_GetCapabilities, + SysKeyboardAImpl_EnumObjects, + IDirectInputDevice2AImpl_GetProperty, + SysKeyboardAImpl_SetProperty, + SysKeyboardAImpl_Acquire, + SysKeyboardAImpl_Unacquire, + SysKeyboardAImpl_GetDeviceState, + SysKeyboardAImpl_GetDeviceData, + IDirectInputDevice2AImpl_SetDataFormat, + SysKeyboardAImpl_SetEventNotification, + IDirectInputDevice2AImpl_SetCooperativeLevel, + SysKeyboardAImpl_GetObjectInfo, + SysKeyboardAImpl_GetDeviceInfo, + IDirectInputDevice2AImpl_RunControlPanel, + IDirectInputDevice2AImpl_Initialize, + IDirectInputDevice2AImpl_CreateEffect, + IDirectInputDevice2AImpl_EnumEffects, + IDirectInputDevice2AImpl_GetEffectInfo, + IDirectInputDevice2AImpl_GetForceFeedbackState, + IDirectInputDevice2AImpl_SendForceFeedbackCommand, + IDirectInputDevice2AImpl_EnumCreatedEffectObjects, + IDirectInputDevice2AImpl_Escape, + IDirectInputDevice2AImpl_Poll, + IDirectInputDevice2AImpl_SendDeviceData, + IDirectInputDevice7AImpl_EnumEffectsInFile, + IDirectInputDevice7AImpl_WriteEffectToFile, + IDirectInputDevice8AImpl_BuildActionMap, + IDirectInputDevice8AImpl_SetActionMap, + IDirectInputDevice8AImpl_GetImageInfo +}; + +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(SysKeyboardWvt.fun)) +#else +# define XCAST(fun) (void*) +#endif + +static IDirectInputDevice8WVtbl SysKeyboardWvt = +{ + IDirectInputDevice2WImpl_QueryInterface, + XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, + XCAST(Release)SysKeyboardAImpl_Release, + XCAST(GetCapabilities)SysKeyboardAImpl_GetCapabilities, + SysKeyboardWImpl_EnumObjects, + XCAST(GetProperty)IDirectInputDevice2AImpl_GetProperty, + XCAST(SetProperty)SysKeyboardAImpl_SetProperty, + XCAST(Acquire)SysKeyboardAImpl_Acquire, + XCAST(Unacquire)SysKeyboardAImpl_Unacquire, + XCAST(GetDeviceState)SysKeyboardAImpl_GetDeviceState, + XCAST(GetDeviceData)SysKeyboardAImpl_GetDeviceData, + XCAST(SetDataFormat)IDirectInputDevice2AImpl_SetDataFormat, + XCAST(SetEventNotification)SysKeyboardAImpl_SetEventNotification, + XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel, + SysKeyboardWImpl_GetObjectInfo, + SysKeyboardWImpl_GetDeviceInfo, + XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel, + XCAST(Initialize)IDirectInputDevice2AImpl_Initialize, + XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect, + IDirectInputDevice2WImpl_EnumEffects, + IDirectInputDevice2WImpl_GetEffectInfo, + XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState, + XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand, + XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects, + XCAST(Escape)IDirectInputDevice2AImpl_Escape, + XCAST(Poll)IDirectInputDevice2AImpl_Poll, + XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData, + IDirectInputDevice7WImpl_EnumEffectsInFile, + IDirectInputDevice7WImpl_WriteEffectToFile, + IDirectInputDevice8WImpl_BuildActionMap, + IDirectInputDevice8WImpl_SetActionMap, + IDirectInputDevice8WImpl_GetImageInfo +}; +#undef XCAST diff --git a/reactos/lib/dinput/mouse.c b/reactos/lib/dinput/mouse.c new file mode 100644 index 00000000000..e0602f0a77a --- /dev/null +++ b/reactos/lib/dinput/mouse.c @@ -0,0 +1,1355 @@ +/* DirectInput Mouse device + * + * Copyright 1998 Marcus Meissner + * Copyright 1998,1999 Lionel Ulmer + * Copyright 2000-2001 TransGaming Technologies Inc. + * + * 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.1 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 + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winerror.h" +#include "dinput.h" + +#include "dinput_private.h" +#include "device_private.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +#define MOUSE_HACK + +WINE_DEFAULT_DEBUG_CHANNEL(dinput); +typedef struct { + POINT pt; + DWORD mouseData; + DWORD flags; + DWORD time; + ULONG_PTR dwExtraInfo; +} MSLLHOOKSTRUCT, *PMSLLHOOKSTRUCT; + +/* Wine mouse driver object instances */ +#define WINE_MOUSE_X_AXIS_INSTANCE 0 +#define WINE_MOUSE_Y_AXIS_INSTANCE 1 +#define WINE_MOUSE_Z_AXIS_INSTANCE 2 +#define WINE_MOUSE_L_BUTTON_INSTANCE 0 +#define WINE_MOUSE_R_BUTTON_INSTANCE 1 +#define WINE_MOUSE_M_BUTTON_INSTANCE 2 +#define WINE_MOUSE_D_BUTTON_INSTANCE 3 + +/* ------------------------------- */ +/* Wine mouse internal data format */ +/* ------------------------------- */ + +/* Constants used to access the offset array */ +#define WINE_MOUSE_X_POSITION 0 +#define WINE_MOUSE_Y_POSITION 1 +#define WINE_MOUSE_Z_POSITION 2 +#define WINE_MOUSE_L_POSITION 3 +#define WINE_MOUSE_R_POSITION 4 +#define WINE_MOUSE_M_POSITION 5 + +typedef struct { + LONG lX; + LONG lY; + LONG lZ; + BYTE rgbButtons[4]; +} Wine_InternalMouseData; + +#define WINE_INTERNALMOUSE_NUM_OBJS 6 + +static const DIOBJECTDATAFORMAT Wine_InternalMouseObjectFormat[WINE_INTERNALMOUSE_NUM_OBJS] = { + { &GUID_XAxis, FIELD_OFFSET(Wine_InternalMouseData, lX), + DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 }, + { &GUID_YAxis, FIELD_OFFSET(Wine_InternalMouseData, lY), + DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 }, + { &GUID_ZAxis, FIELD_OFFSET(Wine_InternalMouseData, lZ), + DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 }, + { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 0, + DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 }, + { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 1, + DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 }, + { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 2, + DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 } +}; + +static const DIDATAFORMAT Wine_InternalMouseFormat = { + 0, /* dwSize - unused */ + 0, /* dwObjsize - unused */ + 0, /* dwFlags - unused */ + sizeof(Wine_InternalMouseData), + WINE_INTERNALMOUSE_NUM_OBJS, /* dwNumObjs */ + (LPDIOBJECTDATAFORMAT) Wine_InternalMouseObjectFormat +}; + +static IDirectInputDevice8AVtbl SysMouseAvt; +static IDirectInputDevice8WVtbl SysMouseWvt; + +typedef struct SysMouseImpl SysMouseImpl; + +typedef enum { + WARP_DONE, /* Warping has been done */ + WARP_NEEDED, /* Warping is needed */ + WARP_STARTED /* Warping has been done, waiting for the warp event */ +} WARP_STATUS; + +struct SysMouseImpl +{ + LPVOID lpVtbl; + DWORD ref; + GUID guid; + + IDirectInputImpl *dinput; + + /* The current data format and the conversion between internal + and external data formats */ + DIDATAFORMAT *df; + DataFormat *wine_df; + int offset_array[WINE_INTERNALMOUSE_NUM_OBJS]; + + /* SysMouseAImpl */ + BYTE absolute; + /* Previous position for relative moves */ + LONG prevX, prevY; + /* These are used in case of relative -> absolute transitions */ + POINT org_coords; + HHOOK hook; + HWND win; + DWORD dwCoopLevel; + POINT mapped_center; + DWORD win_centerX, win_centerY; + LPDIDEVICEOBJECTDATA data_queue; + int queue_head, queue_tail, queue_len; + BOOL overflow; + /* warping: whether we need to move mouse back to middle once we + * reach window borders (for e.g. shooters, "surface movement" games) */ + WARP_STATUS need_warp; + int acquired; + HANDLE hEvent; + CRITICAL_SECTION crit; + + /* This is for mouse reporting. */ + Wine_InternalMouseData m_state; +}; + +/* FIXME: This is ugly and not thread safe :/ */ +static IDirectInputDevice8A* current_lock = NULL; + +/* FIXME: This is ugly but needed on Windows */ +static int mouse_set = 0; + +static GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */ + 0x9e573ed8, + 0x7734, + 0x11d2, + {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7} +}; + +static void fill_mouse_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, int version) { + DWORD dwSize; + DIDEVICEINSTANCEA ddi; + + dwSize = lpddi->dwSize; + + TRACE("%ld %p\n", dwSize, lpddi); + + memset(lpddi, 0, dwSize); + memset(&ddi, 0, sizeof(ddi)); + + ddi.dwSize = dwSize; + ddi.guidInstance = GUID_SysMouse;/* DInput's GUID */ + ddi.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */ + if (version >= 8) + ddi.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8); + else + ddi.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8); + strcpy(ddi.tszInstanceName, "Mouse"); + strcpy(ddi.tszProductName, "Wine Mouse"); + + memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi))); +} + +static void fill_mouse_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, int version) { + DWORD dwSize; + DIDEVICEINSTANCEW ddi; + + dwSize = lpddi->dwSize; + + TRACE("%ld %p\n", dwSize, lpddi); + + memset(lpddi, 0, dwSize); + memset(&ddi, 0, sizeof(ddi)); + + ddi.dwSize = dwSize; + ddi.guidInstance = GUID_SysMouse;/* DInput's GUID */ + ddi.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */ + if (version >= 8) + ddi.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8); + else + ddi.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8); + MultiByteToWideChar(CP_ACP, 0, "Mouse", -1, ddi.tszInstanceName, MAX_PATH); + MultiByteToWideChar(CP_ACP, 0, "Wine Mouse", -1, ddi.tszProductName, MAX_PATH); + + memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi))); +} + +static BOOL mousedev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, int version, int id) +{ + if (id != 0) + return FALSE; + + if ((dwDevType == 0) || + ((dwDevType == DIDEVTYPE_MOUSE) && (version < 8)) || + ((dwDevType == DI8DEVTYPE_MOUSE) && (version >= 8))) { + TRACE("Enumerating the mouse device\n"); + + fill_mouse_dideviceinstanceA(lpddi, version); + + return TRUE; + } + + return FALSE; +} + +static BOOL mousedev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, int version, int id) +{ + if (id != 0) + return FALSE; + + if ((dwDevType == 0) || + ((dwDevType == DIDEVTYPE_MOUSE) && (version < 8)) || + ((dwDevType == DI8DEVTYPE_MOUSE) && (version >= 8))) { + TRACE("Enumerating the mouse device\n"); + + fill_mouse_dideviceinstanceW(lpddi, version); + + return TRUE; + } + + return FALSE; +} + +static SysMouseImpl *alloc_device_mouse(REFGUID rguid, LPVOID mvt, IDirectInputImpl *dinput) +{ + int offset_array[WINE_INTERNALMOUSE_NUM_OBJS] = { + FIELD_OFFSET(Wine_InternalMouseData, lX), + FIELD_OFFSET(Wine_InternalMouseData, lY), + FIELD_OFFSET(Wine_InternalMouseData, lZ), + FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 0, + FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 1, + FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 2 + }; + SysMouseImpl* newDevice; + newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseImpl)); + newDevice->ref = 1; + newDevice->lpVtbl = mvt; +#ifndef __REACTOS__ + InitializeCriticalSection(&(newDevice->crit)); +#endif + memcpy(&(newDevice->guid),rguid,sizeof(*rguid)); + + /* Per default, Wine uses its internal data format */ + newDevice->df = (DIDATAFORMAT *) &Wine_InternalMouseFormat; + memcpy(newDevice->offset_array, offset_array, WINE_INTERNALMOUSE_NUM_OBJS * sizeof(int)); + newDevice->wine_df = (DataFormat *) HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat)); + newDevice->wine_df->size = 0; + newDevice->wine_df->internal_format_size = Wine_InternalMouseFormat.dwDataSize; + newDevice->wine_df->dt = NULL; + newDevice->dinput = dinput; + + return newDevice; +} + +static HRESULT mousedev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev) +{ + if ((IsEqualGUID(&GUID_SysMouse,rguid)) || /* Generic Mouse */ + (IsEqualGUID(&DInput_Wine_Mouse_GUID,rguid))) { /* Wine Mouse */ + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceA,riid) || + IsEqualGUID(&IID_IDirectInputDevice2A,riid) || + IsEqualGUID(&IID_IDirectInputDevice7A,riid) || + IsEqualGUID(&IID_IDirectInputDevice8A,riid)) { + *pdev = (IDirectInputDeviceA*) alloc_device_mouse(rguid, &SysMouseAvt, dinput); + TRACE("Creating a Mouse device (%p)\n", *pdev); + return DI_OK; + } else + return DIERR_NOINTERFACE; + } + + return DIERR_DEVICENOTREG; +} + +static HRESULT mousedev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev) +{ + if ((IsEqualGUID(&GUID_SysMouse,rguid)) || /* Generic Mouse */ + (IsEqualGUID(&DInput_Wine_Mouse_GUID,rguid))) { /* Wine Mouse */ + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceW,riid) || + IsEqualGUID(&IID_IDirectInputDevice2W,riid) || + IsEqualGUID(&IID_IDirectInputDevice7W,riid) || + IsEqualGUID(&IID_IDirectInputDevice8W,riid)) { + *pdev = (IDirectInputDeviceW*) alloc_device_mouse(rguid, &SysMouseWvt, dinput); + TRACE("Creating a Mouse device (%p)\n", *pdev); + return DI_OK; + } else + return DIERR_NOINTERFACE; + } + + return DIERR_DEVICENOTREG; +} + +static dinput_device mousedev = { + 100, + "Wine mouse driver", + mousedev_enum_deviceA, + mousedev_enum_deviceW, + mousedev_create_deviceA, + mousedev_create_deviceW +}; + +void scan_mouse() +{ + dinput_register_device(&mousedev); +} + +DECL_GLOBAL_CONSTRUCTOR(mousedev_register) { dinput_register_device(&mousedev); } + +/****************************************************************************** + * SysMouseA (DInput Mouse support) + */ + +/****************************************************************************** + * Release : release the mouse buffer. + */ +static ULONG WINAPI SysMouseAImpl_Release(LPDIRECTINPUTDEVICE8A iface) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + ULONG ref; + + ref = InterlockedDecrement(&(This->ref)); + if (ref) + return ref; + + /* Free the data queue */ + if (This->data_queue != NULL) + HeapFree(GetProcessHeap(),0,This->data_queue); + +#ifndef __REACTOS__ + if (This->hook) { + UnhookWindowsHookEx( This->hook ); + if (This->dwCoopLevel & DISCL_EXCLUSIVE) + ShowCursor(TRUE); /* show cursor */ + } + DeleteCriticalSection(&(This->crit)); +#endif + +#ifdef __REACTOS__ +if (This->dwCoopLevel & DISCL_EXCLUSIVE) + ShowCursor(TRUE); /* show cursor */ + +#endif + /* Free the DataFormat */ + if (This->df != &(Wine_InternalMouseFormat)) { + HeapFree(GetProcessHeap(), 0, This->df->rgodf); + HeapFree(GetProcessHeap(), 0, This->df); + } + + HeapFree(GetProcessHeap(),0,This); + return 0; +} + + +/****************************************************************************** + * SetCooperativeLevel : store the window in which we will do our + * grabbing. + */ +static HRESULT WINAPI SysMouseAImpl_SetCooperativeLevel( + LPDIRECTINPUTDEVICE8A iface,HWND hwnd,DWORD dwflags +) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + + TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags); + + if (TRACE_ON(dinput)) { + TRACE(" cooperative level : "); + _dump_cooperativelevel_DI(dwflags); + } + + /* Store the window which asks for the mouse */ + if (!hwnd) + hwnd = GetDesktopWindow(); + This->win = hwnd; + This->dwCoopLevel = dwflags; + + return DI_OK; +} + + +/****************************************************************************** + * SetDataFormat : the application can choose the format of the data + * the device driver sends back with GetDeviceState. + * + * For the moment, only the "standard" configuration (c_dfDIMouse) is supported + * in absolute and relative mode. + */ +static HRESULT WINAPI SysMouseAImpl_SetDataFormat( + LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df +) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + + TRACE("(this=%p,%p)\n",This,df); + + _dump_DIDATAFORMAT(df); + + /* Tests under windows show that a call to SetDataFormat always sets the mouse + in relative mode whatever the dwFlags value (DIDF_ABSAXIS/DIDF_RELAXIS). + To switch in absolute mode, SetProperty must be used. */ + This->absolute = 0; + + /* Store the new data format */ + This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize); + memcpy(This->df, df, df->dwSize); + This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize); + memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize); + + /* Prepare all the data-conversion filters */ + This->wine_df = create_DataFormat(&(Wine_InternalMouseFormat), df, This->offset_array); + + return DI_OK; +} + +/* low-level mouse hook */ +static LRESULT CALLBACK dinput_mouse_hook( int code, WPARAM wparam, LPARAM lparam ) +{ + LRESULT ret; + MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam; + SysMouseImpl* This = (SysMouseImpl*) current_lock; + DWORD dwCoop; + static long last_event = 0; + int wdata; + + if (code != HC_ACTION) return CallNextHookEx( This->hook, code, wparam, lparam ); + + EnterCriticalSection(&(This->crit)); + dwCoop = This->dwCoopLevel; + + /* Only allow mouse events every 10 ms. + * This is to allow the cursor to start acceleration before + * the warps happen. But if it involves a mouse button event we + * allow it since we don't want to loose the clicks. + */ + if (((GetCurrentTime() - last_event) < 10) + && wparam == WM_MOUSEMOVE) + goto end; + else last_event = GetCurrentTime(); + + /* Mouse moved -> send event if asked */ + if (This->hEvent) + SetEvent(This->hEvent); + + if (wparam == WM_MOUSEMOVE) { + if (This->absolute) { + if (hook->pt.x != This->prevX) + GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x, hook->time, 0); + if (hook->pt.y != This->prevY) + GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y, hook->time, 0); + } else { + /* Now, warp handling */ + if ((This->need_warp == WARP_STARTED) && + (hook->pt.x == This->mapped_center.x) && (hook->pt.y == This->mapped_center.y)) { + /* Warp has been done... */ + This->need_warp = WARP_DONE; + goto end; + } + + /* Relative mouse input with absolute mouse event : the real fun starts here... */ + if ((This->need_warp == WARP_NEEDED) || + (This->need_warp == WARP_STARTED)) { + if (hook->pt.x != This->prevX) + GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->prevX, + hook->time, (This->dinput->evsequence)++); + if (hook->pt.y != This->prevY) + GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->prevY, + hook->time, (This->dinput->evsequence)++); + } else { + /* This is the first time the event handler has been called after a + GetDeviceData or GetDeviceState. */ + if (hook->pt.x != This->mapped_center.x) { + GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->mapped_center.x, + hook->time, (This->dinput->evsequence)++); + This->need_warp = WARP_NEEDED; + } + + if (hook->pt.y != This->mapped_center.y) { + GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->mapped_center.y, + hook->time, (This->dinput->evsequence)++); + This->need_warp = WARP_NEEDED; + } + } + } + + This->prevX = hook->pt.x; + This->prevY = hook->pt.y; + + if (This->absolute) { + This->m_state.lX = hook->pt.x; + This->m_state.lY = hook->pt.y; + } else { + This->m_state.lX = hook->pt.x - This->mapped_center.x; + This->m_state.lY = hook->pt.y - This->mapped_center.y; + } + } + + TRACE(" msg %x pt %ld %ld (W=%d)\n", + wparam, hook->pt.x, hook->pt.y, (!This->absolute) && This->need_warp ); + + switch(wparam) { + case WM_LBUTTONDOWN: + GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0xFF, + hook->time, This->dinput->evsequence++); + This->m_state.rgbButtons[0] = 0xFF; + break; + case WM_LBUTTONUP: + GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0x00, + hook->time, This->dinput->evsequence++); + This->m_state.rgbButtons[0] = 0x00; + break; + case WM_RBUTTONDOWN: + GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0xFF, + hook->time, This->dinput->evsequence++); + This->m_state.rgbButtons[1] = 0xFF; + break; + case WM_RBUTTONUP: + GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0x00, + hook->time, This->dinput->evsequence++); + This->m_state.rgbButtons[1] = 0x00; + break; + case WM_MBUTTONDOWN: + GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0xFF, + hook->time, This->dinput->evsequence++); + This->m_state.rgbButtons[2] = 0xFF; + break; + case WM_MBUTTONUP: + GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0x00, + hook->time, This->dinput->evsequence++); + This->m_state.rgbButtons[2] = 0x00; + break; + case WM_MOUSEWHEEL: + wdata = (short)HIWORD(hook->mouseData); + GEN_EVENT(This->offset_array[WINE_MOUSE_Z_POSITION], wdata, + hook->time, This->dinput->evsequence++); + This->m_state.lZ += wdata; + break; + } + + TRACE("(X: %ld - Y: %ld L: %02x M: %02x R: %02x)\n", + This->m_state.lX, This->m_state.lY, + This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]); + + end: + LeaveCriticalSection(&(This->crit)); + + if (dwCoop & DISCL_NONEXCLUSIVE) { + /* Pass the events down to previous handlers (e.g. win32 input) */ + ret = CallNextHookEx( This->hook, code, wparam, lparam ); + } else { + /* Ignore message */ + ret = 1; + } + return ret; +} + + +static void dinput_window_check(SysMouseImpl* This) { + RECT rect; + DWORD centerX, centerY; + + /* make sure the window hasn't moved */ + GetWindowRect(This->win, &rect); + centerX = (rect.right - rect.left) / 2; + centerY = (rect.bottom - rect.top ) / 2; + if (This->win_centerX != centerX || This->win_centerY != centerY) { + This->win_centerX = centerX; + This->win_centerY = centerY; + } + This->mapped_center.x = This->win_centerX; + This->mapped_center.y = This->win_centerY; + MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1); +} + + +/****************************************************************************** + * Acquire : gets exclusive control of the mouse + */ +static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + RECT rect; + + TRACE("(this=%p)\n",This); + + + + if (This->acquired == 0) { + POINT point; + + + + /* Store (in a global variable) the current lock */ + current_lock = (IDirectInputDevice8A*)This; + + /* Init the mouse state */ + GetCursorPos( &point ); + if (This->absolute) { + This->m_state.lX = point.x; + This->m_state.lY = point.y; + This->prevX = point.x; + This->prevY = point.y; + } else { + This->m_state.lX = 0; + This->m_state.lY = 0; + This->org_coords = point; + } + This->m_state.lZ = 0; + This->m_state.rgbButtons[0] = ((GetKeyState(VK_LBUTTON) & 0x80) ? 0xFF : 0x00); + This->m_state.rgbButtons[1] = ((GetKeyState(VK_RBUTTON) & 0x80) ? 0xFF : 0x00); + This->m_state.rgbButtons[2] = ((GetKeyState(VK_MBUTTON) & 0x80) ? 0xFF : 0x00); + + /* Install our mouse hook */ + if (This->dwCoopLevel & DISCL_EXCLUSIVE) + ShowCursor(FALSE); /* hide cursor */ +#ifndef __REACTOS__ + This->hook = SetWindowsHookExA( WH_MOUSE_LL, dinput_mouse_hook, DINPUT_instance, 0 ); +#endif + /* Get the window dimension and find the center */ + GetWindowRect(This->win, &rect); + This->win_centerX = (rect.right - rect.left) / 2; + This->win_centerY = (rect.bottom - rect.top ) / 2; + + /* Warp the mouse to the center of the window */ + if (This->absolute == 0) { + This->mapped_center.x = This->win_centerX; + This->mapped_center.y = This->win_centerY; + MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1); + TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); + SetCursorPos( This->mapped_center.x, This->mapped_center.y ); +#ifdef MOUSE_HACK + This->need_warp = WARP_DONE; +#else + This->need_warp = WARP_STARTED; +#endif + } + + This->acquired = 1; + return DI_OK; + } + return S_FALSE; +} + +/****************************************************************************** + * Unacquire : frees the mouse + */ +static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + + TRACE("(this=%p)\n",This); + + if (This->acquired) { + /* Reinstall previous mouse event handler */ + +#ifndef __REACTOS__ + if (This->hook) { + UnhookWindowsHookEx( This->hook ); + This->hook = 0; + + if (This->dwCoopLevel & DISCL_EXCLUSIVE) + ShowCursor(TRUE); /* show cursor */ + } +#endif +#ifdef __REACTOS__ + if (This->dwCoopLevel & DISCL_EXCLUSIVE) + ShowCursor(TRUE); /* show cursor */ +#endif + + /* No more locks */ + current_lock = NULL; + + /* Unacquire device */ + This->acquired = 0; + + /* And put the mouse cursor back where it was at acquire time */ + if (This->absolute == 0) { + TRACE(" warping mouse back to (%ld , %ld)\n", This->org_coords.x, This->org_coords.y); + SetCursorPos(This->org_coords.x, This->org_coords.y); + } + } else { + return DI_NOEFFECT; + } + + return DI_OK; +} + +// if you call poll then to getdevicestate +// it did not send back right value in windows +int poll_mouse=0; + +#ifdef __REACTOS__ +void getmousesvalue(LPDIRECTINPUTDEVICE8A iface); +int filp=0; +void getmousesvalue(LPDIRECTINPUTDEVICE8A iface) +{ + static long last_event = 0; + + POINT point; + SysMouseImpl *This = (SysMouseImpl *)iface; + + This->m_state.rgbButtons[0] = ((GetKeyState(VK_LBUTTON) & 0x80) ? 0xFF : 0x00); + This->m_state.rgbButtons[1] = ((GetKeyState(VK_RBUTTON) & 0x80) ? 0xFF : 0x00); + This->m_state.rgbButtons[2] = ((GetKeyState(VK_MBUTTON) & 0x80) ? 0xFF : 0x00); + This->m_state.rgbButtons[3] = ((GetKeyState(VK_XBUTTON1) & 0x80) ? 0xFF : 0x00); + This->m_state.rgbButtons[4] = ((GetKeyState(VK_XBUTTON2) & 0x80) ? 0xFF : 0x00); + + + + + if (poll_mouse==1) filp=0; + if (filp==2) filp=0; + if (filp==0) { + GetCursorPos( &point ); + + if (This->prevX == point.x) This->m_state.lX = 0; + else { + This->prevX = point.x; + This->m_state.lX = point.x - This->org_coords.x; + } + + if (This->prevY == point.y) This->m_state.lY = 0; + else { + This->prevY = point.y; + This->m_state.lY = point.y - This->org_coords.y; + } + + } + else + { + This->m_state.lX = 0; + This->m_state.lY = 0; + } + filp++; + +// check see if buffer have been set + +} + +#endif + +static HRESULT WINAPI SysMouseAImpl_Poll(LPDIRECTINPUTDEVICE8A iface) +{ + int retValue = DI_OK; + +SysMouseImpl *This = (SysMouseImpl *)iface; + if (poll_mouse==0) { + retValue=SysMouseAImpl_Acquire(iface); + poll_mouse=1; + if (retValue!=DI_OK) retValue=DIERR_NOTACQUIRED; + else retValue = DI_OK; + } + + return retValue; +} + + +/****************************************************************************** + * GetDeviceState : returns the "state" of the mouse. + * + * For the moment, only the "standard" return structure (DIMOUSESTATE) is + * supported. + */ +static HRESULT WINAPI SysMouseAImpl_GetDeviceState( + LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr +) { + SysMouseImpl *This = (SysMouseImpl *)iface; + POINT point; + +#ifndef __REACTOS__ + EnterCriticalSection(&(This->crit)); +#endif + +#ifdef __REACTOS__ +getmousesvalue(iface); +#endif + TRACE("(this=%p,0x%08lx,%p): \n",This,len,ptr); + + /* Copy the current mouse state */ + fill_DataFormat(ptr, &(This->m_state), This->wine_df); + + + // this fix windows bugs when + // some program calling on mouse poll + if (poll_mouse==1) poll_mouse=0; + else { + if (This->absolute == 0) { + This->m_state.lX = 0; + This->m_state.lY = 0; + This->m_state.lZ = 0; + } + } + + + /* Check if we need to do a mouse warping */ + if (This->need_warp == WARP_NEEDED) { + dinput_window_check(This); + TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); + if (mouse_set==0){ + SetCursorPos( This->mapped_center.x, This->mapped_center.y ); + mouse_set++; + } + +#ifdef MOUSE_HACK + This->need_warp = WARP_DONE; +#else + This->need_warp = WARP_STARTED; +#endif + } + +#ifndef __REACTOS__ + LeaveCriticalSection(&(This->crit)); +#endif + + TRACE("(X: %ld - Y: %ld - Z: %ld L: %02x M: %02x R: %02x)\n", + This->m_state.lX, This->m_state.lY, This->m_state.lZ, + This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]); + + return DI_OK; +} + +/****************************************************************************** + * GetDeviceState : gets buffered input data. + */ + +static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface, + DWORD dodsize, + LPDIDEVICEOBJECTDATA dod, + LPDWORD entries, + DWORD flags +) { + SysMouseImpl *This = (SysMouseImpl *)iface; + DWORD len; + int nqtail; +#ifdef __REACTOS__ +static int last_event=0; +const int size = sizeof(DIDEVICEOBJECTDATA) * 1; +static count=0; +static DWORD time=0; +#endif + + + TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags); + +#ifdef __REACTOS__ +getmousesvalue(iface); +#endif + + // windows does not get any data if + // we do not call manual to mouse Acquire + // this is only need if some apps calling on getdevice data direcly + // in windows GetdeviceData does always update first the data + // then return it. + SysMouseAImpl_Acquire(iface); + + + if (This->acquired == 0) { + WARN(" application tries to get data from an unacquired device !\n"); + return DIERR_NOTACQUIRED; + } + +#ifdef __REACTOS__ + FIXME("This is broken in Tribes, need right implant of the buffer!!!!!!!!\n"); + + *entries = 5; + if (GetTickCount()-time <50) return DI_OK; + time = GetTickCount(); + + dod[0].dwOfs = DIMOFS_X; + dod[0].dwData = This->m_state.lX; + dod[0].dwTimeStamp = 0; + dod[0].dwSequence = last_event++; + + dod[1].dwOfs = DIMOFS_Y; + dod[1].dwData = This->m_state.lY; + dod[1].dwTimeStamp = 0; + dod[1].dwSequence = last_event++; + + dod[2].dwOfs = DIMOFS_BUTTON0; + dod[2].dwData = This->m_state.rgbButtons[0]; + dod[2].dwTimeStamp = 0; + dod[2].dwSequence = last_event++; + + dod[3].dwOfs = DIMOFS_BUTTON1; + dod[3].dwData = This->m_state.rgbButtons[1]; + dod[3].dwTimeStamp = 0; + dod[0].dwSequence = last_event++; + + dod[4].dwOfs = DIMOFS_BUTTON2; + dod[4].dwData = This->m_state.rgbButtons[2]; + dod[4].dwTimeStamp = 50; + dod[4].dwSequence = last_event++; + +#endif + +#ifndef __REACTOS__ + EnterCriticalSection(&(This->crit)); + + + // FIXME mouse are bit choppy here. + + len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0) + + (This->queue_head - This->queue_tail); + if (len > *entries) len = *entries; + + if (dod == NULL) { + if (len) + TRACE("Application discarding %ld event(s).\n", len); + + *entries = len; + nqtail = This->queue_tail + len; + while (nqtail >= This->queue_len) nqtail -= This->queue_len; + } else { + if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3)) { + ERR("Wrong structure size !\n"); + + LeaveCriticalSection(&(This->crit)); + + return DIERR_INVALIDPARAM; + } + + if (len) + TRACE("Application retrieving %ld event(s).\n", len); + + *entries = 0; + nqtail = This->queue_tail; + while (len) { + DWORD span = ((This->queue_head < nqtail) ? This->queue_len : This->queue_head) - nqtail; + if (span > len) + span = len; + + /* Copy the buffered data into the application queue */ + memcpy(dod + *entries, This->data_queue + nqtail, span * dodsize); + + /* Advance position */ + nqtail += span; + if (nqtail >= This->queue_len) nqtail -= This->queue_len; + *entries += span; + len -= span; + } + } + if (!(flags & DIGDD_PEEK)) + This->queue_tail = nqtail; + + LeaveCriticalSection(&(This->crit)); + + /* Check if we need to do a mouse warping */ + + + if (This->need_warp == WARP_NEEDED) { + dinput_window_check(This); + TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); + if (mouse_set==0){ + SetCursorPos( This->mapped_center.x, This->mapped_center.y ); + mouse_set++; + } + +#ifdef MOUSE_HACK + This->need_warp = WARP_DONE; +#else + This->need_warp = WARP_STARTED; +#endif + } +#endif + return DI_OK; +} + +/****************************************************************************** + * SetProperty : change input device properties + */ +static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPCDIPROPHEADER ph) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + + TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph); + + if (!HIWORD(rguid)) { + switch ((DWORD)rguid) { + case (DWORD) DIPROP_BUFFERSIZE: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + + TRACE("buffersize = %ld\n",pd->dwData); + + This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0, + pd->dwData * sizeof(DIDEVICEOBJECTDATA)); + This->queue_head = 0; + This->queue_tail = 0; + This->queue_len = pd->dwData; + break; + } + case (DWORD) DIPROP_AXISMODE: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + This->absolute = !(pd->dwData); + TRACE("Using %s coordinates mode now\n", This->absolute ? "absolute" : "relative"); + break; + } + default: + FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); + break; + } + } + + return DI_OK; +} + +/****************************************************************************** + * GetProperty : get input device properties + */ +static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPDIPROPHEADER pdiph) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + + TRACE("(this=%p,%s,%p): stub!\n", + iface, debugstr_guid(rguid), pdiph); + + if (TRACE_ON(dinput)) + _dump_DIPROPHEADER(pdiph); + + if (!HIWORD(rguid)) { + switch ((DWORD)rguid) { + case (DWORD) DIPROP_BUFFERSIZE: { + LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; + + TRACE(" return buffersize = %d\n",This->queue_len); + pd->dwData = This->queue_len; + break; + } + + case (DWORD) DIPROP_GRANULARITY: { + LPDIPROPDWORD pr = (LPDIPROPDWORD) pdiph; + + /* We'll just assume that the app asks about the Z axis */ + pr->dwData = WHEEL_DELTA; + + break; + } + + case (DWORD) DIPROP_RANGE: { + LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph; + + if ((pdiph->dwHow == DIPH_BYID) && + ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) || + (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) { + /* Querying the range of either the X or the Y axis. As I do + not know the range, do as if the range were + unrestricted...*/ + pr->lMin = DIPROPRANGE_NOMIN; + pr->lMax = DIPROPRANGE_NOMAX; + } + + break; + } + + default: + FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); + break; + } + } + + return DI_OK; +} + + + +/****************************************************************************** + * SetEventNotification : specifies event to be sent on state change + */ +static HRESULT WINAPI SysMouseAImpl_SetEventNotification(LPDIRECTINPUTDEVICE8A iface, + HANDLE hnd) { + SysMouseImpl *This = (SysMouseImpl *)iface; + + TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd); + + This->hEvent = hnd; + + return DI_OK; +} + +/****************************************************************************** + * GetCapabilities : get the device capablitites + */ +static HRESULT WINAPI SysMouseAImpl_GetCapabilities( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVCAPS lpDIDevCaps) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + + TRACE("(this=%p,%p)\n",This,lpDIDevCaps); + + if (lpDIDevCaps->dwSize == sizeof(DIDEVCAPS)) { + lpDIDevCaps->dwFlags = DIDC_ATTACHED; + if (This->dinput->version >= 8) + lpDIDevCaps->dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8); + else + lpDIDevCaps->dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8); + lpDIDevCaps->dwAxes = 3; + lpDIDevCaps->dwButtons = 3; + lpDIDevCaps->dwPOVs = 0; + lpDIDevCaps->dwFFSamplePeriod = 0; + lpDIDevCaps->dwFFMinTimeResolution = 0; + lpDIDevCaps->dwFirmwareRevision = 100; + lpDIDevCaps->dwHardwareRevision = 100; + lpDIDevCaps->dwFFDriverVersion = 0; + } else if (lpDIDevCaps->dwSize == sizeof(DIDEVCAPS_DX3)) { + lpDIDevCaps->dwFlags = DIDC_ATTACHED; + lpDIDevCaps->dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8); + lpDIDevCaps->dwAxes = 3; + lpDIDevCaps->dwButtons = 3; + lpDIDevCaps->dwPOVs = 0; + } else { + WARN("invalid parameter\n"); + return DIERR_INVALIDPARAM; + } + + return DI_OK; +} + + +/****************************************************************************** + * EnumObjects : enumerate the different buttons and axis... + */ +static HRESULT WINAPI SysMouseAImpl_EnumObjects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + DIDEVICEOBJECTINSTANCEA ddoi; + + TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags); + if (TRACE_ON(dinput)) { + TRACE(" - flags = "); + _dump_EnumObjects_flags(dwFlags); + TRACE("\n"); + } + + /* Only the fields till dwFFMaxForce are relevant */ + memset(&ddoi, 0, sizeof(ddoi)); + ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce); + + /* In a mouse, we have : two relative axis and three buttons */ + if ((dwFlags == DIDFT_ALL) || + (dwFlags & DIDFT_AXIS)) { + /* X axis */ + ddoi.guidType = GUID_XAxis; + ddoi.dwOfs = This->offset_array[WINE_MOUSE_X_POSITION]; + ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS; + strcpy(ddoi.tszName, "X-Axis"); + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; + + /* Y axis */ + ddoi.guidType = GUID_YAxis; + ddoi.dwOfs = This->offset_array[WINE_MOUSE_Y_POSITION]; + ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS; + strcpy(ddoi.tszName, "Y-Axis"); + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; + + /* Z axis */ + ddoi.guidType = GUID_ZAxis; + ddoi.dwOfs = This->offset_array[WINE_MOUSE_Z_POSITION]; + ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS; + strcpy(ddoi.tszName, "Z-Axis"); + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; + } + + if ((dwFlags == DIDFT_ALL) || + (dwFlags & DIDFT_BUTTON)) { + ddoi.guidType = GUID_Button; + + /* Left button */ + ddoi.dwOfs = This->offset_array[WINE_MOUSE_L_POSITION]; + ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON; + strcpy(ddoi.tszName, "Left-Button"); + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; + + /* Right button */ + ddoi.dwOfs = This->offset_array[WINE_MOUSE_R_POSITION]; + ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON; + strcpy(ddoi.tszName, "Right-Button"); + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; + + /* Middle button */ + ddoi.dwOfs = This->offset_array[WINE_MOUSE_M_POSITION]; + ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON; + strcpy(ddoi.tszName, "Middle-Button"); + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; + } + + return DI_OK; +} + +static HRESULT WINAPI SysMouseWImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface, LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID lpvRef,DWORD dwFlags) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + + device_enumobjects_AtoWcb_data data; + + data.lpCallBack = lpCallback; + data.lpvRef = lpvRef; + + return SysMouseAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags); +} + +/****************************************************************************** + * GetDeviceInfo : get information about a device's identity + */ +static HRESULT WINAPI SysMouseAImpl_GetDeviceInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEINSTANCEA pdidi) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + TRACE("(this=%p,%p)\n", This, pdidi); + + if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)) { + WARN(" dinput3 not supporte yet...\n"); + return DI_OK; + } + + fill_mouse_dideviceinstanceA(pdidi, This->dinput->version); + + return DI_OK; +} + +static HRESULT WINAPI SysMouseWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEINSTANCEW pdidi) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + TRACE("(this=%p,%p)\n", This, pdidi); + + if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW)) { + WARN(" dinput3 not supporte yet...\n"); + return DI_OK; + } + + fill_mouse_dideviceinstanceW(pdidi, This->dinput->version); + + return DI_OK; +} + + +static IDirectInputDevice8AVtbl SysMouseAvt = +{ + IDirectInputDevice2AImpl_QueryInterface, + IDirectInputDevice2AImpl_AddRef, + SysMouseAImpl_Release, + SysMouseAImpl_GetCapabilities, + SysMouseAImpl_EnumObjects, + SysMouseAImpl_GetProperty, + SysMouseAImpl_SetProperty, + SysMouseAImpl_Acquire, + SysMouseAImpl_Unacquire, + SysMouseAImpl_GetDeviceState, + SysMouseAImpl_GetDeviceData, + SysMouseAImpl_SetDataFormat, + SysMouseAImpl_SetEventNotification, + SysMouseAImpl_SetCooperativeLevel, + IDirectInputDevice2AImpl_GetObjectInfo, + SysMouseAImpl_GetDeviceInfo, + IDirectInputDevice2AImpl_RunControlPanel, + IDirectInputDevice2AImpl_Initialize, + IDirectInputDevice2AImpl_CreateEffect, + IDirectInputDevice2AImpl_EnumEffects, + IDirectInputDevice2AImpl_GetEffectInfo, + IDirectInputDevice2AImpl_GetForceFeedbackState, + IDirectInputDevice2AImpl_SendForceFeedbackCommand, + IDirectInputDevice2AImpl_EnumCreatedEffectObjects, + IDirectInputDevice2AImpl_Escape, + SysMouseAImpl_Poll, + IDirectInputDevice2AImpl_SendDeviceData, + IDirectInputDevice7AImpl_EnumEffectsInFile, + IDirectInputDevice7AImpl_WriteEffectToFile, + IDirectInputDevice8AImpl_BuildActionMap, + IDirectInputDevice8AImpl_SetActionMap, + IDirectInputDevice8AImpl_GetImageInfo +}; + +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(SysMouseWvt.fun)) +#else +# define XCAST(fun) (void*) +#endif + +static IDirectInputDevice8WVtbl SysMouseWvt = +{ + IDirectInputDevice2WImpl_QueryInterface, + XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, + XCAST(Release)SysMouseAImpl_Release, + XCAST(GetCapabilities)SysMouseAImpl_GetCapabilities, + SysMouseWImpl_EnumObjects, + XCAST(GetProperty)SysMouseAImpl_GetProperty, + XCAST(SetProperty)SysMouseAImpl_SetProperty, + XCAST(Acquire)SysMouseAImpl_Acquire, + XCAST(Unacquire)SysMouseAImpl_Unacquire, + XCAST(GetDeviceState)SysMouseAImpl_GetDeviceState, + XCAST(GetDeviceData)SysMouseAImpl_GetDeviceData, + XCAST(SetDataFormat)SysMouseAImpl_SetDataFormat, + XCAST(SetEventNotification)SysMouseAImpl_SetEventNotification, + XCAST(SetCooperativeLevel)SysMouseAImpl_SetCooperativeLevel, + IDirectInputDevice2WImpl_GetObjectInfo, + SysMouseWImpl_GetDeviceInfo, + XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel, + XCAST(Initialize)IDirectInputDevice2AImpl_Initialize, + XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect, + IDirectInputDevice2WImpl_EnumEffects, + IDirectInputDevice2WImpl_GetEffectInfo, + XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState, + XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand, + XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects, + XCAST(Escape)IDirectInputDevice2AImpl_Escape, + XCAST(Poll)SysMouseAImpl_Poll, + XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData, + IDirectInputDevice7WImpl_EnumEffectsInFile, + IDirectInputDevice7WImpl_WriteEffectToFile, + IDirectInputDevice8WImpl_BuildActionMap, + IDirectInputDevice8WImpl_SetActionMap, + IDirectInputDevice8WImpl_GetImageInfo +}; +#undef XCAST diff --git a/reactos/lib/dinput/regsvr.c b/reactos/lib/dinput/regsvr.c new file mode 100644 index 00000000000..47c085daf7a --- /dev/null +++ b/reactos/lib/dinput/regsvr.c @@ -0,0 +1,558 @@ +/* + * self-registerable dll functions for dinput.dll + * + * Copyright (C) 2003 John K. Hohm + * + * 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.1 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 + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winreg.h" +#include "winerror.h" + +#include "dinput.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dinput); + +/* + * Near the bottom of this file are the exported DllRegisterServer and + * DllUnregisterServer, which make all this worthwhile. + */ + +/*********************************************************************** + * interface for self-registering + */ +struct regsvr_interface +{ + IID const *iid; /* NULL for end of list */ + LPCSTR name; /* can be NULL to omit */ + IID const *base_iid; /* can be NULL to omit */ + int num_methods; /* can be <0 to omit */ + CLSID const *ps_clsid; /* can be NULL to omit */ + CLSID const *ps_clsid32; /* can be NULL to omit */ +}; + +static HRESULT register_interfaces(struct regsvr_interface const *list); +static HRESULT unregister_interfaces(struct regsvr_interface const *list); + +struct regsvr_coclass +{ + CLSID const *clsid; /* NULL for end of list */ + LPCSTR name; /* can be NULL to omit */ + LPCSTR ips; /* can be NULL to omit */ + LPCSTR ips32; /* can be NULL to omit */ + LPCSTR ips32_tmodel; /* can be NULL to omit */ + LPCSTR progid; /* can be NULL to omit */ + LPCSTR viprogid; /* can be NULL to omit */ + LPCSTR progid_extra; /* can be NULL to omit */ +}; + +static HRESULT register_coclasses(struct regsvr_coclass const *list); +static HRESULT unregister_coclasses(struct regsvr_coclass const *list); + +/*********************************************************************** + * static string constants + */ +static WCHAR const interface_keyname[10] = { + 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 }; +static WCHAR const base_ifa_keyname[14] = { + 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', + 'e', 0 }; +static WCHAR const num_methods_keyname[11] = { + 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 }; +static WCHAR const ps_clsid_keyname[15] = { + 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', + 'i', 'd', 0 }; +static WCHAR const ps_clsid32_keyname[17] = { + 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', + 'i', 'd', '3', '2', 0 }; +static WCHAR const clsid_keyname[6] = { + 'C', 'L', 'S', 'I', 'D', 0 }; +static WCHAR const curver_keyname[7] = { + 'C', 'u', 'r', 'V', 'e', 'r', 0 }; +static WCHAR const ips_keyname[13] = { + 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', + 0 }; +static WCHAR const ips32_keyname[15] = { + 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', + '3', '2', 0 }; +static WCHAR const progid_keyname[7] = { + 'P', 'r', 'o', 'g', 'I', 'D', 0 }; +static WCHAR const viprogid_keyname[25] = { + 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p', + 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D', + 0 }; +static char const tmodel_valuename[] = "ThreadingModel"; + +/*********************************************************************** + * static helper functions + */ +static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid); +static LONG register_key_defvalueW(HKEY base, WCHAR const *name, + WCHAR const *value); +static LONG register_key_defvalueA(HKEY base, WCHAR const *name, + char const *value); +static LONG register_progid(WCHAR const *clsid, + char const *progid, char const *curver_progid, + char const *name, char const *extra); +static LONG recursive_delete_key(HKEY key); +static LONG recursive_delete_keyA(HKEY base, char const *name); +static LONG recursive_delete_keyW(HKEY base, WCHAR const *name); + +/*********************************************************************** + * register_interfaces + */ +static HRESULT register_interfaces(struct regsvr_interface const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY interface_key; + + res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &interface_key, NULL); + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->iid; ++list) { + WCHAR buf[39]; + HKEY iid_key; + + StringFromGUID2(list->iid, buf, 39); + res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &iid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_interface_key; + + if (list->name) { + res = RegSetValueExA(iid_key, NULL, 0, REG_SZ, + (CONST BYTE*)(list->name), + strlen(list->name) + 1); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->base_iid) { + register_key_guid(iid_key, base_ifa_keyname, list->base_iid); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (0 <= list->num_methods) { + static WCHAR const fmt[3] = { '%', 'd', 0 }; + HKEY key; + + res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + + wsprintfW(buf, fmt, list->num_methods); + res = RegSetValueExW(key, NULL, 0, REG_SZ, + (CONST BYTE*)buf, + (lstrlenW(buf) + 1) * sizeof(WCHAR)); + RegCloseKey(key); + + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->ps_clsid) { + register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->ps_clsid32) { + register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + error_close_iid_key: + RegCloseKey(iid_key); + } + +error_close_interface_key: + RegCloseKey(interface_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * unregister_interfaces + */ +static HRESULT unregister_interfaces(struct regsvr_interface const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY interface_key; + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, + KEY_READ | KEY_WRITE, &interface_key); + if (res == ERROR_FILE_NOT_FOUND) return S_OK; + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->iid; ++list) { + WCHAR buf[39]; + + StringFromGUID2(list->iid, buf, 39); + res = recursive_delete_keyW(interface_key, buf); + } + + RegCloseKey(interface_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * register_coclasses + */ +static HRESULT register_coclasses(struct regsvr_coclass const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY coclass_key; + + res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL); + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->clsid; ++list) { + WCHAR buf[39]; + HKEY clsid_key; + + StringFromGUID2(list->clsid, buf, 39); + res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + + if (list->name) { + res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ, + (CONST BYTE*)(list->name), + strlen(list->name) + 1); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->ips) { + res = register_key_defvalueA(clsid_key, ips_keyname, list->ips); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->ips32) { + HKEY ips32_key; + + res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, + &ips32_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ, + (CONST BYTE*)list->ips32, + lstrlenA(list->ips32) + 1); + if (res == ERROR_SUCCESS && list->ips32_tmodel) + res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ, + (CONST BYTE*)list->ips32_tmodel, + strlen(list->ips32_tmodel) + 1); + RegCloseKey(ips32_key); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->progid) { + res = register_key_defvalueA(clsid_key, progid_keyname, + list->progid); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = register_progid(buf, list->progid, NULL, + list->name, list->progid_extra); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->viprogid) { + res = register_key_defvalueA(clsid_key, viprogid_keyname, + list->viprogid); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = register_progid(buf, list->viprogid, list->progid, + list->name, list->progid_extra); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + error_close_clsid_key: + RegCloseKey(clsid_key); + } + +error_close_coclass_key: + RegCloseKey(coclass_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * unregister_coclasses + */ +static HRESULT unregister_coclasses(struct regsvr_coclass const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY coclass_key; + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, + KEY_READ | KEY_WRITE, &coclass_key); + if (res == ERROR_FILE_NOT_FOUND) return S_OK; + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->clsid; ++list) { + WCHAR buf[39]; + + StringFromGUID2(list->clsid, buf, 39); + res = recursive_delete_keyW(coclass_key, buf); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + + if (list->progid) { + res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + } + + if (list->viprogid) { + res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + } + } + +error_close_coclass_key: + RegCloseKey(coclass_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * regsvr_key_guid + */ +static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) +{ + WCHAR buf[39]; + + StringFromGUID2(guid, buf, 39); + return register_key_defvalueW(base, name, buf); +} + +/*********************************************************************** + * regsvr_key_defvalueW + */ +static LONG register_key_defvalueW( + HKEY base, + WCHAR const *name, + WCHAR const *value) +{ + LONG res; + HKEY key; + + res = RegCreateKeyExW(base, name, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) return res; + res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value, + (lstrlenW(value) + 1) * sizeof(WCHAR)); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * regsvr_key_defvalueA + */ +static LONG register_key_defvalueA( + HKEY base, + WCHAR const *name, + char const *value) +{ + LONG res; + HKEY key; + + res = RegCreateKeyExW(base, name, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) return res; + res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value, + lstrlenA(value) + 1); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * regsvr_progid + */ +static LONG register_progid( + WCHAR const *clsid, + char const *progid, + char const *curver_progid, + char const *name, + char const *extra) +{ + LONG res; + HKEY progid_key; + + res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0, + NULL, 0, KEY_READ | KEY_WRITE, NULL, + &progid_key, NULL); + if (res != ERROR_SUCCESS) return res; + + if (name) { + res = RegSetValueExA(progid_key, NULL, 0, REG_SZ, + (CONST BYTE*)name, strlen(name) + 1); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + + if (clsid) { + res = register_key_defvalueW(progid_key, clsid_keyname, clsid); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + + if (curver_progid) { + res = register_key_defvalueA(progid_key, curver_keyname, + curver_progid); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + + if (extra) { + HKEY extra_key; + + res = RegCreateKeyExA(progid_key, extra, 0, + NULL, 0, KEY_READ | KEY_WRITE, NULL, + &extra_key, NULL); + if (res == ERROR_SUCCESS) + RegCloseKey(extra_key); + } + +error_close_progid_key: + RegCloseKey(progid_key); + return res; +} + +/*********************************************************************** + * recursive_delete_key + */ +static LONG recursive_delete_key(HKEY key) +{ + LONG res; + WCHAR subkey_name[MAX_PATH]; + DWORD cName; + HKEY subkey; + + for (;;) { + cName = sizeof(subkey_name) / sizeof(WCHAR); + res = RegEnumKeyExW(key, 0, subkey_name, &cName, + NULL, NULL, NULL, NULL); + if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) { + res = ERROR_SUCCESS; /* presumably we're done enumerating */ + break; + } + res = RegOpenKeyExW(key, subkey_name, 0, + KEY_READ | KEY_WRITE, &subkey); + if (res == ERROR_FILE_NOT_FOUND) continue; + if (res != ERROR_SUCCESS) break; + + res = recursive_delete_key(subkey); + RegCloseKey(subkey); + if (res != ERROR_SUCCESS) break; + } + + if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0); + return res; +} + +/*********************************************************************** + * recursive_delete_keyA + */ +static LONG recursive_delete_keyA(HKEY base, char const *name) +{ + LONG res; + HKEY key; + + res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key); + if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; + if (res != ERROR_SUCCESS) return res; + res = recursive_delete_key(key); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * recursive_delete_keyW + */ +static LONG recursive_delete_keyW(HKEY base, WCHAR const *name) +{ + LONG res; + HKEY key; + + res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key); + if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; + if (res != ERROR_SUCCESS) return res; + res = recursive_delete_key(key); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * coclass list + */ +static struct regsvr_coclass const coclass_list[] = { + { + &CLSID_DirectInput, + "DirectInput Object", + NULL, + "dinput.dll", + "Both" + }, + { + &CLSID_DirectInputDevice, + "DirectInputDevice Object", + NULL, + "dinput.dll", + "Both" + }, + { NULL } /* list terminator */ +}; + +/*********************************************************************** + * interface list + */ + +static struct regsvr_interface const interface_list[] = { + { NULL } /* list terminator */ +}; + +/*********************************************************************** + * DllRegisterServer (DINPUT.@) + */ +HRESULT WINAPI DINPUT_DllRegisterServer(void) +{ + HRESULT hr; + + TRACE("\n"); + + hr = register_coclasses(coclass_list); + if (SUCCEEDED(hr)) + hr = register_interfaces(interface_list); + return hr; +} + +/*********************************************************************** + * DllUnregisterServer (DINPUT.@) + */ +HRESULT WINAPI DINPUT_DllUnregisterServer(void) +{ + HRESULT hr; + + TRACE("\n"); + + hr = unregister_coclasses(coclass_list); + if (SUCCEEDED(hr)) + hr = unregister_interfaces(interface_list); + return hr; +} diff --git a/reactos/lib/dinput/version.rc b/reactos/lib/dinput/version.rc new file mode 100644 index 00000000000..53df0b62226 --- /dev/null +++ b/reactos/lib/dinput/version.rc @@ -0,0 +1,26 @@ +/* + * Copyright 2001 Ove Kaaven + * + * 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.1 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 + */ + +#define WINE_FILEDESCRIPTION_STR "Wine DirectInput" +#define WINE_FILENAME_STR "dinput.dll" +#define WINE_FILEVERSION 5,1,2600,881 +#define WINE_FILEVERSION_STR "5.1.2600.881" +#define WINE_PRODUCTVERSION 5,1,2600,881 +#define WINE_PRODUCTVERSION_STR "5.1" + +#include "wine/wine_common_ver.rc"