- sync dinput with wine
[reactos.git] / reactos / dll / directx / dinput / device.c
index a1e4031..941206c 100644 (file)
@@ -16,7 +16,7 @@
  *
  * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 /* This file contains all the Device specific functions that can be used as stubs
 #include "wine/unicode.h"
 #include "windef.h"
 #include "winbase.h"
+#include "winreg.h"
+#include "winuser.h"
 #include "winerror.h"
 #include "dinput.h"
 #include "device_private.h"
+#include "dinput_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
 
 /******************************************************************************
  *     Various debugging tools
  */
-void _dump_cooperativelevel_DI(DWORD dwFlags) {
+static void _dump_cooperativelevel_DI(DWORD dwFlags) {
     if (TRACE_ON(dinput)) {
        unsigned int   i;
        static const struct {
@@ -52,17 +55,19 @@ void _dump_cooperativelevel_DI(DWORD dwFlags) {
            FE(DISCL_BACKGROUND),
            FE(DISCL_EXCLUSIVE),
            FE(DISCL_FOREGROUND),
-           FE(DISCL_NONEXCLUSIVE)
+           FE(DISCL_NONEXCLUSIVE),
+           FE(DISCL_NOWINKEY)
 #undef FE
        };
+       TRACE(" cooperative level : ");
        for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++)
            if (flags[i].mask & dwFlags)
-               DPRINTF("%s ",flags[i].name);
-       DPRINTF("\n");
+               TRACE("%s ",flags[i].name);
+       TRACE("\n");
     }
 }
 
-void _dump_EnumObjects_flags(DWORD dwFlags) {
+static void _dump_EnumObjects_flags(DWORD dwFlags) {
     if (TRACE_ON(dinput)) {
        unsigned int   i;
        DWORD type, instance;
@@ -77,7 +82,7 @@ void _dump_EnumObjects_flags(DWORD dwFlags) {
            FE(DIDFT_TGLBUTTON),
            FE(DIDFT_POV),
            FE(DIDFT_COLLECTION),
-           FE(DIDFT_NODATA),
+           FE(DIDFT_NODATA),       
            FE(DIDFT_FFACTUATOR),
            FE(DIDFT_FFEFFECTTRIGGER),
            FE(DIDFT_OUTPUT),
@@ -88,51 +93,47 @@ void _dump_EnumObjects_flags(DWORD dwFlags) {
        };
        type = (dwFlags & 0xFF0000FF);
        instance = ((dwFlags >> 8) & 0xFFFF);
-       DPRINTF("Type:");
+       TRACE("Type:");
        if (type == DIDFT_ALL) {
-           DPRINTF(" DIDFT_ALL");
+           TRACE(" 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);
+                   TRACE(" %s",flags[i].name);
                }
            }
            if (type) {
-               DPRINTF(" (unhandled: %08lx)", type);
+                TRACE(" (unhandled: %08x)", type);
            }
        }
-       DPRINTF(" / Instance: ");
+       TRACE(" / Instance: ");
        if (instance == ((DIDFT_ANYINSTANCE >> 8) & 0xFFFF)) {
-           DPRINTF("DIDFT_ANYINSTANCE");
+           TRACE("DIDFT_ANYINSTANCE");
        } else {
-           DPRINTF("%3ld", instance);
+            TRACE("%3d", 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")));
+        TRACE("  - dwObj = 0x%08x\n", diph->dwObj);
+        TRACE("  - 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_OBJECTINSTANCEA(const DIDEVICEOBJECTINSTANCEA *ddoi) {
+    TRACE("    - enumerating : %s ('%s') - %2d - 0x%08x - %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));
-    }
+void _dump_OBJECTINSTANCEW(const DIDEVICEOBJECTINSTANCEW *ddoi) {
+    TRACE("    - enumerating : %s ('%s'), - %2d - 0x%08x - %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 */
@@ -178,70 +179,122 @@ const char *_dump_dinput_GUID(const GUID *guid) {
            return guids[i].name;
        }
     }
-    return "Unknown GUID";
+    return debugstr_guid(guid);
 }
 
 void _dump_DIDATAFORMAT(const DIDATAFORMAT *df) {
     unsigned int i;
 
     TRACE("Dumping DIDATAFORMAT structure:\n");
-    TRACE("  - dwSize: %ld\n", df->dwSize);
+    TRACE("  - dwSize: %d\n", df->dwSize);
     if (df->dwSize != sizeof(DIDATAFORMAT)) {
-       WARN("Non-standard DIDATAFORMAT structure size (%ld instead of %d).\n", df->dwSize, sizeof(DIDATAFORMAT));
+        WARN("Non-standard DIDATAFORMAT structure size %d\n", df->dwSize);
     }
-    TRACE("  - dwObjsize: %ld\n", df->dwObjSize);
+    TRACE("  - dwObjsize: %d\n", df->dwObjSize);
     if (df->dwObjSize != sizeof(DIOBJECTDATAFORMAT)) {
-       WARN("Non-standard DIOBJECTDATAFORMAT structure size (%ld instead of %d).\n", df->dwObjSize, sizeof(DIOBJECTDATAFORMAT));
+        WARN("Non-standard DIOBJECTDATAFORMAT structure size %d\n", df->dwObjSize);
     }
-    TRACE("  - dwFlags: 0x%08lx (", df->dwFlags);
+    TRACE("  - dwFlags: 0x%08x (", 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);
-
+    TRACE("  - dwDataSize: %d\n", df->dwDataSize);
+    TRACE("  - dwNumObjs: %d\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("      * dwOfs: %d\n", df->rgodf[i].dwOfs);
+        TRACE("      * dwType: 0x%08x\n", df->rgodf[i].dwType);
        TRACE("        "); _dump_EnumObjects_flags(df->rgodf[i].dwType); TRACE("\n");
-       TRACE("      * dwFlags: 0x%08lx\n", df->rgodf[i].dwFlags);
+        TRACE("      * dwFlags: 0x%08x\n", df->rgodf[i].dwFlags);
     }
 }
 
+/******************************************************************************
+ * Get the default and the app-specific config keys.
+ */
+BOOL get_app_key(HKEY *defkey, HKEY *appkey)
+{
+    char buffer[MAX_PATH+16];
+    DWORD len;
+
+    *appkey = 0;
+
+    /* @@ Wine registry key: HKCU\Software\Wine\DirectInput */
+    if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\DirectInput", defkey))
+        *defkey = 0;
+
+    len = GetModuleFileNameA(0, buffer, MAX_PATH);
+    if (len && len < MAX_PATH)
+    {
+        HKEY tmpkey;
+
+        /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\DirectInput */
+        if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey))
+        {
+            char *p, *appname = buffer;
+            if ((p = strrchr(appname, '/'))) appname = p + 1;
+            if ((p = strrchr(appname, '\\'))) appname = p + 1;
+            strcat(appname, "\\DirectInput");
+
+            if (RegOpenKeyA(tmpkey, appname, appkey)) *appkey = 0;
+            RegCloseKey(tmpkey);
+        }
+    }
+
+    return *defkey || *appkey;
+}
+
+/******************************************************************************
+ * Get a config key from either the app-specific or the default config
+ */
+DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
+                             char *buffer, DWORD size )
+{
+    if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size ))
+        return 0;
+
+    if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size ))
+        return 0;
+
+    return ERROR_FILE_NOT_FOUND;
+}
+
 /* Conversion between internal data buffer and external data buffer */
