// F10 — Pointer: relative motion, lock & confine, Win32 implementation
// (../../../features/f10-pointer-capture.md). Extends the scaffold
// (../scaffold/app.d) into a raw-input / ClipCursor observatory:
//
// * RegisterRawInputDevices(usage 1:2, RIDEV_INPUTSINK, hwndTarget) feeds
// WM_INPUT; every RAWMOUSE is logged with lLastX/lLastY and the
// MOUSE_MOVE_RELATIVE vs MOUSE_MOVE_ABSOLUTE flag, alongside the cooked
// WM_MOUSEMOVE stream — so injected motion can be diffed raw-vs-cooked.
// GetRegisteredRawInputDevices reads the registration back.
// * Pointer "lock" is the classic Win32 assembly: GetCursorPos (save) →
// ClipCursor(1×1 rect at the window center) → ShowCursor(FALSE); unlock
// reverses it and SetCursorPos-restores the saved position. The
// ShowCursor display COUNTER (not a flag) is probed explicitly: two
// ShowCursor(FALSE) need two ShowCursor(TRUE).
// * Confine: ClipCursor(center-half-of-window rect), clamping proved by
// SetCursorPos requests outside the rect + GetCursorPos read-back, and a
// huge injected relative move. GetClipCursor read-back after every change.
// Headless-reachable auto-clear probes: focus loss to a second window and
// SW_MINIMIZE, each followed by GetClipCursor.
// * Motion is driven in-process (winewayland has no external warp tool):
// SetCursorPos absolute warps, SendInput MOUSEEVENTF_MOVE relative
// injection, and one legacy mouse_event call. Pointer-ballistics state is
// logged via SystemParametersInfoW SPI_GETMOUSE / SPI_GETMOUSESPEED.
// * Interactive mode (no WSI_AUTO_EXIT): L toggles mouselook, C toggles
// confine; a crosshair displaced by the accumulated raw deltas (yaw/pitch)
// visualizes mouselook.
//
// WSI_AUTO_EXIT=1 bounds the run (~2 s); exit 0 in all modes.
//
// Only druntime's built-in core.sys.windows bindings — no third-party packages.
module (module) appapp;
import (package) corecore.(package) core.syssys.(package) core.sys.windowswindows.(module) core.sys.windows.windowsWindows API header module
Translated from MinGW API for MS-Windows 4.0
Source
core/sys/windows/windows.d
windows;
import instrument;
// ---------------------------------------------------------------------------
// Demo state.
enum UINT_PTR (constant) _error_ app.TIMER_ID = __errorTIMER_ID = 1;
enum (constant) int app.TICK_MS = 16TICK_MS = 16;
struct (struct) app.DemoDemo
{
HDC (field) _error_ app.Demo.memDcmemDc;
HBITMAP (field) _error_ app.Demo.dibdib, (field) _error_ app.Demo.stockBmpstockBmp;
uint* (field) uint* app.Demo.pixelspixels;
int (field) int app.Demo.widthwidth, (field) int app.Demo.heightheight;
uint (field) uint app.Demo.frameframe, (field) uint app.Demo.ticksticks;
HWND (field) _error_ app.Demo.hwndhwnd; // the main window
HWND (field) _error_ app.Demo.otherother; // focus-loss probe target
bool (field) bool app.Demo.autoExitautoExit;
bool (field) bool app.Demo.lockedlocked, (field) bool app.Demo.confinedconfined;
POINT (field) _error_ app.Demo.savedPossavedPos; // cursor position at lock time (restored on unlock)
POINT (field) _error_ app.Demo.pinPospinPos; // where the 1x1 lock rect pins the cursor
int (field) int app.Demo.yawyaw, (field) int app.Demo.pitchpitch; // accumulated raw deltas while locked (crosshair readout)
uint (field) uint app.Demo.nMouseMovenMouseMove, (field) uint app.Demo.nInputnInput;
}
__gshared (struct) app.DemoDemo _error_ app.gg;
// ---------------------------------------------------------------------------
// Probes.
void void app.probeAccelState() nothrowprobeAccelState() nothrow
{
int[3] (local variable) int[3] mousemouse; // [xThreshold, yThreshold, accelOn]
int (local variable) int speedspeed;
const (local variable) const(_error_) okMokM = SystemParametersInfoW(SPI_GETMOUSE, 0, mouse.ptr, 0);
const (local variable) const(_error_) okSokS = SystemParametersInfoW(SPI_GETMOUSESPEED, 0, &speed, 0);
logEvent("accel_state spi_getmouse=%d,%d,%d ok=%d speed=%d ok=%d",
mouse[0], mouse[1], mouse[2], okM, speed, okS);
}
// ShowCursor maintains a per-input-desktop display COUNTER, not a flag: the
// cursor is shown while the counter is >= 0. Two hides need two shows.
void void app.probeShowCursorCounter() nothrowprobeShowCursorCounter() nothrow
{
const (local variable) const(_error_) h1h1 = ShowCursor(FALSE);
const (local variable) const(_error_) h2h2 = ShowCursor(FALSE);
const (local variable) const(_error_) s1s1 = ShowCursor(TRUE);
const (local variable) const(_error_) s2s2 = ShowCursor(TRUE);
logEvent("showcursor_probe hide1=%d hide2=%d show1=%d show2=%d visible=%d",
h1, h2, s1, s2, s2 >= 0);
}
void app.registerRawMouseregisterRawMouse(HWND (parameter) HWND hwndhwnd) nothrow
{
RAWINPUTDEVICE _error_ ridrid;
rid.usUsagePage = 1; // HID_USAGE_PAGE_GENERIC
rid.usUsage = 2; // HID_USAGE_GENERIC_MOUSE
rid.dwFlags = RIDEV_INPUTSINK; // probe: deltas even while unfocused
rid.hwndTarget = hwnd; // INPUTSINK requires an explicit target
const _error_ okok = RegisterRawInputDevices(&rid, 1, RAWINPUTDEVICE.sizeof);
logEvent("raw_register usage=1:2 flags=RIDEV_INPUTSINK ok=%d err=%lu",
ok, ok ? 0 : GetLastError());
RAWINPUTDEVICE[4] _error_ backback;
UINT _error_ nn = back.length;
const _error_ gotgot = GetRegisteredRawInputDevices(back.ptr, &n, RAWINPUTDEVICE.sizeof);
if (got != cast(UINT)-1 && got >= 1)
logEvent("raw_register_readback count=%u flags=0x%lx target=%p",
got, back[0].dwFlags, back[0].hwndTarget);
else
logEvent("raw_register_readback count=%u err=%lu", got, GetLastError());
}
void void app.logClipReadback(const(char)* tag) nothrowlogClipReadback(const(char)* (parameter) const(char)* tagtag) nothrow
{
RECT (local variable) _error_ rbrb;
GetClipCursor(&rb);
logEvent("%s clip_readback=%d,%d-%d,%d", tag,
cast(int) rb.left, cast(int) rb.top, cast(int) rb.right, cast(int) rb.bottom);
}
// ---------------------------------------------------------------------------
// Lock / confine.
void app.lockPointerlockPointer(HWND (parameter) HWND hwndhwnd) nothrow
{
GetCursorPos(&g.g.savedPossavedPos);
RECT _error_ rcrc;
GetClientRect(hwnd, &rc);
POINT _error_ cc = POINT(rc.right / 2, rc.bottom / 2);
ClientToScreen(hwnd, &c);
g.g.pinPospinPos = c;
RECT _error_ pinpin = RECT(c.c.xx, c.c.yy, c.c.xx + 1, c.c.yy + 1); // the 1x1 lock idiom
if (!ClipCursor(&pin))
logEvent("error what=ClipCursor code=%lu", GetLastError());
SetCursorPos(c.c.xx, c.c.yy);
const _error_ scsc = ShowCursor(FALSE);
g.g.lockedlocked = true;
g.g.yawyaw = g.g.pitchpitch = 0;
logEvent("lock state=on pin=%d,%d saved=%d,%d showcursor=%d",
cast(int) c.c.xx, cast(int) c.c.yy,
cast(int) g.g.savedPossavedPos.g.savedPos.xx, cast(int) g.g.savedPossavedPos.g.savedPos.yy, sc);
logClipReadback("lock");
}
void void app.unlockPointer() nothrowunlockPointer() nothrow
{
ClipCursor(null);
const (local variable) const(_error_) scsc = ShowCursor(TRUE);
SetCursorPos(g.g.savedPossavedPos.g.savedPos.xx, g.g.savedPossavedPos.g.savedPos.yy);
POINT (local variable) _error_ pp;
GetCursorPos(&p);
g.g.lockedlocked = false;
logEvent("lock state=off showcursor=%d restored_to=%d,%d actual=%d,%d",
sc, cast(int) g.g.savedPossavedPos.g.savedPos.xx, cast(int) g.g.savedPossavedPos.g.savedPos.yy,
cast(int) p.p.xx, cast(int) p.p.yy);
void app.logClipReadback(const(char)* tag) nothrowlogClipReadback("unlock");
}
// Confine to the center half of the window (quarter-area centered rect).
void app.confinePointerconfinePointer(HWND (parameter) HWND hwndhwnd) nothrow
{
RECT _error_ rcrc;
GetClientRect(hwnd, &rc);
RECT _error_ rr = RECT(rc.right / 4, rc.bottom / 4, rc.right * 3 / 4, rc.bottom * 3 / 4);
MapWindowPoints(hwnd, null, cast(POINT*)&r, 2); // client -> screen
if (!ClipCursor(&r))
logEvent("error what=ClipCursor code=%lu", GetLastError());
g.g.confinedconfined = true;
logEvent("confine rect=%d,%d-%d,%d",
cast(int) r.left, cast(int) r.top, cast(int) r.right, cast(int) r.bottom);
logClipReadback("confine");
}
void void app.unconfinePointer() nothrowunconfinePointer() nothrow
{
ClipCursor(null);
g.g.confinedconfined = false;
logEvent("confine rect=none");
void app.logClipReadback(const(char)* tag) nothrowlogClipReadback("unconfine");
}
// SetCursorPos to a screen position, then read where the cursor actually
// landed — with a clip rect active the system clamps the request.
void void app.probeWarp(const(char)* label, int x, int y) nothrowprobeWarp(const(char)* (parameter) const(char)* labellabel, int (parameter) int xx, int (parameter) int yy) nothrow
{
SetCursorPos(x, y);
POINT (local variable) _error_ pp;
GetCursorPos(&p);
logEvent("confine_probe target=%s requested=%d,%d actual=%d,%d clamped=%d",
label, x, y, cast(int) p.p.xx, cast(int) p.p.yy, p.p.xx != x || p.p.yy != y);
}
// ---------------------------------------------------------------------------
// In-process motion drivers.
void app.warpClientwarpClient(HWND (parameter) HWND hwndhwnd, int nx, int ny) nothrow // numerators over /4
{
RECT _error_ rcrc;
GetClientRect(hwnd, &rc);
POINT _error_ pp = POINT(rc.right * nx / 4, rc.bottom * ny / 4);
ClientToScreen(hwnd, &p);
logEvent("inject method=SetCursorPos kind=abs screen=%d,%d",
cast(int) p.p.xx, cast(int) p.p.yy);
SetCursorPos(p.p.xx, p.p.yy);
}
void void app.injectRel(int dx, int dy) nothrowinjectRel(int (parameter) int dxdx, int (parameter) int dydy) nothrow
{
INPUT (local variable) _error_ inpinp;
inp.type = INPUT_MOUSE;
inp.mi.inp.mi.dxdx = dx;
inp.mi.inp.mi.dydy = dy;
inp.mi.dwFlags = MOUSEEVENTF_MOVE; // relative motion
logEvent("inject method=SendInput kind=rel dx=%d dy=%d", dx, dy);
if (SendInput(1, &inp, INPUT.sizeof) != 1)
logEvent("error what=SendInput code=%lu", GetLastError());
}
// ---------------------------------------------------------------------------
// Backbuffer + crosshair rendering (scaffold gradient, dimmed; the crosshair
// is displaced by the accumulated raw deltas while locked).
void void app.createBackbuffer(int w, int h) nothrowcreateBackbuffer(int (parameter) int ww, int (parameter) int hh) nothrow
{
if (g.(field) _error_ g.dibdib !is null)
{
SelectObject(g.g.memDcmemDc, g.g.stockBmpstockBmp);
DeleteObject(g.g.dibdib);
g.g.dibdib = null;
g.g.pixelspixels = null;
g.g.widthwidth = g.g.heightheight = 0;
}
if ((parameter) int ww <= 0 || (parameter) int hh <= 0)
return;
BITMAPINFO (local variable) _error_ bmibmi;
bmi.bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
bmi.bmiHeader.biWidth = w;
bmi.bmiHeader.biHeight = -h;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
void* (local variable) void* bitsbits;
g.g.dibdib = CreateDIBSection(null, &bmi, DIB_RGB_COLORS, &bits, null, 0);
if (g.(field) _error_ g.dibdib is null)
{
logEvent("error what=CreateDIBSection code=%lu", GetLastError());
return;
}
g.g.pixelspixels = cast(uint*) bits;
g.g.widthwidth = w;
g.g.heightheight = h;
g.g.stockBmpstockBmp = cast(HBITMAP) SelectObject(g.g.memDcmemDc, g.g.dibdib);
}
void void app.drawFrame() nothrowdrawFrame() nothrow
{
if (g.(field) _error_ g.pixelspixels is null)
return;
const (local variable) const(_error_) ww = g.(field) _error_ g.widthwidth, (local variable) const(_error_) hh = g.(field) _error_ g.heightheight;
foreach ((parameter) yy; 0 .. h)
{
uint* _error_ rowrow = g.g.pixelspixels + cast(size_t) y * w;
const _error_ greengreen = h > 1 ? (y * 96) / (h - 1) : 0;
foreach ((parameter) xx; 0 .. w)
row[x] = cast(uint)(((x * 96 / (w > 1 ? w - 1 : 1)) << 16) | (green << 8));
}
if (g.(field) _error_ g.confinedconfined) // show the confine rect
{
foreach ((parameter) _error_ xx; w / 4 .. w * 3 / 4)
{
g.g.pixelspixels[cast(size_t)(h / 4) * w + x] = 0x00ffff;
g.g.pixelspixels[cast(size_t)(h * 3 / 4) * w + x] = 0x00ffff;
}
foreach ((parameter) _error_ yy; h / 4 .. h * 3 / 4)
{
g.g.pixelspixels[cast(size_t) y * w + w / 4] = 0x00ffff;
g.g.pixelspixels[cast(size_t) y * w + w * 3 / 4] = 0x00ffff;
}
}
// Crosshair at center + (yaw, pitch)/4, clamped to the client area.
int (local variable) int cxcx = w / 2 + g.(field) _error_ g.yawyaw / 4, (local variable) int cycy = h / 2 + g.(field) _error_ g.pitchpitch / 4;
if ((local variable) int cxcx < 8) (local variable) int cxcx = 8; if ((local variable) int cxcx > w - 9) (local variable) int cxcx = w - 9;
if ((local variable) int cycy < 8) (local variable) int cycy = 8; if ((local variable) int cycy > h - 9) (local variable) int cycy = h - 9;
const (local variable) const(_error_) colorcolor = g.(field) _error_ g.lockedlocked ? 0xffff00 : 0xffffff;
foreach ((local variable) int dd; -8 .. 9)
{
g.(field) _error_ g.pixelspixels[cast(size_t) cy * w + cx + d] = color;
g.(field) _error_ g.pixelspixels[cast(size_t)(cy + d) * w + cx] = color;
}
}
// ---------------------------------------------------------------------------
// The bounded-run schedule (one entry per WM_TIMER tick).
void app.runSchedulerunSchedule(HWND (parameter) HWND hwndhwnd) nothrow
{
switch (g.g.ticksticks)
{
// Phase A — absolute warps while unlocked: the WM_MOUSEMOVE / WM_INPUT
// baseline (which flavor does a SetCursorPos warp produce?).
case 6:
logEvent("phase name=abs_tour");
warpClient(hwnd, 1, 1);
break;
case 10: warpClient(hwnd, 3, 1); break;
case 14: warpClient(hwnd, 3, 3); break;
case 18: warpClient(hwnd, 2, 2); break;
// Phase B — the same relative injection observed on both streams:
// WM_INPUT should report the injected delta verbatim (raw bypasses
// pointer ballistics); WM_MOUSEMOVE reports the post-ballistics position.
case 24:
logEvent("phase name=inject_compare");
injectRel(16, 8);
break;
case 28: injectRel(16, 8); break;
case 32: injectRel(-16, -8); break;
case 36:
logEvent("inject method=mouse_event kind=rel dx=-16 dy=-8");
mouse_event(MOUSEEVENTF_MOVE, cast(DWORD)-16, cast(DWORD)-8, 0, 0);
break;
// Phase C — mouselook: lock (ClipCursor 1x1 + ShowCursor(FALSE)), feed
// relative injections, prove the cursor stays pinned, unlock + restore.
case 44:
logEvent("phase name=mouselook");
lockPointer(hwnd);
break;
case 48: injectRel(7, -3); break;
case 52: injectRel(40, 0); break;
case 56: injectRel(-13, 22); break;
case 60:
POINT _error_ pp;
GetCursorPos(&p);
logEvent("locked_cursor x=%d y=%d pin=%d,%d yaw=%d pitch=%d",
cast(int) p.p.xx, cast(int) p.p.yy,
cast(int) g.g.pinPospinPos.g.pinPos.xx, cast(int) g.g.pinPospinPos.g.pinPos.yy, g.g.yawyaw, g.g.pitchpitch);
break;
case 64: unlockPointer(); break;
// Phase D — confine to the center half; prove clamping.
case 70:
logEvent("phase name=confine");
confinePointer(hwnd);
break;
case 74: // inside the rect: granted verbatim
RECT _error_ rcrc;
GetClipCursor(&rc);
probeWarp("inside", (rc.left + rc.right) / 2, (rc.top + rc.bottom) / 2);
break;
case 78: // window corner, outside the rect: must clamp
POINT _error_ cc;
ClientToScreen(hwnd, &c); // client (0,0)
probeWarp("window_corner", c.c.xx, c.c.yy);
break;
case 82: probeWarp("screen_origin", 0, 0); break;
case 86: injectRel(2000, 2000); break; // huge relative move: clamps too
case 88:
POINT _error_ pp;
GetCursorPos(&p);
logEvent("confine_probe target=rel_2000 actual=%d,%d",
cast(int) p.p.xx, cast(int) p.p.yy);
break;
// Phase E — what clears a ClipCursor? (headless-reachable probes)
case 92:
logEvent("phase name=clip_clear_probes");
logEvent("probe name=focus_loss action=SetForegroundWindow(other)");
SetForegroundWindow(g.g.otherother);
break;
case 96:
logClipReadback("after_focus_loss");
SetForegroundWindow(hwnd);
break;
case 100:
logEvent("probe name=minimize action=ShowWindow(SW_MINIMIZE)");
ShowWindow(hwnd, SW_MINIMIZE);
break;
case 104:
logClipReadback("after_minimize");
ShowWindow(hwnd, SW_RESTORE);
break;
case 108:
unconfinePointer();
break;
case 112:
logEvent("summary wm_mousemove=%u wm_input=%u", g.g.nMouseMovenMouseMove, g.g.nInputnInput);
DestroyWindow(hwnd);
break;
default:
break;
}
}
// ---------------------------------------------------------------------------
extern (Windows) LRESULT app.wndProcwndProc(HWND (parameter) HWND hwndhwnd, UINT (parameter) UINT msgmsg, WPARAM wParam, LPARAM lParam) nothrow
{
switch (msg)
{
case WM_CREATE:
if (g.g.memDcmemDc is null)
g.g.memDcmemDc = CreateCompatibleDC(null);
return 0;
case WM_INPUT:
RAWINPUT _error_ riri;
UINT _error_ sizesize = RAWINPUT.sizeof;
const _error_ gotgot = GetRawInputData(cast(HRAWINPUT) lParam, RID_INPUT,
&ri, &size, RAWINPUTHEADER.sizeof);
if (got != cast(UINT)-1 && ri.header.dwType == RIM_TYPEMOUSE)
{
++g.g.nInputnInput;
const _error_ flfl = ri.data.ri.data.mousemouse.usFlags;
logEvent("pointer rel dx=%d dy=%d raw=1 flags=0x%x mode=%s buttons=0x%x",
cast(int) ri.data.ri.data.mousemouse.lLastX, cast(int) ri.data.ri.data.mousemouse.lLastY,
fl, (fl & MOUSE_MOVE_ABSOLUTE) ? "absolute".ptr : "relative".ptr,
ri.data.ri.data.mousemouse.usButtonFlags);
if (g.g.lockedlocked && !(fl & MOUSE_MOVE_ABSOLUTE))
{
g.g.yawyaw += ri.data.ri.data.mousemouse.lLastX;
g.g.pitchpitch += ri.data.ri.data.mousemouse.lLastY;
logEvent("mouselook yaw=%d pitch=%d", g.g.yawyaw, g.g.pitchpitch);
}
}
goto default; // DefWindowProc must see WM_INPUT (it frees the buffer)
case WM_MOUSEMOVE:
++g.g.nMouseMovenMouseMove;
logEvent("pointer abs x=%d y=%d raw=0",
cast(int) cast(short)(lParam & 0xffff),
cast(int) cast(short)((lParam >> 16) & 0xffff));
return 0;
case WM_KEYDOWN: // interactive mode: L = lock toggle, C = confine toggle
if (wParam == 'L')
g.g.lockedlocked ? unlockPointer() : lockPointer(hwnd);
else if (wParam == 'C')
g.g.confinedconfined ? unconfinePointer() : confinePointer(hwnd);
return 0;
case WM_KILLFOCUS:
logEvent("msg name=WM_KILLFOCUS");
return 0;
case WM_SETFOCUS:
logEvent("msg name=WM_SETFOCUS");
return 0;
case WM_SIZE:
const _error_ ww = cast(int)(lParam & 0xffff);
const _error_ hh = cast(int)((lParam >> 16) & 0xffff);
if (wParam == SIZE_MINIMIZED)
return 0;
if (w != g.g.widthwidth || h != g.g.heightheight)
createBackbuffer(w, h);
return 0;
case WM_PAINT:
PAINTSTRUCT _error_ psps;
HDC _error_ hdchdc = BeginPaint(hwnd, &ps);
++g.g.frameframe;
drawFrame();
if (g.g.pixelspixels !is null)
BitBlt(hdc, 0, 0, g.g.widthwidth, g.g.heightheight, g.g.memDcmemDc, 0, 0, SRCCOPY);
EndPaint(hwnd, &ps);
return 0;
case WM_TIMER:
if (wParam != TIMER_ID)
return 0;
++g.g.ticksticks;
InvalidateRect(hwnd, null, FALSE);
if (g.g.autoExitautoExit)
runSchedule(hwnd);
return 0;
case WM_CLOSE:
logEvent("close_requested");
goto default;
case WM_DESTROY:
KillTimer(hwnd, TIMER_ID);
ClipCursor(null); // hygiene: ClipCursor is GLOBAL state — always release
if (g.g.lockedlocked)
ShowCursor(TRUE);
createBackbuffer(0, 0);
if (g.g.memDcmemDc !is null)
{
DeleteDC(g.g.memDcmemDc);
g.g.memDcmemDc = null;
}
PostQuitMessage(0);
return 0;
default:
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
}
// Minimal WndProc for the focus-loss probe window.
extern (Windows) LRESULT app.otherWndProcotherWndProc(HWND (parameter) HWND hwndhwnd, UINT (parameter) UINT msgmsg, WPARAM wParam, LPARAM lParam) nothrow
{
if (msg == WM_SETFOCUS)
logEvent("msg name=WM_SETFOCUS window=other");
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
// ---------------------------------------------------------------------------
bool bool app.envFlag(const(wchar)* name) nothrowenvFlag(const(wchar)* (parameter) const(wchar)* namename) nothrow
{
WCHAR[16] (local variable) _error_ bufbuf;
const (local variable) const(_error_) nn = GetEnvironmentVariableW(name, buf.ptr, buf.length);
return n >= 1 && n < buf.length && buf[0] == '1';
}
int int D main()main()
{
instrumentInit("f10_pointer_win32");
logEvent("init_start");
g.g.autoExitautoExit = envFlag("WSI_AUTO_EXIT"w.ptr);
logEvent("mode auto_exit=%d", g.g.autoExitautoExit ? 1 : 0);
void app.probeAccelState() nothrowprobeAccelState();
HINSTANCE (local variable) _error_ hInsthInst = GetModuleHandleW(null);
HCURSOR (local variable) _error_ arrowarrow = LoadCursorW(null, IDC_ARROW);
auto (local variable) wstring clsNameclsName = "wsi-f10-class"w;
WNDCLASSEXW (local variable) _error_ wcwc;
wc.cbSize = WNDCLASSEXW.sizeof;
wc.lpfnWndProc = &wndProc;
wc.hInstance = hInst;
wc.lpszClassName = clsName.ptr;
wc.hCursor = arrow;
if (!RegisterClassExW(&wc))
{
logEvent("error what=RegisterClassExW code=%lu", GetLastError());
return 1;
}
auto (local variable) wstring otherClsotherCls = "wsi-f10-other-class"w;
WNDCLASSEXW (local variable) _error_ wc2wc2;
wc2.cbSize = WNDCLASSEXW.sizeof;
wc2.lpfnWndProc = &otherWndProc;
wc2.hInstance = hInst;
wc2.lpszClassName = otherCls.ptr;
wc2.hCursor = arrow;
RegisterClassExW(&wc2);
HWND (local variable) _error_ hwndhwnd = CreateWindowExW(0, clsName.ptr, "wsi-f10-pointer"w.ptr,
WS_OVERLAPPEDWINDOW, 100, 100, 480, 320, null, null, hInst, null);
if (hwnd is null)
{
logEvent("error what=CreateWindowExW code=%lu", GetLastError());
return 1;
}
g.g.hwndhwnd = hwnd;
logEvent("window_created");
// The focus-loss probe target, shown without stealing activation.
g.g.otherother = CreateWindowExW(0, otherCls.ptr, "wsi-f10-other"w.ptr,
WS_OVERLAPPEDWINDOW, 640, 100, 160, 120, null, null, hInst, null);
ShowWindow(g.g.otherother, SW_SHOWNOACTIVATE);
void app.probeShowCursorCounter() nothrowprobeShowCursorCounter();
void app.logClipReadback(const(char)* tag) nothrowlogClipReadback("baseline"); // unclipped = the full screen rect
registerRawMouse(hwnd);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
SetTimer(hwnd, TIMER_ID, TICK_MS, null);
MSG (local variable) _error_ msgmsg;
while (GetMessageW(&msg, null, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
logEvent("exit code=%d", cast(int) msg.wParam);
return cast(int) msg.wParam;
}