godot icon indicating copy to clipboard operation
godot copied to clipboard

Windows Clipboard file / file path handling

Open sievaxx opened this issue 1 year ago • 6 comments

The system clipboard functions returned nothing on windows when there were files (CF_HDROP) on the clipboard. This is unlike linux, which is able to return clipboard file paths as a newline-seperated list.

This adds simple handling for them, returning files as file:// URIs in a newline seperated list like linux does, for cross compatibility.

clipboard_has appears to make more sense as a "clipboard_has_text", so i made a clipboard_has_file check, and a clipboard_file_count that returns the number of files selected. I have only wrote these for windows, because linux is able to return file paths as strings on its own, and I don't know how to grab the number of selected files there.

sievaxx avatar Sep 15 '24 08:09 sievaxx

my bad, i was supposed to mark it as a draft first, because i haven't written any documentation, but i misclicked.

sievaxx avatar Sep 15 '24 08:09 sievaxx

I get a build error here with this PR rebased on top of master:

 *  Executing task: scons platform=windows progress=no optimize=none fast_unsafe=yes debug_symbols=yes compiledb=no d3d12=yes -j32 

scons: Reading SConscript files ...
Using SCons-detected MSVC version 14.3, arch x86_64
Building for platform "windows", architecture "x86_64", target "editor".
Checking for C header file mntent.h... (cached) no
scons: done reading SConscript files.
scons: Building targets ...
Linking Program bin\godot.windows.editor.x86_64.exe ...
progress_finish(["progress_finish"], [])
servers.windows.editor.x86_64.lib(display_server.windows.editor.x86_64.obj) : error LNK2001: unresolved external symbol "public: virtual int __cdecl DisplayServer::clipboard_get_file_count(void)const " (?clipboard_get_file_count@DisplayServer@@UEBAHXZ)
servers.windows.editor.x86_64.lib(display_server.windows.editor.x86_64.obj) : error LNK2001: unresolved external symbol "public: virtual bool __cdecl DisplayServer::clipboard_has_file(void)const " (?clipboard_has_file@DisplayServer@@UEBA_NXZ)
bin\godot.windows.editor.x86_64.exe : fatal error LNK1120: 2 unresolved externals
scons: *** [bin\godot.windows.editor.x86_64.exe] Error 1120
scons: building terminated because of errors.

Calinou avatar Sep 17 '24 12:09 Calinou

I get a build error here with this PR rebased on top of master:

i forgot to include the .cpp file, i don't know how i missed that one.

sievaxx avatar Sep 17 '24 14:09 sievaxx

Sorry for taking a while, i was focused on some other stuff. the returned buffer length from DragQueryFileW doesn't count the terminator character. But then when sending the buffer size to the function later, it requires space for the terminator character, so it's off by one. can just add size += 1 to the code to fix this, explaining this in a comment

sievaxx avatar Oct 19 '24 14:10 sievaxx

I think this is all i really needed to do, this was already doing what i needed (the ability to paste images from both the clipboard and the filesystem into a chat window) on the first version i wrote so it's all good now. I dunno why the mono version in the CI is failing since i wrote the documentation and it removed it, but shrug

sievaxx avatar Oct 19 '24 20:10 sievaxx

Tested locally (rebased on top of master https://github.com/godotengine/godot/commit/44fa552343722bb048e2d7c6d3661174a95a8a3c), it works as expected. File path behavior is now fixed as of the latest revision (last character is no longer trimmed). I've also tested file paths containing Unicode characters and it works correctly.

Reading very long file paths also works, but they get shortened using Windows' own approach if the path is over 260 characters long:

image

I dunno why the mono version in the CI is failing since i wrote the documentation and it removed it, but shrug

This is because the clipboard_get_file_count() and clipboard_has_file() methods are no longer exposed to the scripting API in the latest revision of this PR. Therefore, they are no longer documented in the class reference, so you should remove their method blocks in the XML accordingly (or re-expose the methods if this is intended).

Calinou avatar Oct 21 '24 17:10 Calinou

Reading very long file paths also works, but they get shortened using Windows' own approach if the path is over 260 characters long

Fixed, there wasn't any mention that DragQueryFileW doesn't return long paths on its docs page, instead it wasn't mentioned on the page that says the functions that do. Now it passes all the paths into GetLongPathNameW to guarantee

This is because the clipboard_get_file_count() and clipboard_has_file() methods are no longer exposed to the scripting API in the latest revision of this PR. Therefore, they are no longer documented in the class reference, so you should remove their method blocks in the XML accordingly (or re-expose the methods if this is intended).

my bad, i thought i did expose them but looks like i never did.

sievaxx avatar Oct 22 '24 09:10 sievaxx

Needs rebase

Repiteo avatar Oct 07 '25 19:10 Repiteo

I think the note in the documentation for clipboard_get could be worded better, but i'm struggling to write it any better myself without it feeling unnaturally verbose. I feel like it should explain exactly that it returns files with a file URI only because linux, or at least X11, represents files on its clipboard like that. My code only forces it to behave like that on windows to make cross-platform file handling easier. But, I don't know if anyone else feels that users actually need to know that?

sievaxx avatar Oct 10 '25 01:10 sievaxx

When i wrote this code originally, I didn't have a mac to test with. I now do own a mac, and i've found that at least for godot, most files return just the file name and not the full file path when on the clipboard. I don't know anything Obj-C to attempt to add this functionality myself, everything i've tried so far seems to crash. I'm not sure i'd like this PR to be just for windows now that I know its worse then just not existing on mac.

sievaxx avatar Oct 10 '25 02:10 sievaxx

OK, I was able to get something reasonable for MacOS too. It has the same behavior across all 3 platforms now I think.

sievaxx avatar Oct 10 '25 03:10 sievaxx

My suggestion is:

  • use a separate Vector<String> clipboard_get_files, without file:\\ prefixes and with real unescaped paths.
  • on Linux, it (as well as has and get_count) can be implemented by parsing clipboard strings and checking if file exist (not necessarily in the same PR).

The expectation from the use standpoint should be - get string and use it with Godot file API as is, which won't work with URIs.

bruvzg avatar Oct 10 '25 06:10 bruvzg

on Linux, it (as well as has and get_count) can be implemented by parsing clipboard strings and checking if file exist (not necessarily in the same PR).

For the reference - https://github.com/godotengine/godot/pull/111582

bruvzg avatar Oct 13 '25 10:10 bruvzg

Oh wait, I re-requested bruvzg thinking this got the changes implemented, but it seems they've yet to be integrated. @sievaxx are you still available to make further adjustments to this PR?

Repiteo avatar Nov 25 '25 15:11 Repiteo