On Tue, Jul 19, 2011 at 09:40:37PM -0300, Lucas Zawacki wrote: > Hey, I've got a couple patches implementing build and setactionmap for > joysticks and I'd like you guys to give them a look.
The patches look good to my eyes. This part: > + if ((lpdiaf->rgoAction[i].dwSemantic & genre) == genre) still looks strange (as the first genre should be a some kind of bitmask instead of genre?), but will likely work as-is for now. > These implementations are very generic and I think I could use them > for the keyboard and the mouse too. If everything's alright with these > patches that'll be my next step. > > The mapping can be tested this small app I built: > https://github.com/downloads/lfzawacki/dinput-samples/dolphin.exe > provided that you have one joystick attached (it will chose the first > one if there are more). Works with my Joystick here at least. Not sure what it should output, A and X button works, the ranges go to 10/-10 expect for "Down" just going to -5 (might be a issue with the joystick). Ciao, Marcus > 2011/7/5 Lucas Zawacki <lfzawa...@gmail.com>: > > Hi guys. > > > > Now that all the initial patches are in I have several smaller tasks > > to work on as listed here > > http://lfzawacki.heroku.com/wine/published/Road+Map and hopefully > > they're more straightforward. I've already started working on getting > > EnumDevicesBySemantics correct with joysticks and the passed flags > > and, after that, BuildActionMap for the joysticks will follow. Maybe > > now it's time to discuss how to implement EnumDevicesBySemantics as a > > crosscall, but I really don't know how to do it (or if it's worth it) > > and everywhere I look in dinput I see similar cases of this > > "duplication pattern". > > > > Another thing that I've been thinking is that I might as well end up > > rolling a version of ConfigureDevices > > (http://msdn.microsoft.com/en-us/library/microsoft.directx_sdk.idirectinput8.idirectinput8.configuredevices%28v=VS.85%29.aspx) > > because so far I've seen two of the games affected by bug 8754 use it > > to configure controls. I've not had time to find and test all of them, > > but if someone on the list knows about other games that use it I'd > > like to be informed. > > > > Last but not least, thanks for Wylda for testing NFSU and keeping bug > > 8754 informed. I actually can't run the game properly, most likely > > because of the crappy intel graphics card in my laptop. > > > > Anyway, feedback on the tasks is welcome. > > > > --- > > lfz > > > From b492c54d5ca7179e0905f63cec183d0920555e1d Mon Sep 17 00:00:00 2001 > From: Lucas Fialho Zawacki <lfzawa...@gmail.com> > Date: Tue, 19 Jul 2011 17:52:12 -0300 > Subject: [PATCH 1/4] dinput: EnumDevicesBySemantics enumerating joysticks > with priority flags > > Added an utility function that checks the priority of a device for a given > mapping. This can be modified later to return priority 2 mappings, if > necessary. > --- > dlls/dinput/dinput_main.c | 50 ++++++++++++++++++++++++++++++++------------ > 1 files changed, 36 insertions(+), 14 deletions(-) > > diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c > index b653307..1d59cdc 100644 > --- a/dlls/dinput/dinput_main.c > +++ b/dlls/dinput/dinput_main.c > @@ -317,6 +317,38 @@ void _copy_diactionformatWtoA(LPDIACTIONFORMATA to, > LPDIACTIONFORMATW from) > } > } > > +/* _diactionformat_priorityA > + * > + * Given a DIACTIONFORMAT structure and a DI genre, returns the enumeration > + * priority. Joysticks should pass the game genre, and mouse or keyboard > their > + * respective DI*_MASK > + */ > +static DWORD _diactionformat_priorityA(LPDIACTIONFORMATA lpdiaf, DWORD genre) > +{ > + int i; > + DWORD priorityFlags = 0; > + > + /* If there's at least one action for the device it's priority 1 */ > + for(i=0; i < lpdiaf->dwActionSize; i++) > + if ((lpdiaf->rgoAction[i].dwSemantic & genre) == genre) > + priorityFlags |= DIEDBS_MAPPEDPRI1; > + > + return priorityFlags; > +} > + > +static DWORD _diactionformat_priorityW(LPDIACTIONFORMATW lpdiaf, DWORD genre) > +{ > + int i; > + DWORD priorityFlags = 0; > + > + /* If there's at least one action for the device it's priority 1 */ > + for(i=0; i < lpdiaf->dwActionSize; i++) > + if ((lpdiaf->rgoAction[i].dwSemantic & genre) == genre) > + priorityFlags |= DIEDBS_MAPPEDPRI1; > + > + return priorityFlags; > +} > + > > /****************************************************************************** > * IDirectInputA_EnumDevices > */ > @@ -877,7 +909,7 @@ static HRESULT WINAPI > IDirectInput8AImpl_EnumDevicesBySemantics( > { > TRACE(" - checking device %u ('%s')\n", i, > dinput_devices[i]->name); > > - callbackFlags = 0; > + callbackFlags = _diactionformat_priorityA(lpdiActionFormat, > lpdiActionFormat->dwGenre); > /* Default behavior is to enumerate attached game controllers */ > enumSuccess = > dinput_devices[i]->enum_deviceA(DI8DEVCLASS_GAMECTRL, DIEDFL_ATTACHEDONLY | > dwFlags, &didevi, This->dwVersion, j); > if (enumSuccess) > @@ -895,16 +927,11 @@ static HRESULT WINAPI > IDirectInput8AImpl_EnumDevicesBySemantics( > /* Enumerate keyboard and mouse */ > for(i=0; i < sizeof(guids)/sizeof(guids[0]); i++) > { > - callbackFlags = 0; > + callbackFlags = _diactionformat_priorityA(lpdiActionFormat, > actionMasks[i]); > > IDirectInput_CreateDevice(iface, guids[i], &lpdid, NULL); > IDirectInputDevice_GetDeviceInfo(lpdid, &didevi); > > - /* If there's at least one action for the device it's priority 1 */ > - for(j=0; j < lpdiActionFormat->dwActionSize; j++) > - if ((lpdiActionFormat->rgoAction[j].dwSemantic & actionMasks[i]) > == actionMasks[i]) > - callbackFlags |= DIEDBS_MAPPEDPRI1; > - > if (lpCallback(&didevi, lpdid, callbackFlags, > sizeof(guids)/sizeof(guids[0]) - (i+1), pvRef) == DIENUM_STOP) > return DI_OK; > } > @@ -942,7 +969,7 @@ static HRESULT WINAPI > IDirectInput8WImpl_EnumDevicesBySemantics( > { > TRACE(" - checking device %u ('%s')\n", i, > dinput_devices[i]->name); > > - callbackFlags = 0; > + callbackFlags = _diactionformat_priorityW(lpdiActionFormat, > lpdiActionFormat->dwGenre); > /* Default behavior is to enumerate attached game controllers */ > enumSuccess = > dinput_devices[i]->enum_deviceW(DI8DEVCLASS_GAMECTRL, DIEDFL_ATTACHEDONLY | > dwFlags, &didevi, This->dwVersion, j); > if (enumSuccess) > @@ -960,16 +987,11 @@ static HRESULT WINAPI > IDirectInput8WImpl_EnumDevicesBySemantics( > /* Enumerate keyboard and mouse */ > for(i=0; i < sizeof(guids)/sizeof(guids[0]); i++) > { > - callbackFlags = 0; > + callbackFlags = _diactionformat_priorityW(lpdiActionFormat, > actionMasks[i]); > > IDirectInput_CreateDevice(iface, guids[i], &lpdid, NULL); > IDirectInputDevice_GetDeviceInfo(lpdid, &didevi); > > - /* If there's at least one action for the device it's priority 1 */ > - for(j=0; j < lpdiActionFormat->dwActionSize; j++) > - if ((lpdiActionFormat->rgoAction[j].dwSemantic & actionMasks[i]) > == actionMasks[i]) > - callbackFlags |= DIEDBS_MAPPEDPRI1; > - > if (lpCallback(&didevi, lpdid, callbackFlags, > sizeof(guids)/sizeof(guids[0]) - (i+1), pvRef) == DIENUM_STOP) > return DI_OK; > } > -- > 1.7.0.4 > > From 2c97c4d622a4731721705b81416191b47b738d71 Mon Sep 17 00:00:00 2001 > From: Lucas Fialho Zawacki <lfzawa...@gmail.com> > Date: Tue, 19 Jul 2011 20:25:48 -0300 > Subject: [PATCH 2/4] dinput: BuildActionMap for all joysticks. For the moment > only for buttons and axis. > > Added an utility function that finds the Nth dataformat object of a given > type. > --- > dlls/dinput/device.c | 23 +++++++++++++++++++++++ > dlls/dinput/device_private.h | 1 + > dlls/dinput/joystick.c | 40 +++++++++++++++++++++++++++++++++++++++- > 3 files changed, 63 insertions(+), 1 deletions(-) > > diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c > index 22632ea..2bd5d6c 100644 > --- a/dlls/dinput/device.c > +++ b/dlls/dinput/device.c > @@ -366,6 +366,29 @@ static inline LPDIOBJECTDATAFORMAT > dataformat_to_odf(LPCDIDATAFORMAT df, int idx > return (LPDIOBJECTDATAFORMAT)((LPBYTE)df->rgodf + idx * df->dwObjSize); > } > > +/* dataformat_to_odf_by_type > + * Find the Nth object of the selected type in the DataFormat > + */ > +LPDIOBJECTDATAFORMAT dataformat_to_odf_by_type(LPCDIDATAFORMAT df, int n, > DWORD type) > +{ > + int i, nfound = 0; > + > + for (i=0; i < df->dwNumObjs; i++) > + { > + LPDIOBJECTDATAFORMAT odf = dataformat_to_odf(df, i); > + > + if (odf->dwType & type) > + { > + if (n == nfound) > + return odf; > + > + nfound++; > + } > + } > + > + return NULL; > +} > + > static HRESULT create_DataFormat(LPCDIDATAFORMAT asked_format, DataFormat > *format) > { > DataTransform *dt; > diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h > index 503698a..6c061b2 100644 > --- a/dlls/dinput/device_private.h > +++ b/dlls/dinput/device_private.h > @@ -125,6 +125,7 @@ extern void _dump_DIDATAFORMAT(const DIDATAFORMAT *df) > DECLSPEC_HIDDEN; > extern const char *_dump_dinput_GUID(const GUID *guid) DECLSPEC_HIDDEN; > > extern DWORD semantic_to_obj_id(IDirectInputDeviceImpl* This, DWORD > dwSemantic) DECLSPEC_HIDDEN; > +extern LPDIOBJECTDATAFORMAT dataformat_to_odf_by_type(LPCDIDATAFORMAT df, > int n, DWORD type) DECLSPEC_HIDDEN; > > /* And the stubs */ > extern HRESULT WINAPI IDirectInputDevice2AImpl_Acquire(LPDIRECTINPUTDEVICE8A > iface) DECLSPEC_HIDDEN; > diff --git a/dlls/dinput/joystick.c b/dlls/dinput/joystick.c > index 68dcc6a..d821748 100644 > --- a/dlls/dinput/joystick.c > +++ b/dlls/dinput/joystick.c > @@ -432,9 +432,47 @@ HRESULT WINAPI > JoystickWGenericImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface, > LPCWSTR lpszUserName, > DWORD dwFlags) > { > + JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface); > + int i, j, has_actions = 0; > + DWORD object_types[] = { DIDFT_BUTTON, DIDFT_AXIS }; > + DWORD type_map[] = { DIDFT_PSHBUTTON, DIDFT_RELAXIS }; > + > FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf, > debugstr_w(lpszUserName), dwFlags); > > - return DI_NOEFFECT; > + for (i=0; i < lpdiaf->dwNumActions; i++) > + { > + DWORD inst = (0x000000ff & (lpdiaf->rgoAction[i].dwSemantic)) - 1; > + DWORD type = 0x000000ff & (lpdiaf->rgoAction[i].dwSemantic >> 8); > + DWORD genre = 0xff000000 & lpdiaf->rgoAction[i].dwSemantic; > + > + /* Only consider actions of the right genre */ > + if (lpdiaf->dwGenre != genre) continue; > + > + for (j=0; j < sizeof(object_types)/sizeof(object_types[0]); j++) > + { > + if (type & object_types[j]) > + { > + /* Assure that the object exists */ > + LPDIOBJECTDATAFORMAT odf = > dataformat_to_odf_by_type(This->base.data_format.wine_df, inst, DIDFT_BUTTON); > + > + if (odf != NULL) > + { > + lpdiaf->rgoAction[i].dwObjID = type_map[j] | (0x0000ff00 > & (inst << 8)); > + lpdiaf->rgoAction[i].guidInstance = This->base.guid; > + lpdiaf->rgoAction[i].dwHow = DIAH_DEFAULT; > + > + has_actions = 1; > + > + /* No need to try other types if the action was already > mapped */ > + break; > + } > + } > + } > + } > + > + if (!has_actions) return DI_NOEFFECT; > + > + return IDirectInputDevice8WImpl_BuildActionMap(iface, lpdiaf, > lpszUserName, dwFlags); > } > > HRESULT WINAPI JoystickAGenericImpl_BuildActionMap(LPDIRECTINPUTDEVICE8A > iface, > -- > 1.7.0.4 > > From a71ddba6092dd7a843c5359b26c4e9254311edfb Mon Sep 17 00:00:00 2001 > From: Lucas Fialho Zawacki <lfzawa...@gmail.com> > Date: Tue, 19 Jul 2011 20:44:36 -0300 > Subject: [PATCH 3/4] dinput: SetActionMap for joysticks. > > --- > dlls/dinput/joystick.c | 60 > +++++++++++++++++++++++++++++++++++++++++++++++- > 1 files changed, 59 insertions(+), 1 deletions(-) > > diff --git a/dlls/dinput/joystick.c b/dlls/dinput/joystick.c > index d821748..c63def9 100644 > --- a/dlls/dinput/joystick.c > +++ b/dlls/dinput/joystick.c > @@ -500,9 +500,67 @@ HRESULT WINAPI > JoystickWGenericImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface, > LPCWSTR lpszUserName, > DWORD dwFlags) > { > + JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface); > + DIDATAFORMAT data_format; > + DIOBJECTDATAFORMAT *obj_df = NULL; > + int i, action = 0, num_actions = 0; > + unsigned int offset = 0; > + > FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf, > debugstr_w(lpszUserName), dwFlags); > > - return DI_NOEFFECT; > + if (This->base.acquired) return DIERR_ACQUIRED; > + > + data_format.dwSize = sizeof(data_format); > + data_format.dwObjSize = sizeof(DIOBJECTDATAFORMAT); > + data_format.dwFlags = DIDF_RELAXIS; > + data_format.dwDataSize = lpdiaf->dwDataSize; > + > + /* count the actions */ > + for (i=0; i < lpdiaf->dwNumActions; i++) > + if (IsEqualGUID(&This->base.guid, > &lpdiaf->rgoAction[i].guidInstance)) > + num_actions++; > + > + if (num_actions == 0) return DI_NOEFFECT; > + > + This->base.num_actions = num_actions; > + > + /* Construct the dataformat and actionmap */ > + obj_df = HeapAlloc(GetProcessHeap(), 0, > sizeof(DIOBJECTDATAFORMAT)*num_actions); > + data_format.rgodf = (LPDIOBJECTDATAFORMAT)obj_df; > + data_format.dwNumObjs = num_actions; > + > + This->base.action_map = HeapAlloc(GetProcessHeap(), 0, > sizeof(ActionMap)*num_actions); > + > + for (i = 0; i < lpdiaf->dwNumActions; i++) > + { > + if (IsEqualGUID(&This->base.guid, > &lpdiaf->rgoAction[i].guidInstance)) > + { > + LPDIDATAFORMAT df = This->base.data_format.wine_df; > + DWORD inst = DIDFT_GETINSTANCE(lpdiaf->rgoAction[i].dwObjID); > + DWORD type = DIDFT_GETTYPE(lpdiaf->rgoAction[i].dwObjID); > + LPDIOBJECTDATAFORMAT obj; > + > + if (type == DIDFT_PSHBUTTON) type = DIDFT_BUTTON; > + if (type == DIDFT_RELAXIS) type = DIDFT_AXIS; > + > + obj = dataformat_to_odf_by_type(df, inst, type); > + > + memcpy(&obj_df[action], obj, df->dwObjSize); > + > + This->base.action_map[action].uAppData = > lpdiaf->rgoAction[i].uAppData; > + This->base.action_map[action].offset = offset; > + obj_df[action].dwOfs = offset; > + offset += (type & DIDFT_BUTTON) ? 1 : 4; > + > + action++; > + } > + } > + > + IDirectInputDevice8_SetDataFormat(iface, &data_format); > + > + HeapFree(GetProcessHeap(), 0, obj_df); > + > + return IDirectInputDevice8WImpl_SetActionMap(iface, lpdiaf, > lpszUserName, dwFlags); > } > > HRESULT WINAPI JoystickAGenericImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface, > -- > 1.7.0.4 > > From 4f18cfb471707c461135ecfde5f975324b37e696 Mon Sep 17 00:00:00 2001 > From: Lucas Fialho Zawacki <lfzawa...@gmail.com> > Date: Tue, 19 Jul 2011 21:03:16 -0300 > Subject: [PATCH 4/4] dinput: SetActionMap setting the axis range according to > the action format > > --- > dlls/dinput/device.c | 8 ++++++++ > dlls/dinput8/tests/device.c | 15 +++++++++++++++ > 2 files changed, 23 insertions(+), 0 deletions(-) > > diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c > index 2bd5d6c..58d4e14 100644 > --- a/dlls/dinput/device.c > +++ b/dlls/dinput/device.c > @@ -1483,9 +1483,17 @@ HRESULT WINAPI > IDirectInputDevice8WImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface > DWORD dwFlags) > { > DIPROPDWORD dp; > + DIPROPRANGE dpr; > > FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf, > debugstr_w(lpszUserName), dwFlags); > > + dpr.diph.dwSize = sizeof(DIPROPRANGE); > + dpr.lMin = lpdiaf->lAxisMin; > + dpr.lMax = lpdiaf->lAxisMax; > + dpr.diph.dwHeaderSize = sizeof(DIPROPHEADER); > + dpr.diph.dwHow = DIPH_DEVICE; > + IDirectInputDevice8_SetProperty(iface, DIPROP_RANGE, &dpr.diph); > + > if (lpdiaf->dwBufferSize > 0) > { > dp.diph.dwSize = sizeof(DIPROPDWORD); > diff --git a/dlls/dinput8/tests/device.c b/dlls/dinput8/tests/device.c > index cedad80..31e2e3f 100644 > --- a/dlls/dinput8/tests/device.c > +++ b/dlls/dinput8/tests/device.c > @@ -132,6 +132,7 @@ static BOOL CALLBACK enumeration_callback( > { > HRESULT hr; > DIPROPDWORD dp; > + DIPROPRANGE dpr; > struct enum_data *data = pvRef; > if (!data) return DIENUM_CONTINUE; > > @@ -179,6 +180,20 @@ static BOOL CALLBACK enumeration_callback( > ok (SUCCEEDED(hr), "GetProperty failed hr=%08x\n", hr); > ok (dp.dwData == data->lpdiaf->dwBufferSize, "SetActionMap must set the > buffer, buffersize=%d\n", dp.dwData); > > + /* Test axis range */ > + memset(&dpr, 0, sizeof(dpr)); > + dpr.diph.dwSize = sizeof(dpr); > + dpr.diph.dwHeaderSize = sizeof(DIPROPHEADER); > + dpr.diph.dwHow = DIPH_DEVICE; > + > + hr = IDirectInputDevice_GetProperty(lpdid, DIPROP_RANGE, &dpr.diph); > + /* Only test if device supports the range property */ > + if (SUCCEEDED(hr)) > + { > + ok (dpr.lMin == data->lpdiaf->lAxisMin, "SetActionMap must set the > min axis range expected=%d got=%d\n", data->lpdiaf->lAxisMin, dpr.lMin); > + ok (dpr.lMax == data->lpdiaf->lAxisMax, "SetActionMap must set the > max axis range expected=%d got=%d\n", data->lpdiaf->lAxisMax, dpr.lMax); > + } > + > /* SetActionMap has set the data format so now it should work */ > hr = IDirectInputDevice8_Acquire(lpdid); > ok (SUCCEEDED(hr), "Acquire failed hr=%08x\n", hr); > -- > 1.7.0.4 > >