2021年6月27日日曜日

12: PythonでLinuxまたはWindowsクリップボード: マルチフォーマットで

<このシリーズの前の記事 | このシリーズの目次 | このシリーズの次の記事>

wxPythonを使用します。テキストフォーマットだけではありません。多くのフォーマットがサポートされます。

話題


About: Pythonプログラミング言語

この記事の目次


開始コンテキスト


  • 読者は、Python プログラミング言語の基本的知識を持っている。

ターゲットコンテキスト



  • 読者は、フォーマット毎データの複合体をオペレーティングシステムクリップボードから取得しオペレーティングシステムクリップボードへセットする方法を知る、Pythonにて、wxPythonを用いて。

オリエンテーション


多くの、しかし全てではない、フォーマット群が、本テクニックではサポートされています。

より多くの、しかしそれでも全てではない、フォーマット群が、Microsoft WindowsのためのC#によるあるテクニックによってサポートされています、別シリーズの以降のある記事にて紹介されるとおり。

全てのフォーマットが、LinuxまたはMicrosoft WindowsのためのC++によるあるテクニックによってサポートされています、別シリーズの以降のある記事にて紹介されるとおり

Python変数はどれもポインターである(必須知識)ことの理由が、ある以前の記事にて説明されています。


本体


1: ねらい: あるワードプロセッサにコピーマルチバッファを実装すること


Hypothesizer 7
私はテキストエディターにVimを使っているが、その恩恵の1つは、コピーマルチバッファが備わっていること: あるテキスト断片をバッファ'a'へコピーし、別のテキスト断片をバッファ'b'へコピーし、などとすることができる。それはとても大きな助けになる。

私はワードプロセッサにLibreOffice Writerを使っているが、そこにもその機能を欲しい。

実のところ、その機能になれているので、それが欠けているのは、少なからぬフラストレーションになる。

Pythonマクロでその機能を実装できる、もしも、それがクリップボードデータを取得およびセットできれば。


2: テキストフォーマットだけでは充分でない


Hypothesizer 7
テキストフォーマットクリップボードデータを取得・セットするのは容易だ。例えば、'pyperclip'がそれを成し遂げられる。

しかし、明らかに、それはワードプロセッサには充分でない: フォント情報がコピーされる必要がある、最低限でも。それに、イメージデータや表のようなオブジェクトも、マルチバッファへコピーされてほしいかもしれない。

理想を言えば、クリップボードデータ全体が、あるがままにコピーされるべきである。


3: 私はwxPythonを使う


Hypothesizer 7
インターネットで探したところ、Pythonでクリップボードデータ全体を取得・設定することのチュートリアルを見つけることはできなかった(テキストデータを操作するものは沢山あるが)。

私はwxPythonを使っているので、それがその機能を持っているかもしれないと期待して、オフィシャルwxPythonドキュメントの中で探してみて、若干の情報を見つけた。

'wx.CustomDataObjec'は有望そうな名前だが、シングルフォーマットのデータのためのものであり、フォーマット毎データの複合体のためのものでないことが判明した。

'wx.DataObjectComposite'は、複合体のためのものだが、かなり扱いにくそうだ、サポートされているデータフォーマット群が事前に確定しているのでなければ。

えーと、'wx.DataObject'(それは、当該ドキュメント中に"for maximum flexibility and efficiency, but it is also the most difficult to implement(最大の柔軟性と効率性があるが、実装するのが最も難しい)"と記述されている)が、私が使うべきもののようだが、それさえも、サポートされているデータフォーマット群が事前に確定していることが前提のようだ(私にはそうではない)。

結局、wxPythonのクリップボード操作のコンセプトは、クリップボードデータ全体を、それがいかなるマルチデータフォーマット群のものであろうとも、取得・セットするという私の関心事にマッチしないが、それで私が何をできるかを見てみよう。


4: クリップボードデータフォーマット群の若干の基礎


Hypothesizer 7
X WindowシステムのクリップボードメカニズムとMicrosoft Windowsのそれとは大いに違っているが、少なくともwxPython的には、各クリップボードデータフォーマットは、常に、そのフォーマットのアイデンティティとして、1つの数字を持っている。

しかし、その数字は、一時的なものであるかもしれない、というのは、あるフォーマットは、ある時は'49161'を持ち、別の時は'49162'を持つということになる。したがって、一般的に言って、恒久的にあるフォーマットをその番号で同定するということはできない('Text'等の一部のおきまりのフォーマットたちは固定された番号を持っているが)。

他方、一部のフォーマットは名前を持っていない(または、少なくとも、それらの名前はAPIで取得できない)。

