Page 1 of 1

How to copy a string to the clipboard?

Posted: Sun Jan 03, 2016 10:51 pm
by Zinn
I have a string variable s: ARRAY 64 OF CHAR; and would like to copy its contents to the clipboard.
It is a 0X terminated string.
How do do it inside a Component Pascal Program?
Thank you very much for any help.
Helmut

Re: How to copy a string to the clipboard?

Posted: Mon Jan 04, 2016 1:44 pm
by Josef Templ
I do it in the following way:

Code: Select all

PROCEDURE CopyToClipboard(IN str: ARRAY OF CHAR);
  VAR i: INTEGER; T: TextModels.Model; W: TextModels.Writer;
BEGIN
  T := TextModels.dir.New();
  W := T.NewWriter(NIL);
  FOR i := 0 TO LEN(str$) DO W.WriteChar(str[i]) END ;
  HostClipboard.Register(TextViews.dir.New(T), 0, 0, FALSE)
END CopyToClipboard;
- Josef

Re: How to copy a string to the clipboard?

Posted: Mon Jan 04, 2016 6:32 pm
by Zinn
Josef, thank you very much. It works perfectly. Helmut

Re: How to copy a string to the clipboard?

Posted: Sat Jan 09, 2016 6:32 pm
by manumart1
What about Paste, i.e. read the content stored in the clipboard?

I have tried two versions:

Code: Select all

PROCEDURE PasteFromClipboard* (): POINTER TO ARRAY OF CHAR;
    VAR i: INTEGER; T: TextModels.Model; S: TextMappers.Scanner;
        v: Views.View; w, h: INTEGER; isSingle: BOOLEAN;
        str: POINTER TO ARRAY OF CHAR; ch: CHAR;
BEGIN
    HostClipboard.GetClipView("", v, w, h, isSingle);
    IF (v # NIL) & (v.ThisModel() # NIL) & (v.ThisModel() IS TextModels.Model) THEN
        (* Views.OpenView(v); *)
        T := v.ThisModel()(TextModels.Model);
        S.ConnectTo(T);
        NEW(str, T.Length() + 1);
        i := 0; S.rider.ReadChar(ch);
        WHILE ~S.rider.eot DO
            IF S.rider.view = NIL THEN str^[i] := ch; INC(i) END;
            S.rider.ReadChar(ch)
        END;
        str^[i] := 0X
    ELSE
        NEW(str, 1); str^[0] := 0X
    END;
    RETURN str
END PasteFromClipboard;

PROCEDURE PasteFromClipboard* (OUT str: ARRAY OF CHAR);
    VAR i: INTEGER; T: TextModels.Model; S: TextMappers.Scanner;
        v: Views.View; w, h: INTEGER; isSingle: BOOLEAN;
        ch: CHAR;
BEGIN
    HostClipboard.GetClipView("", v, w, h, isSingle);
    IF (v # NIL) & (v.ThisModel() # NIL) & (v.ThisModel() IS TextModels.Model) THEN
        (* Views.OpenView(v); *)
        T := v.ThisModel()(TextModels.Model);
        S.ConnectTo(T);
        i := 0; S.rider.ReadChar(ch);
        WHILE (i < LEN(str) - 1) & ~S.rider.eot DO
            IF S.rider.view = NIL THEN str[i] := ch; INC(i) END;
            S.rider.ReadChar(ch)
        END;
        str[i] := 0X
    ELSE
        str[0] := 0X
    END
END PasteFromClipboard;
At first I felt a bit unable to decide which interface was better, whether a or b:

a) PROCEDURE PasteFromClipboard* (): POINTER TO ARRAY OF CHAR
b) PROCEDURE PasteFromClipboard* (OUT str: ARRAY OF CHAR)

Interface "a" seems more usable because can be called directly even without having a destination array, e.g.:

Code: Select all

 StdLog.String("Content = '" + PasteFromClipboard() + "'")
Also it is fine that the client does not need to worry about the size of the array, but ... caution should be taken if the clipboard has got a large amount of data; otherwise execution traps with "stack overflow" or "illegal memory write". I also have noticed that if the clipboard, instead of chars, has got a file, then there is no problem because HostClipboard.GetClipView gives value NIL to variable v, and nothing is returned.

I reckon that interface "b" can be more efficient because the procedure does not need to allocate the array, but a truncation will be produced if the content of the clipboard is greater than the VAR parameter received.

Because of the possible traps, I favour "b" over "a".

On the other hand ... the client can be interested in reading the content of the clipboard in other ways, rather than as bare chars. I mean, he might want to read the list of numbers stored in the clipboard, for example. In that case, to read the clipboard it is better to use "S.Scan, S.type and S.int", instead of "S.rider.ReadChar(ch)".

What I want to say is that the above procedure PasteFromClipboard (returning chars) is not a general utility function, and that the client will have to write his ad hoc procedure to read the clipboard.
Anyway, it is useful to have at hand a procedure like PasteFromClipboard (returning chars), because it gives clues about how to read the clipboard.

Regards

Re: How to copy a string to the clipboard?

Posted: Mon Jan 11, 2016 4:16 pm
by manumart1
How is it possible that module HostPictures uses HostClipboard.len, if len does not exist in module HostClipboard?

Re: How to copy a string to the clipboard?

Posted: Tue Jan 12, 2016 5:46 am
by Ivan Denisov
manumart1 wrote:How is it possible that module HostPictures uses HostClipboard.len, if len does not exist in module HostClipboard?
This part of code in HostPictures is commented.

Re: How to copy a string to the clipboard?

Posted: Tue Jan 12, 2016 7:57 am
by manumart1
Thank you, I didn't see it.
I think that putting in green colour the commented out lines is a good idea.
I usually use CpcBeautifier, but I like to have the "Ident Check" on, and therefore the ident of the commented out block is destroyed, which is not nice:

PROCEDURE ImportC*;
VAR v: StdView; pic: MemoryMgr.Handle; s, d, len: LONGINT; ch: CHAR;
BEGIN
len := HostClipboard.len;
pic := MemoryMgr.NewHandle(len); MemoryMgr.HLock(pic);
s := HostClipboard.adr; d := SYSTEM.ADR(pic^);
WHILE len # 0 DO
SYSTEM.GET(s, ch); SYSTEM.PUT(d, ch); INC(s); INC(d); DEC(len)
END;
NEW(v); v.Init;
v.model := NewModel(SYSTEM.VAL(QuickDraw.PicHandle, pic));
HostClipboard.view := v
END ImportC;