ActiveState Code

Recipe 410615: Manipulate Mac OS clipboard


This is a clipboard manipulation module that demonstrates some simple use of Carbon API. It can double as a Unix-style command-line tool that prints the clipboard contents to stdout or, if specified, copies its stdin to the clipboard, although pbcopy(1) and pbpaste(1) are better suited for that.

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#!/usr/bin/env python

"""Manipulate Mac OS clipboard ("scrap") from Python.

See also: pbcopy(1), pbpaste(1)"""

from sys import stdin, stdout
from optparse import OptionParser
from Carbon.Scrap import GetCurrentScrap, ClearCurrentScrap
import MacOS

def paste(flavorType='TEXT', verbose=False):
    try:
        scrap = GetCurrentScrap()
        return scrap.GetScrapFlavorData(flavorType)
    except MacOS.Error, e:
        if verbose or e[0] != -102:
            # -102 == noTypeErr
            raise
        return ""

def copy(text, flavorType='TEXT'):
    ClearCurrentScrap()
    scrap = GetCurrentScrap()
    scrap.PutScrapFlavor(flavorType, 0, text)

def list_flavors():
    scrap = GetCurrentScrap()
    return [(name, scrap.GetScrapFlavorSize(name))
            for name, flags in scrap.GetScrapFlavorInfoList()]

def main():
    parser = OptionParser()
    parser.set_defaults(flavor='TEXT', translate=True, copy=False,
                        list_=False, verbose=False)
    parser.add_option("-c", "--copy", dest="copy", action="store_true",
                      help="copy stdin to clipboard [default: paste clipboard"
                           " to stdout]")
    parser.add_option("-l", "--list", dest="list_", action="store_true",
                      help="list currently available flavors with data sizes")
    parser.add_option("-x", "--notrans", dest="translate",
                      action="store_false",
                      help="don't translate CR to LF on output")
    parser.add_option("-f", "--flavor", dest="flavor", action="store",
                      help="specify flavor [default: TEXT]")
    parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
                      help="complain if scrap flavor not found [default:"
                           " treat as empty]")
    
    options, args = parser.parse_args()
    if options.list_:
        for flavor in list_flavors():
            print "'%s' %9d" % flavor
    elif options.copy:
        copy(stdin.read(), options.flavor)
    else:
        text = paste(options.flavor, options.verbose)
        if options.translate:
            text = text.replace('\r', '\n')
        stdout.write(text)

__all__ = ['paste', 'copy', 'list_flavors', 'main']

if __name__ == "__main__":
    main()

Discussion

By default, the most reasonable choice of the 'TEXT' flavour is used. Other flavors for special uses can be specified. If there is no "scrap" of a given flavor, Mac OS API report this as an error. Normally this is suppressed and treated as empty clipboard, but user can request the program to complain.

By default, the line endings are translated from '\r' (Mac) to '\n' (Unix) when printing to stdout.

Comments

  1. 1. At 3:42 p.m. on 20 apr 2005, Bob Ippolito said:

    Of course, this is just about the slowest possible way to do it for ascii/rtf/postscript because Mac OS X comes with pbcopy(1) and pbpaste(1), which don't have the overhead of starting a Python interpreter, etc.

  2. 2. At 11:44 a.m. on 21 apr 2005, Artur de Sousa Rocha (the author) said:

    Indeed. Thanks for spoiling the fun. No, just kidding, thanks for pointing those out. Added some improvements/corrections anyway.

Sign in to comment