しかしながら、そうしたフォーマットたちは、固定された番号を持っているはずだ。

したがって、名前を持っているフォーマットたちは名前で同定でき、名前を持っていないフォーマットたちは番号で同定できるということになる。


5: 'wx.DataObject'の仕様


Hypothesizer 7
オフィシャルドキュメントはこのクラスの仕様についてあまり明確でない(特に、各メソッドがいつ呼ばれるかという点について)ので、私は実験をして、必要な情報を知らなければならなかった。

私が発見した重要な1つのポイントは、'wx.DataObject'のインスタンスは、'wx.Clipboard'の'SetData'メソッドに渡された後に無効になるということだ('無効'というのは、'SetData'に再び渡すことはできないということだ)。

えーと、それは、'wx.DataObject'は、私の目的のためにクリップボードデータコンテナとしては使えないということだ(私のクリップボードデータはクリップボードへ繰り返しセットできなければならないから)。したがって、'wx.DataObject'は、クリップボードイベント群ハンドラーだということになる、私にとっては。

以下は、メソッド群がコールされるタイミングについて私が発見したことだ。

メソッドいつコールされるか
GetFormatCount'wx.Clipboard.GetData'がコールされた時
複合体に対して最初に
フォーマット毎に最初に
'wx.Clipboard.SetData'がコールされた時
複合体に対して'GetPreferredFormat'の後に
フォーマット毎に最初に
GetAllFormats'wx.Clipboard.GetData'がコールされた時
複合体に対して'GetFormatCount'の後に
フォーマット毎に'GetFormatCount'の後に
'wx.Clipboard.SetData'がコールされた時
複合体に対して'GetFormatCount'の後に
フォーマット毎に'GetFormatCount'の後に
GetDataHere'wx.Clipboard.SetData'がコールされた時
フォーマット毎に'GetDataSize'の後に
GetDataSize'wx.Clipboard.SetData'がコールされた時
フォーマット毎に'GetAllFormats'の後に2度
GetPreferredFormat'wx.Clipboard.SetData'がコールされた時
複合体に対して最初に
IsSupported決して呼ばれない
SetData'wx.Clipboard.GetData'がコールされた時
フォーマット毎に'GetAllFormats'の後に

'wx.Clipboard.GetData'のために、'GetFormatCount'および'GetAllFormats'は、先験的に知られた全ての可能なデータフォーマットで返答しなければならない、なぜなら、クリップボード内にどんなデータフォーマット群が存在しているかは私のプログラムには分からないから。しかし、フォーマット毎にコールされるメソッド群は、クリップボード内に存在しているデータフォーマット分のみコールされる('GetAllFormats'にリターンされた全てのフォーマット分ではない)という点は信頼できる。

いずれにせよ、いくつの点が私には謎である。第1に、なぜ、'GetFormatCount'および'GetAllFormats'はフォーマット毎にコールされるのか?第2に、なぜ、'GetDataSize'はフォーマット毎に2度コールされるのか?第3に、'GetPreferredFormat'は、オフィシャルドキュメントに反して'wx.Clipboard.SetData'に対してのみコールされ、それが何をリターンしようが、何の効果も私には見えない。

'GetDataHere'および'SetData'の'buf'引数は、'memoryview'インスタンスである。


6: 可能なデータフォーマット群をどのようにして先験的に知るか


Hypothesizer 7
可能なデータフォーマット群を、どうすれば先験的に知れるだろうか?

Linuxにおいては、以下のコマンドは、クリップボード内に存在するデータフォーマット群を示す。

@bash ソースコード
xclip -t TARGETS -o

Microsoft Windowsにおいては、えーと、あるC++ Win32 APIプログラムを私は作成した、別のシリーズの以降の記事に見られるとおり。

例えば、LibreOffice Writer内のテキスト断片がLinuxにおいてコピーされた時、利用可能なフォーマット群は以下のものだ。

@出力
application/x-openoffice-embed-source-xml;windows_formatname="Star Embed Source (XML)"
text/rtf
text/richtext
text/html
text/plain;charset=utf-16
application/x-openoffice-objectdescriptor-xml;windows_formatname="Star Object Descriptor (XML)";classname="8BC6B165-B1B2-4EDD-aa47-dae2ee689dd6";typename="LibreOffice 6.4 Text Document";viewaspect="1";width="16999";height="2995";posx="0";posy="0"
text/plain;charset=utf-8
text/plain
UTF8_STRING
STRING
TEXT
TARGETS
MULTIPLE
TIMESTAMP
SAVE_TARGETS

