Skip to content

Commit a69f2b1

Browse files
committed
feat(ptk): add Windows implemention for clipboard
1 parent d3197db commit a69f2b1

File tree

5 files changed

+273
-0
lines changed

5 files changed

+273
-0
lines changed

lib/ptk/src/clipboard.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
#include <string.h>
1515
#include "ptk/app.h"
1616
#include "linux/x11clipboard.h"
17+
#ifdef PTK_WIN_DESKTOP
18+
#include "windows/win32clipboard.h"
19+
#endif
1720

1821
static struct ptk_clipboard_module {
1922
char *text;
@@ -26,6 +29,11 @@ int ptk_clipboard_request_text(ptk_clipboard_callback_t callback, void *arg)
2629
if (ptk_get_app_id() == PTK_APP_ID_LINUX_X11) {
2730
return ptk_x11clipboard_request_text(callback, arg);
2831
}
32+
#endif
33+
#ifdef PTK_WIN_DESKTOP
34+
if (ptk_get_app_id() == PTK_APP_ID_WIN_DESKTOP) {
35+
return ptk_win32clipboard_request_text(callback, arg);
36+
}
2937
#endif
3038
size_t len = ptk_clipboard.text_len + 1;
3139
wchar_t *wstr = malloc(sizeof(wchar_t) * len);
@@ -52,6 +60,11 @@ int ptk_clipboard_set_text(const wchar_t *text, size_t len)
5260
if (ptk_get_app_id() == PTK_APP_ID_LINUX_X11) {
5361
return ptk_x11clipboard_set_text(text, len);
5462
}
63+
#endif
64+
#ifdef PTK_WIN_DESKTOP
65+
if (ptk_get_app_id() == PTK_APP_ID_WIN_DESKTOP) {
66+
return ptk_win32clipboard_set_text(text, len);
67+
}
5568
#endif
5669
size_t raw_len = encode_utf8(NULL, text, 0);
5770
char *raw_text = malloc((raw_len + 1) * sizeof(char));
@@ -74,6 +87,12 @@ void ptk_clipboard_init(void)
7487
return;
7588
}
7689
#endif
90+
#ifdef PTK_WIN_DESKTOP
91+
if (ptk_get_app_id() == PTK_APP_ID_WIN_DESKTOP) {
92+
ptk_win32clipboard_init();
93+
return;
94+
}
95+
#endif
7796
}
7897

