Acorn Arcade forums: Programming: Clipboard Protocol
|
Clipboard Protocol |
|
Chris (12:35 6/10/2010) arawnsley (14:26 6/10/2010) Chris (15:02 6/10/2010) Lampi (15:42 6/10/2010) Chris (16:12 6/10/2010) Chris (20:51 6/10/2010) swirlythingy (19:00 8/10/2010) Chris (19:12 8/10/2010) swirlythingy (19:50 8/10/2010) Lampi (01:07 9/10/2010)
|
|
Chris |
Message #115581, posted by Chris at 12:35, 6/10/2010 |
Member
Posts: 283
|
I've been trying to get the hang of the RISC OS clipboard protocol, and not getting very far. As I understand it, the first step is to broadcast the user message ClaimEntity (&F) when my app has gained the input focus. I should also be able to receive the same message from other apps, telling me when they've claimed the input focus. My code to do this is like this:
AppFocus%=FALSE (Flag indicating whether I own the caret)
SYS "Wimp_Poll",1,Block% TO reason% CASE reason% OF WHEN 17,18,19: (Pick up user messages from other apps) CASE Block%!16 OF WHEN &F: (Someone's issued ClaimEntity) IF Block%!20 AND (1<<0) THEN AppFocus%=FALSE IF Block%!20 AND (1<<1) THEN AppFocus%=FALSE ENDCASE ENDCASE
DEF PROCwimp_claimentity (called when the user clicks on my app's window) IF AppFocus%=FALSE THEN Block%!0=24 (Message length) Block%!12=0 (My ref) Block%!16=&F (ClaimEntity message code) Block%!20=3 (Bits 0 and 1 set) SYS "Wimp_SendMessage",17,Block%,0 AppFocus%=TRUE ENDIF ENDPROC
This code doesn't seem to work - I can't pick up ClaimEntity messages from other apps when they take over the input focus (I've tried ArtWorks and StrongED, which apparently use the Clipboard protocol). I've ensured that &F is on the list of user messages my app can receive in Wimp_Initialise.
TBH, I struggle to understand both the user message system, and bitwise operations, so I'm guessing my code is a right dog's dinner. Any help on improving it would be much appreciated.
Documentation on the protocol itself can be found here: http://www.wss.co.uk/pinknoise/Docs/Arc/Apps/Clipboard.html
[Edited by Chris at 13:40, 6/10/2010] |
|
[ Log in to reply ] |
|
Andrew Rawnsley |
Message #115582, posted by arawnsley at 14:26, 6/10/2010, in reply to message #115581 |
R-Comp chap
Posts: 600
|
Clipboard stuff can be a nightmare, as different apps implement it in different ways. As far as we can tell, there were slightly different guidelines from Acorn at different points
Then you find it's slightly different again on Adjust vs RO5 (Clipboard Holder module).
You can imagine the "fun" we had getting UniClip working when you add in network interactions and clipboard occurances on remote machines!
I implemented it for all icons in DialUp and NetFetch (I like copy/paste between icons!) but that code is in C so probably wouldn't be much help to you. |
|
[ Log in to reply ] |
|
Chris |
Message #115583, posted by Chris at 15:02, 6/10/2010, in reply to message #115582 |
Member
Posts: 283
|
I implemented it for all icons in DialUp and NetFetch (I like copy/paste between icons!) but that code is in C so probably wouldn't be much help to you. Thanks for the reply. If you have the code snippets in C, that would be helpful, assuming it uses the same Clipboard model as I'm trying to. FWIW, my code only needs to support the RO5 way of doing things. |
|
[ Log in to reply ] |
|
James Lampard |
Message #115585, posted by Lampi at 15:42, 6/10/2010, in reply to message #115581 |
Posts: 190
|
This code doesn't seem to work - I can't pick up ClaimEntity messages from other apps when they take over the input focus (I've tried ArtWorks and StrongED, which apparently use the Clipboard protocol). I've ensured that &F is on the list of user messages my app can receive in Wimp_Initialise.
Are you sure, are you using reporter after those IF statements?
Anyway here are my observations: When you broadcast Message_ClaimEntity it goes to every task including yourself. So if I read your code correctly you are sending the message, receiving it again then setting AppFocus to False.
Reason code 19 probably wants to be in a seperate case statement. You will only receive this if one of your sent messages is unacknowledged and you certainly shouldn't receive Message_ClaimEntity from via this method.
When you choose the "Copy to clipboard" menu item in StrongEd it will only broadcast Message_ClaimEntity the first time afterwards the task knows it owns the clipboard and optimizes it away (Until another task claims the clipboard)
I strongly suggest you use the WimpMon task both to check if your own task receives the messages and to observe working clipboard tasks like StrongEd and Zap. |
|
[ Log in to reply ] |
|
Chris |
Message #115586, posted by Chris at 16:12, 6/10/2010, in reply to message #115585 |
Member
Posts: 283
|
When you broadcast Message_ClaimEntity it goes to every task including yourself. So if I read your code correctly you are sending the message, receiving it again then setting AppFocus to False. Yes, sorry, I was aware of that, and left out the relevant bit of code exempting broadcasts from my own app for simplicity. I could pick my own broadcasts up fine, but didn't seem to pick up anything from other apps, which made me think there was a more general problem with the code.
Reason code 19 probably wants to be in a seperate case statement. You will only receive this if one of your sent messages is unacknowledged and you certainly shouldn't receive Message_ClaimEntity from via this method. Ta - that's useful to know.
When you choose the "Copy to clipboard" menu item in StrongEd it will only broadcast Message_ClaimEntity the first time afterwards the task knows it owns the clipboard and optimizes it away (Until another task claims the clipboard) OK, I'll test with StrongEd some more. However, I thought the idea was that a task broadcasts the ClaimEntity message when it takes over the caret, not just when a selection has been made?
Are you using Reporter after those IF statements? I strongly suggest you use the WimpMon task both to check if your own task receives the messages and to observe working clipboard tasks like StrongEd and Zap. No, I'm not using Reporter or WimpMon. Time I downloaded them and figured out how to use them, I think.
Thanks very much for your help - I'll keep at it, and let you know how I get on. |
|
[ Log in to reply ] |
|
Chris |
Message #115587, posted by Chris at 20:51, 6/10/2010, in reply to message #115586 |
Member
Posts: 283
|
OK, thanks to James, WimpMon and StrongHelp, I'm part of the way there. My app can successfully claim the caret and the clipboard, and is picking up all the messages it needs to in order to do its thing. Now I need to respond to other apps when they initiate a Paste operation, and ensure they can get hold of the content.
According to the documentation I've been using, I need to initiate a DataSave message, just as if I were saving a file to a Filer window (say), and follow the standard procedure from there. In the case of my app, though, there's no file to save - it's just a text string that I want exported. So I'm guessing I need to create a temporary text file somewhere with the contents of that string, and transfer that when I get a Paste request. I figured the easiest place to create the file is in <Wimp$Scrap>, and once the transfer is over, delete it.
Is that the right idea? Or is there a better, less awkward, way of doing things? |
|
[ Log in to reply ] |
|
Martin Bazley |
Message #115601, posted by swirlythingy at 19:00, 8/10/2010, in reply to message #115587 |
Posts: 460
|
That's the usual way, yes. The alternative is RamFetch (message code 6), which the pasting application sends to you in response to your DataSave. If you receive this, you should write your data to the address specified in the message block (using Wimp_TransferBlock), and reply with RamTransmit (7).
As with most things Wimp, it isn't quite as simple as it could be. For starters, the application on the other end of the Wimp_SendMessage tin can is not legally required to allocate sufficient memory for all of your data to fit in the buffer at once (particularly if you're not quite sure how much data there's going to be yourself). RAMTransmit has an API for this, too, although it isn't much of one - if the buffer is too small, you just write as much as you can fit and send using poll code 18. If the buffer is big enough, just use poll code 17. It is entirely the responsibility of the sender (i.e. you), to keep track of how much data has been written across successive RamTransmits.
The main snag with RamFetch is that not all applications support it, and it is the privilege of the receiver to decide which protocol it prefers. The standard is that if code 6 returns with a poll code of 19, the sender ignored it and you should send DataSaveAck (2) instead. On the other hand, a lot of programs just send code 2 straight off, which everybody is expected to cope with. (This standard is probably because, in general, it's easier to write data to memory then save it to a file than to write data to a file and then load it into memory.)
So, briefly, listen for both codes 2 and 6, and take the appropriate action. The DataSaveAck block contains a string giving the receiver's preferred filename, so you don't need to worry about that. |
|
[ Log in to reply ] |
|
Chris |
Message #115602, posted by Chris at 19:12, 8/10/2010, in reply to message #115601 |
Member
Posts: 283
|
Good grief, that's complicated. Thanks for the very helpful notes. I'll try to get the standard DataSaveAck method working first, and if I have the stomach for it, RamTransmit afterwards.
Ta. |
|
[ Log in to reply ] |
|
Martin Bazley |
Message #115603, posted by swirlythingy at 19:50, 8/10/2010, in reply to message #115602 |
Posts: 460
|
If you receive a DataSaveAck, offset 44 in the message block contains the filename to write to. Note that whatever you put in offset 36 will probably have been changed to -1.
On receiving, just save the contents of the block using:
SYS "OS_File",10,$(Block%+44),Block%!40,,pastedata%,pastedata%+pastelen%
(Beware string terminators.)
After that, just copy my_ref to your_ref and send DataLoad (3). Technically speaking, you will then receive a DataLoadAck (4) back, but nobody cares about that one.
I find a good source of information on this is the StrongHelp Wimp manual, now available from riscos.info. (According to the history, most of the pertinent sections were in fact written by the Bazley everyone's heard of.) |
|
[ Log in to reply ] |
|
James Lampard |
Message #115606, posted by Lampi at 01:07, 9/10/2010, in reply to message #115602 |
Posts: 190
|
I would point out the RamTransmit protocol is completely optional. All applications are expected to handle transfer via files. RamTransmit is an optional extension to the protocol. |
|
[ Log in to reply ] |
|
|
Acorn Arcade forums: Programming: Clipboard Protocol |