Microsoft Windowsでは、利用可能なフォーマット群は以下のものだ。

@出力
DataObject
Star Embed Source (XML)
Rich Text Format
Richtext Format
HTML (HyperText Markup Language)
HTML Format
UnicodeText
Text
Link
Star Object Descriptor (XML)
Ole Private Data
Locale
OEMText


7: 私のコード


Hypothesizer 7
先程気づいたとおり、'wx.DataObject'は私の目的にはデータコンテナとしては使えない。そこで、私はあるデータコンテナクラス、'theBiasPlanet.coreUtilities.clipboardHandling.ClipboardFormatSpecificDataComposite'(および'theBiasPlanet.coreUtilities.clipboardHandling.ClipboardFormatSpecificDatum'をそのコンポーネントとして)およびあるデータヒストリークラス、'theBiasPlanet.coreUtilities.clipboardHandling.ClipboardFormatSpecificDataCompositesHistory'(それがマルチバッファコンテナである)を作成した。

theBiasPlanet/coreUtilities/clipboardHandling/ClipboardFormatSpecificDatum.py

@Python ソースコード

class ClipboardFormatSpecificDatum:
	def __init__ (a_this: "ClipboardFormatSpecificDatum", a_formatName: str, a_formatNumber: int, a_datum: bytearray) -> None:
		a_this.i_formatName: str = a_formatName
		a_this.i_formatNumber: int = a_formatNumber
		a_this.i_datum: bytearray = a_datum
	
	def __del__ (a_this: "ClipboardFormatSpecificDatum") -> None:
		None
	
	def getFormatName (a_this: "ClipboardFormatSpecificDatum") -> str:
		return a_this.i_formatName
	
	def getFormatNumber (a_this: "ClipboardFormatSpecificDatum") -> int:
		return a_this.i_formatNumber
	
	def getDatumSize (a_this: "ClipboardFormatSpecificDatum") -> int:
		return len (a_this.i_datum)
	
	def getDatum (a_this: "ClipboardFormatSpecificDatum") -> bytearray:
		return a_this.i_datum


theBiasPlanet/coreUtilities/clipboardHandling/ClipboardFormatSpecificDataComposite.py

@Python ソースコード
from typing import List
from collections import OrderedDict
from theBiasPlanet.coreUtilities.clipboardHandling.ClipboardFormatSpecificDatum import ClipboardFormatSpecificDatum

class ClipboardFormatSpecificDataComposite:
	def __init__ (a_this: "ClipboardFormatSpecificDataComposite") -> None:
		a_this.i_formatNameToDatumMap: "OrderedDict [str, ClipboardFormatSpecificDatum]" = OrderedDict ()
	
	def __del__ (a_this: "ClipboardFormatSpecificDataComposite") -> None:
		None
	
	def addFormatSpecificDatum (a_this: "ClipboardFormatSpecificDataComposite", a_formatSpecificDatum: "ClipboardFormatSpecificDatum") -> bool:
		a_this.i_formatNameToDatumMap [a_formatSpecificDatum.getFormatName ()] = a_formatSpecificDatum
		return True
	
	def getFormatNames (a_this: "ClipboardFormatSpecificDataComposite") -> List [str]:
		l_formatNames: List [str] = []
		l_formatName: str = None
		for l_formatName in a_this.i_formatNameToDatumMap:
			l_formatNames.append (l_formatName)
		return l_formatNames
	
	def getFormatSpecificDatum (a_this: "ClipboardFormatSpecificDataComposite", a_formatName: str) -> "ClipboardFormatSpecificDatum":
		l_formatSpecificDatum: "ClipboardFormatSpecificDatum" = None
		try:
			l_formatSpecificDatum = a_this.i_formatNameToDatumMap [a_formatName]
		except (KeyError) as l_exception:
			None
		return l_formatSpecificDatum


theBiasPlanet/coreUtilities/clipboardHandling/ClipboardFormatSpecificDataCompositesHistory.py

@Python ソースコード
from collections import OrderedDict
from theBiasPlanet.coreUtilities.clipboardHandling.ClipboardFormatSpecificDataComposite import ClipboardFormatSpecificDataComposite

