From 16503c3b91694f5ce9262e7edd7607b85926327d Mon Sep 17 00:00:00 2001 From: Fakhri Mouad Date: Wed, 28 Aug 2024 16:36:06 +0100 Subject: [PATCH 1/4] Add Win32 procs needed to handle clipboard --- core/sys/windows/kernel32.odin | 3 ++ core/sys/windows/user32.odin | 35 +++++++++++++++ tests/core/sys/windows/test_clipboard.odin | 52 ++++++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 tests/core/sys/windows/test_clipboard.odin diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 629ece3de..81db67185 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -400,6 +400,9 @@ foreign kernel32 { GlobalAlloc :: proc(flags: UINT, bytes: SIZE_T) -> LPVOID --- GlobalReAlloc :: proc(mem: LPVOID, bytes: SIZE_T, flags: UINT) -> LPVOID --- GlobalFree :: proc(mem: LPVOID) -> LPVOID --- + + GlobalLock :: proc(hMem: HGLOBAL) -> LPVOID --- + GlobalUnlock :: proc(hMem: HGLOBAL) -> BOOL --- ReadDirectoryChangesW :: proc( hDirectory: HANDLE, diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 31fc59f72..e13dcd55f 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -305,6 +305,13 @@ foreign user32 { GetProcessWindowStation :: proc() -> HWINSTA --- GetUserObjectInformationW :: proc(hObj: HANDLE, nIndex: GetUserObjectInformationFlags, pvInfo: PVOID, nLength: DWORD, lpnLengthNeeded: LPDWORD) -> BOOL --- + + OpenClipboard :: proc(hWndNewOwner: HWND) -> BOOL --- + CloseClipboard :: proc() -> BOOL --- + GetClipboardData :: proc(uFormat: UINT) -> HANDLE --- + SetClipboardData :: proc(uFormat: UINT, hMem: HANDLE) -> HANDLE --- + IsClipboardFormatAvailable :: proc(format: UINT) -> BOOL --- + EmptyClipboard :: proc() -> BOOL --- } CreateWindowW :: #force_inline proc "system" ( @@ -746,3 +753,31 @@ WinEventFlag :: enum DWORD { SKIPOWNPROCESS = 1, INCONTEXT = 2, } + +// Standard Clipboard Formats +CF_TEXT :: 1 +CF_BITMAP :: 2 +CF_METAFILEPICT :: 3 +CF_SYLK :: 4 +CF_DIF :: 5 +CF_TIFF :: 6 +CF_OEMTEXT :: 7 +CF_DIB :: 8 +CF_PALETTE :: 9 +CF_PENDATA :: 10 +CF_RIFF :: 11 +CF_WAVE :: 12 +CF_UNICODETEXT :: 13 +CF_ENHMETAFILE :: 14 +CF_HDROP :: 15 +CF_LOCALE :: 16 +CF_DIBV5 :: 17 +CF_DSPBITMAP :: 0x0082 +CF_DSPENHMETAFILE :: 0x008E +CF_DSPMETAFILEPICT :: 0x0083 +CF_DSPTEXT :: 0x0081 +CF_GDIOBJFIRST :: 0x0300 +CF_GDIOBJLAST :: 0x03FF +CF_OWNERDISPLAY :: 0x0080 +CF_PRIVATEFIRST :: 0x0200 +CF_PRIVATELAST :: 0x02FF diff --git a/tests/core/sys/windows/test_clipboard.odin b/tests/core/sys/windows/test_clipboard.odin new file mode 100644 index 000000000..460012cae --- /dev/null +++ b/tests/core/sys/windows/test_clipboard.odin @@ -0,0 +1,52 @@ +//+build windows +package test_core_sys_windows + +import "core:testing" +import win32 "core:sys/windows" +import "base:runtime" +import "core:strings" +import "core:mem" + +read_from_clipboard :: proc(wnd_handle: win32.HWND, allocator: runtime.Allocator) -> (result: string) +{ + if !win32.IsClipboardFormatAvailable(win32.CF_TEXT) do return; + + if !win32.OpenClipboard(wnd_handle) do return; + defer win32.CloseClipboard(); + + clipboard_data := win32.GetClipboardData(win32.CF_TEXT); + if clipboard_data != nil { + if cstr := cstring(win32.GlobalLock(win32.HGLOBAL(clipboard_data))); cstr != nil { + result = strings.clone_from_cstring(cstr, allocator); + } + win32.GlobalUnlock(win32.HGLOBAL(clipboard_data)); + } + return; +} + +write_to_clipboard :: proc(wnd_handle: win32.HWND, text: string) +{ + if !win32.OpenClipboard(wnd_handle) do return; + defer win32.CloseClipboard(); + win32.EmptyClipboard(); + + h_mem := win32.HGLOBAL(win32.GlobalAlloc(win32.GMEM_MOVEABLE, len(text) + 1)); + if h_mem == nil do return; + + cstr_dst := cast([^]u8)win32.GlobalLock(h_mem); + defer win32.GlobalUnlock(h_mem); + if cstr_dst == nil do return; + + mem.copy(rawptr(cstr_dst), raw_data(text), len(text)); + cstr_dst[len(text)] = 0; + + win32.SetClipboardData(win32.CF_TEXT, win32.HANDLE(h_mem)); +} + + +@(test) +verify_win32_clipboard :: proc(t: ^testing.T) { + write_to_clipboard(nil, "Hello everynyan! OH MY GAH"); + clipboard_content := read_from_clipboard(nil, context.temp_allocator); + testing.expect_value(t, clipboard_content, "Hello everynyan! OH MY GAH"); +} From 967b6d46b285e31e3c47d12ead35dc95e1370013 Mon Sep 17 00:00:00 2001 From: Fakhri Mouad Date: Wed, 28 Aug 2024 17:27:27 +0100 Subject: [PATCH 2/4] avoid using `do` statement in odin codebase --- tests/core/sys/windows/test_clipboard.odin | 23 +++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/tests/core/sys/windows/test_clipboard.odin b/tests/core/sys/windows/test_clipboard.odin index 460012cae..f1ffeca28 100644 --- a/tests/core/sys/windows/test_clipboard.odin +++ b/tests/core/sys/windows/test_clipboard.odin @@ -7,46 +7,51 @@ import "base:runtime" import "core:strings" import "core:mem" -read_from_clipboard :: proc(wnd_handle: win32.HWND, allocator: runtime.Allocator) -> (result: string) +read_from_clipboard :: proc(wnd_handle: win32.HWND, allocator: runtime.Allocator) -> (result: string, ok: win32.BOOL) { - if !win32.IsClipboardFormatAvailable(win32.CF_TEXT) do return; + win32.IsClipboardFormatAvailable(win32.CF_TEXT) or_return; - if !win32.OpenClipboard(wnd_handle) do return; + win32.OpenClipboard(wnd_handle) or_return; defer win32.CloseClipboard(); clipboard_data := win32.GetClipboardData(win32.CF_TEXT); if clipboard_data != nil { if cstr := cstring(win32.GlobalLock(win32.HGLOBAL(clipboard_data))); cstr != nil { result = strings.clone_from_cstring(cstr, allocator); + ok = true; } win32.GlobalUnlock(win32.HGLOBAL(clipboard_data)); } return; } -write_to_clipboard :: proc(wnd_handle: win32.HWND, text: string) +write_to_clipboard :: proc(wnd_handle: win32.HWND, text: string) -> win32.BOOL { - if !win32.OpenClipboard(wnd_handle) do return; + win32.OpenClipboard(wnd_handle) or_return; defer win32.CloseClipboard(); win32.EmptyClipboard(); h_mem := win32.HGLOBAL(win32.GlobalAlloc(win32.GMEM_MOVEABLE, len(text) + 1)); - if h_mem == nil do return; + if h_mem == nil {return false}; cstr_dst := cast([^]u8)win32.GlobalLock(h_mem); defer win32.GlobalUnlock(h_mem); - if cstr_dst == nil do return; + if cstr_dst == nil {return false}; mem.copy(rawptr(cstr_dst), raw_data(text), len(text)); cstr_dst[len(text)] = 0; win32.SetClipboardData(win32.CF_TEXT, win32.HANDLE(h_mem)); + return true; } @(test) verify_win32_clipboard :: proc(t: ^testing.T) { - write_to_clipboard(nil, "Hello everynyan! OH MY GAH"); - clipboard_content := read_from_clipboard(nil, context.temp_allocator); + ok1 := write_to_clipboard(nil, "Hello everynyan! OH MY GAH"); + testing.expect_value(t, ok1, true); + + clipboard_content, ok2 := read_from_clipboard(nil, context.temp_allocator); + testing.expect_value(t, ok2, true); testing.expect_value(t, clipboard_content, "Hello everynyan! OH MY GAH"); } From 7e4750c3033ea54a4c2d6e1abb670078b1506c87 Mon Sep 17 00:00:00 2001 From: Fakhri Mouad Date: Wed, 28 Aug 2024 17:30:30 +0100 Subject: [PATCH 3/4] fix indentation in test file --- tests/core/sys/windows/test_clipboard.odin | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/core/sys/windows/test_clipboard.odin b/tests/core/sys/windows/test_clipboard.odin index f1ffeca28..6835e465d 100644 --- a/tests/core/sys/windows/test_clipboard.odin +++ b/tests/core/sys/windows/test_clipboard.odin @@ -9,19 +9,19 @@ import "core:mem" read_from_clipboard :: proc(wnd_handle: win32.HWND, allocator: runtime.Allocator) -> (result: string, ok: win32.BOOL) { - win32.IsClipboardFormatAvailable(win32.CF_TEXT) or_return; + win32.IsClipboardFormatAvailable(win32.CF_TEXT) or_return; - win32.OpenClipboard(wnd_handle) or_return; - defer win32.CloseClipboard(); - - clipboard_data := win32.GetClipboardData(win32.CF_TEXT); - if clipboard_data != nil { - if cstr := cstring(win32.GlobalLock(win32.HGLOBAL(clipboard_data))); cstr != nil { - result = strings.clone_from_cstring(cstr, allocator); - ok = true; - } - win32.GlobalUnlock(win32.HGLOBAL(clipboard_data)); + win32.OpenClipboard(wnd_handle) or_return; + defer win32.CloseClipboard(); + + clipboard_data := win32.GetClipboardData(win32.CF_TEXT); + if clipboard_data != nil { + if cstr := cstring(win32.GlobalLock(win32.HGLOBAL(clipboard_data))); cstr != nil { + result = strings.clone_from_cstring(cstr, allocator); + ok = true; } + win32.GlobalUnlock(win32.HGLOBAL(clipboard_data)); + } return; } From b08c14b710c889b1db47e0e1331bb74ade51bf06 Mon Sep 17 00:00:00 2001 From: Fakhri Mouad Date: Wed, 28 Aug 2024 17:52:58 +0100 Subject: [PATCH 4/4] fix style, ensure we compile with flags `-vet -strict-style -disallow-do` --- tests/core/sys/windows/test_clipboard.odin | 56 +++++++++++----------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/tests/core/sys/windows/test_clipboard.odin b/tests/core/sys/windows/test_clipboard.odin index 6835e465d..67fa6e4a2 100644 --- a/tests/core/sys/windows/test_clipboard.odin +++ b/tests/core/sys/windows/test_clipboard.odin @@ -7,51 +7,49 @@ import "base:runtime" import "core:strings" import "core:mem" -read_from_clipboard :: proc(wnd_handle: win32.HWND, allocator: runtime.Allocator) -> (result: string, ok: win32.BOOL) -{ - win32.IsClipboardFormatAvailable(win32.CF_TEXT) or_return; +read_from_clipboard :: proc(wnd_handle: win32.HWND, allocator: runtime.Allocator) -> (result: string, ok: win32.BOOL) { + win32.IsClipboardFormatAvailable(win32.CF_TEXT) or_return - win32.OpenClipboard(wnd_handle) or_return; - defer win32.CloseClipboard(); + win32.OpenClipboard(wnd_handle) or_return + defer win32.CloseClipboard() - clipboard_data := win32.GetClipboardData(win32.CF_TEXT); + clipboard_data := win32.GetClipboardData(win32.CF_TEXT) if clipboard_data != nil { if cstr := cstring(win32.GlobalLock(win32.HGLOBAL(clipboard_data))); cstr != nil { - result = strings.clone_from_cstring(cstr, allocator); - ok = true; + result = strings.clone_from_cstring(cstr, allocator) + ok = true } - win32.GlobalUnlock(win32.HGLOBAL(clipboard_data)); + win32.GlobalUnlock(win32.HGLOBAL(clipboard_data)) } - return; + return } -write_to_clipboard :: proc(wnd_handle: win32.HWND, text: string) -> win32.BOOL -{ - win32.OpenClipboard(wnd_handle) or_return; - defer win32.CloseClipboard(); - win32.EmptyClipboard(); +write_to_clipboard :: proc(wnd_handle: win32.HWND, text: string) -> win32.BOOL { + win32.OpenClipboard(wnd_handle) or_return + defer win32.CloseClipboard() + win32.EmptyClipboard() - h_mem := win32.HGLOBAL(win32.GlobalAlloc(win32.GMEM_MOVEABLE, len(text) + 1)); - if h_mem == nil {return false}; + h_mem := win32.HGLOBAL(win32.GlobalAlloc(win32.GMEM_MOVEABLE, len(text) + 1)) + if h_mem == nil {return false} - cstr_dst := cast([^]u8)win32.GlobalLock(h_mem); - defer win32.GlobalUnlock(h_mem); - if cstr_dst == nil {return false}; + cstr_dst := cast([^]u8)win32.GlobalLock(h_mem) + defer win32.GlobalUnlock(h_mem) + if cstr_dst == nil {return false} - mem.copy(rawptr(cstr_dst), raw_data(text), len(text)); - cstr_dst[len(text)] = 0; + mem.copy(rawptr(cstr_dst), raw_data(text), len(text)) + cstr_dst[len(text)] = 0 - win32.SetClipboardData(win32.CF_TEXT, win32.HANDLE(h_mem)); - return true; + win32.SetClipboardData(win32.CF_TEXT, win32.HANDLE(h_mem)) + return true } @(test) verify_win32_clipboard :: proc(t: ^testing.T) { - ok1 := write_to_clipboard(nil, "Hello everynyan! OH MY GAH"); - testing.expect_value(t, ok1, true); + ok1 := write_to_clipboard(nil, "Hello everynyan! OH MY GAH") + testing.expect_value(t, ok1, true) - clipboard_content, ok2 := read_from_clipboard(nil, context.temp_allocator); - testing.expect_value(t, ok2, true); - testing.expect_value(t, clipboard_content, "Hello everynyan! OH MY GAH"); + clipboard_content, ok2 := read_from_clipboard(nil, context.temp_allocator) + testing.expect_value(t, ok2, true) + testing.expect_value(t, clipboard_content, "Hello everynyan! OH MY GAH") }