Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

[Class] WinClip - direct clipboard manipulations


  • Please log in to reply
94 replies to this topic
Deo
  • Members
  • 199 posts
  • Last active: Jan 31 2014 03:19 PM
  • Joined: 16 May 2010
Hello
WinClip is a clipboard manipulation class which allow you to do a bit more than the common ahk clipboard can

intended for:
[*:3kwk6bth] AHK_L unicode x32/x64
Download
Documentation

include WinClipAPI.ahk before WinClip.ahk!

Features:

[*:3kwk6bth] Change clipboard directly or operate on in-memory copy of it
[*:3kwk6bth] Ready-to-use methods to keep and maintain any number of clipboards at once
[*:3kwk6bth] Big number of functions to get different types of data from clipboard
[*:3kwk6bth] Possibility to get/change text on clipboard without touching other formats
[*:3kwk6bth] Easy way to get picture from clipboard and use it on your needs
[*:3kwk6bth] And other cookies...

Tips:

[*:3kwk6bth]You can use Markdown2HTML.ahk from fincs' GenDocs v3 viewtopic.php?p=555703#p555703 script to transform Markdown text to html format + WinClip.SetHTML(html) to be able to paste it directly in say your Office documents or an rich text email.


Full list of methods:
Snap( ByRefdata )
Restore( ByRefdata )
Clear()
GetFormats()
Save( filePath )
Load( filePath )
Copy()
Paste( plainText = "" )
GetFiles()
SetFiles( files, isCut = 0 )
AppendFiles( files, isCut = 0 )
GetBitmap()
SetBitmap( bitmap )
SaveBitmap( filePath, format )
GetText()
SetText( textData )
AppendText( textData )
GetHTML()
SetHTML( html, source = "" )
IsEmpty()
HasFormat( fmt )

Here is a small example of how to use it in the similar way you do with common ahk's "clipboardall" and "clipboard":
Getting data from clipboard:
clipData := clipboardall
clipSize := WinClip.Snap( clipData )
Restoring it up:
clipboard := clipData
bytesRestored := WinClip.Restore( clipData )
Getting plain text from clipboard:
plainText = %clipboard%
plainText := WinClip.GetPlainText()
filesList := WinClip.GetFilesList()
Well, if you don't need anything besides that, it's best to keep up with standard clipboard.
Here is what it can do above basic stuff:
Get html format:
rawHTML := WinClip.GetHTML()

Get all formats currently on clipboard:
objFormats := WinClip.GetFormats()
list =
for nFmt, params in objFormats
{
; format_number : format_name : data_size : data_size again
; the "buffer" is an object member containing actual format data
  list .= "`n" nFmt " : " params.name " : " params.size " : " params.GetCapacity( "buffer " )
}
msgbox % list

GetBitmap and use it as picture in GUI:
;copy any picture first
hBitmap := WinClip.GetBitmap()
Gui, Add, Picture,% "hwndPicHwnd +" SS_BITMAP := 0xE
SendMessage,% STM_SETIMAGE := 0x0172,% IMAGE_BITMAP := 0,% hBitmap,, ahk_id %PicHwnd%
DllCall("DeleteObject", "Ptr", hBitmap )
Gui, Show, w1000 h700

Set or append text without changing whole clipboard into plain text:
WinClip.SetText( "hey, you!" )
WinClip.AppendText( "`nand you!" )

+ Copy, Paste, Clear methods.

!!! Make attention, that data from clipboardall, and WinClip.Snap() is not compatible

Another part of the WinClip class is the all the same function with "i" prefix which work with instantiated copy of WinClip class. It allows you to manipulate with in-memory copy of clipboard without changing the main one. Or you can just keep any number of different clipboards. Prefect for clipboards managers kind.
Here is an example:
wc := new WinClip
clipSize := wc.iSnap() ;copies clip data into inner buffer for later using
wc.Clear() ;clears Windows clipboard
bytesRestored := wc.iRestore() ;restores data back to clipboards

All this described better in documentation

test.ahk inside downloadable .zip also offer some easy tutorial survey

Update 20/03/2012
Fixed SetHTML() function to use UTF-8

Update 7/02/2012
Added following methods to retrieve or set RTF format:
GetRTF(),iGetRTF
SetRTF( text ),iSetRTF( text )