class ClipboardFormatSpecificDataCompositesHistory:
	def __init__ (a_this: "ClipboardFormatSpecificDataCompositesHistory") -> None:
		a_this.i_dataCompositeKeyToDataCompositeMap: "OrderedDict [str, ClipboardFormatSpecificDataComposite]" = OrderedDict ()
	
	def __del__ (a_this: "ClipboardFormatSpecificDataCompositesHistory") -> None:
		None
	
	def addDataComposite (a_this: "ClipboardFormatSpecificDataCompositesHistory", a_dataCompositeKey: str, a_dataComposite: "ClipboardFormatSpecificDataComposite") -> bool:
		a_this.i_dataCompositeKeyToDataCompositeMap [a_dataCompositeKey] = a_dataComposite
		return True
	
	def removeDataComposite (a_this: "ClipboardFormatSpecificDataCompositesHistory", a_dataCompositeKey: str) -> bool:
		try:
			a_this.i_dataCompositeKeyToDataCompositeMap.pop (a_dataCompositeKey)
			return True
		except (KeyError) as l_exception:
			return False
	
	def getDataComposite (a_this: "ClipboardFormatSpecificDataCompositesHistory", a_dataCompositeKey: str) -> "ClipboardFormatSpecificDataComposite":
		l_dataComposite: "ClipboardFormatSpecificDataComposite" = None
		try:
			l_dataComposite = a_this.i_dataCompositeKeyToDataCompositeMap [a_dataCompositeKey]
		except (KeyError) as l_exception:
			None
		return l_dataComposite


'wx.DataObject'を拡張したクラスは以下のものだ。

theBiasPlanet/coreUtilities/clipboardHandling/WxPythonClipboardEventsHandler.py

@Python ソースコード
from typing import List
from typing import cast
from collections import OrderedDict
import sys
from wx import DataFormat as wx_DataFormat
from wx import DataObject as wx_DataObject
import wx
from theBiasPlanet.coreUtilities.clipboardHandling.ClipboardFormatSpecificDataComposite import ClipboardFormatSpecificDataComposite
from theBiasPlanet.coreUtilities.clipboardHandling.ClipboardFormatSpecificDatum import ClipboardFormatSpecificDatum