-void fill_DataFormat(void *out, const void *in, DataFormat *df) {
+void fill_DataFormat(void *out, DWORD size, const void *in, const DataFormat *df)
+{
     int i;
-    char *in_c = (char *) in;
-    char *out_c = (char *) out;
+    const char *in_c = in;
+    char *out_c = out;
 
+    memset(out, 0, size);
     if (df->dt == NULL) {
        /* This means that the app uses Wine's internal data format */
-       memcpy(out, in, df->internal_format_size);
+        memcpy(out, in, min(size, 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));
+                              df->dt[i].offset_out, df->dt[i].offset_in, *(in_c + df->dt[i].offset_in));
+                       *(out_c + df->dt[i].offset_out) = *(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));
+                             df->dt[i].offset_out, df->dt[i].offset_in, *((const short *)(in_c + df->dt[i].offset_in)));
+                       *((short *)(out_c + df->dt[i].offset_out)) = *((const 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));
+                              df->dt[i].offset_out, df->dt[i].offset_in, *((const int *)(in_c + df->dt[i].offset_in)));
+                        *((int *)(out_c + df->dt[i].offset_out)) = *((const int *)(in_c + df->dt[i].offset_in));
                        break;
 
                    default:
@@ -253,23 +306,23 @@ void fill_DataFormat(void *out, const void *in, DataFormat *df) {
                    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;
+                       *(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;
+                       *((int *) (out_c + df->dt[i].offset_out)) = df->dt[i].value;
                        break;
-
+                       
                    default:
-                       memset((out_c + df->dt[i].offset_out), df->dt[i].size, 0);
+                       memset((out_c + df->dt[i].offset_out), 0, df->dt[i].size);
                        break;
                }
            }
