mirror of
https://github.com/libsdl-org/SDL.git
synced 2024-11-30 15:23:28 +08:00
Support SDL_EVENT_DROP_FILE in Windows with IDropTarget instead of WM_DROPFILES
Support SDL_EVENT_DROP_TEXT in Windows src/video/windows/SDL_windowsvideo.c + .h Connect to COM WIN_CoInitialize + OLE OleInitialize in WIN_VideoInit Disconnect from COM WIN_CoUninitialize + OLE OleUninitialize in WIN_VideoQuit src/video/windows/SDL_windowswindow.c + .h Create / Destroy IDropTarget or use fallback WM_DROPFILES depending on OleInitialize success in WIN_VideoInit Handle text/uri-list, text/plain;charset=utf-8, CF_UNICODE_TEXT, CF_TEXT, CF_HDROP Call terminating WIN_AcceptDragAndDrop from WIN_DestroyWindow ( CleanupVideoData )
This commit is contained in:
parent
efefc4a1f3
commit
808c312b2a
@ -467,6 +467,21 @@ static void WIN_InitDPIAwareness(SDL_VideoDevice *_this)
|
||||
int WIN_VideoInit(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
HRESULT hr;
|
||||
|
||||
hr = WIN_CoInitialize();
|
||||
if (SUCCEEDED(hr)) {
|
||||
data->coinitialized = SDL_TRUE;
|
||||
|
||||
hr = OleInitialize(NULL);
|
||||
if (SUCCEEDED(hr)) {
|
||||
data->oleinitialized = SDL_TRUE;
|
||||
} else {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "OleInitialize() failed: 0x%.8x, using fallback drag-n-drop functionality\n", (unsigned int)hr);
|
||||
}
|
||||
} else {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "CoInitialize() failed: 0x%.8x, using fallback drag-n-drop functionality\n", (unsigned int)hr);
|
||||
}
|
||||
|
||||
WIN_InitDPIAwareness(_this);
|
||||
|
||||
@ -511,6 +526,8 @@ int WIN_VideoInit(SDL_VideoDevice *_this)
|
||||
|
||||
void WIN_VideoQuit(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
WIN_QuitModes(_this);
|
||||
WIN_QuitDeviceNotification();
|
||||
@ -525,6 +542,15 @@ void WIN_VideoQuit(SDL_VideoDevice *_this)
|
||||
|
||||
WIN_SetRawMouseEnabled(_this, SDL_FALSE);
|
||||
WIN_SetRawKeyboardEnabled(_this, SDL_FALSE);
|
||||
|
||||
if (data->oleinitialized) {
|
||||
OleUninitialize();
|
||||
data->oleinitialized = SDL_FALSE;
|
||||
}
|
||||
if (data->coinitialized) {
|
||||
WIN_CoUninitialize();
|
||||
data->coinitialized = SDL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
|
@ -379,6 +379,9 @@ struct SDL_VideoData
|
||||
{
|
||||
int render;
|
||||
|
||||
SDL_bool coinitialized;
|
||||
SDL_bool oleinitialized;
|
||||
|
||||
DWORD clipboard_count;
|
||||
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) /* Xbox doesn't support user32/shcore*/
|
||||
|
@ -24,12 +24,13 @@
|
||||
|
||||
#include "../../core/windows/SDL_windows.h"
|
||||
|
||||
#include "../SDL_sysvideo.h"
|
||||
#include "../SDL_pixels_c.h"
|
||||
#include "../../SDL_hints_c.h"
|
||||
#include "../../events/SDL_dropevents_c.h"
|
||||
#include "../../events/SDL_keyboard_c.h"
|
||||
#include "../../events/SDL_mouse_c.h"
|
||||
#include "../../events/SDL_windowevents_c.h"
|
||||
#include "../../SDL_hints_c.h"
|
||||
#include "../SDL_pixels_c.h"
|
||||
#include "../SDL_sysvideo.h"
|
||||
|
||||
#include "SDL_windowsvideo.h"
|
||||
#include "SDL_windowswindow.h"
|
||||
@ -188,26 +189,27 @@ static int WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, DWORD
|
||||
|
||||
/* Client rect, in points */
|
||||
switch (rect_type) {
|
||||
case SDL_WINDOWRECT_CURRENT:
|
||||
SDL_RelativeToGlobalForWindow(window, window->x, window->y, x, y);
|
||||
*width = window->w;
|
||||
*height = window->h;
|
||||
break;
|
||||
case SDL_WINDOWRECT_WINDOWED:
|
||||
SDL_RelativeToGlobalForWindow(window, window->windowed.x, window->windowed.y, x, y);
|
||||
*width = window->windowed.w;
|
||||
*height = window->windowed.h;
|
||||
break;
|
||||
case SDL_WINDOWRECT_FLOATING:
|
||||
SDL_RelativeToGlobalForWindow(window, window->floating.x, window->floating.y, x, y);
|
||||
*width = window->floating.w;
|
||||
*height = window->floating.h;
|
||||
break;
|
||||
default:
|
||||
/* Should never be here */
|
||||
SDL_assert_release(SDL_FALSE);
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
case SDL_WINDOWRECT_CURRENT:
|
||||
SDL_RelativeToGlobalForWindow(window, window->x, window->y, x, y);
|
||||
*width = window->w;
|
||||
*height = window->h;
|
||||
break;
|
||||
case SDL_WINDOWRECT_WINDOWED:
|
||||
SDL_RelativeToGlobalForWindow(window, window->windowed.x, window->windowed.y, x, y);
|
||||
*width = window->windowed.w;
|
||||
*height = window->windowed.h;
|
||||
break;
|
||||
case SDL_WINDOWRECT_FLOATING:
|
||||
SDL_RelativeToGlobalForWindow(window, window->floating.x, window->floating.y, x, y);
|
||||
*width = window->floating.w;
|
||||
*height = window->floating.h;
|
||||
break;
|
||||
default:
|
||||
/* Should never be here */
|
||||
SDL_assert_release(SDL_FALSE);
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Copy the client size in pixels into this rect structure,
|
||||
@ -587,6 +589,10 @@ static void CleanupWindowData(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
if (data) {
|
||||
SDL_DelHintCallback(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, WIN_MouseRelativeModeCenterChanged, data);
|
||||
|
||||
if (data->drop_target) {
|
||||
WIN_AcceptDragAndDrop(window, SDL_FALSE);
|
||||
}
|
||||
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
if (data->ICMFileName) {
|
||||
SDL_free(data->ICMFileName);
|
||||
@ -1136,7 +1142,7 @@ void WIN_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
SetWindowPos(hwnd, HWND_TOP, fx, fy, fw, fh, data->copybits_flag | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
|
||||
data->expected_resize = SDL_FALSE;
|
||||
}
|
||||
}else {
|
||||
} else {
|
||||
data->windowed_mode_was_maximized = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
@ -1693,10 +1699,468 @@ int WIN_SetWindowOpacity(SDL_VideoDevice *_this, SDL_Window *window, float opaci
|
||||
}
|
||||
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
|
||||
static const char *SDLGetClipboardFormatName(UINT cf, char *text, int len)
|
||||
{
|
||||
switch (cf) {
|
||||
case CF_TEXT:
|
||||
return "CF_TEXT";
|
||||
case CF_BITMAP:
|
||||
return "CF_BITMAP";
|
||||
case CF_METAFILEPICT:
|
||||
return "CF_METAFILEPICT";
|
||||
case CF_SYLK:
|
||||
return "CF_SYLK";
|
||||
case CF_DIF:
|
||||
return "CF_DIF";
|
||||
case CF_TIFF:
|
||||
return "CF_TIFF";
|
||||
case CF_OEMTEXT:
|
||||
return "CF_OEMTEXT";
|
||||
case CF_DIB:
|
||||
return "CF_DIB";
|
||||
case CF_PALETTE:
|
||||
return "CF_PALETTE";
|
||||
case CF_PENDATA:
|
||||
return "CF_PENDATA";
|
||||
case CF_RIFF:
|
||||
return "CF_RIFF";
|
||||
case CF_WAVE:
|
||||
return "CF_WAVE";
|
||||
case CF_UNICODETEXT:
|
||||
return "CF_UNICODETEXT";
|
||||
case CF_ENHMETAFILE:
|
||||
return "CF_ENHMETAFILE";
|
||||
case CF_HDROP:
|
||||
return "CF_HDROP";
|
||||
case CF_LOCALE:
|
||||
return "CF_LOCALE";
|
||||
case CF_DIBV5:
|
||||
return "CF_DIBV5";
|
||||
case CF_OWNERDISPLAY:
|
||||
return "CF_OWNERDISPLAY";
|
||||
case CF_DSPTEXT:
|
||||
return "CF_DSPTEXT";
|
||||
case CF_DSPBITMAP:
|
||||
return "CF_DSPBITMAP";
|
||||
case CF_DSPMETAFILEPICT:
|
||||
return "CF_DSPMETAFILEPICT";
|
||||
case CF_DSPENHMETAFILE:
|
||||
return "CF_DSPENHMETAFILE";
|
||||
default:
|
||||
if (GetClipboardFormatNameA(cf, text, len)) {
|
||||
return text;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static STDMETHODIMP_(ULONG) SDLDropTarget_AddRef(SDLDropTarget *target)
|
||||
{
|
||||
return ++target->refcount;
|
||||
}
|
||||
|
||||
static STDMETHODIMP_(ULONG) SDLDropTarget_Release(SDLDropTarget *target)
|
||||
{
|
||||
--target->refcount;
|
||||
if (target->refcount == 0) {
|
||||
SDL_free(target);
|
||||
return 0;
|
||||
}
|
||||
return target->refcount;
|
||||
}
|
||||
|
||||
static STDMETHODIMP SDLDropTarget_QueryInterface(SDLDropTarget *target, REFIID riid, PVOID *ppv)
|
||||
{
|
||||
if (ppv == NULL) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
*ppv = NULL;
|
||||
if (WIN_IsEqualIID(riid, &IID_IUnknown) ||
|
||||
WIN_IsEqualIID(riid, &IID_IDropTarget)) {
|
||||
*ppv = (void *)target;
|
||||
}
|
||||
if (*ppv) {
|
||||
SDLDropTarget_AddRef(target);
|
||||
return S_OK;
|
||||
}
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
static STDMETHODIMP SDLDropTarget_DragEnter(SDLDropTarget *target,
|
||||
IDataObject *pDataObject, DWORD grfKeyState,
|
||||
POINTL pt, DWORD *pdwEffect)
|
||||
{
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In DragEnter at %ld, %ld\n", pt.x, pt.y);
|
||||
*pdwEffect = DROPEFFECT_COPY;
|
||||
POINT pnt = { pt.x, pt.y };
|
||||
if (ScreenToClient(target->hwnd, &pnt)) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In DragEnter at %ld, %ld => window %u at %ld, %ld\n", pt.x, pt.y, target->window->id, pnt.x, pnt.y);
|
||||
SDL_SendDropPosition(target->window, pnt.x, pnt.y);
|
||||
} else {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In DragEnter at %ld, %ld => nil, nil\n", pt.x, pt.y);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP SDLDropTarget_DragOver(SDLDropTarget *target,
|
||||
DWORD grfKeyState,
|
||||
POINTL pt, DWORD *pdwEffect)
|
||||
{
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In DragOver at %ld, %ld\n", pt.x, pt.y);
|
||||
*pdwEffect = DROPEFFECT_COPY;
|
||||
POINT pnt = { pt.x, pt.y };
|
||||
if (ScreenToClient(target->hwnd, &pnt)) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In DragOver at %ld, %ld => window %u at %ld, %ld\n", pt.x, pt.y, target->window->id, pnt.x, pnt.y);
|
||||
SDL_SendDropPosition(target->window, pnt.x, pnt.y);
|
||||
} else {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In DragOver at %ld, %ld => nil, nil\n", pt.x, pt.y);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP SDLDropTarget_DragLeave(SDLDropTarget *target)
|
||||
{
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In DragLeave\n");
|
||||
SDL_SendDropComplete(target->window);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP SDLDropTarget_Drop(SDLDropTarget *target,
|
||||
IDataObject *pDataObject, DWORD grfKeyState,
|
||||
POINTL pt, DWORD *pdwEffect)
|
||||
{
|
||||
*pdwEffect = DROPEFFECT_COPY;
|
||||
POINT pnt = { pt.x, pt.y };
|
||||
if (ScreenToClient(target->hwnd, &pnt)) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop at %ld, %ld => window %u at %ld, %ld\n", pt.x, pt.y, target->window->id, pnt.x, pnt.y);
|
||||
SDL_SendDropPosition(target->window, pnt.x, pnt.y);
|
||||
} else {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop at %ld, %ld => nil, nil\n", pt.x, pt.y);
|
||||
}
|
||||
|
||||
{
|
||||
IEnumFORMATETC *pEnumFormatEtc;
|
||||
HRESULT hres;
|
||||
hres = pDataObject->lpVtbl->EnumFormatEtc(pDataObject, DATADIR_GET, &pEnumFormatEtc);
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop for EnumFormatEtc, HRESULT is %08lx\n", hres);
|
||||
if (hres == S_OK) {
|
||||
FORMATETC fetc;
|
||||
while (pEnumFormatEtc->lpVtbl->Next(pEnumFormatEtc, 1, &fetc, NULL) == S_OK) {
|
||||
char name[257] = { 0 };
|
||||
const char *cfnm = SDLGetClipboardFormatName(fetc.cfFormat, name, 256);
|
||||
if (cfnm) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop, Supported format is %08x, '%s'\n", fetc.cfFormat, cfnm);
|
||||
} else {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop, Supported format is %08x, Predefined\n", fetc.cfFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
FORMATETC fetc;
|
||||
fetc.cfFormat = target->format_file;
|
||||
fetc.ptd = NULL;
|
||||
fetc.dwAspect = DVASPECT_CONTENT;
|
||||
fetc.lindex = -1;
|
||||
fetc.tymed = TYMED_HGLOBAL;
|
||||
const char *format_mime = "text/uri-list";
|
||||
if (SUCCEEDED(pDataObject->lpVtbl->QueryGetData(pDataObject, &fetc))) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop File for QueryGetData, format %08x '%s', success\n",
|
||||
fetc.cfFormat, format_mime);
|
||||
STGMEDIUM med;
|
||||
HRESULT hres = pDataObject->lpVtbl->GetData(pDataObject, &fetc, &med);
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop File for GetData, format %08x '%s', HRESULT is %08lx\n",
|
||||
fetc.cfFormat, format_mime, hres);
|
||||
if (SUCCEEDED(hres)) {
|
||||
const size_t bsize = GlobalSize(med.hGlobal);
|
||||
const void *buffer = (void *)GlobalLock(med.hGlobal);
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop File for GlobalLock, format %08x '%s', memory (%lu) %p\n",
|
||||
fetc.cfFormat, format_mime, (unsigned long)bsize, buffer);
|
||||
if (buffer) {
|
||||
char *text = SDL_malloc(bsize + sizeof(Uint32));
|
||||
SDL_memcpy((Uint8 *)text, buffer, bsize);
|
||||
SDL_memset((Uint8 *)text + bsize, 0, sizeof(Uint32));
|
||||
char *saveptr = NULL;
|
||||
char *token = SDL_strtok_r(text, "\r\n", &saveptr);
|
||||
while (token != NULL) {
|
||||
if (SDL_URIToLocal(token, token) >= 0) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop File, file (%lu of %lu) '%s'\n",
|
||||
(unsigned long)strlen(token), (unsigned long)bsize, token);
|
||||
SDL_SendDropFile(target->window, NULL, token);
|
||||
}
|
||||
token = SDL_strtok_r(NULL, "\r\n", &saveptr);
|
||||
}
|
||||
SDL_free(text);
|
||||
}
|
||||
GlobalUnlock(med.hGlobal);
|
||||
ReleaseStgMedium(&med);
|
||||
SDL_SendDropComplete(target->window);
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
FORMATETC fetc;
|
||||
fetc.cfFormat = target->format_text;
|
||||
fetc.ptd = NULL;
|
||||
fetc.dwAspect = DVASPECT_CONTENT;
|
||||
fetc.lindex = -1;
|
||||
fetc.tymed = TYMED_HGLOBAL;
|
||||
const char *format_mime = "text/plain;charset=utf-8";
|
||||
if (SUCCEEDED(pDataObject->lpVtbl->QueryGetData(pDataObject, &fetc))) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop Text for QueryGetData, format %08x '%s', success\n",
|
||||
fetc.cfFormat, format_mime);
|
||||
STGMEDIUM med;
|
||||
HRESULT hres = pDataObject->lpVtbl->GetData(pDataObject, &fetc, &med);
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop Text for GetData, format %08x '%s', HRESULT is %08lx\n",
|
||||
fetc.cfFormat, format_mime, hres);
|
||||
if (SUCCEEDED(hres)) {
|
||||
const size_t bsize = GlobalSize(med.hGlobal);
|
||||
const void *buffer = (void *)GlobalLock(med.hGlobal);
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop Text for GlobalLock, format %08x '%s', memory (%lu) %p\n",
|
||||
fetc.cfFormat, format_mime, (unsigned long)bsize, buffer);
|
||||
if (buffer) {
|
||||
char *text = SDL_malloc(bsize + sizeof(Uint32));
|
||||
SDL_memcpy((Uint8 *)text, buffer, bsize);
|
||||
SDL_memset((Uint8 *)text + bsize, 0, sizeof(Uint32));
|
||||
char *saveptr = NULL;
|
||||
char *token = SDL_strtok_r(text, "\r\n", &saveptr);
|
||||
while (token != NULL) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop Text, text (%lu of %lu) '%s'\n",
|
||||
(unsigned long)strlen(token), (unsigned long)bsize, token);
|
||||
SDL_SendDropText(target->window, (char *)token);
|
||||
token = SDL_strtok_r(NULL, "\r\n", &saveptr);
|
||||
}
|
||||
SDL_free(text);
|
||||
}
|
||||
GlobalUnlock(med.hGlobal);
|
||||
ReleaseStgMedium(&med);
|
||||
SDL_SendDropComplete(target->window);
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
FORMATETC fetc;
|
||||
fetc.cfFormat = CF_UNICODETEXT;
|
||||
fetc.ptd = NULL;
|
||||
fetc.dwAspect = DVASPECT_CONTENT;
|
||||
fetc.lindex = -1;
|
||||
fetc.tymed = TYMED_HGLOBAL;
|
||||
const char *format_mime = "CF_UNICODETEXT";
|
||||
if (SUCCEEDED(pDataObject->lpVtbl->QueryGetData(pDataObject, &fetc))) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop Text for QueryGetData, format %08x '%s', success\n",
|
||||
fetc.cfFormat, format_mime);
|
||||
STGMEDIUM med;
|
||||
HRESULT hres = pDataObject->lpVtbl->GetData(pDataObject, &fetc, &med);
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop Text for GetData, format %08x '%s', HRESULT is %08lx\n",
|
||||
fetc.cfFormat, format_mime, hres);
|
||||
if (SUCCEEDED(hres)) {
|
||||
const size_t bsize = GlobalSize(med.hGlobal);
|
||||
const void *buffer = (void *)GlobalLock(med.hGlobal);
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop Text for GlobalLock, format %08x '%s', memory (%lu) %p\n",
|
||||
fetc.cfFormat, format_mime, (unsigned long)bsize, buffer);
|
||||
if (buffer) {
|
||||
buffer = WIN_StringToUTF8(buffer);
|
||||
if (buffer) {
|
||||
const size_t lbuffer = strlen(buffer);
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop Text for StringToUTF8, format %08x '%s', memory (%lu) %p\n",
|
||||
fetc.cfFormat, format_mime, (unsigned long)lbuffer, buffer);
|
||||
char *text = SDL_malloc(lbuffer + sizeof(Uint32));
|
||||
SDL_memcpy((Uint8 *)text, buffer, lbuffer);
|
||||
SDL_memset((Uint8 *)text + lbuffer, 0, sizeof(Uint32));
|
||||
char *saveptr = NULL;
|
||||
char *token = SDL_strtok_r(text, "\r\n", &saveptr);
|
||||
while (token != NULL) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop Text, text (%lu of %lu) '%s'\n",
|
||||
(unsigned long)strlen(token), (unsigned long)lbuffer, token);
|
||||
SDL_SendDropText(target->window, (char *)token);
|
||||
token = SDL_strtok_r(NULL, "\r\n", &saveptr);
|
||||
}
|
||||
SDL_free(text);
|
||||
SDL_free((void *)buffer);
|
||||
}
|
||||
}
|
||||
GlobalUnlock(med.hGlobal);
|
||||
ReleaseStgMedium(&med);
|
||||
SDL_SendDropComplete(target->window);
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
FORMATETC fetc;
|
||||
fetc.cfFormat = CF_TEXT;
|
||||
fetc.ptd = NULL;
|
||||
fetc.dwAspect = DVASPECT_CONTENT;
|
||||
fetc.lindex = -1;
|
||||
fetc.tymed = TYMED_HGLOBAL;
|
||||
const char *format_mime = "CF_TEXT";
|
||||
if (SUCCEEDED(pDataObject->lpVtbl->QueryGetData(pDataObject, &fetc))) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop Text for QueryGetData, format %08x '%s', success\n",
|
||||
fetc.cfFormat, format_mime);
|
||||
STGMEDIUM med;
|
||||
HRESULT hres = pDataObject->lpVtbl->GetData(pDataObject, &fetc, &med);
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop Text for GetData, format %08x '%s', HRESULT is %08lx\n",
|
||||
fetc.cfFormat, format_mime, hres);
|
||||
if (SUCCEEDED(hres)) {
|
||||
const size_t bsize = GlobalSize(med.hGlobal);
|
||||
const void *buffer = (void *)GlobalLock(med.hGlobal);
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop Text for GlobalLock, format %08x '%s', memory (%lu) %p\n",
|
||||
fetc.cfFormat, format_mime, (unsigned long)bsize, buffer);
|
||||
if (buffer) {
|
||||
char *text = SDL_malloc(bsize + sizeof(Uint32));
|
||||
SDL_memcpy((Uint8 *)text, buffer, bsize);
|
||||
SDL_memset((Uint8 *)text + bsize, 0, sizeof(Uint32));
|
||||
char *saveptr = NULL;
|
||||
char *token = SDL_strtok_r(text, "\r\n", &saveptr);
|
||||
while (token != NULL) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop Text, text (%lu of %lu) '%s'\n",
|
||||
(unsigned long)strlen(token), (unsigned long)bsize, token);
|
||||
SDL_SendDropText(target->window, (char *)token);
|
||||
token = SDL_strtok_r(NULL, "\r\n", &saveptr);
|
||||
}
|
||||
SDL_free(text);
|
||||
}
|
||||
GlobalUnlock(med.hGlobal);
|
||||
ReleaseStgMedium(&med);
|
||||
SDL_SendDropComplete(target->window);
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
FORMATETC fetc;
|
||||
fetc.cfFormat = CF_HDROP;
|
||||
fetc.ptd = NULL;
|
||||
fetc.dwAspect = DVASPECT_CONTENT;
|
||||
fetc.lindex = -1;
|
||||
fetc.tymed = TYMED_HGLOBAL;
|
||||
const char *format_mime = "CF_HDROP";
|
||||
if (SUCCEEDED(pDataObject->lpVtbl->QueryGetData(pDataObject, &fetc))) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop File for QueryGetData, format %08x '%s', success\n",
|
||||
fetc.cfFormat, format_mime);
|
||||
STGMEDIUM med;
|
||||
HRESULT hres = pDataObject->lpVtbl->GetData(pDataObject, &fetc, &med);
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop File for GetData, format %08x '%s', HRESULT is %08lx\n",
|
||||
fetc.cfFormat, format_mime, hres);
|
||||
if (SUCCEEDED(hres)) {
|
||||
const size_t bsize = GlobalSize(med.hGlobal);
|
||||
HDROP drop = (HDROP)GlobalLock(med.hGlobal);
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop File for GlobalLock, format %08x '%s', memory (%lu) %p\n",
|
||||
fetc.cfFormat, format_mime, (unsigned long)bsize, drop);
|
||||
UINT count = DragQueryFile(drop, 0xFFFFFFFF, NULL, 0);
|
||||
for (UINT i = 0; i < count; ++i) {
|
||||
SDL_bool isstack;
|
||||
UINT size = DragQueryFile(drop, i, NULL, 0) + 1;
|
||||
LPTSTR buffer = SDL_small_alloc(TCHAR, size, &isstack);
|
||||
if (buffer) {
|
||||
if (DragQueryFile(drop, i, buffer, size)) {
|
||||
char *file = WIN_StringToUTF8(buffer);
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Drop File, file (%lu of %lu) '%s'\n",
|
||||
(unsigned long)strlen(file), (unsigned long)bsize, file);
|
||||
SDL_SendDropFile(target->window, NULL, file);
|
||||
SDL_free(file);
|
||||
}
|
||||
SDL_small_free(buffer, isstack);
|
||||
}
|
||||
}
|
||||
GlobalUnlock(med.hGlobal);
|
||||
ReleaseStgMedium(&med);
|
||||
SDL_SendDropComplete(target->window);
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SendDropComplete(target->window);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static void *vtDropTarget[] = {
|
||||
(void *)(SDLDropTarget_QueryInterface),
|
||||
(void *)(SDLDropTarget_AddRef),
|
||||
(void *)(SDLDropTarget_Release),
|
||||
(void *)(SDLDropTarget_DragEnter),
|
||||
(void *)(SDLDropTarget_DragOver),
|
||||
(void *)(SDLDropTarget_DragLeave),
|
||||
(void *)(SDLDropTarget_Drop)
|
||||
};
|
||||
|
||||
void WIN_AcceptDragAndDrop(SDL_Window *window, SDL_bool accept)
|
||||
{
|
||||
const SDL_WindowData *data = window->internal;
|
||||
DragAcceptFiles(data->hwnd, accept ? TRUE : FALSE);
|
||||
SDL_WindowData *data = window->internal;
|
||||
if (data->videodata->oleinitialized) {
|
||||
if (accept && !data->drop_target) {
|
||||
SDLDropTarget *drop_target = (SDLDropTarget *)SDL_calloc(1, sizeof(SDLDropTarget));
|
||||
if (drop_target != NULL) {
|
||||
drop_target->lpVtbl = vtDropTarget;
|
||||
drop_target->window = window;
|
||||
drop_target->hwnd = data->hwnd;
|
||||
drop_target->format_file = RegisterClipboardFormat(L"text/uri-list");
|
||||
drop_target->format_text = RegisterClipboardFormat(L"text/plain;charset=utf-8");
|
||||
data->drop_target = drop_target;
|
||||
SDLDropTarget_AddRef(drop_target);
|
||||
RegisterDragDrop(data->hwnd, (LPDROPTARGET)drop_target);
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Accept Drag and Drop, window %u, enabled Full OLE IDropTarget\n",
|
||||
window->id);
|
||||
}
|
||||
} else if (!accept && data->drop_target) {
|
||||
RevokeDragDrop(data->hwnd);
|
||||
SDLDropTarget_Release(data->drop_target);
|
||||
data->drop_target = NULL;
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Accept Drag and Drop, window %u, disabled Full OLE IDropTarget\n",
|
||||
window->id);
|
||||
}
|
||||
} else {
|
||||
DragAcceptFiles(data->hwnd, accept ? TRUE : FALSE);
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
". In Accept Drag and Drop, window %u, %s Fallback WM_DROPFILES\n",
|
||||
window->id, (accept ? "enabled" : "disabled"));
|
||||
}
|
||||
}
|
||||
|
||||
int WIN_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation)
|
||||
|
@ -48,6 +48,16 @@ typedef enum SDL_WindowEraseBackgroundMode
|
||||
SDL_ERASEBACKGROUNDMODE_ALWAYS,
|
||||
} SDL_WindowEraseBackgroundMode;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void **lpVtbl;
|
||||
int refcount;
|
||||
SDL_Window *window;
|
||||
HWND hwnd;
|
||||
UINT format_text;
|
||||
UINT format_file;
|
||||
} SDLDropTarget;
|
||||
|
||||
struct SDL_WindowData
|
||||
{
|
||||
SDL_Window *window;
|
||||
@ -89,6 +99,7 @@ struct SDL_WindowData
|
||||
|
||||
/* Whether we retain the content of the window when changing state */
|
||||
UINT copybits_flag;
|
||||
SDLDropTarget *drop_target;
|
||||
};
|
||||
|
||||
extern int WIN_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props);
|
||||
|
Loading…
Reference in New Issue
Block a user