Update 31/01/2012
Class name shortened to WinClip :)
all functions used by WinClip moved to another class, so you don't need to care about any similar you may have in your script (you must inlcude WinClipAPI.ahk first though )
Methods added ( check documentation for info ):
SetHTML,iSetHTML
iSetData
IsEmpty,iIsEmpty
HasFormat,iHasFormat
SaveBitmap,iSaveBitmap

Update 12/20/2011
Renamed methods:
GetPlainText() -> GetText()
iGetPlainText() -> iGetText()
GetFilesList() -> GetFiles()
iGetFilesList() -> iGetFiles()

Added methods:
SetFiles( files, isCut = 0 )
iSetFiles( .. )
AppendFiles( .. )
iAppendFiles( .. )
SetBitmap( bitmapPath or hBitmap )
iSetBitmap( .. )
iGetData( Data )

WinClipboard.Paste( plainText = "" ) method now can be called with parameter to paste raw text without changing actual clipboard data (iPaste does not support this)

Improved Copy/Paste methods so they work more reliable/faster now

Functiona added to WinClipboard_foos.ahk:
RemoveDubls
RegisterClipboardFormat
GetOpenClipboardWindow
StrSplit

Attached Files



capitalH
  • Members
  • 64 posts
  • Last active: Apr 05 2012 05:18 AM
  • Joined: 23 Apr 2010
Some recommendations
1)
WinClipboard_foos.ahk and PUM_foos.ahk share:

ErrorFormat
IsInteger
LoadDllFunction
Gdip_Shutdown
Gdip_Startup

Since I am now using PUM and WinClipBoard in a single project - this cause duplicate functions. I moved these to Deo_foos.ahk - but if I were to update it would be there again. Can you consider doing something similar please?

2) I am not an OOP expert - but I would expect that
WinClipboard.SetText("hello")
WinClipboard.Paste()
and
WinClipboard.SetText("hello").Paste()
should both work (second version does not work)

(3)
Currently pasting plaintext saved internal buffer seems to be done via

oldClipboard:= new WinClipboard
oldClipboard.iSnap()

;Stuff happens here

TempClipBoard := new WinClipboard
TempClipBoard.iSnap() 
WinClipboard.clear()
WinClipboard.SetText(oldClipboard.iGetPlainText())
WinClipboard.Paste()
TempClipBoard.iRestore()

Consider:
oldClipboard:= new WinClipboard
oldClipboard.iSnap()

;Stuff happens here
oldClipboard.Paste("PlainText")

Unless I am missing something (open for suggestions)

4) Not a recommendation, but I love it that it does not trigger OnClipBoardChange!

Edit: added (2) , (3) and (4)

[/code]

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
You can probably use the gdip library as a prerequisite for your functions and call those directly, unless you use other gdi+ functions that are not covered.