7998
void ptk_clipboard_destroy(void)
@@ -83,6 +102,12 @@ void ptk_clipboard_destroy(void)
83102
ptk_x11clipboard_destroy();
84103
return;
85104
}
105+
#endif
106+
#ifdef PTK_WIN_DESKTOP
107+
if (ptk_get_app_id() == PTK_APP_ID_WIN_DESKTOP) {
108+
ptk_win32clipboard_destroy();
109+
return;
110+
}
86111
#endif
87112
if (ptk_clipboard.text) {
88113
free(ptk_clipboard.text);
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/*
2+
* lib/ptk/src/windows/win32clipboard.c: clipboard support for Windows
3+
*
4+
* Copyright (c) 2025, Liu Chao <[email protected]> All rights reserved.
5+
*
6+
* SPDX-License-Identifier: MIT
7+
*
8+
* This file is part of LCUI, distributed under the MIT License found in the
9+
* LICENSE.TXT file in the root directory of this source tree.
10+
*/
11+
12+
/*
13+
* References:
14+
* - https://docs.microsoft.com/en-us/windows/win32/dataxchg/using-the-clipboard
15+
* -
16+
* https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-openclipboard
17+
* -
18+
* https://github.com/libsdl-org/SDL/blob/main/src/video/windows/SDL_windowsclipboard.c
19+
*/
20+
21+
#include <yutil.h>
22+
#include "ptk/app.h"
23+
24+
#ifdef PTK_WIN_DESKTOP
25+
26+
#include <windows.h>
27+
#include <stdlib.h>
28+
#include <string.h>
29+
#include "win32clipboard.h"
30+
31+
static struct ptk_win32clipboard_module {
32+
char *text;
33+
size_t text_len;
34+
HWND hwnd; // Window handle for clipboard operations
35+
} ptk_win32clipboard;
36+
37+
int ptk_win32clipboard_request_text(ptk_clipboard_callback_t callback,
38+
void *arg)
39+
{
40+
ptk_clipboard_t clipboard = { 0 };
41+
wchar_t *clipboard_text = NULL;
42+
size_t len = 0;
43+
44+
// Open the clipboard
45+
if (!OpenClipboard(ptk_win32clipboard.hwnd)) {
46+
logger_warning("Failed to open clipboard\n");
47+
// Return empty clipboard data
48+
clipboard.text = calloc(1, sizeof(wchar_t));
49+
clipboard.len = 0;
50+
clipboard.image = NULL;
51+
callback(&clipboard, arg);
52+
free(clipboard.text);
53+
return -1;
54+
}
55+
56+
// Get clipboard data handle
57+
HANDLE hData = GetClipboardData(CF_UNICODETEXT);
58+
if (hData == NULL) {
59+
// No Unicode text available, try ANSI text
60+
hData = GetClipboardData(CF_TEXT);
61+
if (hData != NULL) {
62+
// Convert ANSI to Unicode
63+
char *ansi_text = (char *)GlobalLock(hData);
64+
if (ansi_text != NULL) {
65+
int wlen = MultiByteToWideChar(
66+
CP_ACP, 0, ansi_text, -1, NULL, 0);
67+
if (wlen > 0) {
68+
clipboard_text =
69+
malloc(wlen * sizeof(wchar_t));
70+
if (clipboard_text != NULL) {
71+
MultiByteToWideChar(
72+
CP_ACP, 0, ansi_text, -1,
73+
clipboard_text, wlen);
74+
len =
75+
wlen - 1; // Exclude null
76+
// terminator
77+
}
78+
}
79+
GlobalUnlock(hData);
80+
}
81+
}
82+
} else {
83+
// Unicode text available
84+
wchar_t *unicode_text = (wchar_t *)GlobalLock(hData);
85+
if (unicode_text != NULL) {
86+
len = wcslen(unicode_text);
87+
clipboard_text = malloc((len + 1) * sizeof(wchar_t));
88+
if (clipboard_text != NULL) {
89+
wcscpy(clipboard_text, unicode_text);
90+
}
91+
GlobalUnlock(hData);
92+
}
93+
}
94+
95+
CloseClipboard();
96+
97+
// Prepare clipboard data
98+
if (clipboard_text == NULL) {
99+
clipboard_text = calloc(1, sizeof(wchar_t));
100+
len = 0;
101+
}
102+
103+
clipboard.text = clipboard_text;
104+
clipboard.len = len;
105+
clipboard.image = NULL;
106+
107+
callback(&clipboard, arg);
108+
109+
free(clipboard_text);
110+
return 0;
111+
}
112+
113+
int ptk_win32clipboard_set_text(const wchar_t *text, size_t len)
114+
{
115+
HGLOBAL hMem;
116+
wchar_t *pMem;
117+
size_t size;
118+
119+
if (!text || len == 0) {
120+
return -1;
121+
}
122+
123+
// Open the clipboard
124+
if (!OpenClipboard(ptk_win32clipboard.hwnd)) {
125+
logger_warning("Failed to open clipboard for writing\n");
126+
return -1;
127+
}
128+
129+
// Empty the clipboard
130+
if (!EmptyClipboard()) {
131+
logger_warning("Failed to empty clipboard\n");
132+
CloseClipboard();
133+
return -1;
134+
}
135+
136+
// Allocate global memory for the text
137+
size = (len + 1) * sizeof(wchar_t);
138+
hMem = GlobalAlloc(GMEM_MOVEABLE, size);
139+
if (hMem == NULL) {
140+
logger_warning(
141+
"Failed to allocate memory for clipboard text\n");
142+
CloseClipboard();
143+
return -1;
144+
}
145+
146+
// Lock the memory and copy the text
147+
pMem = (wchar_t *)GlobalLock(hMem);
148+
if (pMem == NULL) {
149+
logger_warning("Failed to lock clipboard memory\n");
150+
GlobalFree(hMem);
151+
CloseClipboard();
152+
return -1;
153+
}
154+
155+
wcsncpy(pMem, text, len);
156+
pMem[len] = L'\0';
157+
GlobalUnlock(hMem);
158+
159+
// Set the clipboard data
160+
if (SetClipboardData(CF_UNICODETEXT, hMem) == NULL) {
161+
logger_warning("Failed to set clipboard data\n");
162+
GlobalFree(hMem);
163+
CloseClipboard();
164+
return -1;
165+
}
166+
167+
CloseClipboard();
168+
169+
// Update internal text buffer for fallback
170+
size_t utf8_len = encode_utf8(NULL, text, 0);
171+
char *utf8_text = malloc((utf8_len + 1) * sizeof(char));
172+
if (utf8_text != NULL) {
173+
utf8_len = encode_utf8(utf8_text, text, utf8_len);
174+
utf8_text[utf8_len] = '\0';
175+
176+
if (ptk_win32clipboard.text) {
177+
free(ptk_win32clipboard.text);
178+
}
179+
ptk_win32clipboard.text = utf8_text;
180+
ptk_win32clipboard.text_len = utf8_len;
181+
}
182+
183+
return 0;
184+
}
185+
186+
void ptk_win32clipboard_init(void)
187+
{
188+
ptk_win32clipboard.text = NULL;
189+
ptk_win32clipboard.text_len = 0;
190+
191+
// Get the main window handle for clipboard operations
192+
// This should be set by the main application window
193+
ptk_win32clipboard.hwnd = GetActiveWindow();
194+
if (ptk_win32clipboard.hwnd == NULL) {
195+
ptk_win32clipboard.hwnd = GetDesktopWindow();
196+
}
197+
198+
logger_debug("Win32 clipboard initialized with HWND: %p\n",
199+
ptk_win32clipboard.hwnd);
200+
}
201+
202+
void ptk_win32clipboard_destroy(void)
203+
{
204+
if (ptk_win32clipboard.text) {
205+
free(ptk_win32clipboard.text);
206+
ptk_win32clipboard.text = NULL;
207+
}
208+
ptk_win32clipboard.text_len = 0;
209+
ptk_win32clipboard.hwnd = NULL;
210+
}
211+
212+
// Function to set the window handle for clipboard operations
213+
// This should be called by the main application window
214+
void ptk_win32clipboard_set_window(HWND hwnd)
215+
{
216+
ptk_win32clipboard.hwnd = hwnd;
217+
}
218+
219+
#endif // PTK_WIN_DESKTOP
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* lib/ptk/src/windows/win32clipboard.h
3+
*
4+
* Copyright (c) 2025, Liu Chao <[email protected]> All rights reserved.
5+
*
6+
* SPDX-License-Identifier: MIT
7+
*
8+
* This file is part of LCUI, distributed under the MIT License found in the
9+
* LICENSE.TXT file in the root directory of this source tree.
10+
*/
11+
12+
#ifndef PTK_WIN32CLIPBOARD_H
13+
#define PTK_WIN32CLIPBOARD_H
14+
15+
#include "ptk/clipboard.h"
16+
17+
#ifdef PTK_WIN_DESKTOP
18+
#include <windows.h>
19+
20+
int ptk_win32clipboard_request_text(ptk_clipboard_callback_t callback,
21+
void *arg);
22+
int ptk_win32clipboard_set_text(const wchar_t *text, size_t len);
23+
void ptk_win32clipboard_init(void);
24+
void ptk_win32clipboard_destroy(void);
25+
void ptk_win32clipboard_set_window(HWND hwnd);
26+
27+
#endif
28+
29+
#endif

0 commit comments

Comments
 (0)