@@ -279,13 +332,24 @@ void fill_DataFormat(void *out, const void *in, DataFormat *df) {
 
 void release_DataFormat(DataFormat * format)
 {
-    TRACE("Deleting DataTransform :\n");
+    TRACE("Deleting DataFormat: %p\n", format);
 
     HeapFree(GetProcessHeap(), 0, format->dt);
+    format->dt = NULL;
+    HeapFree(GetProcessHeap(), 0, format->offsets);
+    format->offsets = NULL;
+    HeapFree(GetProcessHeap(), 0, format->user_df);
+    format->user_df = NULL;
+}
+
+static inline LPDIOBJECTDATAFORMAT dataformat_to_odf(LPCDIDATAFORMAT df, int idx)
+{
+    if (idx < 0 || idx >= df->dwNumObjs) return NULL;
+    return (LPDIOBJECTDATAFORMAT)((LPBYTE)df->rgodf + idx * df->dwObjSize);
 }
 
-DataFormat *create_DataFormat(const DIDATAFORMAT *wine_format, LPCDIDATAFORMAT asked_format, int *offset) {
-    DataFormat *ret;
+static HRESULT create_DataFormat(LPCDIDATAFORMAT asked_format, DataFormat *format)
+{
     DataTransform *dt;
     unsigned int i, j;
     int same = 1;
@@ -293,84 +357,81 @@ DataFormat *create_DataFormat(const DIDATAFORMAT *wine_format, LPCDIDATAFORMAT a
     int index = 0;
     DWORD next = 0;
 
-    ret = HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat));
+    if (!format->wine_df) return DIERR_INVALIDPARAM;
+    done = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, asked_format->dwNumObjs * sizeof(int));
+    dt = HeapAlloc(GetProcessHeap(), 0, asked_format->dwNumObjs * sizeof(DataTransform));
+    if (!dt || !done) goto failed;
 
-    done = HeapAlloc(GetProcessHeap(), 0, sizeof(int) * asked_format->dwNumObjs);
-    memset(done, 0, sizeof(int) * asked_format->dwNumObjs);
+    if (!(format->offsets = HeapAlloc(GetProcessHeap(), 0, format->wine_df->dwNumObjs * sizeof(int))))
+        goto failed;
 
-    dt = HeapAlloc(GetProcessHeap(), 0, asked_format->dwNumObjs * sizeof(DataTransform));
+    if (!(format->user_df = HeapAlloc(GetProcessHeap(), 0, asked_format->dwSize)))
+        goto failed;
+    memcpy(format->user_df, asked_format, asked_format->dwSize);
 
     TRACE("Creating DataTransform :\n");
-
-    for (i = 0; i < wine_format->dwNumObjs; i++) {
-       offset[i] = -1;
+    
+    for (i = 0; i < format->wine_df->dwNumObjs; i++)
+    {
+        format->offsets[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) ||
-                (wine_format->rgodf[i].pguid == NULL) ||
-                (IsEqualGUID(wine_format->rgodf[i].pguid, asked_format->rgodf[j].pguid)))
+                (format->wine_df->rgodf[i].pguid == NULL) ||
+                (IsEqualGUID(format->wine_df->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.
                  */
-                (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == 0xFFFF) ||
+                ((asked_format->rgodf[j].dwType & DIDFT_INSTANCEMASK) == DIDFT_ANYINSTANCE) ||
                 (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == 0x00FF) || /* This is mentionned in no DX docs, but it works fine - tested on WinXP */
-                (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == DIDFT_GETINSTANCE(wine_format->rgodf[i].dwType)))
+                (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == DIDFT_GETINSTANCE(format->wine_df->rgodf[i].dwType)))
                &&
                ( /* Then if the asked type matches the one Wine provides */
-                wine_format->rgodf[i].dwType & asked_format->rgodf[j].dwType)) {
-
+                 DIDFT_GETTYPE(asked_format->rgodf[j].dwType) & format->wine_df->rgodf[i].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("       * Offset: %3d\n", asked_format->rgodf[j].dwOfs);
+                TRACE("       * dwType: %08x\n", asked_format->rgodf[j].dwType);
                TRACE("         "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n");
-
+               
                TRACE("   - Wine  (%d) :\n", i);
                TRACE("       * GUID: %s ('%s')\n",
-                     debugstr_guid(wine_format->rgodf[i].pguid),
-                     _dump_dinput_GUID(wine_format->rgodf[i].pguid));
-               TRACE("       * Offset: %3ld\n", wine_format->rgodf[i].dwOfs);
-               TRACE("       * dwType: %08lx\n", wine_format->rgodf[i].dwType);
-               TRACE("         "); _dump_EnumObjects_flags(wine_format->rgodf[i].dwType); TRACE("\n");
-
-               if (wine_format->rgodf[i].dwType & DIDFT_BUTTON)
+                      debugstr_guid(format->wine_df->rgodf[i].pguid),
+                      _dump_dinput_GUID(format->wine_df->rgodf[i].pguid));
+                TRACE("       * Offset: %3d\n", format->wine_df->rgodf[i].dwOfs);
+                TRACE("       * dwType: %08x\n", format->wine_df->rgodf[i].dwType);
+                TRACE("         "); _dump_EnumObjects_flags(format->wine_df->rgodf[i].dwType); TRACE("\n");
+               
+                if (format->wine_df->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].offset_in = format->wine_df->rgodf[i].dwOfs;
+                dt[index].offset_out = asked_format->rgodf[j].dwOfs;
+                format->offsets[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)
+               
+                if (format->wine_df->rgodf[i].dwOfs != dt[index].offset_out)
                    same = 0;
-
+               
                index++;
                break;
            }
        }
-
-       if (j == asked_format->dwNumObjs)
-           same = 0;
     }
 
     TRACE("Setting to default value :\n");
@@ -380,68 +441,170 @@ DataFormat *create_DataFormat(const DIDATAFORMAT *wine_format, LPCDIDATAFORMAT a
            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("       * Offset: %3d\n", asked_format->rgodf[j].dwOfs);
+            TRACE("       * dwType: %08x\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;
+            if (asked_format->rgodf[j].dwType & DIDFT_POV)
+                dt[index].value = -1;
+            else
+                dt[index].value = 0;
            index++;
 
            same = 0;
        }
     }
-
-    ret->internal_format_size = wine_format->dwDataSize;
-    ret->size = index;
+    
+    format->internal_format_size = format->wine_df->dwDataSize;
+    format->size = index;
     if (same) {
-       ret->dt = NULL;
        HeapFree(GetProcessHeap(), 0, dt);
-    } else {
-       ret->dt = dt;
+        dt = NULL;
     }
+    format->dt = dt;
 
     HeapFree(GetProcessHeap(), 0, done);
 
-    return ret;
+    return DI_OK;
+
+failed:
+    HeapFree(GetProcessHeap(), 0, done);
+    HeapFree(GetProcessHeap(), 0, dt);
+    format->dt = NULL;
+    HeapFree(GetProcessHeap(), 0, format->offsets);
+    format->offsets = NULL;
+    HeapFree(GetProcessHeap(), 0, format->user_df);
+    format->user_df = NULL;
+
+    return DIERR_OUTOFMEMORY;
 }
 
-BOOL DIEnumDevicesCallbackAtoW(LPCDIDEVICEOBJECTINSTANCEA lpddi, LPVOID lpvRef) {
-    DIDEVICEOBJECTINSTANCEW ddtmp;
-    device_enumobjects_AtoWcb_data* data;
+/* find an object by it's offset in a data format */
+static int offset_to_object(const DataFormat *df, int offset)
+{
+    int i;
 
-    data = (device_enumobjects_AtoWcb_data*) lpvRef;
+    if (!df->offsets) return -1;
 
-    memset(&ddtmp, 0, sizeof(ddtmp));
+    for (i = 0; i < df->wine_df->dwNumObjs; i++)
+        if (df->offsets[i] == offset) return i;
 
-    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);
+    return -1;
+}
 
