basic clipboard monitoring working in Windows

This commit is contained in:
Emil Lerch 2021-11-17 17:05:24 -08:00
parent b72469b046
commit b6ffab3ae3
Signed by: lobo
GPG Key ID: A7B62D657EF764F8
2 changed files with 653 additions and 6 deletions

View File

@ -45,6 +45,7 @@ pub fn build(b: *std.build.Builder) void {
if (target.getOs().tag == .windows) { if (target.getOs().tag == .windows) {
// woah...we don't actually need libc! // woah...we don't actually need libc!
exe.linkSystemLibrary("user32"); exe.linkSystemLibrary("user32");
exe.linkSystemLibrary("kernel32");
} }
exe.install(); exe.install();

View File

@ -192,6 +192,10 @@ extern "USER32" fn RegisterClassA(
lpWndClass: ?*const WNDCLASSA, lpWndClass: ?*const WNDCLASSA,
) callconv(w.WINAPI) u16; ) callconv(w.WINAPI) u16;
extern "USER32" fn DestroyWindow(
hWnd: ?w.HWND,
) callconv(w.WINAPI) w.BOOL;
const WS_OVERLAPPEDWINDOW = WINDOW_STYLE.TILEDWINDOW; const WS_OVERLAPPEDWINDOW = WINDOW_STYLE.TILEDWINDOW;
const CW_USEDEFAULT = @as(i32, -2147483648); const CW_USEDEFAULT = @as(i32, -2147483648);
const BOOL = i32; const BOOL = i32;
@ -270,6 +274,359 @@ extern "USER32" fn DispatchMessageA(
lpMsg: ?*const MSG, lpMsg: ?*const MSG,
) callconv(w.WINAPI) LRESULT; ) callconv(w.WINAPI) LRESULT;
const WM_NULL = @as(u32, 0);
const WM_CREATE = @as(u32, 1);
const WM_DESTROY = @as(u32, 2);
const WM_MOVE = @as(u32, 3);
const WM_SIZE = @as(u32, 5);
const WM_ACTIVATE = @as(u32, 6);
const WA_INACTIVE = @as(u32, 0);
const WA_ACTIVE = @as(u32, 1);
const WA_CLICKACTIVE = @as(u32, 2);
const WM_SETFOCUS = @as(u32, 7);
const WM_KILLFOCUS = @as(u32, 8);
const WM_ENABLE = @as(u32, 10);
const WM_SETREDRAW = @as(u32, 11);
const WM_SETTEXT = @as(u32, 12);
const WM_GETTEXT = @as(u32, 13);
const WM_GETTEXTLENGTH = @as(u32, 14);
const WM_PAINT = @as(u32, 15);
const WM_CLOSE = @as(u32, 16);
const WM_QUERYENDSESSION = @as(u32, 17);
const WM_QUERYOPEN = @as(u32, 19);
const WM_ENDSESSION = @as(u32, 22);
const WM_QUIT = @as(u32, 18);
const WM_ERASEBKGND = @as(u32, 20);
const WM_SYSCOLORCHANGE = @as(u32, 21);
const WM_SHOWWINDOW = @as(u32, 24);
const WM_WININICHANGE = @as(u32, 26);
const WM_SETTINGCHANGE = @as(u32, 26);
const WM_DEVMODECHANGE = @as(u32, 27);
const WM_ACTIVATEAPP = @as(u32, 28);
const WM_FONTCHANGE = @as(u32, 29);
const WM_TIMECHANGE = @as(u32, 30);
const WM_CANCELMODE = @as(u32, 31);
const WM_SETCURSOR = @as(u32, 32);
const WM_MOUSEACTIVATE = @as(u32, 33);
const WM_CHILDACTIVATE = @as(u32, 34);
const WM_QUEUESYNC = @as(u32, 35);
const WM_GETMINMAXINFO = @as(u32, 36);
const WM_PAINTICON = @as(u32, 38);
const WM_ICONERASEBKGND = @as(u32, 39);
const WM_NEXTDLGCTL = @as(u32, 40);
const WM_SPOOLERSTATUS = @as(u32, 42);
const WM_DRAWITEM = @as(u32, 43);
const WM_MEASUREITEM = @as(u32, 44);
const WM_DELETEITEM = @as(u32, 45);
const WM_VKEYTOITEM = @as(u32, 46);
const WM_CHARTOITEM = @as(u32, 47);
const WM_SETFONT = @as(u32, 48);
const WM_GETFONT = @as(u32, 49);
const WM_SETHOTKEY = @as(u32, 50);
const WM_GETHOTKEY = @as(u32, 51);
const WM_QUERYDRAGICON = @as(u32, 55);
const WM_COMPAREITEM = @as(u32, 57);
const WM_GETOBJECT = @as(u32, 61);
const WM_COMPACTING = @as(u32, 65);
const WM_COMMNOTIFY = @as(u32, 68);
const WM_WINDOWPOSCHANGING = @as(u32, 70);
const WM_WINDOWPOSCHANGED = @as(u32, 71);
const WM_POWER = @as(u32, 72);
const WM_COMMAND = @as(u32, 273);
const WM_INITMENU = @as(u32, 278);
const WM_INITMENUPOPUP = @as(u32, 279);
const WM_DRAWCLIPBOARD = @as(u32, 776);
const WM_SIZECLIPBOARD = @as(u32, 779);
const WM_CHANGECBCHAIN = @as(u32, 781);
const RECT = extern struct {
left: i32,
top: i32,
right: i32,
bottom: i32,
};
extern "USER32" fn GetClientRect(
hWnd: ?w.HWND,
lpRect: ?*RECT,
) callconv(w.WINAPI) BOOL;
extern "USER32" fn SendMessageA(
hWnd: ?w.HWND,
Msg: u32,
wParam: w.WPARAM,
lParam: w.LPARAM,
) callconv(w.WINAPI) LRESULT;
extern "USER32" fn DefWindowProcA(
hWnd: ?w.HWND,
Msg: u32,
wParam: w.WPARAM,
lParam: w.LPARAM,
) callconv(w.WINAPI) LRESULT;
// GDI
const HDC = *opaque {};
pub const PAINTSTRUCT = extern struct {
hdc: ?HDC,
fErase: BOOL,
rcPaint: RECT,
fRestore: BOOL,
fIncUpdate: BOOL,
rgbReserved: [32]u8,
};
extern "USER32" fn BeginPaint(
hWnd: ?w.HWND,
lpPaint: ?*PAINTSTRUCT,
) callconv(w.WINAPI) ?HDC;
extern "USER32" fn EndPaint(
hWnd: ?w.HWND,
lpPaint: ?*const PAINTSTRUCT,
) callconv(w.WINAPI) BOOL;
const DRAW_TEXT_FORMAT = enum(u32) {
BOTTOM = 8,
CALCRECT = 1024,
CENTER = 1,
EDITCONTROL = 8192,
END_ELLIPSIS = 32768,
EXPANDTABS = 64,
EXTERNALLEADING = 512,
HIDEPREFIX = 1048576,
INTERNAL = 4096,
LEFT = 0,
MODIFYSTRING = 65536,
NOCLIP = 256,
NOFULLWIDTHCHARBREAK = 524288,
NOPREFIX = 2048,
PATH_ELLIPSIS = 16384,
PREFIXONLY = 2097152,
RIGHT = 2,
RTLREADING = 131072,
SINGLELINE = 32,
TABSTOP = 128,
// TOP = 0, this enum value conflicts with LEFT
VCENTER = 4,
WORDBREAK = 16,
WORD_ELLIPSIS = 262144,
_,
pub fn initFlags(o: struct {
BOTTOM: u1 = 0,
CALCRECT: u1 = 0,
CENTER: u1 = 0,
EDITCONTROL: u1 = 0,
END_ELLIPSIS: u1 = 0,
EXPANDTABS: u1 = 0,
EXTERNALLEADING: u1 = 0,
HIDEPREFIX: u1 = 0,
INTERNAL: u1 = 0,
LEFT: u1 = 0,
MODIFYSTRING: u1 = 0,
NOCLIP: u1 = 0,
NOFULLWIDTHCHARBREAK: u1 = 0,
NOPREFIX: u1 = 0,
PATH_ELLIPSIS: u1 = 0,
PREFIXONLY: u1 = 0,
RIGHT: u1 = 0,
RTLREADING: u1 = 0,
SINGLELINE: u1 = 0,
TABSTOP: u1 = 0,
VCENTER: u1 = 0,
WORDBREAK: u1 = 0,
WORD_ELLIPSIS: u1 = 0,
}) DRAW_TEXT_FORMAT {
return @intToEnum(DRAW_TEXT_FORMAT, (if (o.BOTTOM == 1) @enumToInt(DRAW_TEXT_FORMAT.BOTTOM) else 0) | (if (o.CALCRECT == 1) @enumToInt(DRAW_TEXT_FORMAT.CALCRECT) else 0) | (if (o.CENTER == 1) @enumToInt(DRAW_TEXT_FORMAT.CENTER) else 0) | (if (o.EDITCONTROL == 1) @enumToInt(DRAW_TEXT_FORMAT.EDITCONTROL) else 0) | (if (o.END_ELLIPSIS == 1) @enumToInt(DRAW_TEXT_FORMAT.END_ELLIPSIS) else 0) | (if (o.EXPANDTABS == 1) @enumToInt(DRAW_TEXT_FORMAT.EXPANDTABS) else 0) | (if (o.EXTERNALLEADING == 1) @enumToInt(DRAW_TEXT_FORMAT.EXTERNALLEADING) else 0) | (if (o.HIDEPREFIX == 1) @enumToInt(DRAW_TEXT_FORMAT.HIDEPREFIX) else 0) | (if (o.INTERNAL == 1) @enumToInt(DRAW_TEXT_FORMAT.INTERNAL) else 0) | (if (o.LEFT == 1) @enumToInt(DRAW_TEXT_FORMAT.LEFT) else 0) | (if (o.MODIFYSTRING == 1) @enumToInt(DRAW_TEXT_FORMAT.MODIFYSTRING) else 0) | (if (o.NOCLIP == 1) @enumToInt(DRAW_TEXT_FORMAT.NOCLIP) else 0) | (if (o.NOFULLWIDTHCHARBREAK == 1) @enumToInt(DRAW_TEXT_FORMAT.NOFULLWIDTHCHARBREAK) else 0) | (if (o.NOPREFIX == 1) @enumToInt(DRAW_TEXT_FORMAT.NOPREFIX) else 0) | (if (o.PATH_ELLIPSIS == 1) @enumToInt(DRAW_TEXT_FORMAT.PATH_ELLIPSIS) else 0) | (if (o.PREFIXONLY == 1) @enumToInt(DRAW_TEXT_FORMAT.PREFIXONLY) else 0) | (if (o.RIGHT == 1) @enumToInt(DRAW_TEXT_FORMAT.RIGHT) else 0) | (if (o.RTLREADING == 1) @enumToInt(DRAW_TEXT_FORMAT.RTLREADING) else 0) | (if (o.SINGLELINE == 1) @enumToInt(DRAW_TEXT_FORMAT.SINGLELINE) else 0) | (if (o.TABSTOP == 1) @enumToInt(DRAW_TEXT_FORMAT.TABSTOP) else 0) | (if (o.VCENTER == 1) @enumToInt(DRAW_TEXT_FORMAT.VCENTER) else 0) | (if (o.WORDBREAK == 1) @enumToInt(DRAW_TEXT_FORMAT.WORDBREAK) else 0) | (if (o.WORD_ELLIPSIS == 1) @enumToInt(DRAW_TEXT_FORMAT.WORD_ELLIPSIS) else 0));
}
};
const DT_BOTTOM = DRAW_TEXT_FORMAT.BOTTOM;
const DT_CALCRECT = DRAW_TEXT_FORMAT.CALCRECT;
const DT_CENTER = DRAW_TEXT_FORMAT.CENTER;
const DT_EDITCONTROL = DRAW_TEXT_FORMAT.EDITCONTROL;
const DT_END_ELLIPSIS = DRAW_TEXT_FORMAT.END_ELLIPSIS;
const DT_EXPANDTABS = DRAW_TEXT_FORMAT.EXPANDTABS;
const DT_EXTERNALLEADING = DRAW_TEXT_FORMAT.EXTERNALLEADING;
const DT_HIDEPREFIX = DRAW_TEXT_FORMAT.HIDEPREFIX;
const DT_INTERNAL = DRAW_TEXT_FORMAT.INTERNAL;
const DT_LEFT = DRAW_TEXT_FORMAT.LEFT;
const DT_MODIFYSTRING = DRAW_TEXT_FORMAT.MODIFYSTRING;
const DT_NOCLIP = DRAW_TEXT_FORMAT.NOCLIP;
const DT_NOFULLWIDTHCHARBREAK = DRAW_TEXT_FORMAT.NOFULLWIDTHCHARBREAK;
const DT_NOPREFIX = DRAW_TEXT_FORMAT.NOPREFIX;
const DT_PATH_ELLIPSIS = DRAW_TEXT_FORMAT.PATH_ELLIPSIS;
const DT_PREFIXONLY = DRAW_TEXT_FORMAT.PREFIXONLY;
const DT_RIGHT = DRAW_TEXT_FORMAT.RIGHT;
const DT_RTLREADING = DRAW_TEXT_FORMAT.RTLREADING;
const DT_SINGLELINE = DRAW_TEXT_FORMAT.SINGLELINE;
const DT_TABSTOP = DRAW_TEXT_FORMAT.TABSTOP;
const DT_TOP = DRAW_TEXT_FORMAT.LEFT;
const DT_VCENTER = DRAW_TEXT_FORMAT.VCENTER;
const DT_WORDBREAK = DRAW_TEXT_FORMAT.WORDBREAK;
const DT_WORD_ELLIPSIS = DRAW_TEXT_FORMAT.WORD_ELLIPSIS;
extern "USER32" fn DrawTextA(
hdc: ?HDC,
lpchText: [*:0]const u8,
cchText: i32,
lprc: ?*RECT,
format: DRAW_TEXT_FORMAT,
) callconv(w.WINAPI) i32;
extern "USER32" fn InvalidateRect(
hWnd: ?w.HWND,
lpRect: ?*const RECT,
bErase: w.BOOL,
) callconv(w.WINAPI) BOOL;
extern "USER32" fn UpdateWindow(
hWnd: ?w.HWND,
) callconv(w.WINAPI) BOOL;
// Data exchange
extern "USER32" fn GetClipboardData(
uFormat: u32,
) callconv(w.WINAPI) ?w.HANDLE;
extern "USER32" fn GetClipboardOwner() callconv(w.WINAPI) ?w.HWND;
extern "USER32" fn SetClipboardViewer(
hWndNewViewer: ?w.HWND,
) callconv(w.WINAPI) ?w.HWND;
extern "USER32" fn OpenClipboard(
hWndNewOwner: ?w.HWND,
) callconv(w.WINAPI) BOOL;
extern "USER32" fn CloseClipboard() callconv(w.WINAPI) BOOL;
extern "USER32" fn ChangeClipboardChain(
hWndRemove: ?w.HWND,
hWndNewNext: ?w.HWND,
) callconv(w.WINAPI) BOOL;
extern "USER32" fn GetPriorityClipboardFormat(
paFormatPriorityList: [*]u32,
cFormats: i32,
) callconv(w.WINAPI) i32;
// System
extern "USER32" fn PostQuitMessage(
nExitCode: i32,
) callconv(w.WINAPI) void;
const CLIPBOARD_FORMATS = enum(u32) {
TEXT = 1,
BITMAP = 2,
METAFILEPICT = 3,
SYLK = 4,
DIF = 5,
TIFF = 6,
OEMTEXT = 7,
DIB = 8,
PALETTE = 9,
PENDATA = 10,
RIFF = 11,
WAVE = 12,
UNICODETEXT = 13,
ENHMETAFILE = 14,
HDROP = 15,
LOCALE = 16,
DIBV5 = 17,
MAX = 18,
OWNERDISPLAY = 128,
DSPTEXT = 129,
DSPBITMAP = 130,
DSPMETAFILEPICT = 131,
DSPENHMETAFILE = 142,
PRIVATEFIRST = 512,
PRIVATELAST = 767,
GDIOBJFIRST = 768,
GDIOBJLAST = 1023,
};
const CF_TEXT = CLIPBOARD_FORMATS.TEXT;
const CF_BITMAP = CLIPBOARD_FORMATS.BITMAP;
const CF_METAFILEPICT = CLIPBOARD_FORMATS.METAFILEPICT;
const CF_SYLK = CLIPBOARD_FORMATS.SYLK;
const CF_DIF = CLIPBOARD_FORMATS.DIF;
const CF_TIFF = CLIPBOARD_FORMATS.TIFF;
const CF_OEMTEXT = CLIPBOARD_FORMATS.OEMTEXT;
const CF_DIB = CLIPBOARD_FORMATS.DIB;
const CF_PALETTE = CLIPBOARD_FORMATS.PALETTE;
const CF_PENDATA = CLIPBOARD_FORMATS.PENDATA;
const CF_RIFF = CLIPBOARD_FORMATS.RIFF;
const CF_WAVE = CLIPBOARD_FORMATS.WAVE;
const CF_UNICODETEXT = CLIPBOARD_FORMATS.UNICODETEXT;
const CF_ENHMETAFILE = CLIPBOARD_FORMATS.ENHMETAFILE;
const CF_HDROP = CLIPBOARD_FORMATS.HDROP;
const CF_LOCALE = CLIPBOARD_FORMATS.LOCALE;
const CF_DIBV5 = CLIPBOARD_FORMATS.DIBV5;
const CF_MAX = CLIPBOARD_FORMATS.MAX;
const CF_OWNERDISPLAY = CLIPBOARD_FORMATS.OWNERDISPLAY;
const CF_DSPTEXT = CLIPBOARD_FORMATS.DSPTEXT;
const CF_DSPBITMAP = CLIPBOARD_FORMATS.DSPBITMAP;
const CF_DSPMETAFILEPICT = CLIPBOARD_FORMATS.DSPMETAFILEPICT;
const CF_DSPENHMETAFILE = CLIPBOARD_FORMATS.DSPENHMETAFILE;
const CF_PRIVATEFIRST = CLIPBOARD_FORMATS.PRIVATEFIRST;
const CF_PRIVATELAST = CLIPBOARD_FORMATS.PRIVATELAST;
const CF_GDIOBJFIRST = CLIPBOARD_FORMATS.GDIOBJFIRST;
const CF_GDIOBJLAST = CLIPBOARD_FORMATS.GDIOBJLAST;
// memory
extern "KERNEL32" fn GlobalUnlock(
hMem: isize,
) callconv(w.WINAPI) BOOL;
extern "KERNEL32" fn GlobalLock(
hMem: isize,
) callconv(w.WINAPI) ?*c_void;
const GLOBAL_ALLOC_FLAGS = enum(u32) {
HND = 66,
MEM_FIXED = 0,
MEM_MOVEABLE = 2,
MEM_ZEROINIT = 64,
// PTR = 64, this enum value conflicts with MEM_ZEROINIT
_,
pub fn initFlags(o: struct {
HND: u1 = 0,
MEM_FIXED: u1 = 0,
MEM_MOVEABLE: u1 = 0,
MEM_ZEROINIT: u1 = 0,
}) GLOBAL_ALLOC_FLAGS {
return @intToEnum(GLOBAL_ALLOC_FLAGS, (if (o.HND == 1) @enumToInt(GLOBAL_ALLOC_FLAGS.HND) else 0) | (if (o.MEM_FIXED == 1) @enumToInt(GLOBAL_ALLOC_FLAGS.MEM_FIXED) else 0) | (if (o.MEM_MOVEABLE == 1) @enumToInt(GLOBAL_ALLOC_FLAGS.MEM_MOVEABLE) else 0) | (if (o.MEM_ZEROINIT == 1) @enumToInt(GLOBAL_ALLOC_FLAGS.MEM_ZEROINIT) else 0));
}
};
const GHND = GLOBAL_ALLOC_FLAGS.HND;
const GMEM_FIXED = GLOBAL_ALLOC_FLAGS.MEM_FIXED;
const GMEM_MOVEABLE = GLOBAL_ALLOC_FLAGS.MEM_MOVEABLE;
const GMEM_ZEROINIT = GLOBAL_ALLOC_FLAGS.MEM_ZEROINIT;
const GPTR = GLOBAL_ALLOC_FLAGS.MEM_ZEROINIT;
extern "KERNEL32" fn GlobalAlloc(
uFlags: GLOBAL_ALLOC_FLAGS,
dwBytes: usize,
) callconv(w.WINAPI) isize;
extern "KERNEL32" fn GlobalFree(
hMem: isize,
) callconv(w.WINAPI) isize;
// resource.h
// #define IDD_MFPLAYBACK_DIALOG 102
// #define IDM_EXIT 105
// #define IDC_MFPLAYBACK 109
// #define IDD_OPENURL 129
// #define IDC_EDIT_URL 1000
// #define ID_FILE_OPENFILE 32771
// #define ID_FILE_OPENURL 32772
// #define IDC_STATIC -1
const IDM_EXIT = @as(u32, 105);
pub export fn wWinMain(hInstance: w.HINSTANCE, hPrevInstance: ?w.HINSTANCE, lpCmdLine: w.PWSTR, nCmdShow: w.INT) w.INT { pub export fn wWinMain(hInstance: w.HINSTANCE, hPrevInstance: ?w.HINSTANCE, lpCmdLine: w.PWSTR, nCmdShow: w.INT) w.INT {
_ = hPrevInstance; _ = hPrevInstance;
_ = lpCmdLine; _ = lpCmdLine;
@ -338,14 +695,303 @@ pub export fn wWinMain(hInstance: w.HINSTANCE, hPrevInstance: ?w.HINSTANCE, lpCm
return 0; return 0;
} }
// Globals
var uFormat: w.UINT = @bitReverse(c_uint, 0);
var fAuto: w.BOOL = w.TRUE;
var hwndNextViewer: ?w.HWND = null;
fn MainWndProc(hwnd: w.HWND, uMsg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w.WINAPI) w.LRESULT { //APIENTRY { fn MainWndProc(hwnd: w.HWND, uMsg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w.WINAPI) w.LRESULT { //APIENTRY {
_ = hwnd; // static HWND hwndNextViewer;
_ = uMsg; // uMsg is actually a pointer to the message //
_ = wParam; // HDC hdc;
_ = lParam; // HDC hdcMem;
// PAINTSTRUCT ps;
// LPPAINTSTRUCT lpps;
// RECT rc;
// LPRECT lprc;
// HGLOBAL hglb;
// LPSTR lpstr;
// HBITMAP hbm;
// HENHMETAFILE hemf;
// HWND hwndOwner;
_ = MessageBoxA(null, "all your codebase are belong to us", "title", 0); switch (uMsg) {
std.time.sleep(2 * std.time.ns_per_s); WM_PAINT => {
var ps: PAINTSTRUCT = .{
.hdc = null,
.fErase = 0,
.rcPaint = .{
.left = 0,
.top = 0,
.right = 0,
.bottom = 0,
},
.fRestore = 0,
.fIncUpdate = 0,
.rgbReserved = [_]u8{0} ** 32,
};
var rc: RECT = .{
.left = 0,
.top = 0,
.right = 0,
.bottom = 0,
};
var hdc = BeginPaint(hwnd, &ps);
// Branch depending on the clipboard format.
switch (uFormat) {
@enumToInt(CF_OWNERDISPLAY) => {
// hwndOwner = GetClipboardOwner();
// hglb = GlobalAlloc(GMEM_MOVEABLE,
// sizeof(PAINTSTRUCT));
// lpps = GlobalLock(hglb);
// memcpy(lpps, &ps, sizeof(PAINTSTRUCT));
// GlobalUnlock(hglb);
//
// SendMessage(hwndOwner, WM_PAINTCLIPBOARD,
// (WPARAM) hwnd, (LPARAM) hglb);
//
// GlobalFree(hglb);
},
@enumToInt(CF_BITMAP) => {
// hdcMem = CreateCompatibleDC(hdc);
// if (hdcMem != NULL)
// {
// if (OpenClipboard(hwnd))
// {
// hbm = (HBITMAP)
// GetClipboardData(uFormat);
// SelectObject(hdcMem, hbm);
// GetClientRect(hwnd, &rc);
//
// BitBlt(hdc, 0, 0, rc.right, rc.bottom,
// hdcMem, 0, 0, SRCCOPY);
// CloseClipboard();
// }
// DeleteDC(hdcMem);
// }
},
@enumToInt(CF_TEXT) => {
if (OpenClipboard(hwnd) > 0) {
var hglb = GetClipboardData(uFormat).?;
const hnd = @intCast(isize, @ptrToInt(hglb));
var lpstr = GlobalLock(hnd).?;
_ = GetClientRect(hwnd, &rc);
_ = DrawTextA(hdc, @ptrCast([*:0]const u8, lpstr), -1, &rc, DT_LEFT);
_ = GlobalUnlock(hnd);
_ = CloseClipboard();
}
},
@enumToInt(CF_ENHMETAFILE) => {
// if (OpenClipboard(hwnd))
// {
// hemf = GetClipboardData(uFormat);
// GetClientRect(hwnd, &rc);
// PlayEnhMetaFile(hdc, hemf, &rc);
// CloseClipboard();
// }
},
0 => {
_ = GetClientRect(hwnd, &rc);
_ = DrawTextA(
hdc,
"The clipboard is empty.",
-1,
&rc,
@intToEnum(DRAW_TEXT_FORMAT, @enumToInt(DT_CENTER) | @enumToInt(DT_SINGLELINE) |
@enumToInt(DT_VCENTER)),
);
},
else => {
_ = GetClientRect(hwnd, &rc);
_ = DrawTextA(
hdc,
"Unable to display format.",
-1,
&rc,
@intToEnum(DRAW_TEXT_FORMAT, @enumToInt(DT_CENTER) | @enumToInt(DT_SINGLELINE) |
@enumToInt(DT_VCENTER)),
);
},
}
_ = EndPaint(hwnd, &ps);
},
WM_SIZE => {
if (uFormat == @enumToInt(CF_OWNERDISPLAY)) {
var hwndOwner = GetClipboardOwner().?;
var hglb = GlobalAlloc(GMEM_MOVEABLE, @sizeOf(RECT));
defer _ = GlobalFree(hglb);
var lprc = GlobalLock(hglb);
_ = GetClientRect(hwnd, @ptrCast(?*RECT, @alignCast(@alignOf(?*RECT), lprc)));
_ = GlobalUnlock(hglb);
// hwnd and hglb are just casts
_ = SendMessageA(hwndOwner, WM_SIZECLIPBOARD, @ptrToInt(hwnd), hglb);
}
},
WM_CREATE => {
// Add the window to the clipboard viewer chain.
hwndNextViewer = SetClipboardViewer(hwnd);
},
WM_CHANGECBCHAIN => {
// If the next window is closing, repair the chain.
// if ((HWND) wParam == hwndNextViewer)
if (wParam == @ptrToInt(hwndNextViewer.?)) {
hwndNextViewer = @intToPtr(w.HWND, @intCast(usize, lParam)); // just a cast
// Otherwise, pass the message to the next link.
} else if (hwndNextViewer) |hnv| {
_ = SendMessageA(hnv, uMsg, wParam, lParam);
}
},
WM_DESTROY => {
_ = ChangeClipboardChain(hwnd, hwndNextViewer);
PostQuitMessage(0);
},
WM_DRAWCLIPBOARD => { // clipboard contents changed.
// Update the window by using Auto clipboard format.
SetAutoView(hwnd);
// Pass the message to the next window in clipboard
// viewer chain.
_ = SendMessageA(hwndNextViewer, uMsg, wParam, lParam);
},
WM_INITMENUPOPUP => {
// if (!HIWORD(lParam))
// if (lParam > 0xffffffff)
// InitMenu(hwnd, wParam); // (HMENU) wParam);
},
WM_COMMAND => {
// switch (LOWORD(wParam)) {
switch (wParam & 0xffffffff) {
IDM_EXIT => _ = DestroyWindow(hwnd),
// IDM_AUTO => SetAutoView(hwnd),
else => {
fAuto = w.FALSE;
uFormat = @intCast(w.UINT, wParam & 0xffffffff); // LOWORD(wParam);
_ = InvalidateRect(hwnd, null, w.TRUE);
},
}
},
else => return DefWindowProcA(hwnd, uMsg, wParam, lParam),
}
return 0; return 0;
} }
var auPriorityList: [4]u32 = .{
@enumToInt(CF_OWNERDISPLAY),
@enumToInt(CF_TEXT),
@enumToInt(CF_ENHMETAFILE),
@enumToInt(CF_BITMAP),
};
fn SetAutoView(hwnd: w.HWND) callconv(w.WINAPI) void {
var runtime_zero: usize = 0;
var auPriorityListSlice = auPriorityList[runtime_zero..auPriorityList.len];
uFormat = @intCast(c_uint, GetPriorityClipboardFormat(auPriorityListSlice.ptr, 4));
fAuto = w.TRUE;
_ = InvalidateRect(hwnd, null, w.TRUE);
_ = UpdateWindow(hwnd);
}
// fn InitMenu(hwnd: w.HWND, hmenu: w.HMENU) callconv(w.WINAPI) void {
// // UINT uFormat;
// // char szFormatName[80];
// // LPCSTR lpFormatName;
// // UINT fuFlags;
// // UINT idMenuItem;
//
// // If a menu is not the display menu, no initialization is necessary.
//
// if (GetMenuItemID(hmenu, 0) != IDM_AUTO)
// return;
//
// // Delete all menu items except the first.
//
// while (GetMenuItemCount(hmenu) > 1)
// DeleteMenu(hmenu, 1, MF_BYPOSITION);
//
// // Check or uncheck the Auto menu item.
//
// if (fAuto) {
// fuFlags = MF_BYCOMMAND | MF_CHECKED;
// } else fuFlags = MF_BYCOMMAND | MF_UNCHECKED;
//
// CheckMenuItem(hmenu, IDM_AUTO, fuFlags);
//
// // If there are no clipboard formats, return.
//
// if (CountClipboardFormats() == 0)
// return;
//
// // Open the clipboard.
//
// if (!OpenClipboard(hwnd))
// return;
//
// // Add a separator and then a menu item for each format.
//
// AppendMenu(hmenu, MF_SEPARATOR, 0, null);
// var uFormat = EnumClipboardFormats(0);
//
// while (uFormat) {
// // Call an application-defined function to get the name
// // of the clipboard format.
//
// var lpFormatName = GetPredefinedClipboardFormatName(uFormat);
//
// // For registered formats, get the registered name.
//
// if (lpFormatName == null) {
//
// // Note that, if the format name is larger than the
// // buffer, it is truncated.
// if (GetClipboardFormatName(uFormat, szFormatName, @sizeOf(szFormatName))) {
// lpFormatName = szFormatName;
// } else lpFormatName = "(unknown)";
// }
//
// // Add a menu item for the format. For displayable
// // formats, use the format ID for the menu ID.
//
// if (IsDisplayableFormat(uFormat)) {
// fuFlags = MF_STRING;
// idMenuItem = uFormat;
// } else {
// fuFlags = MF_STRING | MF_GRAYED;
// idMenuItem = 0;
// }
// AppendMenu(hmenu, fuFlags, idMenuItem, lpFormatName);
//
// uFormat = EnumClipboardFormats(uFormat);
// }
// CloseClipboard();
// }
//
// fn IsDisplayableFormat(ufmt: w.UINT) callconv(w.WINAPI) w.BOOL {
// switch (ufmt) {
// CF_OWNERDISPLAY => return true,
// CF_TEXT => return true,
// CF_ENHMETAFILE => return true,
// CF_BITMAP => return true,
// else => return false,
// }
// }