This is a nice library, may I suggest expanding it to support copied files from explorer like regular text? That is, being able to write or append copied files. You can take a look at 7plus source (<!-- m -->http://code.google.com/p/7plus/<!-- m -->, clipboard.ahk) for some pointers on how to do this.

  • Guests
  • Last active:
  • Joined: --
I'll try this later, looks interesting. Two links for reference

Need to save clipboard with formatting to rtf file
<!-- m -->http://www.autohotke...topic65944.html<!-- m --> (see script by SKAN)

SetClipboardData and GetClipboardData functions by PhiLho
<!-- m -->http://www.autohotke.../topic8402.html<!-- m --> (see various formats)

Deo
  • Members
  • 199 posts
  • Last active: Jan 31 2014 03:19 PM
  • Joined: 16 May 2010
thank you for interest to this proj, guys

Since I am now using PUM and WinClipBoard in a single project - this cause duplicate functions. I moved these to Deo_foos.ahk - but if I were to update it would be there again. Can you consider doing something similar please?

i think it is best for you to spend 10 mins and compile all the functions you need together as you did. Because someone may not need all the bunch in one place. For example, PUM has far more functions than WinClip, and only few of them are similar. If any func will be added, you will know about this at startup from ahk, if anything will be changed, i'll write about this in change log.

WinClipboard.SetText("hello").Paste()

good example of functional programming would be, but you'll not be able determine then if SetText() was successful or not.
btw, to shorten the code, you can do the following:
;define WinClipboard instance as super-global var
global wc := new WinClipboard
;you can then use static function as well as instance
;wc can be accessible from any function as well
wc.SetText( "some text" )
wc.Paste()

oldClipboard:= new WinClipboard
oldClipboard.iSnap()

;Stuff happens here

TempClipBoard := new WinClipboard
TempClipBoard.iSnap() 
WinClipboard.clear()
WinClipboard.SetText(oldClipboard.iGetPlainText())
WinClipboard.Paste()
TempClipBoard.iRestore()

oldClipboard:= new WinClipboard
oldClipboard.iSnap()

;Stuff happens here
oldClipboard.Paste("PlainText")

you mean paste some text without changing the original clipboard? Good idea, i'll make it

You can probably use the gdip library as a prerequisite for your functions and call those directly, unless you use other gdi+ functions that are not covered.

i actually use Gdip_Startup & Shutdown only as functions and few others directly through DllCall, so don't think ppl really needs whole library for this

This is a nice library, may I suggest expanding it to support copied files from explorer like regular text? That is, being able to write or append copied files.

good idea, will make this

I love it that it does not trigger OnClipBoardChange!

i didn't know it doesn't :D

ParticleMan
  • Members
  • 32 posts
  • Last active: Jan 22 2013 03:40 AM
  • Joined: 04 Dec 2011
Does this paste function buffer when the keyboard caret is not ready?

I use multiple clipboards in basically the following ways, for instance:
* PasteClip(1)
* SendInput Clip%1%

In my simplistic implementation, the issue of requiring a fixed Sleep duration after SendInput and before restoring the previously backed up Clipboard is my biggest battle.

Problems:
1. Copying: ClipWait is useless when the string is null (ClipWait ,,1 would be ideal).
2. ClipboardAll does not work as expected in at least one case. Text with formatting will paste into Word but not in a Firefox textbox, while it will paste in Firefox when using ":= Clipboard" (not ":= %Clipboard%").
3. Increasing Sleep to thousands of ms is not a solution (unless of course it were possible to make the Sleep and Clipboard restore threaded to the background after SendInput completes, or check an ErrorLevel of SendInput, or something).

Would it work to use a DllCall to the Win32 API to paste instead of using SendInput? Or would this be too complex?

My original thread on this issue is here:
<!-- m -->http://www.autohotke...ic.php?p=497325<!-- m -->

Deo
  • Members
  • 199 posts
  • Last active: Jan 31 2014 03:19 PM
  • Joined: 16 May 2010
ParticleMan
by digging a bit i think i found a solution:
WaitClipReady( timeout = 10000 )
  {
    start_time := A_TickCount
    while ( GetOpenClipboardWindow() && ( A_TickCount - start_time < timeout ) )
      sleep 100
  }

GetOpenClipboardWindow()
{
  return DllCall( "GetOpenClipboardWindow" )
}
just call WaitClipReady after each paste/copy operation to make sure application where you paste data finished processing it:
SendInput, ^{vk56sc02F} ;ctrl+v
WaitClipReady()
i've done a bit testing on it, - if you trying to paste a big piece of text into MS Word 2010 - it works instantly, but if in notepad - it cause run of few loops waiting. Let me know if you'll notice any problems using this method

also, i get rid of using "clipwait" in this module ( starting from next update ) and replaced it with following set of functions:
SendInput, ^{vk43sc02E} ;ctrl+c
WaitClipReady()
if !isClipEmpty()
{
;do some stuff
}

isClipEmpty()
  {
    return !CountClipboardFormats()
  }

CountClipboardFormats()
{
  return DllCall( "CountClipboardFormats" )
}
should work much faster if you got nothing after copying

ParticleMan
  • Members
  • 32 posts
  • Last active: Jan 22 2013 03:40 AM
  • Joined: 04 Dec 2011

by digging a bit i think i found a solution


Wow, thanks for looking into this, and so fast! However, it doesn't seem to work at all for me in any app. Even after the caret has been delayed:
* GetOpenClipboardWindow() is always 0
* A_TickCount, start_time are always equal

Thus it never gets a chance to sleep.

SendInput, ^{vk56sc02F} ;ctrl+v


What is the benefit of using this method over a regular ^v?

should work much faster if you got nothing after copying


Excellent, although I have been making sure the variable isn't null at the outset.

Deo
  • Members
  • 199 posts
  • Last active: Jan 31 2014 03:19 PM
  • Joined: 16 May 2010

it doesn't seem to work at all for me in any app. Even after the caret has been delayed:
* GetOpenClipboardWindow() is always 0
* A_TickCount, start_time are always equal

it solves the problem when after pasting you got old clipboard pasted instead of required one because of lagging (this was mentioned in your topic)

What is the benefit of using this method over a regular ^v?

it multilingual

Excellent, although I have been making sure the variable isn't null at the outset.

sry, i don't understand

nimda
  • Members
  • 4368 posts
  • Last active: Aug 09 2015 02:36 AM
  • Joined: 26 Dec 2010
The solution to the dupe functions is to internalize them,e.g., WinClip._IsInteger()

And a request: WinClip.SetBitmap() -- would call DllCall("SetClipboardData", UInt, 8 ...) and accept either a filename or hBitmap.

  • Guests
  • Last active:
  • Joined: --

it doesn't seem to work at all for me in any app. Even after the caret has been delayed:
* GetOpenClipboardWindow() is always 0
* A_TickCount, start_time are always equal

it solves the problem when after pasting you got old clipboard pasted instead of required one because of lagging (this was mentioned in your topic)

I understand that that is what your WaitClipReady() is supposed to do--which is exactly what I am looking for (and AHK needs to have natively!)--but "my mileage is varying." By using WaitClipReady() instead of a fixed Sleep, it never sleeps because of what I reported above (having attempted to debug it). You get different results, apparently? Could there be a problem on my end?

Excellent, although I have been making sure the variable isn't null at the outset.

sry, i don't understand

See below.
PasteClip(num, fmt) {
    Global

    If (Clip%num% != "") {
        ; proceed with processing
    }
}
According to my function above, included in its entirety in my original thread, there is no need to check for an empty variable after SendInput ^v, such as with your isClipEmpty(), because there is no reason to process null data. But the larger issue is WaitClipReady() not working for me as you say it does for you.

Deo
  • Members
  • 199 posts
  • Last active: Jan 31 2014 03:19 PM
  • Joined: 16 May 2010

I understand that that is what your WaitClipReady() is supposed to do--which is exactly what I am looking for (and AHK needs to have natively!)--but "my mileage is varying." By using WaitClipReady() instead of a fixed Sleep, it never sleeps because of what I reported above (having attempted to debug it). You get different results, apparently? Could there be a problem on my end?

yep, it works for me. Sleep either may or may not be called depending on the speed at which application operates data. As i said, try to paste big piece of text into common Windows notepad and use following function to check what happening.

_waitClipReady( timeout = 10000 )
  {
    start_time := A_TickCount
    while ( GetOpenClipboardWindow() && ( A_TickCount - start_time < timeout ) )
    {
      tooltip % "wait"
      sleep 100
    }
  }


Deo
  • Members
  • 199 posts
  • Last active: Jan 31 2014 03:19 PM
  • Joined: 16 May 2010
this module has been updated
check the first post for info & docs

ParticleMan
  • Members
  • 32 posts
  • Last active: Jan 22 2013 03:40 AM
  • Joined: 04 Dec 2011

yep, it works for me. Sleep either may or may not be called depending on the speed at which application operates data. As i said, try to paste big piece of text into common Windows notepad and use following function to check what happening.

On rare occasion GetOpenClipboardWindow() will be > 0, and on even more rare occasion will it show it's working by displaying the "wait" message. But because WaitClipReady() doesn't execute with every paste, the approach doesn't quite work because I still need a Sleep before restoring the original clipboard.

How else might it be possible to detect whether the window or control is ready to paste into but without getting excessively complex with exceptions?

Deo
  • Members
  • 199 posts
  • Last active: Jan 31 2014 03:19 PM
  • Joined: 16 May 2010

On rare occasion GetOpenClipboardWindow() will be > 0, and on even more rare occasion will it show it's working by displaying the "wait" message

well, if GetOpenClipboardWindow() returned anything != 0, the tooltip will be shown 100%, it can't be any rarely

How else might it be possible to detect whether the window or control is ready to paste into but without getting excessively complex with exceptions?

i have no ideas right now

it would be nice if you can describe any way to reproduce your problem on practice with code example