-    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;
+int id_to_object(LPCDIDATAFORMAT df, int id)
+{
+    int i;
+
+    id &= 0x00ffffff;
+    for (i = 0; i < df->dwNumObjs; i++)
+        if ((dataformat_to_odf(df, i)->dwType & 0x00ffffff) == id)
+            return i;
+
+    return -1;
+}
+
+int id_to_offset(const DataFormat *df, int id)
+{
+    int obj = id_to_object(df->wine_df, id);
+
+    return obj >= 0 && df->offsets ? df->offsets[obj] : -1;
+}
+
+int find_property(const DataFormat *df, LPCDIPROPHEADER ph)
+{
+    switch (ph->dwHow)
+    {
+        case DIPH_BYID:     return id_to_object(df->wine_df, ph->dwObj);
+        case DIPH_BYOFFSET: return offset_to_object(df, ph->dwObj);
+    }
+    FIXME("Unhandled ph->dwHow=='%04X'\n", (unsigned int)ph->dwHow);
+
+    return -1;
+}
+
+/******************************************************************************
+ *     queue_event - add new event to the ring queue
+ */
+
+void queue_event(LPDIRECTINPUTDEVICE8A iface, int ofs, DWORD data, DWORD time, DWORD seq)
+{
+    IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
+    int next_pos;
+
+    /* Event is being set regardless of the queue state */
+    if (This->hEvent) SetEvent(This->hEvent);
+
+    if (!This->queue_len || This->overflow || ofs < 0) return;
+
+    next_pos = (This->queue_head + 1) % This->queue_len;
+    if (next_pos == This->queue_tail)
+    {
+        TRACE(" queue overflowed\n");
+        This->overflow = TRUE;
+        return;
     }
-    return data->lpCallBack(&ddtmp, data->lpvRef);
+
+    TRACE(" queueing %d at offset %d (queue head %d / size %d)\n",
+          data, ofs, This->queue_head, This->queue_len);
+
+    This->data_queue[This->queue_head].dwOfs       = ofs;
+    This->data_queue[This->queue_head].dwData      = data;
+    This->data_queue[This->queue_head].dwTimeStamp = time;
+    This->data_queue[This->queue_head].dwSequence  = seq;
+    This->queue_head = next_pos;
+    /* Send event if asked */
+}
+
+/******************************************************************************
+ *     Acquire
+ */
+
+HRESULT WINAPI IDirectInputDevice2AImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
+{
+    IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
+    HRESULT res;
+
+    if (!This->data_format.user_df) return DIERR_INVALIDPARAM;
+    if (This->dwCoopLevel & DISCL_FOREGROUND && This->win != GetForegroundWindow())
+        return DIERR_OTHERAPPHASPRIO;
+
+    EnterCriticalSection(&This->crit);
+    res = This->acquired ? S_FALSE : DI_OK;
+    This->acquired = 1;
+    if (res == DI_OK)
+    {
+        This->queue_head = This->queue_tail = This->overflow = 0;
+        check_dinput_hooks(iface);
+    }
+    LeaveCriticalSection(&This->crit);
+
+    return res;
+}
+
+/******************************************************************************
+ *     Unacquire
+ */
+
+HRESULT WINAPI IDirectInputDevice2AImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
+{
+    IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
+    HRESULT res;
+
+    EnterCriticalSection(&This->crit);
+    res = !This->acquired ? DI_NOEFFECT : DI_OK;
+    This->acquired = 0;
+    if (res == DI_OK)
+        check_dinput_hooks(iface);
+    LeaveCriticalSection(&This->crit);
+
+    return res;
 }
 
 /******************************************************************************
@@ -449,34 +612,80 @@ BOOL DIEnumDevicesCallbackAtoW(LPCDIDEVICEOBJECTINSTANCEA lpddi, LPVOID lpvRef)
  */
 
 HRESULT WINAPI IDirectInputDevice2AImpl_SetDataFormat(
-       LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df
-{
+        LPDIRECTINPUTDEVICE8A iface, LPCDIDATAFORMAT df)
+{
     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
+    HRESULT res = DI_OK;
 
-    TRACE("(this=%p,%p)\n",This,df);
-
+    if (!df) return E_POINTER;
+    TRACE("(%p) %p\n", This, df);
     _dump_DIDATAFORMAT(df);
 
-    return DI_OK;
+    if (df->dwSize != sizeof(DIDATAFORMAT)) return DIERR_INVALIDPARAM;
+    if (This->acquired) return DIERR_ACQUIRED;
+
+    EnterCriticalSection(&This->crit);
+
+    release_DataFormat(&This->data_format);
+    res = create_DataFormat(df, &This->data_format);
+
+    LeaveCriticalSection(&This->crit);
+    return res;
 }
 
+/******************************************************************************
+  *     SetCooperativeLevel
+  *
+  *  Set cooperative level and the source window for the events.
+  */
 HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel(
-       LPDIRECTINPUTDEVICE8A iface,HWND hwnd,DWORD dwflags
-{
+        LPDIRECTINPUTDEVICE8A iface, HWND hwnd, DWORD dwflags)
+{
     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
-    TRACE("(this=%p,%p,0x%08lx)\n",This,hwnd,dwflags);
-    if (TRACE_ON(dinput)) {
-       TRACE(" cooperative level : ");
-       _dump_cooperativelevel_DI(dwflags);
-    }
+
+    TRACE("(%p) %p,0x%08x\n", This, hwnd, dwflags);
+    _dump_cooperativelevel_DI(dwflags);
+
+    if ((dwflags & (DISCL_EXCLUSIVE | DISCL_NONEXCLUSIVE)) == 0 ||
+        (dwflags & (DISCL_EXCLUSIVE | DISCL_NONEXCLUSIVE)) == (DISCL_EXCLUSIVE | DISCL_NONEXCLUSIVE) ||
+        (dwflags & (DISCL_FOREGROUND | DISCL_BACKGROUND)) == 0 ||
+        (dwflags & (DISCL_FOREGROUND | DISCL_BACKGROUND)) == (DISCL_FOREGROUND | DISCL_BACKGROUND))
+        return DIERR_INVALIDPARAM;
+
+    if (dwflags == (DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))
+        hwnd = GetDesktopWindow();
+
+    if (!hwnd) return E_HANDLE;
+
+    /* For security reasons native does not allow exclusive background level
+       for mouse and keyboard only */
+    if (dwflags & DISCL_EXCLUSIVE && dwflags & DISCL_BACKGROUND &&
+        (IsEqualGUID(&This->guid, &GUID_SysMouse) ||
+         IsEqualGUID(&This->guid, &GUID_SysKeyboard)))
+        return DIERR_UNSUPPORTED;
+
+    /* Store the window which asks for the mouse */
+    EnterCriticalSection(&This->crit);
+    This->win = hwnd;
+    This->dwCoopLevel = dwflags;
+    LeaveCriticalSection(&This->crit);
+
     return DI_OK;
 }
 
+/******************************************************************************
+  *     SetEventNotification : specifies event to be sent on state change
+  */
 HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification(
-       LPDIRECTINPUTDEVICE8A iface,HANDLE hnd
-{
+       LPDIRECTINPUTDEVICE8A iface, HANDLE event)
+{
     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
-    FIXME("(this=%p,%p): stub\n",This,hnd);
+
+    TRACE("(%p) %p\n", This, event);
+
+    EnterCriticalSection(&This->crit);
+    This->hEvent = event;
+    LeaveCriticalSection(&This->crit);
     return DI_OK;
 }
 
@@ -484,10 +693,32 @@ 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;
+    if (ref) return ref;
+
+    IDirectInputDevice_Unacquire(iface);
+    /* Reset the FF state, free all effects, etc */
+    IDirectInputDevice8_SendForceFeedbackCommand(iface, DISFFC_RESET);
+
+    HeapFree(GetProcessHeap(), 0, This->data_queue);
+
+    /* Free data format */
+    HeapFree(GetProcessHeap(), 0, This->data_format.wine_df->rgodf);
+    HeapFree(GetProcessHeap(), 0, This->data_format.wine_df);
+    release_DataFormat(&This->data_format);
+
+    EnterCriticalSection( &This->dinput->crit );
+    list_remove( &This->entry );
+    LeaveCriticalSection( &This->dinput->crit );
+
+    IDirectInput_Release((LPDIRECTINPUTDEVICE8A)This->dinput);
+    This->crit.DebugInfo->Spare[0] = 0;
+    DeleteCriticalSection(&This->crit);
+
+    HeapFree(GetProcessHeap(), 0, This);
+
+    return DI_OK;
 }
 
 HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface(
@@ -495,7 +726,7 @@ HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface(
 )
 {
     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
-
+    
     TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
     if (IsEqualGUID(&IID_IUnknown,riid)) {
        IDirectInputDevice2_AddRef(iface);
@@ -531,7 +762,7 @@ HRESULT WINAPI IDirectInputDevice2WImpl_QueryInterface(
 )
 {
     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
-
+    
     TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
     if (IsEqualGUID(&IID_IUnknown,riid)) {
        IDirectInputDevice2_AddRef(iface);
@@ -569,48 +800,160 @@ ULONG WINAPI IDirectInputDevice2AImpl_AddRef(
     return InterlockedIncrement(&(This->ref));
 }
 
-HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects(
-       LPDIRECTINPUTDEVICE8A iface,
-       LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
-       LPVOID lpvRef,
-       DWORD dwFlags)
+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");
+    IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
+    DIDEVICEOBJECTINSTANCEA ddoi;
+    int i;
+
+    TRACE("(%p) %p,%p flags:%08x)\n", iface, lpCallback, lpvRef, dwFlags);
+    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 < This->data_format.wine_df->dwNumObjs; i++)
+    {
+        LPDIOBJECTDATAFORMAT odf = dataformat_to_odf(This->data_format.wine_df, i);
+
+        if (dwFlags != DIDFT_ALL && !(dwFlags & DIEFT_GETTYPE(odf->dwType))) continue;
+        if (IDirectInputDevice_GetObjectInfo(iface, &ddoi, odf->dwType, DIPH_BYID) != DI_OK)
+            continue;
+
+       if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) break;
     }
 
     return DI_OK;
 }
 
-HRESULT WINAPI IDirectInputDevice2WImpl_EnumObjects(
-       LPDIRECTINPUTDEVICE8W iface,
-       LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback,
-       LPVOID lpvRef,
-       DWORD dwFlags)
+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");
+    IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
+    DIDEVICEOBJECTINSTANCEW ddoi;
+    int i;
+
+    TRACE("(%p) %p,%p flags:%08x)\n", iface, lpCallback, lpvRef, dwFlags);
+    TRACE("  - flags = ");
+    _dump_EnumObjects_flags(dwFlags);
+    TRACE("\n");
+
+    /* Only the fields till dwFFMaxForce are relevant */
+    memset(&ddoi, 0, sizeof(ddoi));
+    ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEW, dwFFMaxForce);
+
+    for (i = 0; i < This->data_format.wine_df->dwNumObjs; i++)
+    {
+        LPDIOBJECTDATAFORMAT odf = dataformat_to_odf(This->data_format.wine_df, i);
+
+        if (dwFlags != DIDFT_ALL && !(dwFlags & DIEFT_GETTYPE(odf->dwType))) continue;
+        if (IDirectInputDevice_GetObjectInfo(iface, &ddoi, odf->dwType, DIPH_BYID) != DI_OK)
+            continue;
+
+       if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) break;
     }
 
     return DI_OK;
 }
 
+/******************************************************************************
+ *     GetProperty
+ */
+
 HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty(
-       LPDIRECTINPUTDEVICE8A iface,
-       REFGUID rguid,
-       LPDIPROPHEADER pdiph)
+       LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph)
+{
+    IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
+
+    TRACE("(%p) %s,%p\n", iface, debugstr_guid(rguid), pdiph);
+    _dump_DIPROPHEADER(pdiph);
+
+    if (HIWORD(rguid)) return DI_OK;
+
+    switch (LOWORD(rguid))
+    {
+        case (DWORD_PTR) DIPROP_BUFFERSIZE:
+        {
+            LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
+
+            if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
+
+            pd->dwData = This->queue_len;
+            TRACE("buffersize = %d\n", pd->dwData);
+            break;
+        }
+        default:
+            WARN("Unknown property %s\n", debugstr_guid(rguid));
+            break;
+    }
+
+    return DI_OK;
+}
+
+/******************************************************************************
+ *     SetProperty
+ */
+
+HRESULT WINAPI IDirectInputDevice2AImpl_SetProperty(
+        LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPCDIPROPHEADER pdiph)
 {
-    FIXME("(this=%p,%s,%p): stub!\n",
-         iface, debugstr_guid(rguid), pdiph);
+    IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
 
-    if (TRACE_ON(dinput))
-       _dump_DIPROPHEADER(pdiph);
+    TRACE("(%p) %s,%p\n", iface, debugstr_guid(rguid), pdiph);
+    _dump_DIPROPHEADER(pdiph);
+
+    if (HIWORD(rguid)) return DI_OK;
+
+    switch (LOWORD(rguid))
+    {
+        case (DWORD_PTR) DIPROP_AXISMODE:
+        {
+            LPCDIPROPDWORD pd = (LPCDIPROPDWORD)pdiph;
+
+            if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
+            if (pdiph->dwHow == DIPH_DEVICE && pdiph->dwObj) return DIERR_INVALIDPARAM;
+            if (This->acquired) return DIERR_ACQUIRED;
+            if (pdiph->dwHow != DIPH_DEVICE) return DIERR_UNSUPPORTED;
+            if (!This->data_format.user_df) return DI_OK;
+
+            TRACE("Axis mode: %s\n", pd->dwData == DIPROPAXISMODE_ABS ? "absolute" :
+                                                                        "relative");
+
+            EnterCriticalSection(&This->crit);
+            This->data_format.user_df->dwFlags &= ~DIDFT_AXIS;
+            This->data_format.user_df->dwFlags |= pd->dwData == DIPROPAXISMODE_ABS ?
+                                                  DIDF_ABSAXIS : DIDF_RELAXIS;
+            LeaveCriticalSection(&This->crit);
+            break;
+        }
+        case (DWORD_PTR) DIPROP_BUFFERSIZE:
+        {
+            LPCDIPROPDWORD pd = (LPCDIPROPDWORD)pdiph;
+
+            if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
+            if (This->acquired) return DIERR_ACQUIRED;
+
+            TRACE("buffersize = %d\n", pd->dwData);
+
+            EnterCriticalSection(&This->crit);
+            HeapFree(GetProcessHeap(), 0, This->data_queue);
+
+            This->data_queue = !pd->dwData ? NULL : HeapAlloc(GetProcessHeap(), 0,
+                                pd->dwData * sizeof(DIDEVICEOBJECTDATA));
+            This->queue_head = This->queue_tail = This->overflow = 0;
+            This->queue_len  = pd->dwData;
+
+            LeaveCriticalSection(&This->crit);
+            break;
+        }
+        default:
+            WARN("Unknown property %s\n", debugstr_guid(rguid));
+            return DIERR_UNSUPPORTED;
+    }
 
     return DI_OK;
 }
