app.dhover×230 error×68all
// F06 — keyboard & keymap, Win32 implementation
// (../../../features/f06-keyboard.md). Extends the scaffold
// (../scaffold/app.d) into a keyboard observatory:
//
//   * The WndProc logs the full chain for every key: WM_KEYDOWN /
//     WM_SYSKEYDOWN (vk from wParam; scancode, extended bit, repeat count and
//     previous-state bit decoded from lParam) -> TranslateMessage ->
//     WM_CHAR / WM_DEADCHAR / WM_SYSCHAR (UTF-16 code units, surrogate pairs
//     recombined) -> WM_KEYUP. WSI_NO_TRANSLATE=1 skips TranslateMessage in
//     the pump to prove every text-level message comes from it and it alone.
//   * A SetTimer-driven script injects scancode-level input into the demo's
//     own (focused) window with SendInput(KEYEVENTF_SCANCODE): a letter, a
//     shifted digit (vk != text proof), a same-key keydown pair (previous-
//     state bit), an Alt chord (WM_SYSKEYDOWN/WM_SYSCHAR), and — after
//     LoadKeyboardLayoutW("00000407") + KLF_ACTIVATE switches the thread to
//     German — the same physical scancodes again (Y/Z swap) plus the dead-key
//     sequence acute (scan 0x0D on de) + E -> WM_DEADCHAR -> WM_CHAR 'é'.
//     A KEYEVENTF_UNICODE pair carries U+1F600 as two surrogate WM_CHARs.
//   * Repeat ownership: the system owns auto-repeat; the demo logs the
//     configured rate/delay from SystemParametersInfoW(SPI_GETKEYBOARDSPEED /
//     SPI_GETKEYBOARDDELAY) at startup.
//
// WSI_AUTO_EXIT=1 runs the script and exits 0 (~1.5 s); without it the window
// stays open for real typing after the script.
//
// Only druntime's built-in core.sys.windows bindings — no third-party packages.
module 
(module) app
app
;
import
(package) core
core
.
(package) core.sys
sys
.
(package) core.sys.windows
windows
.
(module) core.sys.windows.windows

Windows API header module

Translated from MinGW API for MS-Windows 4.0

Source

core/sys/windows/windows.d

