From d5089904cff4af0c06ed6680f2a1dba509171b1f Mon Sep 17 00:00:00 2001
From: Lucas Fialho Zawacki <lfzawacki@gmail.com>
Date: Sat, 11 Jun 2011 15:45:52 -0300
Subject: dinput: SetActionMap internal action mapping and GetDeviceData uAppData retrieval.

---
 dlls/dinput/device.c         |   28 ++++++++++++++++++++++++++++
 dlls/dinput/device_private.h |    6 ++++++
 dlls/dinput8/tests/device.c  |   31 +++++++++++++++++++++++++++++++
 3 files changed, 65 insertions(+), 0 deletions(-)

diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c
index accfe84..39da907 100644
--- a/dlls/dinput/device.c
+++ b/dlls/dinput/device.c
@@ -576,6 +576,8 @@ void queue_event(LPDIRECTINPUTDEVICE8A iface, int inst_id, DWORD data, DWORD tim
     This->data_queue[This->queue_head].dwData      = data;
     This->data_queue[This->queue_head].dwTimeStamp = time;
     This->data_queue[This->queue_head].dwSequence  = seq;
+    if (This->use_actionmap)
+        This->data_queue[This->queue_head].uAppData = This->actionmap[ofs];
     This->queue_head = next_pos;
     /* Send event if asked */
 }
@@ -1393,11 +1395,25 @@ HRESULT WINAPI IDirectInputDevice8AImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface
 {
     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
     DIPROPDWORD dp;
+    int i, has_actions = 0;
 
     FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf, lpszUserName, dwFlags);
 
     if (This->acquired) return DIERR_ACQUIRED;
 
+    /* search for actions for this device and apply them */
+    for (i=0; i < lpdiaf->dwNumActions; i++) {
+        if (IsEqualGUID( &lpdiaf->rgoAction[i].guidInstance, &This->guid ) ) {
+            int actionIndex = DIDFT_GETINSTANCE(lpdiaf->rgoAction[i].dwObjID);
+            This->actionmap[actionIndex] = lpdiaf->rgoAction[i].uAppData;
+            has_actions = 1;
+        }
+    }
+
+    if (!has_actions) return DI_NOEFFECT;
+
+    This->use_actionmap = 1;
+
     IDirectInputDevice8_SetDataFormat(iface, This->data_format.wine_df);
 
     if (lpdiaf->dwBufferSize > 0)
@@ -1420,11 +1436,23 @@ HRESULT WINAPI IDirectInputDevice8WImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface
 {
     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
     DIPROPDWORD dp;
+    int i, has_actions = 0;
 
     FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags);
 
     if (This->acquired) return DIERR_ACQUIRED;
 
+    /* search for actions for this device and apply them */
+    for (i=0; i < lpdiaf->dwNumActions; i++) {
+        if (IsEqualGUID( &lpdiaf->rgoAction[i].guidInstance, &This->guid ) ) {
+            int actionIndex = DIDFT_GETINSTANCE(lpdiaf->rgoAction[i].dwObjID);
+            This->actionmap[actionIndex] = lpdiaf->rgoAction[i].uAppData;
+            has_actions = 1;
+        }
+    }
+
+    if (!has_actions) return DI_NOEFFECT;
+
     IDirectInputDevice8_SetDataFormat(iface, This->data_format.wine_df);
 
     if (lpdiaf->dwBufferSize > 0)
diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h
index f254d7f..2ea95b0 100644
--- a/dlls/dinput/device_private.h
+++ b/dlls/dinput/device_private.h
@@ -28,6 +28,8 @@
 #include "wine/list.h"
 #include "dinput_private.h"
 
+#define MAX_DEVICE_OBJECTS 256
+
 typedef struct
 {
     int size;
@@ -71,6 +73,10 @@ struct IDirectInputDeviceImpl
     BOOL                        overflow;    /* return DI_BUFFEROVERFLOW in 'GetDeviceData' */
 
     DataFormat                  data_format; /* user data format and wine to user format converter */
+
+    int                         use_actionmap;
+    /* each app data is indexed by the device ObjID */
+    UINT_PTR                    actionmap[MAX_DEVICE_OBJECTS];
 };
 
 extern BOOL get_app_key(HKEY*, HKEY*) DECLSPEC_HIDDEN;
diff --git a/dlls/dinput8/tests/device.c b/dlls/dinput8/tests/device.c
index e1b308f..e828bca 100644
--- a/dlls/dinput8/tests/device.c
+++ b/dlls/dinput8/tests/device.c
@@ -57,6 +57,31 @@ DIACTION actionMapping[]=
   { 3, DIMOUSE_BUTTON0 , 0, { "Select" } }
 };
 
+static void test_keyboard_input(LPDIRECTINPUTDEVICE8 lpdid, DWORD key, DWORD expected)
+{
+    HRESULT hr;
+    DIDEVICEOBJECTDATA obj_data;
+    DWORD data_size = 1;
+
+    hr = IDirectInputDevice8_Acquire(lpdid);
+    ok (SUCCEEDED(hr), "Failed to acquire device hr=%08x\n", hr);
+
+    keybd_event( key, 0, 0, 0);
+
+    IDirectInputDevice8_Poll(lpdid);
+    hr = IDirectInputDevice8_GetDeviceData(lpdid, sizeof(obj_data), &obj_data, &data_size, 0);
+
+    if (data_size != 1)
+    {
+        win_skip("We're not able to inject input into Windows dinput8 with events\n");
+        return;
+    }
+
+    ok (data_size == 1, "GetDeviceData did not read any event\n");
+    ok (obj_data.uAppData == expected, "Retrieval of action failed uAppData=%lu expected=%d\n", obj_data.uAppData, expected);
+
+}
+
 static void test_build_action_map(
     LPDIRECTINPUTDEVICE8 lpdid,
     LPDIACTIONFORMAT lpdiaf,
@@ -200,7 +225,10 @@ static void test_action_mapping(void)
     ok( data.mouse != NULL, "EnumDevicesBySemantics should enumerate the mouse\n");
 
     if (data.keyboard != NULL)
+    {
+        test_keyboard_input(data.keyboard,VK_SPACE,2);
         test_build_action_map(data.keyboard,data.lpdiaf,DITEST_KEYBOARDSPACE,DIK_SPACE);
+    }
 
     /* Test BuildActionMap with no suitable actions for a device */
     IDirectInputDevice_Unacquire(data.keyboard);
@@ -210,6 +238,9 @@ static void test_action_mapping(void)
     hr = IDirectInputDevice8_BuildActionMap(data.keyboard,data.lpdiaf,NULL,DIDBAM_INITIALIZE);
     ok (hr == DI_NOEFFECT, "BuildActionMap should have no effect with no actions hr=%08x\n",hr);
 
+    hr = IDirectInputDevice8_SetActionMap(data.keyboard,data.lpdiaf,NULL,0);
+    ok (hr == DI_NOEFFECT, "SetActionMap should have no effect with no actions to map hr=%08x\n",hr);
+
     af.dwDataSize = 4 * sizeof(actionMapping) / sizeof(actionMapping[0]);
     af.dwNumActions = sizeof(actionMapping) / sizeof(actionMapping[0]);
 
-- 
1.7.0.4

