[PATCH 1/5] ddraw/tests: Rewrite SrcColorKey32BlitTest (v2).

Stefan Dösinger stefandoesinger at gmx.at
Sun Feb 19 05:47:50 CST 2017


Version 2: Accept the testbot results for alpha-less color key blits.
Use an ARGB surface for the rest to eliminate driver specific behavior.
Mark non-Wine XRGB behavior broken and document the Windows drivers for
all observed behaviors.

Functional differences from the old version:

*) The DDBLT_KEYDEST | DDBLT_KEYSRC test is disabled. It behaves
differently on different Windows versions or drivers. I doubt there is
an application that relies on this case.
*) Version 4 and 7 use the destination's surface destination blit key,
which is much saner than the v1 / v2 behavior. I have kept the v1 / v2
behavior in wined3d though and marked the new tests todo.
*) Extend the v1 and v2 tests a bit to cover the case where the source
surface has no destination blit key set and DDBLT_KEYDEST is used.
*) Avoid using 0 as color key and test color. Use 0x000000aa instead.
*) A DDBLT_KEYDEST blit without a destination key in the destination
surface is an error, regardless of the used interface version.
*) Accept the Nvidia XRGB color key results with X != 0. I am open to
removing this test entirely as we're accepting a lot of different
outcomes now.

Signed-off-by: Stefan Dösinger <stefandoesinger at gmx.at>
---
 dlls/ddraw/surface.c        |   6 +
 dlls/ddraw/tests/ddraw1.c   | 482 +++++++++++++++++++++++++++++++++++++++++
 dlls/ddraw/tests/ddraw2.c   | 496 ++++++++++++++++++++++++++++++++++++++++++
 dlls/ddraw/tests/ddraw4.c   | 468 ++++++++++++++++++++++++++++++++++++++++
 dlls/ddraw/tests/ddraw7.c   | 468 ++++++++++++++++++++++++++++++++++++++++
 dlls/ddraw/tests/dsurface.c | 510 --------------------------------------------
 6 files changed, 1920 insertions(+), 510 deletions(-)

diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c
index 710f6cd..5695812 100644
--- a/dlls/ddraw/surface.c
+++ b/dlls/ddraw/surface.c
@@ -1657,6 +1657,12 @@ static HRESULT WINAPI DECLSPEC_HOTPATCH ddraw_surface7_Blt(IDirectDrawSurface7 *
 
     if (flags & DDBLT_KEYSRC && (!src_impl || !(src_impl->surface_desc.dwFlags & DDSD_CKSRCBLT)))
     {
+        WARN("DDBLT_KEYSRC blit without color key in surface, returning DDERR_INVALIDPARAMS\n");
+        wined3d_mutex_unlock();
+        return DDERR_INVALIDPARAMS;
+    }
+    if (flags & DDBLT_KEYDEST && !(dst_impl->surface_desc.dwFlags & DDSD_CKDESTBLT))
+    {
         WARN("DDBLT_KEYDEST blit without color key in surface, returning DDERR_INVALIDPARAMS\n");
         wined3d_mutex_unlock();
         return DDERR_INVALIDPARAMS;
diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c
index 1001d4f..8255497 100644
--- a/dlls/ddraw/tests/ddraw1.c
+++ b/dlls/ddraw/tests/ddraw1.c
@@ -10165,6 +10165,487 @@ static void test_texture_load(void)
     DestroyWindow(window);
 }
 
+static void test_ck_operation(void)
+{
+    IDirectDrawSurface *src, *dst;
+    IDirectDrawSurface7 *src7, *dst7;
+    DDSURFACEDESC surface_desc;
+    IDirectDraw *ddraw;
+    ULONG refcount;
+    HWND window;
+    HRESULT hr;
+    D3DCOLOR *color;
+    unsigned int i;
+    DDCOLORKEY ckey;
+    DDBLTFX fx;
+
+    window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
+            0, 0, 640, 480, 0, 0, 0, 0);
+    ddraw = create_ddraw();
+    ok(!!ddraw, "Failed to create a ddraw object.\n");
+    hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
+    ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+    surface_desc.dwWidth = 4;
+    surface_desc.dwHeight = 1;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_RGB;
+    U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
+    U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
+    U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
+    U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
+    hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    surface_desc.dwFlags |= DDSD_CKSRCBLT;
+    surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00ff00ff;
+    surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00ff00ff;
+    hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &src, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_Lock(src, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    ok(!(surface_desc.dwFlags & DDSD_LPSURFACE), "Surface desc has LPSURFACE Flags set.\n");
+    color = surface_desc.lpSurface;
+    color[0] = 0x77010203;
+    color[1] = 0x00010203;
+    color[2] = 0x77ff00ff;
+    color[3] = 0x00ff00ff;
+    hr = IDirectDrawSurface_Unlock(src, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    for (i = 0; i < 2; ++i)
+    {
+        hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        color = surface_desc.lpSurface;
+        color[0] = 0xcccccccc;
+        color[1] = 0xcccccccc;
+        color[2] = 0xcccccccc;
+        color[3] = 0xcccccccc;
+        hr = IDirectDrawSurface_Unlock(dst, NULL);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+        if (i)
+        {
+            hr = IDirectDrawSurface_BltFast(dst, 0, 0, src, NULL, DDBLTFAST_SRCCOLORKEY);
+            ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+        }
+        else
+        {
+            hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC, NULL);
+            ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+        }
+
+        hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT | DDLOCK_READONLY, NULL);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        ok(!(surface_desc.dwFlags & DDSD_LPSURFACE), "Surface desc has LPSURFACE Flags set.\n");
+        color = surface_desc.lpSurface;
+        /* Different behavior on some drivers / windows versions. Some versions ignore the X channel when
+         * color keying, but copy it to the destination surface. Others (sysmem surfaces) apply it for
+         * color keying, but do not copy it into the destination surface. Nvidia neither uses it for
+         * color keying nor copies it. */
+        ok((color[0] == 0x77010203 && color[1] == 0x00010203
+                && color[2] == 0xcccccccc && color[3] == 0xcccccccc) /* AMD, Wine */
+                || broken(color[0] == 0x00010203 && color[1] == 0x00010203
+                && color[2] == 0x00ff00ff && color[3] == 0xcccccccc) /* Sysmem surfaces? */
+                || broken(color[0] == 0x00010203 && color[1] == 0x00010203
+                && color[2] == 0xcccccccc && color[3] == 0xcccccccc) /* Nvidia */
+                || broken(color[0] == 0xff010203 && color[1] == 0xff010203
+                && color[2] == 0xcccccccc && color[3] == 0xcccccccc) /* Testbot */,
+                "Destination data after blitting is %08x %08x %08x %08x, i=%u.\n",
+                color[0], color[1], color[2], color[3], i);
+        hr = IDirectDrawSurface_Unlock(dst, NULL);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+    }
+
+    hr = IDirectDrawSurface_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x00ff00ff && ckey.dwColorSpaceHighValue == 0x00ff00ff,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x0000ff00;
+    hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x0000ff00 && ckey.dwColorSpaceHighValue == 0x0000ff00,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0;
+    surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface_GetSurfaceDesc(src, &surface_desc);
+    ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
+    ok(surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue == 0x0000ff00
+            && surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue == 0x0000ff00,
+            "Got unexpected color key low=%08x high=%08x.\n", surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue,
+            surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue);
+
+    /* Test SetColorKey with dwColorSpaceHighValue < dwColorSpaceLowValue */
+    ckey.dwColorSpaceLowValue = 0x000000ff;
+    ckey.dwColorSpaceHighValue = 0x00000000;
+    hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x000000ff && ckey.dwColorSpaceHighValue == 0x000000ff,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    ckey.dwColorSpaceLowValue = 0x000000ff;
+    ckey.dwColorSpaceHighValue = 0x00000001;
+    hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x000000ff && ckey.dwColorSpaceHighValue == 0x000000ff,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    ckey.dwColorSpaceLowValue = 0x000000fe;
+    ckey.dwColorSpaceHighValue = 0x000000fd;
+    hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x000000fe && ckey.dwColorSpaceHighValue == 0x000000fe,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    IDirectDrawSurface_Release(src);
+    IDirectDrawSurface_Release(dst);
+
+    /* Test source and destination keys and where they are read from. Use a surface with alpha
+     * to avoid driver-dependent content in the X channel. */
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+    surface_desc.dwWidth = 6;
+    surface_desc.dwHeight = 1;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
+    U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
+    U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
+    U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
+    U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
+    U5(surface_desc.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
+    hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+    hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &src, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    ckey.dwColorSpaceLowValue = 0x0000ff00;
+    ckey.dwColorSpaceHighValue = 0x0000ff00;
+    hr = IDirectDrawSurface_SetColorKey(dst, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+    ckey.dwColorSpaceLowValue = 0x00ff0000;
+    ckey.dwColorSpaceHighValue = 0x00ff0000;
+    hr = IDirectDrawSurface_SetColorKey(dst, DDCKEY_DESTBLT, &ckey);
+    ok(SUCCEEDED(hr) || hr == DDERR_NOCOLORKEYHW, "Failed to set color key, hr %#x.\n", hr);
+    if (FAILED(hr))
+    {
+        /* Nvidia reject dest keys, AMD allows them. This applies to vidmem and sysmem surfaces. */
+        skip("Failed to set destination color key, skipping related tests.\n");
+        goto done;
+    }
+
+    ckey.dwColorSpaceLowValue = 0x000000ff;
+    ckey.dwColorSpaceHighValue = 0x000000ff;
+    hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+    ckey.dwColorSpaceLowValue = 0x000000aa;
+    ckey.dwColorSpaceHighValue = 0x000000aa;
+    hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_DESTBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    memset(&fx, 0, sizeof(fx));
+    fx.dwSize = sizeof(fx);
+    fx.ddckSrcColorkey.dwColorSpaceHighValue = 0x00110000;
+    fx.ddckSrcColorkey.dwColorSpaceLowValue = 0x00110000;
+    fx.ddckDestColorkey.dwColorSpaceHighValue = 0x00001100;
+    fx.ddckDestColorkey.dwColorSpaceLowValue = 0x00001100;
+
+    hr = IDirectDrawSurface_Lock(src, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    color[0] = 0x000000ff; /* Applies to src blt key in src surface. */
+    color[1] = 0x000000aa; /* Applies to dst blt key in src surface. */
+    color[2] = 0x00ff0000; /* Dst color key in dst surface. */
+    color[3] = 0x0000ff00; /* Src color key in dst surface. */
+    color[4] = 0x00001100; /* Src color key in ddbltfx. */
+    color[5] = 0x00110000; /* Dst color key in ddbltfx. */
+    hr = IDirectDrawSurface_Unlock(src, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
+    hr = IDirectDrawSurface_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Test a blit without keying. */
+    hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, 0, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Should have copied src data unmodified to dst. */
+    ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
+            color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x00110000,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
+    hr = IDirectDrawSurface_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Src key. */
+    hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Src key applied to color[0]. It is unmodified, the others are copied. */
+    ok(color[0] == 0x55555555 && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
+            color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x00110000,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
+    hr = IDirectDrawSurface_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Src override. */
+    hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYSRCOVERRIDE, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Override key applied to color[5]. It is unmodified, the others are copied. */
+    ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
+            color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x55555555,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
+    hr = IDirectDrawSurface_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Src override AND src key. That is not supposed to work. */
+    hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE, &fx);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Ensure the desination was not changed. */
+    ok(color[0] == 0x55555555 && color[1] == 0x55555555 && color[2] == 0x55555555 &&
+            color[3] == 0x55555555 && color[4] == 0x55555555 && color[5] == 0x55555555,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    /* Use different dst colors for the dst key test. */
+    color[0] = 0x00ff0000; /* Dest key in dst surface. */
+    color[1] = 0x00ff0000; /* Dest key in dst surface. */
+    color[2] = 0x00001100; /* Dest key in override. */
+    color[3] = 0x00001100; /* Dest key in override. */
+    color[4] = 0x000000aa; /* Dest key in src surface. */
+    color[5] = 0x000000aa; /* Dest key in src surface. */
+    hr = IDirectDrawSurface_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Dst key applied to color[4,5], they are the only changed pixels. */
+    ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00001100 &&
+            color[3] == 0x00001100 && color[4] == 0x00001100 && color[5] == 0x00110000,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = 0x00ff0000; /* Dest key in dst surface. */
+    color[1] = 0x00ff0000; /* Dest key in dst surface. */
+    color[2] = 0x00001100; /* Dest key in override. */
+    color[3] = 0x00001100; /* Dest key in override. */
+    color[4] = 0x000000aa; /* Dest key in src surface. */
+    color[5] = 0x000000aa; /* Dest key in src surface. */
+    hr = IDirectDrawSurface_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* What happens with a QI'd newer version of the interface? It takes the key
+     * from the destination surface. */
+    hr = IDirectDrawSurface_QueryInterface(src, &IID_IDirectDrawSurface7, (void **)&src7);
+    ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface interface, hr %#x.\n", hr);
+    hr = IDirectDrawSurface_QueryInterface(dst, &IID_IDirectDrawSurface7, (void **)&dst7);
+    ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface interface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface7_Blt(dst7, NULL, src7, NULL, DDBLT_KEYDEST, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    IDirectDrawSurface7_Release(dst7);
+    IDirectDrawSurface7_Release(src7);
+
+    hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Dst key applied to color[0,1], they are the only changed pixels. */
+    todo_wine ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00001100 &&
+            color[3] == 0x00001100 && color[4] == 0x000000aa && color[5] == 0x000000aa,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = 0x00ff0000; /* Dest key in dst surface. */
+    color[1] = 0x00ff0000; /* Dest key in dst surface. */
+    color[2] = 0x00001100; /* Dest key in override. */
+    color[3] = 0x00001100; /* Dest key in override. */
+    color[4] = 0x000000aa; /* Dest key in src surface. */
+    color[5] = 0x000000aa; /* Dest key in src surface. */
+    hr = IDirectDrawSurface_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Dest override key blit. */
+    hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYDESTOVERRIDE, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Dst key applied to color[2,3], they are the only changed pixels. */
+    ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00ff0000 &&
+            color[3] == 0x0000ff00 && color[4] == 0x000000aa && color[5] == 0x000000aa,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = 0x00ff0000; /* Dest key in dst surface. */
+    color[1] = 0x00ff0000; /* Dest key in dst surface. */
+    color[2] = 0x00001100; /* Dest key in override. */
+    color[3] = 0x00001100; /* Dest key in override. */
+    color[4] = 0x000000aa; /* Dest key in src surface. */
+    color[5] = 0x000000aa; /* Dest key in src surface. */
+    hr = IDirectDrawSurface_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Dest override together with surface key. Supposed to fail. */
+    hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST | DDBLT_KEYDESTOVERRIDE, &fx);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Destination is unchanged. */
+    ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00001100 &&
+            color[3] == 0x00001100 && color[4] == 0x000000aa && color[5] == 0x000000aa,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+    hr = IDirectDrawSurface_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Source and destination key. This is driver dependent. New HW treats it like
+     * DDBLT_KEYSRC. Older HW and some software renderers apply both keys. */
+    if (0)
+    {
+        hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST | DDBLT_KEYSRC, &fx);
+        ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+        hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        color = surface_desc.lpSurface;
+        /* Color[0] is filtered by the src key, 2-5 are filtered by the dst key, if
+         * the driver applies it. */
+        ok(color[0] == 0x00ff0000 && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
+                color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x00110000,
+                "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+                color[0], color[1], color[2], color[3], color[4], color[5]);
+
+        color[0] = 0x00ff0000; /* Dest key in dst surface. */
+        color[1] = 0x00ff0000; /* Dest key in dst surface. */
+        color[2] = 0x00001100; /* Dest key in override. */
+        color[3] = 0x00001100; /* Dest key in override. */
+        color[4] = 0x000000aa; /* Dest key in src surface. */
+        color[5] = 0x000000aa; /* Dest key in src surface. */
+        hr = IDirectDrawSurface_Unlock(dst, NULL);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+    }
+
+    /* Override keys without ddbltfx parameter fail */
+    hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYDESTOVERRIDE, NULL);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYSRCOVERRIDE, NULL);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+    /* Try blitting without keys in the source surface. */
+    hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, NULL);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+    hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_DESTBLT, NULL);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    /* That fails now. Do not bother to check that the data is unmodified. */
+    hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC, &fx);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+    /* Surprisingly this still works. It uses the old key from the src surface. */
+    hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Dst key applied to color[4,5], they are the only changed pixels. */
+    ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00001100 &&
+            color[3] == 0x00001100 && color[4] == 0x00001100 && color[5] == 0x00110000,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+    hr = IDirectDrawSurface_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* This returns DDERR_NOCOLORKEY as expected. */
+    hr = IDirectDrawSurface_GetColorKey(src, DDCKEY_DESTBLT, &ckey);
+    ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x.\n", hr);
+
+    /* GetSurfaceDesc returns a zeroed key as expected. */
+    surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x12345678;
+    surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x12345678;
+    hr = IDirectDrawSurface_GetSurfaceDesc(src, &surface_desc);
+    ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
+    ok(!surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue
+            && !surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue,
+            "Got unexpected color key low=%08x high=%08x.\n", surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue,
+            surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue);
+
+    /* Try blitting without keys in the destination surface. */
+    hr = IDirectDrawSurface_SetColorKey(dst, DDCKEY_SRCBLT, NULL);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+    hr = IDirectDrawSurface_SetColorKey(dst, DDCKEY_DESTBLT, NULL);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    /* This is weird. It makes sense in v4 and v7, but because v1
+     * uses the key from the src surface it makes no sense here. */
+    hr = IDirectDrawSurface_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST, &fx);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+done:
+    IDirectDrawSurface_Release(src);
+    IDirectDrawSurface_Release(dst);
+    refcount = IDirectDraw_Release(ddraw);
+    ok(!refcount, "DirectDraw has %u references left.\n", refcount);
+    DestroyWindow(window);
+}
+
 START_TEST(ddraw1)
 {
     IDirectDraw *ddraw;
@@ -10251,4 +10732,5 @@ START_TEST(ddraw1)
     test_display_mode_surface_pixel_format();
     test_surface_desc_size();
     test_texture_load();
+    test_ck_operation();
 }
diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c
index 1836f76..c8e9a80 100644
--- a/dlls/ddraw/tests/ddraw2.c
+++ b/dlls/ddraw/tests/ddraw2.c
@@ -11489,6 +11489,501 @@ static void test_surface_desc_size(void)
     ok(!refcount, "DirectDraw has %u references left.\n", refcount);
 }
 
+static void test_ck_operation(void)
+{
+    IDirectDrawSurface2 *src, *dst;
+    IDirectDrawSurface7 *src7, *dst7;
+    IDirectDrawSurface *surface1;
+    DDSURFACEDESC surface_desc;
+    IDirectDraw2 *ddraw;
+    ULONG refcount;
+    HWND window;
+    HRESULT hr;
+    D3DCOLOR *color;
+    unsigned int i;
+    DDCOLORKEY ckey;
+    DDBLTFX fx;
+
+    window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
+            0, 0, 640, 480, 0, 0, 0, 0);
+    ddraw = create_ddraw();
+    ok(!!ddraw, "Failed to create a ddraw object.\n");
+    hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
+    ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+    surface_desc.dwWidth = 4;
+    surface_desc.dwHeight = 1;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_RGB;
+    U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
+    U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
+    U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
+    U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
+    hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+    hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&dst);
+    ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface2, hr %#x.\n", hr);
+    IDirectDrawSurface_Release(surface1);
+
+    surface_desc.dwFlags |= DDSD_CKSRCBLT;
+    surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00ff00ff;
+    surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00ff00ff;
+    hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+    hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&src);
+    ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface2, hr %#x.\n", hr);
+    IDirectDrawSurface_Release(surface1);
+
+    hr = IDirectDrawSurface2_Lock(src, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    ok(!(surface_desc.dwFlags & DDSD_LPSURFACE), "Surface desc has LPSURFACE Flags set.\n");
+    color = surface_desc.lpSurface;
+    color[0] = 0x77010203;
+    color[1] = 0x00010203;
+    color[2] = 0x77ff00ff;
+    color[3] = 0x00ff00ff;
+    hr = IDirectDrawSurface2_Unlock(src, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    for (i = 0; i < 2; ++i)
+    {
+        hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        color = surface_desc.lpSurface;
+        color[0] = 0xcccccccc;
+        color[1] = 0xcccccccc;
+        color[2] = 0xcccccccc;
+        color[3] = 0xcccccccc;
+        hr = IDirectDrawSurface2_Unlock(dst, NULL);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+        if (i)
+        {
+            hr = IDirectDrawSurface2_BltFast(dst, 0, 0, src, NULL, DDBLTFAST_SRCCOLORKEY);
+            ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+        }
+        else
+        {
+            hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC, NULL);
+            ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+        }
+
+        hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT | DDLOCK_READONLY, NULL);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        ok(!(surface_desc.dwFlags & DDSD_LPSURFACE), "Surface desc has LPSURFACE Flags set.\n");
+        color = surface_desc.lpSurface;
+        /* Different behavior on some drivers / windows versions. Some versions ignore the X channel when
+         * color keying, but copy it to the destination surface. Others (sysmem surfaces) apply it for
+         * color keying, but do not copy it into the destination surface. Nvidia neither uses it for
+         * color keying nor copies it. */
+        ok((color[0] == 0x77010203 && color[1] == 0x00010203
+                && color[2] == 0xcccccccc && color[3] == 0xcccccccc) /* AMD, Wine */
+                || broken(color[0] == 0x00010203 && color[1] == 0x00010203
+                && color[2] == 0x00ff00ff && color[3] == 0xcccccccc) /* Sysmem surfaces? */
+                || broken(color[0] == 0x00010203 && color[1] == 0x00010203
+                && color[2] == 0xcccccccc && color[3] == 0xcccccccc) /* Nvidia */
+                || broken(color[0] == 0xff010203 && color[1] == 0xff010203
+                && color[2] == 0xcccccccc && color[3] == 0xcccccccc) /* Testbot */,
+                "Destination data after blitting is %08x %08x %08x %08x, i=%u.\n",
+                color[0], color[1], color[2], color[3], i);
+        hr = IDirectDrawSurface2_Unlock(dst, NULL);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+    }
+
+    hr = IDirectDrawSurface2_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x00ff00ff && ckey.dwColorSpaceHighValue == 0x00ff00ff,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x0000ff00;
+    hr = IDirectDrawSurface2_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface2_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x0000ff00 && ckey.dwColorSpaceHighValue == 0x0000ff00,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0;
+    surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface2_GetSurfaceDesc(src, &surface_desc);
+    ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
+    ok(surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue == 0x0000ff00
+            && surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue == 0x0000ff00,
+            "Got unexpected color key low=%08x high=%08x.\n", surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue,
+            surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue);
+
+    /* Test SetColorKey with dwColorSpaceHighValue < dwColorSpaceLowValue */
+    ckey.dwColorSpaceLowValue = 0x000000ff;
+    ckey.dwColorSpaceHighValue = 0x00000000;
+    hr = IDirectDrawSurface2_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface2_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x000000ff && ckey.dwColorSpaceHighValue == 0x000000ff,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    ckey.dwColorSpaceLowValue = 0x000000ff;
+    ckey.dwColorSpaceHighValue = 0x00000001;
+    hr = IDirectDrawSurface2_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface2_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x000000ff && ckey.dwColorSpaceHighValue == 0x000000ff,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    ckey.dwColorSpaceLowValue = 0x000000fe;
+    ckey.dwColorSpaceHighValue = 0x000000fd;
+    hr = IDirectDrawSurface2_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface2_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x000000fe && ckey.dwColorSpaceHighValue == 0x000000fe,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    IDirectDrawSurface2_Release(src);
+    IDirectDrawSurface2_Release(dst);
+
+    /* Test source and destination keys and where they are read from. Use a surface with alpha
+     * to avoid driver-dependent content in the X channel. */
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+    surface_desc.dwWidth = 6;
+    surface_desc.dwHeight = 1;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
+    U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
+    U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
+    U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
+    U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
+    U5(surface_desc.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
+    hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+    hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&dst);
+    ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface2, hr %#x.\n", hr);
+    IDirectDrawSurface_Release(surface1);
+
+    hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+    hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&src);
+    ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface2, hr %#x.\n", hr);
+    IDirectDrawSurface_Release(surface1);
+
+    ckey.dwColorSpaceLowValue = 0x0000ff00;
+    ckey.dwColorSpaceHighValue = 0x0000ff00;
+    hr = IDirectDrawSurface2_SetColorKey(dst, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+    ckey.dwColorSpaceLowValue = 0x00ff0000;
+    ckey.dwColorSpaceHighValue = 0x00ff0000;
+    hr = IDirectDrawSurface2_SetColorKey(dst, DDCKEY_DESTBLT, &ckey);
+    ok(SUCCEEDED(hr) || hr == DDERR_NOCOLORKEYHW, "Failed to set color key, hr %#x.\n", hr);
+    if (FAILED(hr))
+    {
+        /* Nvidia reject dest keys, AMD allows them. This applies to vidmem and sysmem surfaces. */
+        skip("Failed to set destination color key, skipping related tests.\n");
+        goto done;
+    }
+
+    ckey.dwColorSpaceLowValue = 0x000000ff;
+    ckey.dwColorSpaceHighValue = 0x000000ff;
+    hr = IDirectDrawSurface2_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+    ckey.dwColorSpaceLowValue = 0x000000aa;
+    ckey.dwColorSpaceHighValue = 0x000000aa;
+    hr = IDirectDrawSurface2_SetColorKey(src, DDCKEY_DESTBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    memset(&fx, 0, sizeof(fx));
+    fx.dwSize = sizeof(fx);
+    fx.ddckSrcColorkey.dwColorSpaceHighValue = 0x00110000;
+    fx.ddckSrcColorkey.dwColorSpaceLowValue = 0x00110000;
+    fx.ddckDestColorkey.dwColorSpaceHighValue = 0x00001100;
+    fx.ddckDestColorkey.dwColorSpaceLowValue = 0x00001100;
+
+    hr = IDirectDrawSurface2_Lock(src, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    color[0] = 0x000000ff; /* Applies to src blt key in src surface. */
+    color[1] = 0x000000aa; /* Applies to dst blt key in src surface. */
+    color[2] = 0x00ff0000; /* Dst color key in dst surface. */
+    color[3] = 0x0000ff00; /* Src color key in dst surface. */
+    color[4] = 0x00001100; /* Src color key in ddbltfx. */
+    color[5] = 0x00110000; /* Dst color key in ddbltfx. */
+    hr = IDirectDrawSurface2_Unlock(src, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
+    hr = IDirectDrawSurface2_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Test a blit without keying. */
+    hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, 0, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Should have copied src data unmodified to dst. */
+    ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
+            color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x00110000,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
+    hr = IDirectDrawSurface2_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Src key. */
+    hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Src key applied to color[0]. It is unmodified, the others are copied. */
+    ok(color[0] == 0x55555555 && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
+            color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x00110000,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
+    hr = IDirectDrawSurface2_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Src override. */
+    hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYSRCOVERRIDE, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Override key applied to color[5]. It is unmodified, the others are copied. */
+    ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
+            color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x55555555,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
+    hr = IDirectDrawSurface2_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Src override AND src key. That is not supposed to work. */
+    hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE, &fx);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Ensure the desination was not changed. */
+    ok(color[0] == 0x55555555 && color[1] == 0x55555555 && color[2] == 0x55555555 &&
+            color[3] == 0x55555555 && color[4] == 0x55555555 && color[5] == 0x55555555,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    /* Use different dst colors for the dst key test. */
+    color[0] = 0x00ff0000; /* Dest key in dst surface. */
+    color[1] = 0x00ff0000; /* Dest key in dst surface. */
+    color[2] = 0x00001100; /* Dest key in override. */
+    color[3] = 0x00001100; /* Dest key in override. */
+    color[4] = 0x000000aa; /* Dest key in src surface. */
+    color[5] = 0x000000aa; /* Dest key in src surface. */
+    hr = IDirectDrawSurface2_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Dest key blit. The key is taken from the SOURCE surface in v2! */
+    hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Dst key applied to color[4,5], they are the only changed pixels. */
+    ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00001100 &&
+            color[3] == 0x00001100 && color[4] == 0x00001100 && color[5] == 0x00110000,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = 0x00ff0000; /* Dest key in dst surface. */
+    color[1] = 0x00ff0000; /* Dest key in dst surface. */
+    color[2] = 0x00001100; /* Dest key in override. */
+    color[3] = 0x00001100; /* Dest key in override. */
+    color[4] = 0x000000aa; /* Dest key in src surface. */
+    color[5] = 0x000000aa; /* Dest key in src surface. */
+    hr = IDirectDrawSurface2_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* What happens with a QI'd newer version of the interface? It takes the key
+     * from the destination surface. */
+    hr = IDirectDrawSurface2_QueryInterface(src, &IID_IDirectDrawSurface7, (void **)&src7);
+    ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface interface, hr %#x.\n", hr);
+    hr = IDirectDrawSurface2_QueryInterface(dst, &IID_IDirectDrawSurface7, (void **)&dst7);
+    ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface interface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface7_Blt(dst7, NULL, src7, NULL, DDBLT_KEYDEST, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    IDirectDrawSurface7_Release(dst7);
+    IDirectDrawSurface7_Release(src7);
+
+    hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Dst key applied to color[0,1], they are the only changed pixels. */
+    todo_wine ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00001100 &&
+            color[3] == 0x00001100 && color[4] == 0x000000aa && color[5] == 0x000000aa,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = 0x00ff0000; /* Dest key in dst surface. */
+    color[1] = 0x00ff0000; /* Dest key in dst surface. */
+    color[2] = 0x00001100; /* Dest key in override. */
+    color[3] = 0x00001100; /* Dest key in override. */
+    color[4] = 0x000000aa; /* Dest key in src surface. */
+    color[5] = 0x000000aa; /* Dest key in src surface. */
+    hr = IDirectDrawSurface2_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Dest override key blit. */
+    hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYDESTOVERRIDE, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Dst key applied to color[2,3], they are the only changed pixels. */
+    ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00ff0000 &&
+            color[3] == 0x0000ff00 && color[4] == 0x000000aa && color[5] == 0x000000aa,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = 0x00ff0000; /* Dest key in dst surface. */
+    color[1] = 0x00ff0000; /* Dest key in dst surface. */
+    color[2] = 0x00001100; /* Dest key in override. */
+    color[3] = 0x00001100; /* Dest key in override. */
+    color[4] = 0x000000aa; /* Dest key in src surface. */
+    color[5] = 0x000000aa; /* Dest key in src surface. */
+    hr = IDirectDrawSurface2_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Dest override together with surface key. Supposed to fail. */
+    hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST | DDBLT_KEYDESTOVERRIDE, &fx);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Destination is unchanged. */
+    ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00001100 &&
+            color[3] == 0x00001100 && color[4] == 0x000000aa && color[5] == 0x000000aa,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+    hr = IDirectDrawSurface2_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Source and destination key. This is driver dependent. New HW treats it like
+     * DDBLT_KEYSRC. Older HW and some software renderers apply both keys. */
+    if (0)
+    {
+        hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST | DDBLT_KEYSRC, &fx);
+        ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+        hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        color = surface_desc.lpSurface;
+        /* Color[0] is filtered by the src key, 2-5 are filtered by the dst key, if
+         * the driver applies it. */
+        ok(color[0] == 0x00ff0000 && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
+                color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x00110000,
+                "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+                color[0], color[1], color[2], color[3], color[4], color[5]);
+
+        color[0] = 0x00ff0000; /* Dest key in dst surface. */
+        color[1] = 0x00ff0000; /* Dest key in dst surface. */
+        color[2] = 0x00001100; /* Dest key in override. */
+        color[3] = 0x00001100; /* Dest key in override. */
+        color[4] = 0x000000aa; /* Dest key in src surface. */
+        color[5] = 0x000000aa; /* Dest key in src surface. */
+        hr = IDirectDrawSurface2_Unlock(dst, NULL);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+    }
+
+    /* Override keys without ddbltfx parameter fail */
+    hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYDESTOVERRIDE, NULL);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYSRCOVERRIDE, NULL);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+    /* Try blitting without keys in the source surface. */
+    hr = IDirectDrawSurface2_SetColorKey(src, DDCKEY_SRCBLT, NULL);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+    hr = IDirectDrawSurface2_SetColorKey(src, DDCKEY_DESTBLT, NULL);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    /* That fails now. Do not bother to check that the data is unmodified. */
+    hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC, &fx);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+    /* Surprisingly this still works. It uses the old key from the src surface. */
+    hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface2_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Dst key applied to color[4,5], they are the only changed pixels. */
+    ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00001100 &&
+            color[3] == 0x00001100 && color[4] == 0x00001100 && color[5] == 0x00110000,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+    hr = IDirectDrawSurface2_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* This returns DDERR_NOCOLORKEY as expected. */
+    hr = IDirectDrawSurface2_GetColorKey(src, DDCKEY_DESTBLT, &ckey);
+    ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x.\n", hr);
+
+    /* GetSurfaceDesc returns a zeroed key as expected. */
+    surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x12345678;
+    surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x12345678;
+    hr = IDirectDrawSurface2_GetSurfaceDesc(src, &surface_desc);
+    ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
+    ok(!surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue
+            && !surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue,
+            "Got unexpected color key low=%08x high=%08x.\n", surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue,
+            surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue);
+
+    /* Try blitting without keys in the destination surface. */
+    hr = IDirectDrawSurface2_SetColorKey(dst, DDCKEY_SRCBLT, NULL);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+    hr = IDirectDrawSurface2_SetColorKey(dst, DDCKEY_DESTBLT, NULL);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    /* This fails, as sanity would dictate. */
+    hr = IDirectDrawSurface2_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST, &fx);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+done:
+    IDirectDrawSurface2_Release(src);
+    IDirectDrawSurface2_Release(dst);
+    refcount = IDirectDraw2_Release(ddraw);
+    ok(!refcount, "DirectDraw has %u references left.\n", refcount);
+    DestroyWindow(window);
+}
+
 START_TEST(ddraw2)
 {
     IDirectDraw2 *ddraw;
@@ -11583,4 +12078,5 @@ START_TEST(ddraw2)
     test_transform_vertices();
     test_display_mode_surface_pixel_format();
     test_surface_desc_size();
+    test_ck_operation();
 }
diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c
index 557854a..48b079b 100644
--- a/dlls/ddraw/tests/ddraw4.c
+++ b/dlls/ddraw/tests/ddraw4.c
@@ -12887,6 +12887,473 @@ static void test_get_surface_from_dc(void)
     DestroyWindow(window);
 }
 
+static void test_ck_operation(void)
+{
+    IDirectDrawSurface4 *src, *dst;
+    IDirectDrawSurface *src1, *dst1;
+    DDSURFACEDESC2 surface_desc;
+    IDirectDraw4 *ddraw;
+    ULONG refcount;
+    HWND window;
+    HRESULT hr;
+    D3DCOLOR *color;
+    unsigned int i;
+    DDCOLORKEY ckey;
+    DDBLTFX fx;
+
+    window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
+            0, 0, 640, 480, 0, 0, 0, 0);
+    ddraw = create_ddraw();
+    ok(!!ddraw, "Failed to create a ddraw object.\n");
+    hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
+    ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+    surface_desc.dwWidth = 4;
+    surface_desc.dwHeight = 1;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_RGB;
+    U1(U4(surface_desc.ddpfPixelFormat)).dwRGBBitCount = 32;
+    U2(U4(surface_desc.ddpfPixelFormat)).dwRBitMask = 0x00ff0000;
+    U3(U4(surface_desc.ddpfPixelFormat)).dwGBitMask = 0x0000ff00;
+    U4(U4(surface_desc.ddpfPixelFormat)).dwBBitMask = 0x000000ff;
+    hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    surface_desc.dwFlags |= DDSD_CKSRCBLT;
+    surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00ff00ff;
+    surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00ff00ff;
+    hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &src, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface4_Lock(src, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    ok(!(surface_desc.dwFlags & DDSD_LPSURFACE), "Surface desc has LPSURFACE Flags set.\n");
+    color = surface_desc.lpSurface;
+    color[0] = 0x77010203;
+    color[1] = 0x00010203;
+    color[2] = 0x77ff00ff;
+    color[3] = 0x00ff00ff;
+    hr = IDirectDrawSurface4_Unlock(src, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    for (i = 0; i < 2; ++i)
+    {
+        hr = IDirectDrawSurface4_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        color = surface_desc.lpSurface;
+        color[0] = 0xcccccccc;
+        color[1] = 0xcccccccc;
+        color[2] = 0xcccccccc;
+        color[3] = 0xcccccccc;
+        hr = IDirectDrawSurface4_Unlock(dst, NULL);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+        if (i)
+        {
+            hr = IDirectDrawSurface4_BltFast(dst, 0, 0, src, NULL, DDBLTFAST_SRCCOLORKEY);
+            ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+        }
+        else
+        {
+            hr = IDirectDrawSurface4_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC, NULL);
+            ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+        }
+
+        hr = IDirectDrawSurface4_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT | DDLOCK_READONLY, NULL);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        ok(!(surface_desc.dwFlags & DDSD_LPSURFACE), "Surface desc has LPSURFACE Flags set.\n");
+        color = surface_desc.lpSurface;
+        /* Different behavior on some drivers / windows versions. Some versions ignore the X channel when
+         * color keying, but copy it to the destination surface. Others (sysmem surfaces) apply it for
+         * color keying, but do not copy it into the destination surface. Nvidia neither uses it for
+         * color keying nor copies it. */
+        ok((color[0] == 0x77010203 && color[1] == 0x00010203
+                && color[2] == 0xcccccccc && color[3] == 0xcccccccc) /* AMD, Wine */
+                || broken(color[0] == 0x00010203 && color[1] == 0x00010203
+                && color[2] == 0x00ff00ff && color[3] == 0xcccccccc) /* Sysmem surfaces? */
+                || broken(color[0] == 0x00010203 && color[1] == 0x00010203
+                && color[2] == 0xcccccccc && color[3] == 0xcccccccc) /* Nvidia */
+                || broken(color[0] == 0xff010203 && color[1] == 0xff010203
+                && color[2] == 0xcccccccc && color[3] == 0xcccccccc) /* Testbot */,
+                "Destination data after blitting is %08x %08x %08x %08x, i=%u.\n",
+                color[0], color[1], color[2], color[3], i);
+        hr = IDirectDrawSurface4_Unlock(dst, NULL);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+    }
+
+    hr = IDirectDrawSurface4_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x00ff00ff && ckey.dwColorSpaceHighValue == 0x00ff00ff,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x0000ff00;
+    hr = IDirectDrawSurface4_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface4_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x0000ff00 && ckey.dwColorSpaceHighValue == 0x0000ff00,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0;
+    surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface4_GetSurfaceDesc(src, &surface_desc);
+    ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
+    ok(surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue == 0x0000ff00
+            && surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue == 0x0000ff00,
+            "Got unexpected color key low=%08x high=%08x.\n", surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue,
+            surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue);
+
+    /* Test SetColorKey with dwColorSpaceHighValue < dwColorSpaceLowValue */
+    ckey.dwColorSpaceLowValue = 0x000000ff;
+    ckey.dwColorSpaceHighValue = 0x00000000;
+    hr = IDirectDrawSurface4_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface4_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x000000ff && ckey.dwColorSpaceHighValue == 0x000000ff,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    ckey.dwColorSpaceLowValue = 0x000000ff;
+    ckey.dwColorSpaceHighValue = 0x00000001;
+    hr = IDirectDrawSurface4_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface4_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x000000ff && ckey.dwColorSpaceHighValue == 0x000000ff,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    ckey.dwColorSpaceLowValue = 0x000000fe;
+    ckey.dwColorSpaceHighValue = 0x000000fd;
+    hr = IDirectDrawSurface4_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface4_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x000000fe && ckey.dwColorSpaceHighValue == 0x000000fe,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    IDirectDrawSurface4_Release(src);
+    IDirectDrawSurface4_Release(dst);
+
+    /* Test source and destination keys and where they are read from. Use a surface with alpha
+     * to avoid driver-dependent content in the X channel. */
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+    surface_desc.dwWidth = 6;
+    surface_desc.dwHeight = 1;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
+    U1(U4(surface_desc.ddpfPixelFormat)).dwRGBBitCount = 32;
+    U2(U4(surface_desc.ddpfPixelFormat)).dwRBitMask = 0x00ff0000;
+    U3(U4(surface_desc.ddpfPixelFormat)).dwGBitMask = 0x0000ff00;
+    U4(U4(surface_desc.ddpfPixelFormat)).dwBBitMask = 0x000000ff;
+    U5(U4(surface_desc.ddpfPixelFormat)).dwRGBAlphaBitMask = 0xff000000;
+    hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+    hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &src, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    ckey.dwColorSpaceLowValue = 0x0000ff00;
+    ckey.dwColorSpaceHighValue = 0x0000ff00;
+    hr = IDirectDrawSurface4_SetColorKey(dst, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+    ckey.dwColorSpaceLowValue = 0x00ff0000;
+    ckey.dwColorSpaceHighValue = 0x00ff0000;
+    hr = IDirectDrawSurface4_SetColorKey(dst, DDCKEY_DESTBLT, &ckey);
+    ok(SUCCEEDED(hr) || hr == DDERR_NOCOLORKEYHW, "Failed to set color key, hr %#x.\n", hr);
+    if (FAILED(hr))
+    {
+        /* Nvidia reject dest keys, AMD allows them. This applies to vidmem and sysmem surfaces. */
+        skip("Failed to set destination color key, skipping related tests.\n");
+        goto done;
+    }
+
+    ckey.dwColorSpaceLowValue = 0x000000ff;
+    ckey.dwColorSpaceHighValue = 0x000000ff;
+    hr = IDirectDrawSurface4_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+    ckey.dwColorSpaceLowValue = 0x000000aa;
+    ckey.dwColorSpaceHighValue = 0x000000aa;
+    hr = IDirectDrawSurface4_SetColorKey(src, DDCKEY_DESTBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    memset(&fx, 0, sizeof(fx));
+    fx.dwSize = sizeof(fx);
+    fx.ddckSrcColorkey.dwColorSpaceHighValue = 0x00110000;
+    fx.ddckSrcColorkey.dwColorSpaceLowValue = 0x00110000;
+    fx.ddckDestColorkey.dwColorSpaceHighValue = 0x00001100;
+    fx.ddckDestColorkey.dwColorSpaceLowValue = 0x00001100;
+
+    hr = IDirectDrawSurface4_Lock(src, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    color[0] = 0x000000ff; /* Applies to src blt key in src surface. */
+    color[1] = 0x000000aa; /* Applies to dst blt key in src surface. */
+    color[2] = 0x00ff0000; /* Dst color key in dst surface. */
+    color[3] = 0x0000ff00; /* Src color key in dst surface. */
+    color[4] = 0x00001100; /* Src color key in ddbltfx. */
+    color[5] = 0x00110000; /* Dst color key in ddbltfx. */
+    hr = IDirectDrawSurface4_Unlock(src, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface4_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
+    hr = IDirectDrawSurface4_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Test a blit without keying. */
+    hr = IDirectDrawSurface4_Blt(dst, NULL, src, NULL, 0, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface4_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Should have copied src data unmodified to dst. */
+    ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
+            color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x00110000,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
+    hr = IDirectDrawSurface4_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Src key. */
+    hr = IDirectDrawSurface4_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface4_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Src key applied to color[0]. It is unmodified, the others are copied. */
+    ok(color[0] == 0x55555555 && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
+            color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x00110000,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
+    hr = IDirectDrawSurface4_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Src override. */
+    hr = IDirectDrawSurface4_Blt(dst, NULL, src, NULL, DDBLT_KEYSRCOVERRIDE, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface4_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Override key applied to color[5]. It is unmodified, the others are copied. */
+    ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
+            color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x55555555,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
+    hr = IDirectDrawSurface4_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Src override AND src key. That is not supposed to work. */
+    hr = IDirectDrawSurface4_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE, &fx);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface4_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Ensure the desination was not changed. */
+    ok(color[0] == 0x55555555 && color[1] == 0x55555555 && color[2] == 0x55555555 &&
+            color[3] == 0x55555555 && color[4] == 0x55555555 && color[5] == 0x55555555,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    /* Use different dst colors for the dst key test. */
+    color[0] = 0x00ff0000; /* Dest key in dst surface. */
+    color[1] = 0x00ff0000; /* Dest key in dst surface. */
+    color[2] = 0x00001100; /* Dest key in override. */
+    color[3] = 0x00001100; /* Dest key in override. */
+    color[4] = 0x000000aa; /* Dest key in src surface. */
+    color[5] = 0x000000aa; /* Dest key in src surface. */
+    hr = IDirectDrawSurface4_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Dest key blit. The key is taken from the DESTINATION surface in v4! */
+    hr = IDirectDrawSurface4_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface4_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Dst key applied to color[0,1], they are the only changed pixels. */
+    todo_wine ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00001100 &&
+            color[3] == 0x00001100 && color[4] == 0x000000aa && color[5] == 0x000000aa,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = 0x00ff0000; /* Dest key in dst surface. */
+    color[1] = 0x00ff0000; /* Dest key in dst surface. */
+    color[2] = 0x00001100; /* Dest key in override. */
+    color[3] = 0x00001100; /* Dest key in override. */
+    color[4] = 0x000000aa; /* Dest key in src surface. */
+    color[5] = 0x000000aa; /* Dest key in src surface. */
+    hr = IDirectDrawSurface4_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* What happens with a QI'd older version of the interface? It takes the key
+     * from the source surface. */
+    hr = IDirectDrawSurface4_QueryInterface(src, &IID_IDirectDrawSurface, (void **)&src1);
+    ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface interface, hr %#x.\n", hr);
+    hr = IDirectDrawSurface4_QueryInterface(dst, &IID_IDirectDrawSurface, (void **)&dst1);
+    ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface interface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_Blt(dst1, NULL, src1, NULL, DDBLT_KEYDEST, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    IDirectDrawSurface_Release(dst1);
+    IDirectDrawSurface_Release(src1);
+
+    hr = IDirectDrawSurface7_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Dst key applied to color[4,5], they are the only changed pixels. */
+    ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00001100 &&
+            color[3] == 0x00001100 && color[4] == 0x00001100 && color[5] == 0x00110000,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = 0x00ff0000; /* Dest key in dst surface. */
+    color[1] = 0x00ff0000; /* Dest key in dst surface. */
+    color[2] = 0x00001100; /* Dest key in override. */
+    color[3] = 0x00001100; /* Dest key in override. */
+    color[4] = 0x000000aa; /* Dest key in src surface. */
+    color[5] = 0x000000aa; /* Dest key in src surface. */
+    hr = IDirectDrawSurface7_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Dest override key blit. */
+    hr = IDirectDrawSurface4_Blt(dst, NULL, src, NULL, DDBLT_KEYDESTOVERRIDE, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface4_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Dst key applied to color[2,3], they are the only changed pixels. */
+    ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00ff0000 &&
+            color[3] == 0x0000ff00 && color[4] == 0x000000aa && color[5] == 0x000000aa,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = 0x00ff0000; /* Dest key in dst surface. */
+    color[1] = 0x00ff0000; /* Dest key in dst surface. */
+    color[2] = 0x00001100; /* Dest key in override. */
+    color[3] = 0x00001100; /* Dest key in override. */
+    color[4] = 0x000000aa; /* Dest key in src surface. */
+    color[5] = 0x000000aa; /* Dest key in src surface. */
+    hr = IDirectDrawSurface4_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Dest override together with surface key. Supposed to fail. */
+    hr = IDirectDrawSurface4_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST | DDBLT_KEYDESTOVERRIDE, &fx);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface4_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Destination is unchanged. */
+    ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00001100 &&
+            color[3] == 0x00001100 && color[4] == 0x000000aa && color[5] == 0x000000aa,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+    hr = IDirectDrawSurface4_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Source and destination key. This is driver dependent. New HW treats it like
+     * DDBLT_KEYSRC. Older HW and some software renderers apply both keys. */
+    if (0)
+    {
+        hr = IDirectDrawSurface4_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST | DDBLT_KEYSRC, &fx);
+        ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+        hr = IDirectDrawSurface4_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        color = surface_desc.lpSurface;
+        /* Color[0] is filtered by the src key, 2-5 are filtered by the dst key, if
+         * the driver applies it. */
+        ok(color[0] == 0x00ff0000 && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
+                color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x00110000,
+                "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+                color[0], color[1], color[2], color[3], color[4], color[5]);
+
+        color[0] = 0x00ff0000; /* Dest key in dst surface. */
+        color[1] = 0x00ff0000; /* Dest key in dst surface. */
+        color[2] = 0x00001100; /* Dest key in override. */
+        color[3] = 0x00001100; /* Dest key in override. */
+        color[4] = 0x000000aa; /* Dest key in src surface. */
+        color[5] = 0x000000aa; /* Dest key in src surface. */
+        hr = IDirectDrawSurface4_Unlock(dst, NULL);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+    }
+
+    /* Override keys without ddbltfx parameter fail */
+    hr = IDirectDrawSurface4_Blt(dst, NULL, src, NULL, DDBLT_KEYDESTOVERRIDE, NULL);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface4_Blt(dst, NULL, src, NULL, DDBLT_KEYSRCOVERRIDE, NULL);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+    /* Try blitting without keys in the source surface. */
+    hr = IDirectDrawSurface4_SetColorKey(src, DDCKEY_SRCBLT, NULL);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+    hr = IDirectDrawSurface4_SetColorKey(src, DDCKEY_DESTBLT, NULL);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    /* That fails now. Do not bother to check that the data is unmodified. */
+    hr = IDirectDrawSurface4_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC, &fx);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+    /* Dest key blit still works, the destination surface key is used in v4. */
+    hr = IDirectDrawSurface4_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface4_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Dst key applied to color[0,1], they are the only changed pixels. */
+    todo_wine ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00001100 &&
+            color[3] == 0x00001100 && color[4] == 0x000000aa && color[5] == 0x000000aa,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+    hr = IDirectDrawSurface4_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Try blitting without keys in the destination surface. */
+    hr = IDirectDrawSurface4_SetColorKey(dst, DDCKEY_SRCBLT, NULL);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+    hr = IDirectDrawSurface4_SetColorKey(dst, DDCKEY_DESTBLT, NULL);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    /* This fails, as sanity would dictate. */
+    hr = IDirectDrawSurface4_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST, &fx);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+done:
+    IDirectDrawSurface4_Release(src);
+    IDirectDrawSurface4_Release(dst);
+    refcount = IDirectDraw4_Release(ddraw);
+    ok(!refcount, "DirectDraw has %u references left.\n", refcount);
+    DestroyWindow(window);
+}
+
 START_TEST(ddraw4)
 {
     IDirectDraw4 *ddraw;
@@ -12990,4 +13457,5 @@ START_TEST(ddraw4)
     test_display_mode_surface_pixel_format();
     test_surface_desc_size();
     test_get_surface_from_dc();
+    test_ck_operation();
 }
diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c
index 827496b..33fd1f7 100644
--- a/dlls/ddraw/tests/ddraw7.c
+++ b/dlls/ddraw/tests/ddraw7.c
@@ -12560,6 +12560,473 @@ static void test_get_surface_from_dc(void)
     DestroyWindow(window);
 }
 
+static void test_ck_operation(void)
+{
+    IDirectDrawSurface7 *src, *dst;
+    IDirectDrawSurface *src1, *dst1;
+    DDSURFACEDESC2 surface_desc;
+    IDirectDraw7 *ddraw;
+    ULONG refcount;
+    HWND window;
+    HRESULT hr;
+    D3DCOLOR *color;
+    unsigned int i;
+    DDCOLORKEY ckey;
+    DDBLTFX fx;
+
+    window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
+            0, 0, 640, 480, 0, 0, 0, 0);
+    ddraw = create_ddraw();
+    ok(!!ddraw, "Failed to create a ddraw object.\n");
+    hr = IDirectDraw7_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
+    ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+    surface_desc.dwWidth = 4;
+    surface_desc.dwHeight = 1;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_RGB;
+    U1(U4(surface_desc.ddpfPixelFormat)).dwRGBBitCount = 32;
+    U2(U4(surface_desc.ddpfPixelFormat)).dwRBitMask = 0x00ff0000;
+    U3(U4(surface_desc.ddpfPixelFormat)).dwGBitMask = 0x0000ff00;
+    U4(U4(surface_desc.ddpfPixelFormat)).dwBBitMask = 0x000000ff;
+    hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    surface_desc.dwFlags |= DDSD_CKSRCBLT;
+    surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00ff00ff;
+    surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00ff00ff;
+    hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &src, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface7_Lock(src, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    ok(!(surface_desc.dwFlags & DDSD_LPSURFACE), "Surface desc has LPSURFACE Flags set.\n");
+    color = surface_desc.lpSurface;
+    color[0] = 0x77010203;
+    color[1] = 0x00010203;
+    color[2] = 0x77ff00ff;
+    color[3] = 0x00ff00ff;
+    hr = IDirectDrawSurface7_Unlock(src, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    for (i = 0; i < 2; ++i)
+    {
+        hr = IDirectDrawSurface7_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        color = surface_desc.lpSurface;
+        color[0] = 0xcccccccc;
+        color[1] = 0xcccccccc;
+        color[2] = 0xcccccccc;
+        color[3] = 0xcccccccc;
+        hr = IDirectDrawSurface7_Unlock(dst, NULL);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+        if (i)
+        {
+            hr = IDirectDrawSurface7_BltFast(dst, 0, 0, src, NULL, DDBLTFAST_SRCCOLORKEY);
+            ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+        }
+        else
+        {
+            hr = IDirectDrawSurface7_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC, NULL);
+            ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+        }
+
+        hr = IDirectDrawSurface7_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT | DDLOCK_READONLY, NULL);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        ok(!(surface_desc.dwFlags & DDSD_LPSURFACE), "Surface desc has LPSURFACE Flags set.\n");
+        color = surface_desc.lpSurface;
+        /* Different behavior on some drivers / windows versions. Some versions ignore the X channel when
+         * color keying, but copy it to the destination surface. Others (sysmem surfaces) apply it for
+         * color keying, but do not copy it into the destination surface. Nvidia neither uses it for
+         * color keying nor copies it. */
+        ok((color[0] == 0x77010203 && color[1] == 0x00010203
+                && color[2] == 0xcccccccc && color[3] == 0xcccccccc) /* AMD, Wine */
+                || broken(color[0] == 0x00010203 && color[1] == 0x00010203
+                && color[2] == 0x00ff00ff && color[3] == 0xcccccccc) /* Sysmem surfaces? */
+                || broken(color[0] == 0x00010203 && color[1] == 0x00010203
+                && color[2] == 0xcccccccc && color[3] == 0xcccccccc) /* Nvidia */
+                || broken(color[0] == 0xff010203 && color[1] == 0xff010203
+                && color[2] == 0xcccccccc && color[3] == 0xcccccccc) /* Testbot */,
+                "Destination data after blitting is %08x %08x %08x %08x, i=%u.\n",
+                color[0], color[1], color[2], color[3], i);
+        hr = IDirectDrawSurface7_Unlock(dst, NULL);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+    }
+
+    hr = IDirectDrawSurface7_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x00ff00ff && ckey.dwColorSpaceHighValue == 0x00ff00ff,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x0000ff00;
+    hr = IDirectDrawSurface7_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface7_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x0000ff00 && ckey.dwColorSpaceHighValue == 0x0000ff00,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0;
+    surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface7_GetSurfaceDesc(src, &surface_desc);
+    ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
+    ok(surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue == 0x0000ff00
+            && surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue == 0x0000ff00,
+            "Got unexpected color key low=%08x high=%08x.\n", surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue,
+            surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue);
+
+    /* Test SetColorKey with dwColorSpaceHighValue < dwColorSpaceLowValue */
+    ckey.dwColorSpaceLowValue = 0x000000ff;
+    ckey.dwColorSpaceHighValue = 0x00000000;
+    hr = IDirectDrawSurface7_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface7_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x000000ff && ckey.dwColorSpaceHighValue == 0x000000ff,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    ckey.dwColorSpaceLowValue = 0x000000ff;
+    ckey.dwColorSpaceHighValue = 0x00000001;
+    hr = IDirectDrawSurface7_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface7_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x000000ff && ckey.dwColorSpaceHighValue == 0x000000ff,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    ckey.dwColorSpaceLowValue = 0x000000fe;
+    ckey.dwColorSpaceHighValue = 0x000000fd;
+    hr = IDirectDrawSurface7_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0;
+    hr = IDirectDrawSurface7_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to get color key, hr %#x.\n", hr);
+    ok(ckey.dwColorSpaceLowValue == 0x000000fe && ckey.dwColorSpaceHighValue == 0x000000fe,
+            "Got unexpected color key low=%08x high=%08x.\n", ckey.dwColorSpaceLowValue, ckey.dwColorSpaceHighValue);
+
+    IDirectDrawSurface7_Release(src);
+    IDirectDrawSurface7_Release(dst);
+
+    /* Test source and destination keys and where they are read from. Use a surface with alpha
+     * to avoid driver-dependent content in the X channel. */
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+    surface_desc.dwWidth = 6;
+    surface_desc.dwHeight = 1;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
+    U1(U4(surface_desc.ddpfPixelFormat)).dwRGBBitCount = 32;
+    U2(U4(surface_desc.ddpfPixelFormat)).dwRBitMask = 0x00ff0000;
+    U3(U4(surface_desc.ddpfPixelFormat)).dwGBitMask = 0x0000ff00;
+    U4(U4(surface_desc.ddpfPixelFormat)).dwBBitMask = 0x000000ff;
+    U5(U4(surface_desc.ddpfPixelFormat)).dwRGBAlphaBitMask = 0xff000000;
+    hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+    hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &src, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    ckey.dwColorSpaceLowValue = 0x0000ff00;
+    ckey.dwColorSpaceHighValue = 0x0000ff00;
+    hr = IDirectDrawSurface7_SetColorKey(dst, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+    ckey.dwColorSpaceLowValue = 0x00ff0000;
+    ckey.dwColorSpaceHighValue = 0x00ff0000;
+    hr = IDirectDrawSurface7_SetColorKey(dst, DDCKEY_DESTBLT, &ckey);
+    ok(SUCCEEDED(hr) || hr == DDERR_NOCOLORKEYHW, "Failed to set color key, hr %#x.\n", hr);
+    if (FAILED(hr))
+    {
+        /* Nvidia reject dest keys, AMD allows them. This applies to vidmem and sysmem surfaces. */
+        skip("Failed to set destination color key, skipping related tests.\n");
+        goto done;
+    }
+
+    ckey.dwColorSpaceLowValue = 0x000000ff;
+    ckey.dwColorSpaceHighValue = 0x000000ff;
+    hr = IDirectDrawSurface7_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+    ckey.dwColorSpaceLowValue = 0x000000aa;
+    ckey.dwColorSpaceHighValue = 0x000000aa;
+    hr = IDirectDrawSurface7_SetColorKey(src, DDCKEY_DESTBLT, &ckey);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    memset(&fx, 0, sizeof(fx));
+    fx.dwSize = sizeof(fx);
+    fx.ddckSrcColorkey.dwColorSpaceHighValue = 0x00110000;
+    fx.ddckSrcColorkey.dwColorSpaceLowValue = 0x00110000;
+    fx.ddckDestColorkey.dwColorSpaceHighValue = 0x00001100;
+    fx.ddckDestColorkey.dwColorSpaceLowValue = 0x00001100;
+
+    hr = IDirectDrawSurface7_Lock(src, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    color[0] = 0x000000ff; /* Applies to src blt key in src surface. */
+    color[1] = 0x000000aa; /* Applies to dst blt key in src surface. */
+    color[2] = 0x00ff0000; /* Dst color key in dst surface. */
+    color[3] = 0x0000ff00; /* Src color key in dst surface. */
+    color[4] = 0x00001100; /* Src color key in ddbltfx. */
+    color[5] = 0x00110000; /* Dst color key in ddbltfx. */
+    hr = IDirectDrawSurface7_Unlock(src, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface7_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
+    hr = IDirectDrawSurface7_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Test a blit without keying. */
+    hr = IDirectDrawSurface7_Blt(dst, NULL, src, NULL, 0, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface7_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Should have copied src data unmodified to dst. */
+    ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
+            color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x00110000,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
+    hr = IDirectDrawSurface7_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Src key. */
+    hr = IDirectDrawSurface7_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface7_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Src key applied to color[0]. It is unmodified, the others are copied. */
+    ok(color[0] == 0x55555555 && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
+            color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x00110000,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
+    hr = IDirectDrawSurface7_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Src override. */
+    hr = IDirectDrawSurface7_Blt(dst, NULL, src, NULL, DDBLT_KEYSRCOVERRIDE, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface7_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Override key applied to color[5]. It is unmodified, the others are copied. */
+    ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
+            color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x55555555,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = color[1] = color[2] = color[3] = color[4] = color[5] = 0x55555555;
+    hr = IDirectDrawSurface7_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Src override AND src key. That is not supposed to work. */
+    hr = IDirectDrawSurface7_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE, &fx);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface7_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Ensure the desination was not changed. */
+    ok(color[0] == 0x55555555 && color[1] == 0x55555555 && color[2] == 0x55555555 &&
+            color[3] == 0x55555555 && color[4] == 0x55555555 && color[5] == 0x55555555,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    /* Use different dst colors for the dst key test. */
+    color[0] = 0x00ff0000; /* Dest key in dst surface. */
+    color[1] = 0x00ff0000; /* Dest key in dst surface. */
+    color[2] = 0x00001100; /* Dest key in override. */
+    color[3] = 0x00001100; /* Dest key in override. */
+    color[4] = 0x000000aa; /* Dest key in src surface. */
+    color[5] = 0x000000aa; /* Dest key in src surface. */
+    hr = IDirectDrawSurface7_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Dest key blit. The key is taken from the DESTINATION surface in v7! */
+    hr = IDirectDrawSurface7_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface7_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Dst key applied to color[0,1], they are the only changed pixels. */
+    todo_wine ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00001100 &&
+            color[3] == 0x00001100 && color[4] == 0x000000aa && color[5] == 0x000000aa,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = 0x00ff0000; /* Dest key in dst surface. */
+    color[1] = 0x00ff0000; /* Dest key in dst surface. */
+    color[2] = 0x00001100; /* Dest key in override. */
+    color[3] = 0x00001100; /* Dest key in override. */
+    color[4] = 0x000000aa; /* Dest key in src surface. */
+    color[5] = 0x000000aa; /* Dest key in src surface. */
+    hr = IDirectDrawSurface7_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* What happens with a QI'd older version of the interface? It takes the key
+     * from the source surface. */
+    hr = IDirectDrawSurface7_QueryInterface(src, &IID_IDirectDrawSurface, (void **)&src1);
+    ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface interface, hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_QueryInterface(dst, &IID_IDirectDrawSurface, (void **)&dst1);
+    ok(SUCCEEDED(hr), "Failed to query IDirectDrawSurface interface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_Blt(dst1, NULL, src1, NULL, DDBLT_KEYDEST, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    IDirectDrawSurface_Release(dst1);
+    IDirectDrawSurface_Release(src1);
+
+    hr = IDirectDrawSurface7_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Dst key applied to color[4,5], they are the only changed pixels. */
+    ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00001100 &&
+            color[3] == 0x00001100 && color[4] == 0x00001100 && color[5] == 0x00110000,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = 0x00ff0000; /* Dest key in dst surface. */
+    color[1] = 0x00ff0000; /* Dest key in dst surface. */
+    color[2] = 0x00001100; /* Dest key in override. */
+    color[3] = 0x00001100; /* Dest key in override. */
+    color[4] = 0x000000aa; /* Dest key in src surface. */
+    color[5] = 0x000000aa; /* Dest key in src surface. */
+    hr = IDirectDrawSurface7_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Dest override key blit. */
+    hr = IDirectDrawSurface7_Blt(dst, NULL, src, NULL, DDBLT_KEYDESTOVERRIDE, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface7_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Dst key applied to color[2,3], they are the only changed pixels. */
+    ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00ff0000 &&
+            color[3] == 0x0000ff00 && color[4] == 0x000000aa && color[5] == 0x000000aa,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+
+    color[0] = 0x00ff0000; /* Dest key in dst surface. */
+    color[1] = 0x00ff0000; /* Dest key in dst surface. */
+    color[2] = 0x00001100; /* Dest key in override. */
+    color[3] = 0x00001100; /* Dest key in override. */
+    color[4] = 0x000000aa; /* Dest key in src surface. */
+    color[5] = 0x000000aa; /* Dest key in src surface. */
+    hr = IDirectDrawSurface7_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Dest override together with surface key. Supposed to fail. */
+    hr = IDirectDrawSurface7_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST | DDBLT_KEYDESTOVERRIDE, &fx);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface7_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Destination is unchanged. */
+    ok(color[0] == 0x00ff0000 && color[1] == 0x00ff0000 && color[2] == 0x00001100 &&
+            color[3] == 0x00001100 && color[4] == 0x000000aa && color[5] == 0x000000aa,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+    hr = IDirectDrawSurface7_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Source and destination key. This is driver dependent. New HW treats it like
+     * DDBLT_KEYSRC. Older HW and some software renderers apply both keys. */
+    if (0)
+    {
+        hr = IDirectDrawSurface7_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST | DDBLT_KEYSRC, &fx);
+        ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+        hr = IDirectDrawSurface7_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+        ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+        color = surface_desc.lpSurface;
+        /* Color[0] is filtered by the src key, 2-5 are filtered by the dst key, if
+         * the driver applies it. */
+        ok(color[0] == 0x00ff0000 && color[1] == 0x000000aa && color[2] == 0x00ff0000 &&
+                color[3] == 0x0000ff00 && color[4] == 0x00001100 && color[5] == 0x00110000,
+                "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+                color[0], color[1], color[2], color[3], color[4], color[5]);
+
+        color[0] = 0x00ff0000; /* Dest key in dst surface. */
+        color[1] = 0x00ff0000; /* Dest key in dst surface. */
+        color[2] = 0x00001100; /* Dest key in override. */
+        color[3] = 0x00001100; /* Dest key in override. */
+        color[4] = 0x000000aa; /* Dest key in src surface. */
+        color[5] = 0x000000aa; /* Dest key in src surface. */
+        hr = IDirectDrawSurface7_Unlock(dst, NULL);
+        ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+    }
+
+    /* Override keys without ddbltfx parameter fail */
+    hr = IDirectDrawSurface7_Blt(dst, NULL, src, NULL, DDBLT_KEYDESTOVERRIDE, NULL);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_Blt(dst, NULL, src, NULL, DDBLT_KEYSRCOVERRIDE, NULL);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+    /* Try blitting without keys in the source surface. */
+    hr = IDirectDrawSurface7_SetColorKey(src, DDCKEY_SRCBLT, NULL);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_SetColorKey(src, DDCKEY_DESTBLT, NULL);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    /* That fails now. Do not bother to check that the data is unmodified. */
+    hr = IDirectDrawSurface7_Blt(dst, NULL, src, NULL, DDBLT_KEYSRC, &fx);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+    /* Dest key blit still works, the destination surface key is used in v7. */
+    hr = IDirectDrawSurface7_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST, &fx);
+    ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface7_Lock(dst, NULL, &surface_desc, DDLOCK_WAIT, NULL);
+    ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
+    color = surface_desc.lpSurface;
+    /* Dst key applied to color[0,1], they are the only changed pixels. */
+    todo_wine ok(color[0] == 0x000000ff && color[1] == 0x000000aa && color[2] == 0x00001100 &&
+            color[3] == 0x00001100 && color[4] == 0x000000aa && color[5] == 0x000000aa,
+            "Got unexpected content %08x %08x %08x %08x %08x %08x.\n",
+            color[0], color[1], color[2], color[3], color[4], color[5]);
+    hr = IDirectDrawSurface7_Unlock(dst, NULL);
+    ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
+
+    /* Try blitting without keys in the destination surface. */
+    hr = IDirectDrawSurface7_SetColorKey(dst, DDCKEY_SRCBLT, NULL);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_SetColorKey(dst, DDCKEY_DESTBLT, NULL);
+    ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
+
+    /* This fails, as sanity would dictate. */
+    hr = IDirectDrawSurface7_Blt(dst, NULL, src, NULL, DDBLT_KEYDEST, &fx);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+done:
+    IDirectDrawSurface7_Release(src);
+    IDirectDrawSurface7_Release(dst);
+    refcount = IDirectDraw7_Release(ddraw);
+    ok(!refcount, "DirectDraw has %u references left.\n", refcount);
+    DestroyWindow(window);
+}
+
 START_TEST(ddraw7)
 {
     HMODULE module = GetModuleHandleA("ddraw.dll");
@@ -12673,4 +13140,5 @@ START_TEST(ddraw7)
     test_display_mode_surface_pixel_format();
     test_surface_desc_size();
     test_get_surface_from_dc();
+    test_ck_operation();
 }
diff --git a/dlls/ddraw/tests/dsurface.c b/dlls/ddraw/tests/dsurface.c
index 6ecf7fe..9e02295 100644
--- a/dlls/ddraw/tests/dsurface.c
+++ b/dlls/ddraw/tests/dsurface.c
@@ -61,515 +61,6 @@ static void ReleaseDirectDraw(void)
     }
 }
 
-static void SrcColorKey32BlitTest(void)
-{
-    IDirectDrawSurface *lpSrc;
-    IDirectDrawSurface *lpDst;
-    DDSURFACEDESC ddsd, ddsd2;
-    DDCOLORKEY DDColorKey;
-    LPDWORD lpData;
-    HRESULT rc;
-    DDBLTFX fx;
-
-    ddsd2.dwSize = sizeof(ddsd2);
-    ddsd2.ddpfPixelFormat.dwSize = sizeof(ddsd2.ddpfPixelFormat);
-
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
-    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
-    ddsd.dwWidth = 800;
-    ddsd.dwHeight = 600;
-    ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
-    U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
-    U2(ddsd.ddpfPixelFormat).dwRBitMask = 0xFF0000;
-    U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x00FF00;
-    U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x0000FF;
-    rc = IDirectDraw_CreateSurface(lpDD, &ddsd, &lpDst, NULL);
-    ok(rc==DD_OK,"CreateSurface returned: %x\n",rc);
-    if (FAILED(rc))
-    {
-        skip("failed to create surface\n");
-        return;
-    }
-
-    ddsd.dwFlags |= DDSD_CKSRCBLT;
-    ddsd.ddckCKSrcBlt.dwColorSpaceLowValue = 0xFF00FF;
-    ddsd.ddckCKSrcBlt.dwColorSpaceHighValue = 0xFF00FF;
-    rc = IDirectDraw_CreateSurface(lpDD, &ddsd, &lpSrc, NULL);
-    ok(rc==DD_OK,"CreateSurface returned: %x\n",rc);
-    if (FAILED(rc))
-    {
-        skip("failed to create surface\n");
-        return;
-    }
-
-    rc = IDirectDrawSurface_Lock(lpDst, NULL, &ddsd2, DDLOCK_WAIT, NULL);
-    ok(rc==DD_OK,"Lock returned: %x\n",rc);
-    lpData = ddsd2.lpSurface;
-    lpData[0] = 0xCCCCCCCC;
-    lpData[1] = 0xCCCCCCCC;
-    lpData[2] = 0xCCCCCCCC;
-    lpData[3] = 0xCCCCCCCC;
-
-    rc = IDirectDrawSurface_Unlock(lpDst, NULL);
-    ok(rc==DD_OK,"Unlock returned: %x\n",rc);
-
-    rc = IDirectDrawSurface_Lock(lpSrc, NULL, &ddsd2, DDLOCK_WAIT, NULL);
-    ok(rc==DD_OK,"Lock returned: %x\n",rc);
-    ok((ddsd2.dwFlags & DDSD_LPSURFACE) == 0, "Surface desc has LPSURFACE Flags set\n");
-    lpData = ddsd2.lpSurface;
-    lpData[0] = 0x77010203;
-    lpData[1] = 0x00010203;
-    lpData[2] = 0x77FF00FF;
-    lpData[3] = 0x00FF00FF;
-    rc = IDirectDrawSurface_Unlock(lpSrc, NULL);
-    ok(rc==DD_OK,"Unlock returned: %x\n",rc);
-
-    IDirectDrawSurface_Blt(lpDst, NULL, lpSrc, NULL, DDBLT_KEYSRC, NULL);
-
-    rc = IDirectDrawSurface_Lock(lpDst, NULL, &ddsd2, DDLOCK_WAIT, NULL);
-    ok(rc==DD_OK,"Lock returned: %x\n",rc);
-    ok((ddsd2.dwFlags & DDSD_LPSURFACE) == 0, "Surface desc has LPSURFACE Flags set\n");
-    lpData = ddsd2.lpSurface;
-    /* Different behavior on some drivers / windows versions. Some versions ignore the X channel when
-     * color keying, but copy it to the destination surface. Others apply it for color keying, but
-     * do not copy it into the destination surface.
-     */
-    if(lpData[0]==0x00010203) {
-        trace("X channel was not copied into the destination surface\n");
-        ok((lpData[0]==0x00010203)&&(lpData[1]==0x00010203)&&(lpData[2]==0x00FF00FF)&&(lpData[3]==0xCCCCCCCC),
-           "Destination data after blitting is not correct\n");
-    } else {
-        ok((lpData[0]==0x77010203)&&(lpData[1]==0x00010203)&&(lpData[2]==0xCCCCCCCC)&&(lpData[3]==0xCCCCCCCC),
-           "Destination data after blitting is not correct\n");
-    }
-    rc = IDirectDrawSurface_Unlock(lpDst, NULL);
-    ok(rc==DD_OK,"Unlock returned: %x\n",rc);
-
-    /* Below we repeat the same test as above but now using BltFast instead of Blt. Before
-     * we can carry out the test we need to restore the color of the destination surface.
-     */
-    rc = IDirectDrawSurface_Lock(lpDst, NULL, &ddsd2, DDLOCK_WAIT, NULL);
-    ok(rc==DD_OK,"Lock returned: %x\n",rc);
-    lpData = ddsd2.lpSurface;
-    lpData[0] = 0xCCCCCCCC;
-    lpData[1] = 0xCCCCCCCC;
-    lpData[2] = 0xCCCCCCCC;
-    lpData[3] = 0xCCCCCCCC;
-    rc = IDirectDrawSurface_Unlock(lpDst, NULL);
-    ok(rc==DD_OK,"Unlock returned: %x\n",rc);
-
-    IDirectDrawSurface_BltFast(lpDst, 0, 0, lpSrc, NULL, DDBLTFAST_SRCCOLORKEY);
-
-    rc = IDirectDrawSurface_Lock(lpDst, NULL, &ddsd2, DDLOCK_WAIT, NULL);
-    ok(rc==DD_OK,"Lock returned: %x\n",rc);
-    ok((ddsd2.dwFlags & DDSD_LPSURFACE) == 0, "Surface desc has LPSURFACE Flags set\n");
-    lpData = ddsd2.lpSurface;
-    /* Different behavior on some drivers / windows versions. Some versions ignore the X channel when
-     * color keying, but copy it to the destination surface. Others apply it for color keying, but
-     * do not copy it into the destination surface.
-     */
-    if(lpData[0]==0x00010203) {
-        trace("X channel was not copied into the destination surface\n");
-        ok((lpData[0]==0x00010203)&&(lpData[1]==0x00010203)&&(lpData[2]==0x00FF00FF)&&(lpData[3]==0xCCCCCCCC),
-           "Destination data after blitting is not correct\n");
-    } else {
-        ok((lpData[0]==0x77010203)&&(lpData[1]==0x00010203)&&(lpData[2]==0xCCCCCCCC)&&(lpData[3]==0xCCCCCCCC),
-           "Destination data after blitting is not correct\n");
-    }
-    rc = IDirectDrawSurface_Unlock(lpDst, NULL);
-    ok(rc==DD_OK,"Unlock returned: %x\n",rc);
-
-    /* Also test SetColorKey */
-    IDirectDrawSurface_GetColorKey(lpSrc, DDCKEY_SRCBLT, &DDColorKey);
-    ok(DDColorKey.dwColorSpaceLowValue == 0xFF00FF && DDColorKey.dwColorSpaceHighValue == 0xFF00FF,
-       "GetColorKey does not return the colorkey used at surface creation\n");
-
-    DDColorKey.dwColorSpaceLowValue = 0x00FF00;
-    DDColorKey.dwColorSpaceHighValue = 0x00FF00;
-    IDirectDrawSurface_SetColorKey(lpSrc, DDCKEY_SRCBLT, &DDColorKey);
-
-    DDColorKey.dwColorSpaceLowValue = 0;
-    DDColorKey.dwColorSpaceHighValue = 0;
-    IDirectDrawSurface_GetColorKey(lpSrc, DDCKEY_SRCBLT, &DDColorKey);
-    ok(DDColorKey.dwColorSpaceLowValue == 0x00FF00 && DDColorKey.dwColorSpaceHighValue == 0x00FF00,
-       "GetColorKey does not return the colorkey set with SetColorKey\n");
-
-    ddsd.ddckCKSrcBlt.dwColorSpaceLowValue = 0;
-    ddsd.ddckCKSrcBlt.dwColorSpaceHighValue = 0;
-    IDirectDrawSurface_GetSurfaceDesc(lpSrc, &ddsd);
-    ok(ddsd.ddckCKSrcBlt.dwColorSpaceLowValue == 0x00FF00 && ddsd.ddckCKSrcBlt.dwColorSpaceHighValue == 0x00FF00,
-       "GetSurfaceDesc does not return the colorkey set with SetColorKey\n");
-
-    /* Test SetColorKey with dwColorSpaceHighValue < dwColorSpaceLowValue */
-    DDColorKey.dwColorSpaceLowValue = 0x0000FF;
-    DDColorKey.dwColorSpaceHighValue = 0x000000;
-    IDirectDrawSurface_SetColorKey(lpSrc, DDCKEY_SRCBLT, &DDColorKey);
-
-    DDColorKey.dwColorSpaceLowValue = 0;
-    DDColorKey.dwColorSpaceHighValue = 0;
-    IDirectDrawSurface_GetColorKey(lpSrc, DDCKEY_SRCBLT, &DDColorKey);
-    ok(DDColorKey.dwColorSpaceLowValue == 0x0000FF && DDColorKey.dwColorSpaceHighValue == 0x0000FF,
-       "GetColorKey does not return the colorkey set with SetColorKey (%x %x)\n", DDColorKey.dwColorSpaceLowValue, DDColorKey.dwColorSpaceHighValue);
-
-    DDColorKey.dwColorSpaceLowValue = 0x0000FF;
-    DDColorKey.dwColorSpaceHighValue = 0x000001;
-    IDirectDrawSurface_SetColorKey(lpSrc, DDCKEY_SRCBLT, &DDColorKey);
-
-    DDColorKey.dwColorSpaceLowValue = 0;
-    DDColorKey.dwColorSpaceHighValue = 0;
-    IDirectDrawSurface_GetColorKey(lpSrc, DDCKEY_SRCBLT, &DDColorKey);
-    ok(DDColorKey.dwColorSpaceLowValue == 0x0000FF && DDColorKey.dwColorSpaceHighValue == 0x0000FF,
-       "GetColorKey does not return the colorkey set with SetColorKey (%x %x)\n", DDColorKey.dwColorSpaceLowValue, DDColorKey.dwColorSpaceHighValue);
-
-    DDColorKey.dwColorSpaceLowValue = 0x0000FF;
-    DDColorKey.dwColorSpaceHighValue = 0x0000FE;
-    IDirectDrawSurface_SetColorKey(lpSrc, DDCKEY_SRCBLT, &DDColorKey);
-
-    DDColorKey.dwColorSpaceLowValue = 0;
-    DDColorKey.dwColorSpaceHighValue = 0;
-    IDirectDrawSurface_GetColorKey(lpSrc, DDCKEY_SRCBLT, &DDColorKey);
-    ok(DDColorKey.dwColorSpaceLowValue == 0x0000FF && DDColorKey.dwColorSpaceHighValue == 0x0000FF,
-       "GetColorKey does not return the colorkey set with SetColorKey (%x %x)\n", DDColorKey.dwColorSpaceLowValue, DDColorKey.dwColorSpaceHighValue);
-
-    IDirectDrawSurface_Release(lpSrc);
-    IDirectDrawSurface_Release(lpDst);
-
-    /* start with a new set of surfaces to test the color keying parameters to blit */
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
-    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT | DDSD_CKDESTBLT;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
-    ddsd.dwWidth = 800;
-    ddsd.dwHeight = 600;
-    ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
-    U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
-    U2(ddsd.ddpfPixelFormat).dwRBitMask = 0xFF0000;
-    U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x00FF00;
-    U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x0000FF;
-    ddsd.ddckCKDestBlt.dwColorSpaceLowValue = 0xFF0000;
-    ddsd.ddckCKDestBlt.dwColorSpaceHighValue = 0xFF0000;
-    ddsd.ddckCKSrcBlt.dwColorSpaceLowValue = 0x00FF00;
-    ddsd.ddckCKSrcBlt.dwColorSpaceHighValue = 0x00FF00;
-    rc = IDirectDraw_CreateSurface(lpDD, &ddsd, &lpDst, NULL);
-    ok(rc==DD_OK || rc == DDERR_NOCOLORKEYHW,"CreateSurface returned: %x\n",rc);
-    if(FAILED(rc))
-    {
-        skip("Failed to create surface\n");
-        return;
-    }
-
-    /* start with a new set of surfaces to test the color keying parameters to blit */
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
-    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT | DDSD_CKDESTBLT;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
-    ddsd.dwWidth = 800;
-    ddsd.dwHeight = 600;
-    ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
-    U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 32;
-    U2(ddsd.ddpfPixelFormat).dwRBitMask = 0xFF0000;
-    U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x00FF00;
-    U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x0000FF;
-    ddsd.ddckCKSrcBlt.dwColorSpaceLowValue = 0x0000FF;
-    ddsd.ddckCKSrcBlt.dwColorSpaceHighValue = 0x0000FF;
-    ddsd.ddckCKDestBlt.dwColorSpaceLowValue = 0x000000;
-    ddsd.ddckCKDestBlt.dwColorSpaceHighValue = 0x000000;
-    rc = IDirectDraw_CreateSurface(lpDD, &ddsd, &lpSrc, NULL);
-    ok(rc==DD_OK || rc == DDERR_NOCOLORKEYHW,"CreateSurface returned: %x\n",rc);
-    if(FAILED(rc))
-    {
-        skip("Failed to create surface\n");
-        IDirectDrawSurface_Release(lpDst);
-        return;
-    }
-
-    memset(&fx, 0, sizeof(fx));
-    fx.dwSize = sizeof(fx);
-    fx.ddckSrcColorkey.dwColorSpaceHighValue = 0x110000;
-    fx.ddckSrcColorkey.dwColorSpaceLowValue = 0x110000;
-    fx.ddckDestColorkey.dwColorSpaceHighValue = 0x001100;
-    fx.ddckDestColorkey.dwColorSpaceLowValue = 0x001100;
-
-    rc = IDirectDrawSurface_Lock(lpSrc, NULL, &ddsd2, DDLOCK_WAIT, NULL);
-    ok(rc==DD_OK,"Lock returned: %x\n",rc);
-    ok((ddsd2.dwFlags & DDSD_LPSURFACE) == 0, "Surface desc has LPSURFACE Flags set\n");
-    lpData = ddsd2.lpSurface;
-    lpData[0] = 0x000000FF; /* Applies to src blt key in src surface */
-    lpData[1] = 0x00000000; /* Applies to dst blt key in src surface */
-    lpData[2] = 0x00FF0000; /* Dst color key in dst surface */
-    lpData[3] = 0x0000FF00; /* Src color key in dst surface */
-    lpData[4] = 0x00001100; /* Src color key in ddbltfx */
-    lpData[5] = 0x00110000; /* Dst color key in ddbltfx */
-    rc = IDirectDrawSurface_Unlock(lpSrc, NULL);
-    ok(rc==DD_OK,"Unlock returned: %x\n",rc);
-
-    rc = IDirectDrawSurface_Lock(lpDst, NULL, &ddsd2, DDLOCK_WAIT, NULL);
-    ok(rc==DD_OK,"Lock returned: %x\n",rc);
-    ok((ddsd2.dwFlags & DDSD_LPSURFACE) == 0, "Surface desc has LPSURFACE Flags set\n");
-    lpData = ddsd2.lpSurface;
-    lpData[0] = 0x55555555;
-    lpData[1] = 0x55555555;
-    lpData[2] = 0x55555555;
-    lpData[3] = 0x55555555;
-    lpData[4] = 0x55555555;
-    lpData[5] = 0x55555555;
-    rc = IDirectDrawSurface_Unlock(lpDst, NULL);
-    ok(rc==DD_OK,"Unlock returned: %x\n",rc);
-
-    /* Test a blit without keying */
-    rc = IDirectDrawSurface_Blt(lpDst, NULL, lpSrc, NULL, 0, &fx);
-    ok(rc == DD_OK, "IDirectDrawSurface_Blt returned %08x\n", rc);
-
-    rc = IDirectDrawSurface_Lock(lpDst, NULL, &ddsd2, DDLOCK_WAIT, NULL);
-    ok(rc==DD_OK,"Lock returned: %x\n",rc);
-    ok((ddsd2.dwFlags & DDSD_LPSURFACE) == 0, "Surface desc has LPSURFACE Flags set\n");
-    lpData = ddsd2.lpSurface;
-    /* Should have copied src data unmodified to dst */
-    ok(lpData[0] == 0x000000FF &&
-       lpData[1] == 0x00000000 &&
-       lpData[2] == 0x00FF0000 &&
-       lpData[3] == 0x0000FF00 &&
-       lpData[4] == 0x00001100 &&
-       lpData[5] == 0x00110000, "Surface data after unkeyed blit does not match\n");
-
-    lpData[0] = 0x55555555;
-    lpData[1] = 0x55555555;
-    lpData[2] = 0x55555555;
-    lpData[3] = 0x55555555;
-    lpData[4] = 0x55555555;
-    lpData[5] = 0x55555555;
-    rc = IDirectDrawSurface_Unlock(lpDst, NULL);
-    ok(rc==DD_OK,"Unlock returned: %x\n",rc);
-
-    /* Src key */
-    rc = IDirectDrawSurface_Blt(lpDst, NULL, lpSrc, NULL, DDBLT_KEYSRC, &fx);
-    ok(rc == DD_OK, "IDirectDrawSurface_Blt returned %08x\n", rc);
-
-    rc = IDirectDrawSurface_Lock(lpDst, NULL, &ddsd2, DDLOCK_WAIT, NULL);
-    ok(rc==DD_OK,"Lock returned: %x\n",rc);
-    ok((ddsd2.dwFlags & DDSD_LPSURFACE) == 0, "Surface desc has LPSURFACE Flags set\n");
-    lpData = ddsd2.lpSurface;
-
-    ok(lpData[0] == 0x55555555 && /* Here the src key applied */
-       lpData[1] == 0x00000000 &&
-       lpData[2] == 0x00FF0000 &&
-       lpData[3] == 0x0000FF00 &&
-       lpData[4] == 0x00001100 &&
-       lpData[5] == 0x00110000, "Surface data after srckey blit does not match\n");
-
-    lpData[0] = 0x55555555;
-    lpData[1] = 0x55555555;
-    lpData[2] = 0x55555555;
-    lpData[3] = 0x55555555;
-    lpData[4] = 0x55555555;
-    lpData[5] = 0x55555555;
-    rc = IDirectDrawSurface_Unlock(lpDst, NULL);
-    ok(rc==DD_OK,"Unlock returned: %x\n",rc);
-
-    /* Src override */
-    rc = IDirectDrawSurface_Blt(lpDst, NULL, lpSrc, NULL, DDBLT_KEYSRCOVERRIDE, &fx);
-    ok(rc == DD_OK, "IDirectDrawSurface_Blt returned %08x\n", rc);
-
-    rc = IDirectDrawSurface_Lock(lpDst, NULL, &ddsd2, DDLOCK_WAIT, NULL);
-    ok(rc==DD_OK,"Lock returned: %x\n",rc);
-    ok((ddsd2.dwFlags & DDSD_LPSURFACE) == 0, "Surface desc has LPSURFACE Flags set\n");
-    lpData = ddsd2.lpSurface;
-
-    ok(lpData[0] == 0x000000FF &&
-       lpData[1] == 0x00000000 &&
-       lpData[2] == 0x00FF0000 &&
-       lpData[3] == 0x0000FF00 &&
-       lpData[4] == 0x00001100 &&
-       lpData[5] == 0x55555555, /* Override key applies here */
-       "Surface data after src override key blit does not match\n");
-
-    lpData[0] = 0x55555555;
-    lpData[1] = 0x55555555;
-    lpData[2] = 0x55555555;
-    lpData[3] = 0x55555555;
-    lpData[4] = 0x55555555;
-    lpData[5] = 0x55555555;
-    rc = IDirectDrawSurface_Unlock(lpDst, NULL);
-    ok(rc==DD_OK,"Unlock returned: %x\n",rc);
-
-    /* Src override AND src key. That is not supposed to work */
-    rc = IDirectDrawSurface_Blt(lpDst, NULL, lpSrc, NULL, DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE, &fx);
-    ok(rc == DDERR_INVALIDPARAMS, "IDirectDrawSurface_Blt returned %08x\n", rc);
-
-    /* Verify that the destination is unchanged */
-    rc = IDirectDrawSurface_Lock(lpDst, NULL, &ddsd2, DDLOCK_WAIT, NULL);
-    ok(rc==DD_OK,"Lock returned: %x\n",rc);
-    ok((ddsd2.dwFlags & DDSD_LPSURFACE) == 0, "Surface desc has LPSURFACE Flags set\n");
-    lpData = ddsd2.lpSurface;
-
-    ok(lpData[0] == 0x55555555 &&
-       lpData[1] == 0x55555555 &&
-       lpData[2] == 0x55555555 &&
-       lpData[3] == 0x55555555 &&
-       lpData[4] == 0x55555555 &&
-       lpData[5] == 0x55555555, /* Override key applies here */
-       "Surface data after src key blit with override does not match\n");
-
-    lpData[0] = 0x00FF0000; /* Dest key in dst surface */
-    lpData[1] = 0x00FF0000; /* Dest key in dst surface */
-    lpData[2] = 0x00001100; /* Dest key in override */
-    lpData[3] = 0x00001100; /* Dest key in override */
-    lpData[4] = 0x00000000; /* Dest key in src surface */
-    lpData[5] = 0x00000000; /* Dest key in src surface */
-    rc = IDirectDrawSurface_Unlock(lpDst, NULL);
-    ok(rc==DD_OK,"Unlock returned: %x\n",rc);
-
-    /* Dest key blit */
-    rc = IDirectDrawSurface_Blt(lpDst, NULL, lpSrc, NULL, DDBLT_KEYDEST, &fx);
-    ok(rc == DD_OK, "IDirectDrawSurface_Blt returned %08x\n", rc);
-
-    rc = IDirectDrawSurface_Lock(lpDst, NULL, &ddsd2, DDLOCK_WAIT, NULL);
-    ok(rc==DD_OK,"Lock returned: %x\n",rc);
-    ok((ddsd2.dwFlags & DDSD_LPSURFACE) == 0, "Surface desc has LPSURFACE Flags set\n");
-    lpData = ddsd2.lpSurface;
-
-    /* DirectDraw uses the dest blit key from the SOURCE surface ! */
-    ok(lpData[0] == 0x00ff0000 &&
-       lpData[1] == 0x00ff0000 &&
-       lpData[2] == 0x00001100 &&
-       lpData[3] == 0x00001100 &&
-       lpData[4] == 0x00001100 && /* Key applies here */
-       lpData[5] == 0x00110000,   /* Key applies here */
-       "Surface data after dest key blit does not match\n");
-
-    lpData[0] = 0x00FF0000; /* Dest key in dst surface */
-    lpData[1] = 0x00FF0000; /* Dest key in dst surface */
-    lpData[2] = 0x00001100; /* Dest key in override */
-    lpData[3] = 0x00001100; /* Dest key in override */
-    lpData[4] = 0x00000000; /* Dest key in src surface */
-    lpData[5] = 0x00000000; /* Dest key in src surface */
-    rc = IDirectDrawSurface_Unlock(lpDst, NULL);
-    ok(rc==DD_OK,"Unlock returned: %x\n",rc);
-
-    /* Dest override key blit */
-    rc = IDirectDrawSurface_Blt(lpDst, NULL, lpSrc, NULL, DDBLT_KEYDESTOVERRIDE, &fx);
-    ok(rc == DD_OK, "IDirectDrawSurface_Blt returned %08x\n", rc);
-
-    rc = IDirectDrawSurface_Lock(lpDst, NULL, &ddsd2, DDLOCK_WAIT, NULL);
-    ok(rc==DD_OK,"Lock returned: %x\n",rc);
-    ok((ddsd2.dwFlags & DDSD_LPSURFACE) == 0, "Surface desc has LPSURFACE Flags set\n");
-    lpData = ddsd2.lpSurface;
-
-    ok(lpData[0] == 0x00FF0000 &&
-       lpData[1] == 0x00FF0000 &&
-       lpData[2] == 0x00FF0000 && /* Key applies here */
-       lpData[3] == 0x0000FF00 && /* Key applies here */
-       lpData[4] == 0x00000000 &&
-       lpData[5] == 0x00000000,
-       "Surface data after dest key override blit does not match\n");
-
-    lpData[0] = 0x00FF0000; /* Dest key in dst surface */
-    lpData[1] = 0x00FF0000; /* Dest key in dst surface */
-    lpData[2] = 0x00001100; /* Dest key in override */
-    lpData[3] = 0x00001100; /* Dest key in override */
-    lpData[4] = 0x00000000; /* Dest key in src surface */
-    lpData[5] = 0x00000000; /* Dest key in src surface */
-    rc = IDirectDrawSurface_Unlock(lpDst, NULL);
-    ok(rc==DD_OK,"Unlock returned: %x\n",rc);
-
-    /* Dest override key blit. Supposed to fail too */
-    rc = IDirectDrawSurface_Blt(lpDst, NULL, lpSrc, NULL, DDBLT_KEYDEST | DDBLT_KEYDESTOVERRIDE, &fx);
-    ok(rc == DDERR_INVALIDPARAMS, "IDirectDrawSurface_Blt returned %08x\n", rc);
-
-    /* Check for unchanged data */
-    rc = IDirectDrawSurface_Lock(lpDst, NULL, &ddsd2, DDLOCK_WAIT, NULL);
-    ok(rc==DD_OK,"Lock returned: %x\n",rc);
-    ok((ddsd2.dwFlags & DDSD_LPSURFACE) == 0, "Surface desc has LPSURFACE Flags set\n");
-    lpData = ddsd2.lpSurface;
-
-    ok(lpData[0] == 0x00FF0000 &&
-       lpData[1] == 0x00FF0000 &&
-       lpData[2] == 0x00001100 && /* Key applies here */
-       lpData[3] == 0x00001100 && /* Key applies here */
-       lpData[4] == 0x00000000 &&
-       lpData[5] == 0x00000000,
-       "Surface data with dest key and dest override does not match\n");
-
-    lpData[0] = 0x00FF0000; /* Dest key in dst surface */
-    lpData[1] = 0x00FF0000; /* Dest key in dst surface */
-    lpData[2] = 0x00001100; /* Dest key in override */
-    lpData[3] = 0x00001100; /* Dest key in override */
-    lpData[4] = 0x00000000; /* Dest key in src surface */
-    lpData[5] = 0x00000000; /* Dest key in src surface */
-    rc = IDirectDrawSurface_Unlock(lpDst, NULL);
-    ok(rc==DD_OK,"Unlock returned: %x\n",rc);
-
-    /* Modify the source data a bit to give some more conclusive results */
-    rc = IDirectDrawSurface_Lock(lpSrc, NULL, &ddsd2, DDLOCK_WAIT, NULL);
-    ok(rc==DD_OK,"Lock returned: %x\n",rc);
-    ok((ddsd2.dwFlags & DDSD_LPSURFACE) == 0, "Surface desc has LPSURFACE Flags set\n");
-    lpData = ddsd2.lpSurface;
-    lpData[5] = 0x000000FF; /* Applies to src blt key in src surface */
-    rc = IDirectDrawSurface_Unlock(lpSrc, NULL);
-    ok(rc==DD_OK,"Unlock returned: %x\n",rc);
-
-    /* Source and destination key */
-    rc = IDirectDrawSurface_Blt(lpDst, NULL, lpSrc, NULL, DDBLT_KEYDEST | DDBLT_KEYSRC, &fx);
-    ok(rc == DD_OK, "IDirectDrawSurface_Blt returned %08x\n", rc);
-
-    rc = IDirectDrawSurface_Lock(lpDst, NULL, &ddsd2, DDLOCK_WAIT, NULL);
-    ok(rc==DD_OK,"Lock returned: %x\n",rc);
-    ok((ddsd2.dwFlags & DDSD_LPSURFACE) == 0, "Surface desc has LPSURFACE Flags set\n");
-    lpData = ddsd2.lpSurface;
-
-    ok(lpData[0] == 0x00FF0000 && /* Masked by Destination key */
-       lpData[1] == 0x00FF0000 && /* Masked by Destination key */
-       lpData[2] == 0x00001100 && /* Masked by Destination key */
-       lpData[3] == 0x00001100 && /* Masked by Destination key */
-       lpData[4] == 0x00001100 && /* Allowed by destination key, not masked by source key */
-       lpData[5] == 0x00000000,   /* Allowed by dst key, but masked by source key */
-       "Surface data with src key and dest key blit does not match\n");
-
-    lpData[0] = 0x00FF0000; /* Dest key in dst surface */
-    lpData[1] = 0x00FF0000; /* Dest key in dst surface */
-    lpData[2] = 0x00001100; /* Dest key in override */
-    lpData[3] = 0x00001100; /* Dest key in override */
-    lpData[4] = 0x00000000; /* Dest key in src surface */
-    lpData[5] = 0x00000000; /* Dest key in src surface */
-    rc = IDirectDrawSurface_Unlock(lpDst, NULL);
-    ok(rc==DD_OK,"Unlock returned: %x\n",rc);
-
-    /* Override keys without ddbltfx parameter fail */
-    rc = IDirectDrawSurface_Blt(lpDst, NULL, lpSrc, NULL, DDBLT_KEYDESTOVERRIDE, NULL);
-    ok(rc == DDERR_INVALIDPARAMS, "IDirectDrawSurface_Blt returned %08x\n", rc);
-    rc = IDirectDrawSurface_Blt(lpDst, NULL, lpSrc, NULL, DDBLT_KEYSRCOVERRIDE, NULL);
-    ok(rc == DDERR_INVALIDPARAMS, "IDirectDrawSurface_Blt returned %08x\n", rc);
-
-    /* Try blitting without keys in the source surface*/
-    rc = IDirectDrawSurface_SetColorKey(lpSrc, DDCKEY_SRCBLT, NULL);
-    ok(rc == DD_OK, "SetColorKey returned %x\n", rc);
-    rc = IDirectDrawSurface_SetColorKey(lpSrc, DDCKEY_DESTBLT, NULL);
-    ok(rc == DD_OK, "SetColorKey returned %x\n", rc);
-
-    /* That fails now. Do not bother to check that the data is unmodified */
-    rc = IDirectDrawSurface_Blt(lpDst, NULL, lpSrc, NULL, DDBLT_KEYSRC, &fx);
-    ok(rc == DDERR_INVALIDPARAMS, "IDirectDrawSurface_Blt returned %08x\n", rc);
-
-    /* Dest key blit still works. Which key is used this time??? */
-    rc = IDirectDrawSurface_Blt(lpDst, NULL, lpSrc, NULL, DDBLT_KEYDEST, &fx);
-    ok(rc == DD_OK, "IDirectDrawSurface_Blt returned %08x\n", rc);
-
-    /* With correctly passed override keys no key in the surface is needed.
-     * Again, the result was checked before, no need to do that again
-     */
-    rc = IDirectDrawSurface_Blt(lpDst, NULL, lpSrc, NULL, DDBLT_KEYDESTOVERRIDE, &fx);
-    ok(rc == DD_OK, "IDirectDrawSurface_Blt returned %08x\n", rc);
-    rc = IDirectDrawSurface_Blt(lpDst, NULL, lpSrc, NULL, DDBLT_KEYSRCOVERRIDE, &fx);
-    ok(rc == DD_OK, "IDirectDrawSurface_Blt returned %08x\n", rc);
-
-    IDirectDrawSurface_Release(lpSrc);
-    IDirectDrawSurface_Release(lpDst);
-}
-
 static void QueryInterface(void)
 {
     IDirectDrawSurface *dsurface;
@@ -3141,7 +2632,6 @@ START_TEST(dsurface)
         return;
     }
 
-    SrcColorKey32BlitTest();
     QueryInterface();
     GetDDInterface_1();
     GetDDInterface_2();
-- 
2.10.2




More information about the wine-patches mailing list