windows
;
import instrument;
unable to read module `instrument` Expected 'instrument.d' or 'instrument/package.d' in one of the following import paths:
unable to read module `instrument` Expected 'instrument.d' or 'instrument/package.d' in one of the following import paths:
enum UINT_PTR
(constant) _error_ app.TIMER_ID = __error
TIMER_ID
= 1;
undefined identifier `UINT_PTR`
enum
(constant) int app.TICK_MS = 100
TICK_MS
= 100; // one script step per tick
// PC/AT set-1 make codes for the physical positions the script exercises. enum
(enum) app.SC
SC
: ushort
{
(enum value) app.SC.A = cast(ushort)30u
A
= 0x1e,
(enum value) app.SC.B = cast(ushort)48u
B
= 0x30,
(enum value) app.SC.C = cast(ushort)46u
C
= 0x2e,
(enum value) app.SC.E = cast(ushort)18u
E
= 0x12,
(enum value) app.SC.Y = cast(ushort)21u
Y
= 0x15, // QWERTY Y position — types 'z' under de (QWERTZ)
(enum value) app.SC.Z = cast(ushort)44u
Z
= 0x2c, // QWERTY Z position — types 'y' under de
(enum value) app.SC.digit2 = cast(ushort)3u
digit2
= 0x03,
(enum value) app.SC.acute = cast(ushort)13u
acute
= 0x0d, // '=' position on us; the dead acute key on de
(enum value) app.SC.lshift = cast(ushort)42u
lshift
= 0x2a,
(enum value) app.SC.lalt = cast(ushort)56u
lalt
= 0x38,
(enum value) app.SC.space = cast(ushort)57u
space
= 0x39,
} enum ushort
(constant) ushort app.UP = cast(ushort)32768u
UP
= 0x8000; // ORed onto a SC entry: key release
struct
(struct) app.Demo
Demo
{ HWND
(field) _error_ app.Demo.hwnd
hwnd
;
undefined identifier `HWND`
HKL
(field) _error_ app.Demo.hklStart
hklStart
; // layout active at startup (us under a fresh prefix)
undefined identifier `HKL`
HKL
(field) _error_ app.Demo.hklDe
hklDe
; // 00000407 once loaded
undefined identifier `HKL`
uint
(field) uint app.Demo.step
step
; // script position
wchar
(field) wchar app.Demo.pendingHigh
pendingHigh
; // WM_CHAR high surrogate awaiting its low unit
bool
(field) bool app.Demo.autoExit
autoExit
;
bool
(field) bool app.Demo.noTranslate
noTranslate
; // WSI_NO_TRANSLATE=1: pump skips TranslateMessage
uint
(field) uint app.Demo.nKeyDown
nKeyDown
,
(field) uint app.Demo.nKeyUp
nKeyUp
,
(field) uint app.Demo.nSysKeyDown
nSysKeyDown
,
(field) uint app.Demo.nSysKeyUp
nSysKeyUp
;
uint
(field) uint app.Demo.nChar
nChar
,
(field) uint app.Demo.nDeadChar
nDeadChar
,
(field) uint app.Demo.nSysChar
nSysChar
,
(field) uint app.Demo.nSysDeadChar
nSysDeadChar
,
(field) uint app.Demo.nLangChange
nLangChange
;
} __gshared
(struct) app.Demo
Demo
_error_ app.g
g
;
// --------------------------------------------------------------------------- // UTF-16 -> UTF-8 for log lines (nothrow @nogc; the WndProc may not throw). void
void app.encodeUtf8(dchar c, ref char[8] buf) nothrow @nogc
encodeUtf8
(dchar
(parameter) dchar c
c
, ref char[8]
(parameter) char[8] buf
buf
) nothrow @nogc
{ int
(local variable) int n
n
;
if (
(parameter) dchar c
c
< 0x80)
(parameter) char[8] buf
buf
[
(local variable) int n
n
++] = cast(char)
(parameter) dchar c
c
;
else if (
(parameter) dchar c
c
< 0x800)
{
(parameter) char[8] buf
buf
[
(local variable) int n
n
++] = cast(char)(0xc0 | (
(parameter) dchar c
c
>> 6));
(parameter) char[8] buf
buf
[
(local variable) int n
n
++] = cast(char)(0x80 | (
(parameter) dchar c
c
& 0x3f));
} else if (
(parameter) dchar c
c
< 0x10000)
{
(parameter) char[8] buf
buf
[
(local variable) int n
n
++] = cast(char)(0xe0 | (
(parameter) dchar c
c
>> 12));
(parameter) char[8] buf
buf
[
(local variable) int n
n
++] = cast(char)(0x80 | ((
(parameter) dchar c
c
>> 6) & 0x3f));
(parameter) char[8] buf
buf
[
(local variable) int n
n
++] = cast(char)(0x80 | (
(parameter) dchar c
c
& 0x3f));
} else {
(parameter) char[8] buf
buf
[
(local variable) int n
n
++] = cast(char)(0xf0 | (
(parameter) dchar c
c
>> 18));
(parameter) char[8] buf
buf
[
(local variable) int n
n
++] = cast(char)(0x80 | ((
(parameter) dchar c
c
>> 12) & 0x3f));
(parameter) char[8] buf
buf
[
(local variable) int n
n
++] = cast(char)(0x80 | ((
(parameter) dchar c
c
>> 6) & 0x3f));
(parameter) char[8] buf
buf
[
(local variable) int n
n
++] = cast(char)(0x80 | (
(parameter) dchar c
c
& 0x3f));
}
(parameter) char[8] buf
buf
[
(local variable) int n
n
] = 0;
} // --------------------------------------------------------------------------- // Key-event decoding: everything but the vk lives in lParam's bitfields. void
app.logKey
logKey
(const(char)* state, bool
(parameter) bool sys
sys
, WPARAM wParam, LPARAM lParam) nothrow
undefined identifier `WPARAM`
undefined identifier `LPARAM`
{ const
_error_ repeatCount
repeatCount
= cast(uint)(lParam & 0xffff); // bits 0-15
const
_error_ scan
scan
= cast(uint)((lParam >> 16) & 0xff); // bits 16-23
const
_error_ ext
ext
= cast(uint)((lParam >> 24) & 1); // bit 24
const
_error_ prev
prev
= cast(uint)((lParam >> 30) & 1); // bit 30: was down before
// Layout-dependent key name straight from the scancode bits of lParam. WCHAR[32]
_error_ nameW
nameW
= 0;
const
_error_ n
n
= GetKeyNameTextW(cast(LONG)(lParam & 0x03ff_0000), nameW.ptr, nameW.length);
char[64]
_error_ name8
name8
= 0;
int
_error_ o
o
;
foreach (
(parameter) i
i
; 0 .. n) // key names are ASCII-ish; non-ASCII -> '?'
name8[o++] = nameW[i] < 0x80 ? cast(char) nameW[i] : '?'; name8[o] = 0; logEvent("key code=0x%02x ext=%u vk=0x%02x sym=%s text=- state=%s repeat=%u count=%u sys=%d", scan, ext, cast(uint) wParam, name8.ptr, state, prev, repeatCount, sys ? 1 : 0); } void
app.logChar
logChar
(const(char)* kind, WPARAM wParam, LPARAM lParam, bool
(parameter) bool sys
sys
) nothrow
undefined identifier `WPARAM`
undefined identifier `LPARAM`
{ const
_error_ unit
unit
= cast(ushort) wParam;
const
_error_ repeatBit
repeatBit
= cast(uint)((lParam >> 30) & 1);
dchar
_error_ cp
cp
= unit;
if (unit >= 0xd800 && unit <= 0xdbff) // high surrogate: hold for the low { g.
g.pendingHigh
pendingHigh
= unit;
logEvent("char_unit utf16=0x%04x note=high_surrogate_pending", unit); return; } if (unit >= 0xdc00 && unit <= 0xdfff) { cp = g.
g.pendingHigh
pendingHigh
? 0x10000 + ((g.
g.pendingHigh
pendingHigh
- 0xd800) << 10) + (unit - 0xdc00) : 0xfffd;
g.
g.pendingHigh
pendingHigh
= 0;
} char[8]
_error_ u8
u8
;
encodeUtf8(cp, u8); logEvent("%s utf16=0x%04x cp=U+%04X text=%s repeat=%u sys=%d", kind, unit, cast(uint) cp, u8.ptr, repeatBit, sys ? 1 : 0); } // --------------------------------------------------------------------------- // Injection: SendInput at scancode level (wVk=0 + KEYEVENTF_SCANCODE), so the // active layout — not the injector — decides vk and text, exactly like a // physical key. Each step's events go in one SendInput batch (atomic order). void
void app.injectScans(scope const(ushort)[] seq) nothrow
injectScans
(scope const(ushort)[]
(parameter) const(ushort)[] seq
seq
) nothrow
{ INPUT[16]
(local variable) _error_ inp
inp
;
undefined identifier `INPUT`
const
(local variable) const(_error_) n
n
= cast(UINT) seq.length;
undefined identifier `UINT`
foreach (
(parameter) ulong i
i
,
(parameter) const(ushort) e
e
;
(parameter) const(ushort)[] seq
seq
)
{ inp[i].type = INPUT_KEYBOARD; inp[i].ki.wScan = e & 0xff; inp[i].ki.dwFlags = KEYEVENTF_SCANCODE | ((e & UP) ? KEYEVENTF_KEYUP : 0); } const
(local variable) const(_error_) sent
sent
= SendInput(n, inp.ptr, INPUT.sizeof);
undefined identifier `SendInput`
logEvent("inject kind=scancode events=%u sent=%u err=%lu",
undefined identifier `logEvent`
n, sent, sent == n ? 0 : GetLastError()); } void
void app.injectUnicode(scope const(wchar)[] units) nothrow
injectUnicode
(scope const(wchar)[]
(parameter) const(wchar)[] units
units
) nothrow
{ INPUT[8]
(local variable) _error_ inp
inp
;
undefined identifier `INPUT`
UINT
(local variable) _error_ n
n
;
undefined identifier `UINT`
foreach (
(parameter) const(wchar) u
u
;
(parameter) const(wchar)[] units
units
) // per unit: down + up, vk = VK_PACKET internally
{ inp[n].type = INPUT_KEYBOARD; inp[n].ki.wScan = u; inp[n].ki.dwFlags = KEYEVENTF_UNICODE; n++; inp[n] = inp[n - 1]; inp[n].ki.dwFlags |= KEYEVENTF_KEYUP;
undefined identifier `KEYEVENTF_KEYUP`
n++; } const
(local variable) const(_error_) sent
sent
= SendInput(n, inp.ptr, INPUT.sizeof);
undefined identifier `SendInput`
logEvent("inject kind=unicode events=%u sent=%u err=%lu",
undefined identifier `logEvent`
n, sent, sent == n ? 0 : GetLastError()); } // --------------------------------------------------------------------------- // Direct table lookup, the no-injection fallback: scan -> vk (MapVirtualKeyEx) // -> text (ToUnicodeEx) against the start layout and the loaded de layout. // rc semantics: 1 = one char, 0 = no translation, -1 = DEAD KEY (the char in // the buffer is the accent itself). void
void app.probeToUnicode(ushort scan) nothrow
probeToUnicode
(ushort
(parameter) ushort scan
scan
) nothrow
{ static foreach (which; 0 .. 2) { { HKL
(local variable) _error_ hkl
hkl
=
(constant) int app.probeToUnicode.which = 0
which
== 0 ? g.
(field) _error_ g.hklStart
hklStart
: g.
(field) _error_ g.hklDe
hklDe
;
undefined identifier `HKL`
undefined identifier `HKL`
const
(local variable) const(_error_) vk
vk
= MapVirtualKeyExW(scan, MAPVK_VSC_TO_VK, hkl);
undefined identifier `MapVirtualKeyExW`
undefined identifier `MapVirtualKeyExW`
BYTE[256]
(local variable) _error_ kstate
kstate
= 0;
undefined identifier `BYTE`
undefined identifier `BYTE`
WCHAR[8]
(local variable) _error_ out16
out16
= 0;
undefined identifier `WCHAR`
undefined identifier `WCHAR`
const
(local variable) const(_error_) rc
rc
= ToUnicodeEx(vk, scan, kstate.ptr, out16.ptr, out16.length, 0, hkl);
undefined identifier `ToUnicodeEx`
undefined identifier `ToUnicodeEx`
char[8]
(local variable) char[8] u8
u8
= 0;
void app.encodeUtf8(dchar c, ref char[8] buf) nothrow @nogc
encodeUtf8
(out16[0],
(local variable) char[8] u8
u8
);
logEvent("tounicodeex layout=%s hkl=0x%zx scan=0x%02x vk=0x%02x rc=%d text=%s",
undefined identifier `logEvent`
undefined identifier `logEvent`
which == 0 ? "start".ptr : "de".ptr, cast(size_t) hkl, scan, vk, rc, rc != 0 ? u8.ptr : "-".ptr); } } } // --------------------------------------------------------------------------- // The script: one step per WM_TIMER tick, so each batch's messages are pumped // (and logged) before the next batch is injected. void
app.runStep
runStep
(HWND
(parameter) HWND hwnd
hwnd
) nothrow
undefined identifier `HWND`
{ switch (g.
g.step
step
++)
{ case 0: // letter logEvent("script step=letter scan=0x%02x", SC.
SC.A
A
);
injectScans([SC.
SC.A
A
, SC.
SC.A
A
| UP]);
break; case 1: // shifted digit: vk says '2', the text says otherwise logEvent("script step=shifted_digit scan=0x%02x", SC.
SC.digit2
digit2
);
injectScans([SC.
SC.lshift
lshift
, SC.
SC.digit2
digit2
, SC.
SC.digit2
digit2
| UP, SC.
SC.lshift
lshift
| UP]);
break; case 2: // two keydowns, no keyup between: bit 30 flips on the second logEvent("script step=repeat_bit scan=0x%02x", SC.
SC.B
B
);
injectScans([SC.
SC.B
B
, SC.
SC.B
B
, SC.
SC.B
B
| UP]);
break; case 3: // Alt chord -> the WM_SYS* flavor of the same chain logEvent("script step=alt_chord scan=0x%02x", SC.
SC.C
C
);
injectScans([SC.
SC.lalt
lalt
, SC.
SC.C
C
, SC.
SC.C
C
| UP, SC.
SC.lalt
lalt
| UP]);
break; case 4: // switch the thread to German (QWERTZ + dead accents) logEvent("script step=load_layout klid=00000407"); g.
g.hklDe
hklDe
= LoadKeyboardLayoutW("00000407"w.ptr, KLF_ACTIVATE);
if (g.
g.hklDe
hklDe
is null)
{ logEvent("error what=LoadKeyboardLayoutW code=%lu note=de_steps_will_run_on_start_layout", GetLastError()); break; } ActivateKeyboardLayout(g.
g.hklDe
hklDe
, 0);
WCHAR[KL_NAMELENGTH]
_error_ klid
klid
;
GetKeyboardLayoutNameW(klid.ptr); // The HKL value alone does not prove the *tables* switched (Wine's // headless null driver hands back an 0407-tagged HKL whose mapping is // still its built-in default table). Check behaviorally: on a real de // (QWERTZ) layout, the QWERTY-Y-position scancode maps to VK 'Z'. const
_error_ vkYde
vkYde
= MapVirtualKeyExW(SC.
SC.Y
Y
, MAPVK_VSC_TO_VK, g.
g.hklDe
hklDe
);
logEvent("layout_active hkl=0x%zx klid=%c%c%c%c%c%c%c%c tables=%s", cast(size_t) GetKeyboardLayout(0), klid[0], klid[1], klid[2], klid[3], klid[4], klid[5], klid[6], klid[7], vkYde == 'Z' ? "de".ptr : "fallback_not_de".ptr); logEvent("layout_map scan=0x%02x vk_start=0x%02x vk_de=0x%02x", SC.
SC.Y
Y
,
MapVirtualKeyExW(SC.
SC.Y
Y
, MAPVK_VSC_TO_VK, g.
g.hklStart
hklStart
), vkYde);
logEvent("layout_map scan=0x%02x vk_start=0x%02x vk_de=0x%02x", SC.
SC.Z
Z
,
MapVirtualKeyExW(SC.
SC.Z
Z
, MAPVK_VSC_TO_VK, g.
g.hklStart
hklStart
),
MapVirtualKeyExW(SC.
SC.Z
Z
, MAPVK_VSC_TO_VK, g.
g.hklDe
hklDe
));
// Text-level probes straight off the layout tables, no injection: // ToUnicodeEx returns -1 for a dead key. Probing the dead key leaves // a pending accent in the thread's translation state, so a space // probe follows to flush it (its result is logged too — on a real de // layout it yields the standalone accent). probeToUnicode(SC.
SC.Y
Y
);
probeToUnicode(SC.
SC.Z
Z
);
probeToUnicode(SC.
SC.acute
acute
);
probeToUnicode(SC.
SC.space
space
);
break; case 5: // same physical key as step 0's neighbor: QWERTY Y -> de 'z' logEvent("script step=de_y_position scan=0x%02x", SC.
SC.Y
Y
);
injectScans([SC.
SC.Y
Y
, SC.
SC.Y
Y
| UP]);
break; case 6: // and the mirror: QWERTY Z position -> de 'y' logEvent("script step=de_z_position scan=0x%02x", SC.
SC.Z
Z
);
injectScans([SC.
SC.Z
Z
, SC.
SC.Z
Z
| UP]);
break; case 7: // dead key: acute accent, alone -> WM_DEADCHAR only logEvent("script step=dead_acute scan=0x%02x", SC.
SC.acute
acute
);
injectScans([SC.
SC.acute
acute
, SC.
SC.acute
acute
| UP]);
break; case 8: // ... then E composes: WM_CHAR U+00E9 logEvent("script step=dead_then_e scan=0x%02x", SC.
SC.E
E
);
injectScans([SC.
SC.E
E
, SC.
SC.E
E
| UP]);
break; case 9: // supplementary-plane text -> two WM_CHARs (surrogate pair) logEvent("script step=unicode_surrogate cp=U+1F600"); injectUnicode([cast(wchar) 0xd83d, cast(wchar) 0xde00]); break; default: KillTimer(hwnd, TIMER_ID); logEvent("summary keydown=%u keyup=%u syskeydown=%u syskeyup=%u char=%u deadchar=%u syschar=%u sysdeadchar=%u inputlangchange=%u", g.
g.nKeyDown
nKeyDown
, g.
g.nKeyUp
nKeyUp
, g.
g.nSysKeyDown
nSysKeyDown
, g.
g.nSysKeyUp
nSysKeyUp
,
g.
g.nChar
nChar
, g.
g.nDeadChar
nDeadChar
, g.
g.nSysChar
nSysChar
, g.
g.nSysDeadChar
nSysDeadChar
, g.
g.nLangChange
nLangChange
);
if (g.
g.autoExit
autoExit
)
DestroyWindow(hwnd); else logEvent("script_done note=window_stays_open_for_real_typing"); break; } } // --------------------------------------------------------------------------- extern (Windows) LRESULT
app.wndProc
wndProc
(HWND
(parameter) HWND hwnd
hwnd
, UINT
(parameter) UINT msg
msg
, WPARAM wParam, LPARAM lParam) nothrow
undefined identifier `LRESULT`
undefined identifier `HWND`
undefined identifier `UINT`
undefined identifier `WPARAM`
undefined identifier `LPARAM`
{ switch (msg) { case WM_KEYDOWN: ++g.
g.nKeyDown
nKeyDown
;
logKey("down", false, wParam, lParam); return 0; case WM_KEYUP: ++g.
g.nKeyUp
nKeyUp
;
logKey("up", false, wParam, lParam); return 0; case WM_SYSKEYDOWN: ++g.
g.nSysKeyDown
nSysKeyDown
;
logKey("down", true, wParam, lParam); goto default; // DefWindowProcW owns Alt-menu / Alt-F4 handling case WM_SYSKEYUP: ++g.
g.nSysKeyUp
nSysKeyUp
;
logKey("up", true, wParam, lParam); goto default; case WM_CHAR: ++g.
g.nChar
nChar
;
logChar("char", wParam, lParam, false); return 0; case WM_DEADCHAR: ++g.
g.nDeadChar
nDeadChar
;
logChar("deadchar", wParam, lParam, false); return 0; case WM_SYSCHAR: ++g.
g.nSysChar
nSysChar
;
logChar("char", wParam, lParam, true); goto default; case WM_SYSDEADCHAR: ++g.
g.nSysDeadChar
nSysDeadChar
;
logChar("deadchar", wParam, lParam, true); goto default; case WM_INPUTLANGCHANGE: ++g.
g.nLangChange
nLangChange
;
logEvent("msg name=WM_INPUTLANGCHANGE charset=%u hkl=0x%zx", cast(uint) wParam, cast(size_t) lParam); return 1; case WM_TIMER: if (wParam == TIMER_ID) runStep(hwnd); return 0; case WM_PAINT: PAINTSTRUCT
_error_ ps
ps
;
HDC
_error_ hdc
hdc
= BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, cast(HBRUSH)(COLOR_WINDOW + 1)); EndPaint(hwnd, &ps); return 0; case WM_CLOSE: logEvent("close_requested"); goto default; case WM_DESTROY: PostQuitMessage(0); return 0; default: return DefWindowProcW(hwnd, msg, wParam, lParam); } } // --------------------------------------------------------------------------- bool
bool app.envFlag(const(wchar)* name) nothrow
envFlag
(const(wchar)*
(parameter) const(wchar)* name
name
) nothrow
{ WCHAR[8]
(local variable) _error_ buf
buf
;
undefined identifier `WCHAR`
const
(local variable) const(_error_) n
n
= GetEnvironmentVariableW(name, buf.ptr, buf.length);
undefined identifier `GetEnvironmentVariableW`
return n >= 1 && n < buf.length && buf[0] == '1'; } int
int D main()
main
()
{ instrumentInit("f06_keyboard_win32");
undefined identifier `instrumentInit`
logEvent("init_start");
undefined identifier `logEvent`
g.
g.autoExit
autoExit
= envFlag("WSI_AUTO_EXIT"w.ptr);
g.
g.noTranslate
noTranslate
= envFlag("WSI_NO_TRANSLATE"w.ptr);
logEvent("mode auto_exit=%d no_translate=%d", g.
g.autoExit
autoExit
? 1 : 0, g.
g.noTranslate
noTranslate
? 1 : 0);
undefined identifier `logEvent`
HINSTANCE
(local variable) _error_ hInst
hInst
= GetModuleHandleW(null);
undefined identifier `HINSTANCE`
undefined identifier `GetModuleHandleW`
auto
(local variable) wstring clsName
clsName
= "wsi-f06-class"w;
WNDCLASSEXW
(local variable) _error_ wc
wc
;
undefined identifier `WNDCLASSEXW`
wc.cbSize = WNDCLASSEXW.sizeof; wc.lpfnWndProc = &wndProc; wc.hInstance = hInst; wc.lpszClassName = clsName.ptr; wc.hCursor = LoadCursorW(null, IDC_ARROW); if (!RegisterClassExW(&wc))
undefined identifier `RegisterClassExW`
{ logEvent("error what=RegisterClassExW code=%lu", GetLastError());
undefined identifier `logEvent`
return 1; } g.
g.hwnd
hwnd
= CreateWindowExW(0, clsName.ptr, "wsi-f06-keyboard"w.ptr,
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 480, 320, null, null, hInst, null); if (g.
(field) _error_ g.hwnd
hwnd
is null)
{ logEvent("error what=CreateWindowExW code=%lu", GetLastError());
undefined identifier `logEvent`
return 1; } logEvent("window_created");
undefined identifier `logEvent`
ShowWindow(g.
g.hwnd
hwnd
, SW_SHOW);
undefined identifier `ShowWindow`
UpdateWindow(g.
g.hwnd
hwnd
);
undefined identifier `UpdateWindow`
// SendInput targets the foreground window's thread; make sure that's us // (under Wine's headless null driver the fresh window is, but be explicit). SetForegroundWindow(g.
g.hwnd
hwnd
);
undefined identifier `SetForegroundWindow`
SetFocus(g.
g.hwnd
hwnd
);
undefined identifier `SetFocus`
logEvent("focus foreground_is_self=%d focus_is_self=%d",
undefined identifier `logEvent`
GetForegroundWindow() is g.
g.hwnd
hwnd
? 1 : 0, GetFocus() is g.
g.hwnd
hwnd
? 1 : 0);
// Who owns key repeat: the system. Its knobs (and their units) are global. g.
g.hklStart
hklStart
= GetKeyboardLayout(0);
WCHAR[KL_NAMELENGTH]
(local variable) _error_ klid
klid
;
undefined identifier `KL_NAMELENGTH`
GetKeyboardLayoutNameW(klid.ptr);
undefined identifier `GetKeyboardLayoutNameW`
logEvent("layout_start hkl=0x%zx klid=%c%c%c%c%c%c%c%c", cast(size_t) g.
g.hklStart
hklStart
,
undefined identifier `logEvent`
klid[0], klid[1], klid[2], klid[3], klid[4], klid[5], klid[6], klid[7]); DWORD
(local variable) _error_ speed
speed
,
(local variable) _error_ delay
delay
;
undefined identifier `DWORD`
undefined identifier `DWORD`
SystemParametersInfoW(SPI_GETKEYBOARDSPEED, 0, &speed, 0); // 0..31 ~= 2.5..30 cps
undefined identifier `SystemParametersInfoW`
SystemParametersInfoW(SPI_GETKEYBOARDDELAY, 0, &delay, 0); // 0..3 ~= 250..1000 ms
undefined identifier `SystemParametersInfoW`
logEvent("repeat_config speed=%lu delay=%lu owner=system", speed, delay);
undefined identifier `logEvent`
SetTimer(g.
g.hwnd
hwnd
, TIMER_ID, TICK_MS, null);
undefined identifier `SetTimer`
MSG
(local variable) _error_ msg
msg
;
undefined identifier `MSG`
while (GetMessageW(&msg, null, 0, 0) > 0)
undefined identifier `GetMessageW`
{ // TranslateMessage is the ONLY producer of WM_CHAR/WM_DEADCHAR: it // reads WM_(SYS)KEYDOWN + the thread's keyboard state + active layout // and posts the text-level message(s). Skip it and the text vanishes. if (!g.
(field) _error_ g.noTranslate
noTranslate
)
TranslateMessage(&msg);
undefined identifier `TranslateMessage`
DispatchMessageW(&msg);
undefined identifier `DispatchMessageW`
} logEvent("exit code=%d", cast(int) msg.wParam);
undefined identifier `logEvent`
return cast(int) msg.wParam; }