WindowsのPythonでクリップボードを扱う

WindowsのPythonでwin32clipboardモジュールを使ってクリップボードを扱う方法を説明しています。

win32clipboard以外にもクリップボードを扱うモジュールはありますが、JupyterLabではwin32clipboardは最初から含まれているので別途インストールする必要がありません。

JupyterLabを使わない場合でも、pipでpywin32パッケージをインストールすれば同じように使えます。


info情報 - JupyterLab

JupyterLab(ジュパイター・ラボ/ジュピター・ラボ)は、データ分析などで広く使われているJupyter notebook後継のWebブラウザ上で動くPythonの実行環境です。

プログラムを書いて実行することができます。実行結果も含めることが出来ます。さらにMarkdownを使って表現力豊かなテキストや図表も同時に書くことができます。そして、その結果をHTMLやPDFで出力することができます。

Jupyter notebook/JupyterLabは、Python以外にも多くの言語サポートしています。

Jupyterの読み方は「ジュパイター・ラボ」と「ジュピター・ラボ」の2種類があるようです。どちらが正しいかは色々な意見があるようです。興味がある方は「jupyter ジュパイター ジュピター」で検索してみてください。



インストール

win32clipboardはpywin32パッケージに含まれています。JupyterLabでは標準でpywin32パッケージがインストールされているのでインストールする必要はありません。

pywin32がインストールされていない場合はpipなどでpywin32パッケージをインストールしてください。

> pip install pywin32




文字列用クリップボード関数

以下は文字列をクリップボードに設定する関数と、クリップボードから取得する関数です。

import win32clipboard

def set_clipboard_text(text):
    win32clipboard.OpenClipboard()
    try:
        win32clipboard.EmptyClipboard()
        win32clipboard.SetClipboardData(win32clipboard.CF_UNICODETEXT, text)
    finally:
        win32clipboard.CloseClipboard()

def get_clipboard_text():
    text = None
    win32clipboard.OpenClipboard()
    try:
        text = win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT)
    except TypeError:
        pass
    finally:
        win32clipboard.CloseClipboard()
    return text

使い方は下の通りです。

設定する文字列を引数にしてset_clipboard_text関数を呼び出すとクリップボードに文字列を設定することができます。

get_clipboard_text関数を呼び出すとクリップボードの値が取得できます。

# クリップボードに文字列を設定する
set_clipboard_text("abc")

# クリップボードから文字列を取得する
text = get_clipboard_text()
print(text)

get_clipboard_text関数は、クリップボードに文字列が無いときはNoneを返すようになっています。



解説

win32clipboardモジュールの関数は、ほぼWindowsのクリップボード関連の関数と対応しています。(完全に対応しているわけではありませんが、ほとんど対応しています)

Windowsのクリップボード関連の関数では、クリップボードに設定するデータのためにグローバルメモリオブジェクトを割り当てるなどの処理が必要ですが、グローバルメモリオブジェクトの割り当てなどは、win32clipboardモジュールの中で行っているため気にする必要はありません。


クリップボードを使うときは、OpenClipboard関数でオープンして使い終わったらCloseClipboard関数でクローズします。

OpenClipboard関数を呼び出したあとCloseClipboard関数を呼ぶまで他のアプリケーションがクリップボードを使えません。このため、できるだけOpenClipboard関数 ~ CloseClipboard関数を呼ぶまでの間隔は短くする必要があります。クリップボードに設定するデータを準備するのに時間がかかる場合は、OpenClipboard関数を呼ぶ前にデータを準備してからOpenClipboard関数を呼び出すようにします。


warning注意

OpenClipboard関数でオープンした後は、必ずCloseClipboard関数を呼ぶ必要があります。

以下の解説用のコードでは、シンプルにするためにエラー処理を行っていませんが、実装する場合はfinallyを使ってCloseClipboard関数を呼ぶようにしてください。


クリップボードの扱い方の基本


クリップボードに文字列を設定する

import win32clipboard

data = "クリップボードに設定するテキスト"

win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardData(win32clipboard.CF_UNICODETEXT, data)
win32clipboard.CloseClipboard()
クリップボードに値を設定するときは、EmptyClipboard関数を呼び出してクリップボードを空にしてから、設定するデータ形式と設定するデータを引数としてSetClipboardData関数を呼び出します。SetClipboardData関数は複数回呼び出して複数のデータ形式のデータを設定することもできます。テキストを設定する場合は、CF_UNICODETEXTを指定します。