class WxPythonClipboardEventsHandler (wx_DataObject):
	s_possibleDatumFormatNameToFormatMap: "OrderedDict [str, wx_DataFormat]" = None
	s_preferedDatumFormatName: str = None
	s_possibleDatumFormats: List [wx_DataFormat] = None
	
	@staticmethod
	def getDatumFormatName (a_datumFormat: wx_DataFormat) -> str:
		l_datumFormatNumber: int = a_datumFormat.GetType ()
		l_datumFormatName: str = None
		if l_datumFormatNumber == wx.DF_TEXT:
			l_datumFormatName = "Text"
		elif l_datumFormatNumber == wx.DF_BITMAP:
			l_datumFormatName = "Bitmap"
		elif l_datumFormatNumber == wx.DF_METAFILE:
			l_datumFormatName = "Metafile"
		elif l_datumFormatNumber == wx.DF_FILENAME:
			l_datumFormatName = "Filename"
		elif l_datumFormatNumber == wx.DF_HTML:
			l_datumFormatName = "HTML Format"
		else:
			l_datumFormatName = a_datumFormat.GetId ()
		return l_datumFormatName
	
	def __init__ (a_this: "WxPythonClipboardEventsHandler", a_formatSpecificDataComposite: "ClipboardFormatSpecificDataComposite") -> None:
		a_this.i_formatSpecificDataComposite: "ClipboardFormatSpecificDataComposite" = a_formatSpecificDataComposite
		a_this.i_supportedDatumFormats: List [wx_DataFormat] = None
		
		super ().__init__ ()
	l_availableDatumFormatNames: List [str] = a_this.i_formatSpecificDataComposite.getFormatNames ()
		if len (l_availableDatumFormatNames) > 0:
			a_this.i_supportedDatumFormats = []
		l_datumFormatName: str = None
			for l_datumFormatName in l_availableDatumFormatNames:
				a_this.i_supportedDatumFormats.append (WxPythonClipboardEventsHandler.s_possibleDatumFormatNameToFormatMap [l_datumFormatName])
		else:
			a_this.i_supportedDatumFormats = WxPythonClipboardEventsHandler.s_possibleDatumFormats
	
	def getFormatSpecificDataComposite (a_this: "WxPythonClipboardEventsHandler") -> "ClipboardFormatSpecificDataComposite":
		return a_this.i_formatSpecificDataComposite
	
	def GetFormatCount (a_this: "WxPythonClipboardEventsHandler", a_datumTransferDirection: wx_DataObject.Direction = wx_DataObject.Direction.Get) -> int:
		sys.stdout.write ("### GetFormatCount: {0:d}\n".format (len (a_this.i_supportedDatumFormats)))
		return len (a_this.i_supportedDatumFormats)
	
	def GetAllFormats (a_this: "WxPythonClipboardEventsHandler", a_datumTransferDirection: wx_DataObject.Direction = wx_DataObject.Direction.Get) -> List [wx_DataFormat]:
		sys.stdout.write ("### GetAllFormats:\n")
		return a_this.i_supportedDatumFormats
	
	# 'a_formatSpecificDatum' is not really 'bytearray', but 'memoryview', but the stub of 'memoryview' seems to be mistaken, which makes me use 'bytearray' instead.
	def GetDataHere (a_this: "WxPythonClipboardEventsHandler", a_datumFormat: wx_DataFormat, a_formatSpecificDatum: bytearray) -> bool:
		sys.stdout.write ("### GetDataHere: {0:s}\n".format (WxPythonClipboardEventsHandler.getDatumFormatName (a_datumFormat)))
		l_formatSpecificDatumIsFound: bool = False
		if a_formatSpecificDatum is not None:
			l_formatSpecificDatum: "ClipboardFormatSpecificDatum" = a_this.i_formatSpecificDataComposite.getFormatSpecificDatum (WxPythonClipboardEventsHandler.getDatumFormatName (a_datumFormat))
			if l_formatSpecificDatum is not None:
				l_copiedFormatSpecificDatum: bytearray = l_formatSpecificDatum.getDatum ()
				l_byteIndex: int = 0
				for l_byteIndex in range (0, len (a_formatSpecificDatum), 1):
					#a_formatSpecificDatum [l_byteIndex:l_byteIndex + 1] = cast (Sequence [bytes], bytes ([l_copiedFormatSpecificDatum [l_byteIndex]])) # This is if I rather use 'memoryview'.
					a_formatSpecificDatum [l_byteIndex] = l_copiedFormatSpecificDatum [l_byteIndex]
				l_formatSpecificDatumIsFound = True
		return l_formatSpecificDatumIsFound
	
	def GetDataSize (a_this: "WxPythonClipboardEventsHandler", a_datumFormat: wx_DataFormat) -> int:
		sys.stdout.write ("### GetDataSize:\n")
		l_size: int = 0
		l_formatSpecificDatum: "ClipboardFormatSpecificDatum" = a_this.i_formatSpecificDataComposite.getFormatSpecificDatum (WxPythonClipboardEventsHandler.getDatumFormatName (a_datumFormat))
		if l_formatSpecificDatum is not None:
			l_size = len (l_formatSpecificDatum.getDatum ())
		return l_size
	
	def GetPreferredFormat (a_this: "WxPythonClipboardEventsHandler", a_datumTransferDirection: wx_DataObject.Direction = wx_DataObject.Direction.Get) -> wx_DataFormat:
		sys.stdout.write ("### GetPreferredFormat:\n")
		return WxPythonClipboardEventsHandler.s_possibleDatumFormatNameToFormatMap [WxPythonClipboardEventsHandler.s_preferedDatumFormatName]
	
	def IsSupported (a_this: "WxPythonClipboardEventsHandler", a_datumFormat: wx_DataFormat, a_datumTransferDirection: wx_DataObject.Direction = wx_DataObject.Direction.Get) -> bool:
		sys.stdout.write ("### IsSupported:\n")
		try:
			WxPythonClipboardEventsHandler.s_possibleDatumFormatNameToFormatMap [WxPythonClipboardEventsHandler.getDatumFormatName (a_datumFormat)]
			return True
		except (KeyError) as l_exception:
			return False
	
	def SetData (a_this: "WxPythonClipboardEventsHandler", a_datumFormat: wx_DataFormat, a_formatSpecificDatum: memoryview) -> bool:
		sys.stdout.write ("### SetData: {0:s}\n".format (WxPythonClipboardEventsHandler.getDatumFormatName (a_datumFormat)))
		l_datumFormatName: str = WxPythonClipboardEventsHandler.getDatumFormatName (a_datumFormat)
		if a_formatSpecificDatum is not None:
			l_datumSize = len (a_formatSpecificDatum)
			l_copiedFormatSpecificDatum: bytearray = None
			if l_datumFormatName == "Text" or l_datumFormatName == "HTML Format":
				l_copiedFormatSpecificDatum = bytearray (l_datumSize + 1)
				l_copiedFormatSpecificDatum [l_datumSize] = 0
			else:
				l_copiedFormatSpecificDatum = bytearray (l_datumSize)
			l_byteIndex: int = 0
			for l_byteIndex in range (0, len (a_formatSpecificDatum), 1):
				l_copiedFormatSpecificDatum [l_byteIndex] = a_formatSpecificDatum [l_byteIndex]
			a_this.i_formatSpecificDataComposite.addFormatSpecificDatum (ClipboardFormatSpecificDatum (l_datumFormatName, a_datumFormat.GetType (), l_copiedFormatSpecificDatum))
		return False

