Skip to content

Commit 838af63

Browse files
committed
feat(ptk): add Windows implemention for clipboard
1 parent e5781dd commit 838af63

File tree

5 files changed

+261
-0
lines changed

5 files changed

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

0 commit comments

Comments
 (0)