keyhacとExcelの干渉を回避
大変便利なkeyhacですが、常駐した状態でExcelでクリップボード操作(*1)をすると、そこそこの確率で以下のエラーが発生します。
クリップボードを空にできません。別のアプリケーションがカライップボードを使用している可能性があります。
クリップボードを開くことができません。
どうも双方のクリップボードの処理が干渉しているようです。keyhacはWindows版のVer.1.77です。
(*1)選択したセルをマウスでドラッグした時や、[Ctrl]+[C]でコピーした時など、クリップボード操作をした時等
■ 原因(状況)の調査
何が起こっているのか、誰が悪いのか、犯人探しをしたい訳ではないのだけれど、原因がわからないと直しようがない訳で、色々と調査したところ、以下の事がわかりました。
(a) Excelでコピー操作をすると、WM_CLIPBOARDUPDATEが複数回飛んでくる
(b) WM_CLIPBOARDUPDATEが飛ぶ度にGetClipboardSequenceNumberの値が更新される
(c) keyhacはOpenClipboard/GetClipboardData/CloseClipboardでデータを取得している
(d) クリップボードに、同時アクセスする事はできない (排他利用)
この事から、Excelは複数回に分けてクリップボードを操作しており、以下のように2回目以降の処理がKeyhacの処理とバッティングしている可能性があります。
(1) Excel 1回目のクリップボード操作
(2) WM_CLIPBOARDUPDATE 発生
(3) keyhac OpenClipboard で排他アクセスを開始
(4) Excel 2回目のクリップボード操作 → 失敗
(5) Excelエラーメッセージを表示
■ 回避策
Excelに手を入れる事はできないので、keyhacでなんとかする事にし、以下の2案を考えました。
(a) Excelがアクティブな時、クリップボード監視を中断する
(b) クリップボードからデータを取得するタイミングを遅延させる
ざっと試したところ、(b)の方が良さそうだったのでこちらを採用しました。keyhacで該当の処理は「keyhac_clipboard.py」の「cblister_ClipboardHistory」クラスにあります。
keyhac_clipboard.py
なんかdelayedCallが利用されていた痕跡があったので、これを再利用し、遅延時間を100msに修正する事にします。残念ながらkeyhacの開発環境がないので、メソッドを動的に入れ替えるという技を使います。
この fix_clipboard.py をextensionフォルダに保存します。
config.pyに
import fix_clipboard
の行を追加します。(importの並びの最後にでも追加してください)
※※※ この方法はkeyhacのバージョンに依存します (Ver.1.77専用) ※※※
※※※ 改良版が存在します ※※※
■ 結果
とりあえず、当方の環境ではエラーが激減しました。稀に起きる事もあるのですが、そもそも排他リソースなので完全に無くす事はできないと思います。
また、副作用として、コピー操作のちょうど100ms程度後に別のコピー操作をすると100%エラーが発生するようになります。狙ってできる事ではいと思いますが、遅延で回避するという事はそうゆう事です。
クリップボードを空にできません。別のアプリケーションがカライップボードを使用している可能性があります。
クリップボードを開くことができません。
どうも双方のクリップボードの処理が干渉しているようです。keyhacはWindows版のVer.1.77です。
(*1)選択したセルをマウスでドラッグした時や、[Ctrl]+[C]でコピーした時など、クリップボード操作をした時等
■ 原因(状況)の調査
何が起こっているのか、誰が悪いのか、犯人探しをしたい訳ではないのだけれど、原因がわからないと直しようがない訳で、色々と調査したところ、以下の事がわかりました。
(a) Excelでコピー操作をすると、WM_CLIPBOARDUPDATEが複数回飛んでくる
(b) WM_CLIPBOARDUPDATEが飛ぶ度にGetClipboardSequenceNumberの値が更新される
(c) keyhacはOpenClipboard/GetClipboardData/CloseClipboardでデータを取得している
(d) クリップボードに、同時アクセスする事はできない (排他利用)
この事から、Excelは複数回に分けてクリップボードを操作しており、以下のように2回目以降の処理がKeyhacの処理とバッティングしている可能性があります。
(1) Excel 1回目のクリップボード操作
(2) WM_CLIPBOARDUPDATE 発生
(3) keyhac OpenClipboard で排他アクセスを開始
(4) Excel 2回目のクリップボード操作 → 失敗
(5) Excelエラーメッセージを表示
■ 回避策
Excelに手を入れる事はできないので、keyhacでなんとかする事にし、以下の2案を考えました。
(a) Excelがアクティブな時、クリップボード監視を中断する
(b) クリップボードからデータを取得するタイミングを遅延させる
ざっと試したところ、(b)の方が良さそうだったのでこちらを採用しました。keyhacで該当の処理は「keyhac_clipboard.py」の「cblister_ClipboardHistory」クラスにあります。
keyhac_clipboard.py
なんかdelayedCallが利用されていた痕跡があったので、これを再利用し、遅延時間を100msに修正する事にします。残念ながらkeyhacの開発環境がないので、メソッドを動的に入れ替えるという技を使います。
この fix_clipboard.py をextensionフォルダに保存します。
config.pyに
import fix_clipboard
の行を追加します。(importの並びの最後にでも追加してください)
※※※ この方法はkeyhacのバージョンに依存します (Ver.1.77専用) ※※※
※※※ 改良版が存在します ※※※
■ 結果
とりあえず、当方の環境ではエラーが激減しました。稀に起きる事もあるのですが、そもそも排他リソースなので完全に無くす事はできないと思います。
また、副作用として、コピー操作のちょうど100ms程度後に別のコピー操作をすると100%エラーが発生するようになります。狙ってできる事ではいと思いますが、遅延で回避するという事はそうゆう事です。
この記事へのコメント