クリップボードに値を設定するときEmptyClipboard関数を呼び出さなくて正しく動く場合がありますが、クリップボードに予期しないデータが残っていたり、正しく動作しなくなったりする場合があるので特別な理由がなければ呼び出すようにします。


info情報 - なぜCF_TEXTではなくCF_UNICODETEXTを使うのか


CF_TEXTは、ASCIIキャラク用のため漢字も使う場合はCF_UNICODETEXTを使う必要があります。また、Pythonの文字列がUNICODEなのでCF_TEXTでは正しく設定できません。
CF_TEXTを使う場合は文字列ではなく、バイト配列に変換する必要があります。



クリップボードから文字列を取得する

import win32clipboard

win32clipboard.OpenClipboard()
data=win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT)
win32clipboard.CloseClipboard()

print("クリップボードから取得したテキスト = "+data)

クリップボードの値を取得するときは、取得するデータ形式を引数としてGetClipboardData関数を呼び出します。テキストを取得する場合は、CF_UNICODETEXTを指定します。

クリップボードに指定したデータ形式のデータがない場合は例外(TypeError)が発生します。



複数のデータ形式を扱う


以下のコードで、複数のデータ形式をクリップボードに設定したり取得したりできます。

クリップボードに複数のデータ形式の文字列を設定する

import win32clipboard

win32clipboard.OpenClipboard()
# クリップボードを空にする
win32clipboard.EmptyClipboard()

# CF_TEXT形式のデータを設定
win32clipboard.SetClipboardData(win32clipboard.CF_TEXT, b"CF_TEXT data")

# CF_UNICODETEXT形式のデータを設定
win32clipboard.SetClipboardData(win32clipboard.CF_UNICODETEXT, "CF_UNICODETEXT Data")

win32clipboard.CloseClipboard()

複数のデータ形式を設定する場合は、EmptyClipboard関数を呼び出してクリップボードを空にした後に、設定したいデータ形式とデータを引数としてSetClipboardData関数を複数回呼び出します。


クリップボードから複数のデータ形式を取得する

win32clipboard.OpenClipboard()

# 在クリップボードにあるデータ形式の数を取得する
num_of = win32clipboard.CountClipboardFormats()
print(f"現在クリップボードにあるデータ形式に数={num_of}")

for i in range(num_of):
    # GetClipboardDataの引数に指定するデータ形式を取得する
    type_code = win32clipboard.EnumClipboardFormats(i)

    # 無効なデータ形式(0)が返る場合があるため 0 を除外している
    if type_code != 0:
        data = win32clipboard.GetClipboardData(type_code)
        print(f"データ形式 {type_code} : {data}")
win32clipboard.CloseClipboard()

クリップボードのデータをGetClipboardData関数で取得するためには、引数に取得したいデータ形式を指定する必要があります。このため、最初に現在クリップボードにあるデータ形式を取得する必要があります。

現在クリップボードにあるすべてのデータ形式のデータを取得するには、最初にCountClipboardFormats関数で現在クリップボードにあるデータ形式の数を取得します。

次に、取得したデータ形式の数だけEnumClipboardFormats関数を呼び出してデータ形式を取得し、取得したデータ形式を使ってGetClipboardData関数を呼び出します。


あらかじめ期待するデータ形式がわかっている場合は、CountClipboardFormats関数やEnumClipboardFormats関数で現在クリップボードにあるデータ形式を取得しないで、直接GetClipboardData関数を期待するデータ形式を引数として呼び出すこともできます。

この場合は、期待するデータ形式がクリップボードにないと例外(TypeError)が発生するので例外を処理するようにしてください。


info情報 - CF_xxx

win32clipboardで定義されているCF_xxxの一覧は以下のコマンドで見ることができます。
import win32clipboard
help(win32clipboard)

CF_TEXTやCF_UNICODEなどのCF_xxxは、win32clipboardに定義されていますが、win32conにも定義されています。どちらを使うことも出来ます。
import win32con

win32clipboard.GetClipboardData(win32con.CF_UNICODETEXT)

最終行