勿論、'GetDataHere'で、'a_formatSpecificDatum = l_formatSpecificDatum.getDatum ()'のようにはできない(もしも、できると思われるのであれば、Python変数というものはポインターであることを理解されていない)。

クリップボード操作クラスは以下のものだ。

theBiasPlanet/coreUtilities/clipboardHandling/WxPythonClipboard.py

@Python ソースコード
from typing import List
from collections import OrderedDict
from wx import DataFormat as wx_DataFormat
import wx
from theBiasPlanet.coreUtilities.clipboardHandling.ClipboardFormatSpecificDataComposite import ClipboardFormatSpecificDataComposite
from theBiasPlanet.coreUtilities.clipboardHandling.WxPythonClipboardEventsHandler import WxPythonClipboardEventsHandler

class WxPythonClipboard:
	@staticmethod
	def setUp (a_datumFormatNameToFormatMap: "OrderedDict [str, wx_DataFormat]", a_preferedDatumFormatName: str) -> bool:
		WxPythonClipboardEventsHandler.s_possibleDatumFormatNameToFormatMap = a_datumFormatNameToFormatMap
		WxPythonClipboardEventsHandler.s_preferedDatumFormatName = a_preferedDatumFormatName
		
		WxPythonClipboardEventsHandler.s_possibleDatumFormats = []
		l_datumFormatName: str = None
		for l_datumFormatName in WxPythonClipboardEventsHandler.s_possibleDatumFormatNameToFormatMap:
			WxPythonClipboardEventsHandler.s_possibleDatumFormats.append (WxPythonClipboardEventsHandler.s_possibleDatumFormatNameToFormatMap [l_datumFormatName])
		return True
	
	@staticmethod
	def openClipboard () -> bool:
		wx.TheClipboard.Open ()
		return True
	
	@staticmethod
	def closeClipboard () -> bool:
		wx.TheClipboard.Close ()
		return True
	
	@staticmethod
	def clearClipboard () -> bool:
		wx.TheClipboard.Clear ()
		return True
	
	@staticmethod
	def getFormatSpecificDataComposite () -> "ClipboardFormatSpecificDataComposite":
		l_wxPythonClipboardEventsHandler: "WxPythonClipboardEventsHandler" = WxPythonClipboardEventsHandler (ClipboardFormatSpecificDataComposite ())
		wx.TheClipboard.GetData (l_wxPythonClipboardEventsHandler)
		return l_wxPythonClipboardEventsHandler.getFormatSpecificDataComposite ()
	
	@staticmethod
	def setFormatSpecificDataComposite (a_formatSpecificDataComposite: "ClipboardFormatSpecificDataComposite") -> bool:
		l_wxPythonClipboardEventsHandler: "WxPythonClipboardEventsHandler" = WxPythonClipboardEventsHandler (a_formatSpecificDataComposite)
		wx.TheClipboard.SetData (l_wxPythonClipboardEventsHandler)
		wx.TheClipboard.Flush ()
		return True



8: 限界


Hypothesizer 7
実のところ、全てのフォーマットのデータが、このテクニックで取得・セットできるわけではない。

例えば、Microsoft Windowsでは、LibreOffice Writerクリップボードデータについて、'UnicodeText'、'Locale'、'OEMText'データは取得できない。

なぜか?えーと、Microsoft Windowsでは、任意のフォーマットのデータが1つの共通の方法で単純にバイト配列として取得できるというわけではなく、あるフォーマットのデータは、ある特定の方法で取得しなければならないのだが、wxPythonは、全ての可能なフォーマットをサポートする努力をしなかったということだ。