@@ -621,10 +964,29 @@ HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo(
        DWORD dwObj,
        DWORD dwHow)
 {
-    FIXME("(this=%p,%p,%ld,0x%08lx): stub!\n",
-         iface, pdidoi, dwObj, dwHow);
+    DIDEVICEOBJECTINSTANCEW didoiW;
+    HRESULT res;
+
+    if (!pdidoi ||
+        (pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCEA) &&
+         pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3A)))
+        return DIERR_INVALIDPARAM;
+
+    didoiW.dwSize = sizeof(didoiW);
+    res = IDirectInputDevice2WImpl_GetObjectInfo((LPDIRECTINPUTDEVICE8W)iface, &didoiW, dwObj, dwHow);
+    if (res == DI_OK)
+    {
+        DWORD dwSize = pdidoi->dwSize;
+
+        memset(pdidoi, 0, pdidoi->dwSize);
+        pdidoi->dwSize   = dwSize;
+        pdidoi->guidType = didoiW.guidType;
+        pdidoi->dwOfs    = didoiW.dwOfs;
+        pdidoi->dwType   = didoiW.dwType;
+        pdidoi->dwFlags  = didoiW.dwFlags;
+    }
 
-    return DI_OK;
+    return res;
 }
 
 HRESULT WINAPI IDirectInputDevice2WImpl_GetObjectInfo(
@@ -633,30 +995,104 @@ HRESULT WINAPI IDirectInputDevice2WImpl_GetObjectInfo(
        DWORD dwObj,
        DWORD dwHow)
 {
-    FIXME("(this=%p,%p,%ld,0x%08lx): stub!\n",
-         iface, pdidoi, dwObj, dwHow);
+    IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
+    DWORD dwSize;
+    LPDIOBJECTDATAFORMAT odf;
+    int idx = -1;
+
+    TRACE("(%p) %d(0x%08x) -> %p\n", This, dwHow, dwObj, pdidoi);
+
+    if (!pdidoi ||
+        (pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCEW) &&
+         pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3W)))
+        return DIERR_INVALIDPARAM;
+
+    switch (dwHow)
+    {
+    case DIPH_BYOFFSET:
+        if (!This->data_format.offsets) break;
+        for (idx = This->data_format.wine_df->dwNumObjs - 1; idx >= 0; idx--)
+            if (This->data_format.offsets[idx] == dwObj) break;
+        break;
+    case DIPH_BYID:
+        dwObj &= 0x00ffffff;
+        for (idx = This->data_format.wine_df->dwNumObjs - 1; idx >= 0; idx--)
+            if ((dataformat_to_odf(This->data_format.wine_df, idx)->dwType & 0x00ffffff) == dwObj)
+                break;
+        break;
+
+    case DIPH_BYUSAGE:
+        FIXME("dwHow = DIPH_BYUSAGE not implemented\n");
+        break;
+    default:
+        WARN("invalid parameter: dwHow = %08x\n", dwHow);
+        return DIERR_INVALIDPARAM;
+    }
+    if (idx < 0) return DIERR_OBJECTNOTFOUND;
+
+    odf = dataformat_to_odf(This->data_format.wine_df, idx);
+    dwSize = pdidoi->dwSize; /* save due to memset below */
+    memset(pdidoi, 0, pdidoi->dwSize);
+    pdidoi->dwSize   = dwSize;
+    if (odf->pguid) pdidoi->guidType = *odf->pguid;
+    pdidoi->dwOfs    = This->data_format.offsets ? This->data_format.offsets[idx] : odf->dwOfs;
+    pdidoi->dwType   = odf->dwType;
+    pdidoi->dwFlags  = odf->dwFlags;
 
     return DI_OK;
 }
 
-HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceInfo(
-       LPDIRECTINPUTDEVICE8A iface,
-       LPDIDEVICEINSTANCEA pdidi)
+HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceData(
+        LPDIRECTINPUTDEVICE8A iface, DWORD dodsize, LPDIDEVICEOBJECTDATA dod,
+        LPDWORD entries, DWORD flags)
 {
-    FIXME("(this=%p,%p): stub!\n",
-         iface, pdidi);
+    IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
+    HRESULT ret = DI_OK;
+    int len;
+
+    TRACE("(%p) %p -> %p(%d) x%d, 0x%08x\n",
+          This, dod, entries, entries ? *entries : 0, dodsize, flags);
+
+    if (!This->acquired)
+        return DIERR_NOTACQUIRED;
+    if (!This->queue_len)
+        return DIERR_NOTBUFFERED;
+    if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3))
+        return DIERR_INVALIDPARAM;
+
+    IDirectInputDevice2_Poll(iface);
+    EnterCriticalSection(&This->crit);
+
+    len = This->queue_head - This->queue_tail;
+    if (len < 0) len += This->queue_len;
+
+    if ((*entries != INFINITE) && (len > *entries)) len = *entries;
+
+    if (dod)
+    {
+        int i;
+        for (i = 0; i < len; i++)
+        {
+            int n = (This->queue_tail + i) % This->queue_len;
+            memcpy((char *)dod + dodsize * i, This->data_queue + n, dodsize);
+        }
+    }
+    *entries = len;
 
