Copying text inside CC to a user's clipboard
exerro opened this issue ยท 14 comments
Introduction
I'm suggesting that there should be a mechanism to copy text within CC to a user's real clipboard. There are a few concerns here which I believe are addressed. Firstly, security: you don't want some arbitrary CC script to have control over a user's clipboard. Secondly, multi-user madness: CC computers are accessed by zero-or-more users at once, so the behaviour gets a bit weird.
Suggested solution
My solution to these is having an intermediate buffer of text which I'll refer to as "copyable text". A function such as os.setCopyableText(text: string)
can change the contents of this buffer whenever. The buffer is persistent until reboots/shutdowns etc. When a user presses ctrl+C
(or another keybind specified by MC I guess), the copyable text of the computer they're viewing is set as their clipboard text.
This works for multiple computers and doesn't give CC scripts any direct control over any users' clipboard.
Note that, while in the diagram it says "user selects something", this also works for scripts offering something to be copied and then exiting, as discussed below.
Use cases
pastebin put
By default, pastebin put
generates a pastebin code and prints that to the screen. You still need to write that out by hand to get the pastebin URL for what you uploaded. Instead, the full URL or just the code could be set as the copyable text so the user just presses ctrl+C to get that out from MC.
General purpose standard clipboard
A bunch of programs, OSes, shells etc implement custom clipboard within CC. These are incompatible with one another and code needs to be written specifically for that system to work. By allowing real-world clipboard interactions like this, there's no need for ad-hoc clipboards inside CC.Websocket based code
Generally, when using websockets, you need to do something on the server to get a link then paste that into CC. It's minor, but it'd be more convenient to get that link from CC, particularly when you might not remember/know the server URL but there's easy to use software running on the CC computer.TypeScript!
My original motivation behind this was when I was thinking of a package manager that handled typescript nicely from CC. You can't compile TS from CC afaik, but it would be awesome if the computer could generate a short bash command to compile your code for you (in watch mode, for example).Complications
Click to expand...
Exploitation
While the user still has full control of *when* to copy something, they don't strictly know *what* they're copying. A malicious program could claim to be offering some innocent text while actually offering something dodgy. It's been suggested that Windows 10 has clipboard exploits but I've not found any evidence of this in a way that would impact this system.In my opinion, this isn't really a problem - clipboard text is pretty innocent on its own, the worst things that could happen are a user going to a link that's been copied without checking it (which is more of a general internet problem and fairly unavoidable) and something profane being copied (but this can just be written to the screen anyway).
Redundancy
Maybe this isn't the most helpful or necessary feature in the world, and maybe adding it is more complex than is worthwhile. However, I'd be happy to implement this myself and submit a PR, and a few people on Discord have expressed interest in the feature.Philosophy
I'm not one to say but maybe this goes against the simple nature of CC. Every more advanced feature added takes it away from its little grey flying robot roots and makes it ever so slightly harder to learn about the mod for beginners.However, I think in terms of ease of use this has a much more significant positive impact than negative, and since we already have pasting doesn't really introduce anything drastically new.
One random idea: have a toast system that uses Ctrl + C to confirm a copy, but also confirms automatically if the user has pressed Ctrl + C in the last ~250ms or so. Programs could detect Ctrl + C being pressed through events, call os.offerCopyableText
(example name), and the user that recently pressed Ctrl + C would have it automatically confirmed and copied. If other users were also viewing the UI at the time, or the call was triggered by another event, users could confirm the request by clicking the toast or pressing Ctrl + C within, say, five or ten seconds of being prompted.
One issue I can foresee with this approach is events around the confirming Ctrl + C. Obviously, an automatically confirmed copy won't involve sending any new events, but for copies which are confirmed after the toast shows up via Ctrl + C, it would probably be a good idea to block the event for the C key from actually being fired, to prevent accidentally causing the CC program to offer another copy.
Some other potential variations or additions to this idea:
- Rather than detecting Ctrl + C with the existing key/char events, it might be better to have a new event type, like
copy_request
. This would make the specific key combo an implementation detail of the MC client, which could help with, say, Mac compatibility - I don't remember how the command key works with CC off the top of my head. This would also avoids having to suppress key events for the confirmation as previously described. - A
copy_confirmed
event could be useful to allow programs to automatically proceed when the user copies text. - It would be convenient to have a GUI to see recent copy prompts, so that you can re-copy some text if you need it again or if you missed the toast. This would be especially helpful for programs that would offer copyable text unprompted and immediately exit - e.g.
pastebin put
- If network latency is particularly bad or the CC thread is blocked, the automatic confirmation could time out. It would probably be good to make the delay configurable by the user (and also have a toggle to disable automatic confirmation entirely), or maybe have the server send some timing data behind the scenes to automatically determine an appropriate timeout?
While having trouble around copying NBT hashes and large pseudorandom strings I've come back to see where this issue was and have some feedback for it.
Here's the proposal: Once the user presses the key combo, a copy event is queued. Its first argument is a function that tries to set the clipboard for that user, and returns a boolean whether it was successful or was invalidated (which happens if the user closes the GUI, or after a short timeout). Copy events issued later take precedence over earlier ones. Two users pressing the combo will issue two events, each with their own function and invalidation condition. Events get filtered through like any key
event.
This has the same basic idea as above, except that there is no new os
, shell
or term
function. It also shares the drawback that the program has a bit of control about how far in the future the clipboard can be set after the event is issued.
Two reasons I'm against using events for this:
- No other events, afaik, pass a function which you then call to do something
- As you mentioned, potential exploitation by calling that function later than expected
For the proposal you gave, that's very similar functionally to what's been talked about before, just with the function call/key combo swapped round. Instead of responding to a copy event retroactively, we state ahead-of-time what the user may copy. I do think a copy event could be useful for informing the program that a user did copy some text, however.
No other events, afaik, pass a function which you then call to do something
As of 1.101.0 (Nov 2022), there is now an event that does this, file_transfer
I would like if CC could let the user select the text, and then user just copy the text that has been shown!
Sorry for not looking at this sooner, I know you've put a lot of effort into writing this up!
I do really like this approach - it's definitely the most elegant solution to copying for CC I've seen. That said, I've a couple of concerns which, while I don't think are deal-breakers, are worth discussing:
-
Obviously this is in some ways a workaround for the fact that we don't want to expose a direct "copy" functionality to the user, and this does (unavoidably) leak through in the design.
This is a general problem with CC's whole model though. As mentioned elsewhere on the issue tracker, I really want to make getting files onto/off the computer easier. Again, uploading to the computer is easy (#840), but I've not been able to find a suitable flow for downloading.
-
This is really into nitpicking territory, but I'm not sure how this plays with multishell. For instance, if two tabs call
os.setCopyableText
, we'll copy from the last one, not the currently visible tab.I guess more generally, we've got this hidden bit of UI, and ideally it'd be consistent with the in-computer UI. Obviously that's not possible here (well, not without multishell then overriding
os.setCopyableText
), so not really sure what to do!
I guess more generally, we've got this hidden bit of UI, and ideally it'd be consistent with the in-computer UI. Obviously that's not possible here (well, not without multishell then overriding
os.setCopyableText
), so not really sure what to do!
One solution to that issue would be putting setCopyableText into shell/multishell api instead of os and having a native setCopyableText somewhere? Then each shell/multishell tab would have to be it's own buffer and would swap what is in native buffer when tabs are swapped?
One solution to that issue would be putting setCopyableText into shell/multishell api instead of os and having a native setCopyableText somewhere? Then each shell/multishell tab would have to be it's own buffer and would swap what is in native buffer when tabs are swapped?
How would you tell when to paste from the CC buffer or from the host OS buffer?
This is a general problem with CC's whole model though. As mentioned elsewhere on the issue tracker, I really want to make getting files onto/off the computer easier. Again, uploading to the computer is easy (#840), but I've not been able to find a suitable flow for downloading.
Thoughts on having CC basically make a FTP server on the server that players can log into and access their computers?
How would you tell when to paste from the CC buffer or from the host OS buffer?
I'm assuming what Wojbie is proposing here is that shell.setCopyableText
sets the per-process/tab clipboard, which then propagates up to os.setCopyableText
. Then the user Ctrl-Cs this into the host OS buffer, as per the OP.
Thoughts on having CC basically make a FTP server on the server that players can log into and access their computers?
I want to make things more accessible, not less!
This is a general problem with CC's whole model though.
Honestly, a similar approach could work for files too. Ultimately, you can't directly move something from CC to a user's PC using CC code (and this shouldn't change), but offering things that the user can confirm is the next best thing imo. Whether that's clipboard text or a downloadable file is somewhat irrelevant, although the mechanism for offering and then confirming would likely be different for the two.
I'm not sure how this plays with multishell
I think @Wojbie's approach is a good way to handle this. My only concern would be people abusing/not understanding the difference between os.*
and shell.*
. It would be better if there was one function exposed that was overridden in tabs, but bios-level CC doesn't get a shell
API and overridding os
in shell tabs seems a bit hacky.
Honestly, a similar approach could work for files too. Ultimately, you can't directly move something from CC to a user's PC using CC code (and this shouldn't change), but offering things that the user can confirm is the next best thing imo.
#840 may interest you.
I think @Wojbie's approach is a good way to handle this. My only concern would be people abusing/not understanding the difference between
os.*
andshell.*
. It would be better if there was one function exposed that was overridden in tabs, but bios-level CC doesn't get ashell
API and overriddingos
in shell tabs seems a bit hacky.
A amusing way to hide it would be say that clipboard is part of terminal and hide the native function in native terminal object. Most users don't even know how it is different from normal term api and they rarely interact with it outside of redirect.
We've broken redirect code before (see blit
, setPaletteColour
) and it's not the end of the world. Though I don't think it fits well within term - you can't copy from a monitor! shell
and os
is probably fine, as long as the distinction is made clear.
Whether that's clipboard text or a downloadable file is somewhat irrelevant, although the mechanism for offering and then confirming would likely be different for the two.
Sorry to post another comment, but it occurs to me that another interaction model for both would just be to show a toast notification to currently interacting users saying "X wants to copy to the clipboard, click to do so". This has the explicit intent that it doesn't set any permanent state - it's just a prompt to the user - which makes things easier.
Obvious issue is that then you've got to pull out your mouse, toast notifications flying in and out is a little gross, and don't know if it's any nicer on the fourth-wall nature of things.
Edit: I've, uh, just gone full circle haven't I? Dammit. Ignore this!