サポートされているフォーマット群が満足いくものでないのであれば、別のテクニックへ向かわなければならない(C#用の記事およびC++用の記事があります)だろう。


9: テストする


Hypothesizer 7
私のMicrosoft Windows用のテストコードは以下のものだ。

@Python ソースコード
from typing import List
rom typing import TextIO
import sys
import wx
from theBiasPlanet.coreUtilities.clipboardHandling.ClipboardFormatSpecificDataComposite import ClipboardFormatSpecificDataComposite
from theBiasPlanet.coreUtilities.clipboardHandling.ClipboardFormatSpecificDataCompositesHistory import ClipboardFormatSpecificDataCompositesHistory
from theBiasPlanet.coreUtilities.clipboardHandling.ClipboardFormatSpecificDatum import ClipboardFormatSpecificDatum
from theBiasPlanet.coreUtilities.clipboardHandling.WxPythonClipboard import WxPythonClipboard
from theBiasPlanet.coreUtilities.clipboardHandling.WxPythonClipboardEventsHandler import WxPythonClipboardEventsHandler
from theBiasPlanet.coreUtilities.constantsGroups.ClipboardDatumFormatNameToFormatMapsConstantsGroup import ClipboardDatumFormatNameToFormatMapsConstantsGroup

class Test1Test:
	@staticmethod
	def main (a_arguments: List [str]) -> None:
		Test1Test.test ()
	
	@staticmethod
	def test () -> None:
		l_clipbardFormatSpecificDataCompositesHistory: "ClipboardFormatSpecificDataCompositesHistory" = ClipboardFormatSpecificDataCompositesHistory ()
		l_standardInputReader: TextIO = sys.stdin
		WxPythonClipboard.setUp (ClipboardDatumFormatNameToFormatMapsConstantsGroup.c_windowsDatumFormatNameToFormatMap, "Text")
		while True:
			sys.stdout.write ("### Input 'S' (Set), 'G' (Get), 'D (Display)', or 'Q' (Quit):\n")
			sys.stdout.flush ()
			l_userInput: str = l_standardInputReader.read (2)
			l_clipboardFormatSpecificDataCompositeKey: str
			if l_userInput.startswith ("S") or l_userInput.startswith ("G") or l_userInput.startswith ("D"):
				sys.stdout.write ("### Input the key:\n")
				sys.stdout.flush ()
				l_clipboardFormatSpecificDataCompositeKey = l_standardInputReader.read (2) [0]
				if l_userInput.startswith ("S"):
					WxPythonClipboard.openClipboard ()
					WxPythonClipboard.clearClipboard ()
					WxPythonClipboard.setFormatSpecificDataComposite (l_clipbardFormatSpecificDataCompositesHistory.getDataComposite (l_clipboardFormatSpecificDataCompositeKey))
					WxPythonClipboard.closeClipboard ()
				elif l_userInput.startswith ("G"):
					WxPythonClipboard.openClipboard ()
					l_clipbardFormatSpecificDataCompositesHistory.addDataComposite (l_clipboardFormatSpecificDataCompositeKey, WxPythonClipboard.getFormatSpecificDataComposite ())
					WxPythonClipboard.closeClipboard ()
				elif l_userInput.startswith ("D"):
					l_clipboardFormatSpecificDataComposite: "ClipboardFormatSpecificDataComposite " = l_clipbardFormatSpecificDataCompositesHistory.getDataComposite (l_clipboardFormatSpecificDataCompositeKey)
					l_clipboardDatumFormatNames: List [str] = l_clipboardFormatSpecificDataComposite.getFormatNames ()
					l_clipboardDatumFormatName: str = None
					for l_clipboardDatumFormatName in l_clipboardDatumFormatNames:
						l_clipboardFormatSpecificDatum: "ClipboardFormatSpecificDatum " = l_clipboardFormatSpecificDataComposite.getFormatSpecificDatum (l_clipboardDatumFormatName)
						sys.stdout.write ("### clipboard datum format number, format name, size: {0:d}, {1:s}, {2:d}\n".format (l_clipboardFormatSpecificDatum.getFormatNumber (), l_clipboardDatumFormatName, l_clipboardFormatSpecificDatum.getDatumSize ()))
						sys.stdout.flush ()
			else:
				break

if __name__ == "__main__":
	l_application = wx.App ()
	Test1Test.main (sys.argv)


theBiasPlanet/coreUtilities/constantsGroups/ClipboardDatumFormatNameToFormatMapsConstantsGroup.py

@Python ソースコード
from collections import OrderedDict
from wx import DataFormat as wx_DataFormat
import wx

class ClipboardDatumFormatNameToFormatMapsConstantsGroup:
	c_linuxDatumFormatNameToFormatMap: "OrderedDict [str, wx_DataFormat]" = OrderedDict ({"Text": wx_DataFormat (wx.DF_TEXT), "Bitmap": wx_DataFormat (wx.DF_BITMAP), "Metafile": wx_DataFormat (wx.DF_METAFILE), "Filename": wx_DataFormat (wx.DF_FILENAME), "HTML Format": wx_DataFormat (wx.DF_HTML), "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"": wx_DataFormat ("application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\""), "text/rtf": wx_DataFormat ("text/rtf"), "text/richtext": wx_DataFormat ("text/richtext"), "text/html": wx_DataFormat ("text/html"), "text/plain;charset=utf-16": wx_DataFormat ("text/plain;charset=utf-16"), "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\";classname=\"8BC6B165-B1B2-4EDD-aa47-dae2ee689dd6\";typename=\"LibreOffice 6.4 Text Document\";viewaspect=\"1\";width=\"16999\";height=\"2995\";posx=\"0\";posy=\"0\"": wx_DataFormat ("application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\";classname=\"8BC6B165-B1B2-4EDD-aa47-dae2ee689dd6\";typename=\"LibreOffice 6.4 Text Document\";viewaspect=\"1\";width=\"16999\";height=\"2995\";posx=\"0\";posy=\"0\""), "text/plain;charset=utf-8": wx_DataFormat ("text/plain;charset=utf-8"), "text/plain": wx_DataFormat ("text/plain"), "UTF8_STRING": wx_DataFormat ("UTF8_STRING"), "STRING": wx_DataFormat ("STRING"), "TEXT": wx_DataFormat ("TEXT"), "MULTIPLE": wx_DataFormat ("MULTIPLE"), "TIMESTAMP": wx_DataFormat ("TIMESTAMP")})
	c_windowsDatumFormatNameToFormatMap: "OrderedDict [str, wx_DataFormat]" = OrderedDict ({"Text": wx_DataFormat (wx.DF_TEXT), "Metafile": wx_DataFormat (wx.DF_METAFILE), "Filename": wx_DataFormat (wx.DF_FILENAME), "UnicodeText": wx_DataFormat ("UnicodeText"), "Locale": wx_DataFormat ("Locale"), "OEMText": wx_DataFormat ("OEMText"), "DataObject": wx_DataFormat ("DataObject"), "Preferred DropEffect": wx_DataFormat ("Preferred DropEffect"), "Ole Private Data": wx_DataFormat ("Ole Private Data"), "HTML Format": wx_DataFormat (wx.DF_HTML), "HTML (HyperText Markup Language)": wx_DataFormat ("HTML (HyperText Markup Language)"), "Star Embed Source (XML)": wx_DataFormat ("Star Embed Source (XML)"), "Rich Text Format": wx_DataFormat ("Rich Text Format"), "Richtext Format": wx_DataFormat ("Richtext Format"), "Link": wx_DataFormat ("Link"), "Star Object Descriptor (XML)": wx_DataFormat ("Star Object Descriptor (XML)"), "GDIMetaFile": wx_DataFormat ("GDIMetaFile"), "EnhancedMetafile": wx_DataFormat ("EnhancedMetafile"), "MetaFilePict": wx_DataFormat ("MetaFilePict"), "PNG": wx_DataFormat ("PNG"), "DeviceIndependentBitmap": wx_DataFormat ("DeviceIndependentBitmap"), "Windows Bitmap": wx_DataFormat ("Windows Bitmap"), "SymbolicLink": wx_DataFormat ("SymbolicLink"), "DataInterchangeFormat": wx_DataFormat ("DataInterchangeFormat"), "EditEngine ODF": wx_DataFormat ("EditEngine ODF")})


