How to copy a string to the clipboard?

Usage of the framework, compiler and tools
Post Reply
Zinn
Posts: 123
Joined: Mon Nov 24, 2014 10:47 am
Location: Frankfurt am Main
Contact:

How to copy a string to the clipboard?

Post 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
Josef Templ
Posts: 262
Joined: Tue Sep 17, 2013 6:50 am

Re: How to copy a string to the clipboard?

Post 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
Zinn
Posts: 123
Joined: Mon Nov 24, 2014 10:47 am
Location: Frankfurt am Main
Contact:

Re: How to copy a string to the clipboard?

Post by Zinn »

Josef, thank you very much. It works perfectly. Helmut
manumart1
Posts: 67
Joined: Tue Sep 17, 2013 6:25 am

Re: How to copy a string to the clipboard?

Post 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
manumart1
Posts: 67
Joined: Tue Sep 17, 2013 6:25 am

Re: How to copy a string to the clipboard?

Post by manumart1 »

How is it possible that module HostPictures uses HostClipboard.len, if len does not exist in module HostClipboard?
User avatar
Ivan Denisov
Posts: 362
Joined: Tue Sep 17, 2013 12:21 am
Location: Krasnoyarsk, Russia

Re: How to copy a string to the clipboard?

Post 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.
manumart1
Posts: 67
Joined: Tue Sep 17, 2013 6:25 am

Re: How to copy a string to the clipboard?

Post 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;
Post Reply