-    return DI_OK;
-}
+    if (This->overflow)
+        ret = DI_BUFFEROVERFLOW;
 
-HRESULT WINAPI IDirectInputDevice2WImpl_GetDeviceInfo(
-       LPDIRECTINPUTDEVICE8W iface,
-       LPDIDEVICEINSTANCEW pdidi)
-{
-    FIXME("(this=%p,%p): stub!\n",
-         iface, pdidi);
+    if (!(flags & DIGDD_PEEK))
+    {
+        /* Advance reading position */
+        This->queue_tail = (This->queue_tail + len) % This->queue_len;
+        This->overflow = FALSE;
+    }
 
-    return DI_OK;
+    LeaveCriticalSection(&This->crit);
+
+    TRACE("Returning %d events queued\n", *entries);
+    return ret;
 }
 
 HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel(
@@ -664,7 +1100,7 @@ HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel(
        HWND hwndOwner,
        DWORD dwFlags)
 {
-    FIXME("(this=%p,%p,0x%08lx): stub!\n",
+    FIXME("(this=%p,%p,0x%08x): stub!\n",
          iface, hwndOwner, dwFlags);
 
     return DI_OK;
@@ -676,7 +1112,7 @@ HRESULT WINAPI IDirectInputDevice2AImpl_Initialize(
        DWORD dwVersion,
        REFGUID rguid)
 {
-    FIXME("(this=%p,%p,%ld,%s): stub!\n",
+    FIXME("(this=%p,%p,%d,%s): stub!\n",
          iface, hinst, dwVersion, debugstr_guid(rguid));
     return DI_OK;
 }
@@ -703,9 +1139,9 @@ HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects(
        LPVOID lpvRef,
        DWORD dwFlags)
 {
-    FIXME("(this=%p,%p,%p,0x%08lx): stub!\n",
+    FIXME("(this=%p,%p,%p,0x%08x): stub!\n",
          iface, lpCallback, lpvRef, dwFlags);
-
+    
     return DI_OK;
 }
 
@@ -715,9 +1151,9 @@ HRESULT WINAPI IDirectInputDevice2WImpl_EnumEffects(
        LPVOID lpvRef,
        DWORD dwFlags)
 {
-    FIXME("(this=%p,%p,%p,0x%08lx): stub!\n",
+    FIXME("(this=%p,%p,%p,0x%08x): stub!\n",
          iface, lpCallback, lpvRef, dwFlags);
-
+    
     return DI_OK;
 }
 
@@ -754,9 +1190,8 @@ HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand(
        LPDIRECTINPUTDEVICE8A iface,
        DWORD dwFlags)
 {
-    FIXME("(this=%p,0x%08lx): stub!\n",
-         iface, dwFlags);
-    return DI_OK;
+    TRACE("(%p) 0x%08x:\n", iface, dwFlags);
+    return DI_NOEFFECT;
 }
 
 HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects(
@@ -765,7 +1200,7 @@ HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects(
        LPVOID lpvRef,
        DWORD dwFlags)
 {
-    FIXME("(this=%p,%p,%p,0x%08lx): stub!\n",
+    FIXME("(this=%p,%p,%p,0x%08x): stub!\n",
          iface, lpCallback, lpvRef, dwFlags);
     return DI_OK;
 }
@@ -782,6 +1217,9 @@ HRESULT WINAPI IDirectInputDevice2AImpl_Escape(
 HRESULT WINAPI IDirectInputDevice2AImpl_Poll(
        LPDIRECTINPUTDEVICE8A iface)
 {
+    IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
+
+    if (!This->acquired) return DIERR_NOTACQUIRED;
     /* Because wine devices do not need to be polled, just return DI_NOEFFECT */
     return DI_NOEFFECT;
 }
@@ -793,9 +1231,9 @@ HRESULT WINAPI IDirectInputDevice2AImpl_SendDeviceData(
        LPDWORD pdwInOut,
        DWORD dwFlags)
 {
-    FIXME("(this=%p,0x%08lx,%p,%p,0x%08lx): stub!\n",
+    FIXME("(this=%p,0x%08x,%p,%p,0x%08x): stub!\n",
          iface, cbObjectData, rgdod, pdwInOut, dwFlags);
-
+    
     return DI_OK;
 }
 
@@ -805,8 +1243,8 @@ HRESULT WINAPI IDirectInputDevice7AImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8A
                                                          LPVOID pvRef,
                                                          DWORD dwFlags)
 {
-    FIXME("(%p)->(%s,%p,%p,%08lx): stub !\n", iface, lpszFileName, pec, pvRef, dwFlags);
-
+    FIXME("(%p)->(%s,%p,%p,%08x): stub !\n", iface, lpszFileName, pec, pvRef, dwFlags);
+    
     return DI_OK;
 }
 
@@ -816,8 +1254,8 @@ HRESULT WINAPI IDirectInputDevice7WImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8W
                                                          LPVOID pvRef,
                                                          DWORD dwFlags)
 {
-    FIXME("(%p)->(%s,%p,%p,%08lx): stub !\n", iface, debugstr_w(lpszFileName), pec, pvRef, dwFlags);
-
+    FIXME("(%p)->(%s,%p,%p,%08x): stub !\n", iface, debugstr_w(lpszFileName), pec, pvRef, dwFlags);
+    
     return DI_OK;
 }
 
@@ -827,8 +1265,8 @@ HRESULT WINAPI IDirectInputDevice7AImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8A
                                                          LPDIFILEEFFECT rgDiFileEft,
                                                          DWORD dwFlags)
 {
-    FIXME("(%p)->(%s,%08lx,%p,%08lx): stub !\n", iface, lpszFileName, dwEntries, rgDiFileEft, dwFlags);
-
+    FIXME("(%p)->(%s,%08x,%p,%08x): stub !\n", iface, lpszFileName, dwEntries, rgDiFileEft, dwFlags);
+    
     return DI_OK;
 }
 
@@ -838,8 +1276,8 @@ HRESULT WINAPI IDirectInputDevice7WImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8W
                                                          LPDIFILEEFFECT rgDiFileEft,
                                                          DWORD dwFlags)
 {
-    FIXME("(%p)->(%s,%08lx,%p,%08lx): stub !\n", iface, debugstr_w(lpszFileName), dwEntries, rgDiFileEft, dwFlags);
-
+    FIXME("(%p)->(%s,%08x,%p,%08x): stub !\n", iface, debugstr_w(lpszFileName), dwEntries, rgDiFileEft, dwFlags);
+    
     return DI_OK;
 }
 
@@ -848,8 +1286,14 @@ HRESULT WINAPI IDirectInputDevice8AImpl_BuildActionMap(LPDIRECTINPUTDEVICE8A ifa
                                                       LPCSTR lpszUserName,
                                                       DWORD dwFlags)
 {
-    FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, lpszUserName, dwFlags);
-
+    FIXME("(%p)->(%p,%s,%08x): stub !\n", iface, lpdiaf, lpszUserName, dwFlags);
+#define X(x) if (dwFlags & x) FIXME("\tdwFlags =|"#x"\n");
+       X(DIDBAM_DEFAULT)
+       X(DIDBAM_PRESERVE)
+       X(DIDBAM_INITIALIZE)
+       X(DIDBAM_HWDEFAULTS)
+#undef X
+    _dump_diactionformatA(lpdiaf);
     return DI_OK;
 }
 
@@ -858,8 +1302,14 @@ HRESULT WINAPI IDirectInputDevice8WImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W ifa
                                                       LPCWSTR lpszUserName,
                                                       DWORD dwFlags)
 {
-    FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags);
-
+    FIXME("(%p)->(%p,%s,%08x): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags);
+#define X(x) if (dwFlags & x) FIXME("\tdwFlags =|"#x"\n");
+       X(DIDBAM_DEFAULT)
+       X(DIDBAM_PRESERVE)
+       X(DIDBAM_INITIALIZE)
+       X(DIDBAM_HWDEFAULTS)
+#undef X
+  
     return DI_OK;
 }
 
@@ -868,8 +1318,8 @@ HRESULT WINAPI IDirectInputDevice8AImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface
                                                     LPCSTR lpszUserName,
                                                     DWORD dwFlags)
 {
-    FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, lpszUserName, dwFlags);
-
+    FIXME("(%p)->(%p,%s,%08x): stub !\n", iface, lpdiaf, lpszUserName, dwFlags);
+    
     return DI_OK;
 }
 
@@ -878,8 +1328,8 @@ HRESULT WINAPI IDirectInputDevice8WImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface
                                                     LPCWSTR lpszUserName,
                                                     DWORD dwFlags)
 {
-    FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags);
-
+    FIXME("(%p)->(%p,%s,%08x): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags);
+    
     return DI_OK;
 }
 
@@ -887,7 +1337,7 @@ HRESULT WINAPI IDirectInputDevice8AImpl_GetImageInfo(LPDIRECTINPUTDEVICE8A iface
                                                     LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader)
 {
     FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader);
-
+    
     return DI_OK;
 }
 
@@ -895,6 +1345,6 @@ HRESULT WINAPI IDirectInputDevice8WImpl_GetImageInfo(LPDIRECTINPUTDEVICE8W iface
                                                     LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader)
 {
     FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader);
-
+    
     return DI_OK;
 }