'cmd'ターミナル上であるテキスト断片をコピーした後、'G' -> 'A' -> 'D' -> 'A'というインプットに対して、以下のようなアウトプットを得る。

@出力
### clipboard datum format number, format name, size: 1, Text, 8

LibreOffice Writerインスタンス上であるテキスト断片をコピーした後、'G' -> 'A' -> 'D' -> 'A'というインプットに対して、以下のようなアウトプットを得る。

@出力
### clipboard datum format number, format name, size: 1, Text, 37
### clipboard datum format number, format name, size: 49161, DataObject, 8
### clipboard datum format number, format name, size: 49171, Ole Private Data, 552
### clipboard datum format number, format name, size: 30, HTML Format, 772
### clipboard datum format number, format name, size: 49819, HTML (HyperText Markup Language), 667
### clipboard datum format number, format name, size: 49817, Star Embed Source (XML), 6279
### clipboard datum format number, format name, size: 49285, Rich Text Format, 2675
### clipboard datum format number, format name, size: 49790, Richtext Format, 2675
### clipboard datum format number, format name, size: 49852, Link, 111
### clipboard datum format number, format name, size: 49853, Star Object Descriptor (XML), 164

Linux用には、予期されるクリップボードデータフォーマット群を変更しなければならない。


参考資料


<このシリーズの前の記事 | このシリーズの目次 | このシリーズの次の記事>