CopyQ を使ってクリップボード履歴を管理する の変更点

更新


[[公開メモ]]

* 概要 [#o4c299d3]

#ref(copyq-logo.png,around,right);

Windows は標準で Win + V キーでクリップボード履歴を利用できる。

便利そうではあるのだけれど、パスワードなどの情報が長時間にわたって履歴に残ってしまうと気持ちが悪いので気軽には使えない・・・

そこでクリップボード履歴とスニペットの管理 を CopyQ というフリーソフトで行うことにして、ログイン画面が表示されたら自動的にクリップボード内容を消去する機能を持たせることにした。

> スニペット機能とは?
> 頻出のフレーズを CopyQ に登録しておいて、~
そこから選んで張り付けられる
** 目次 [#b20374b3]

#contents

* Windows では標準で Winキー + V でクリップボード履歴にアクセスできる [#zde4f568]

例えばこの記事でも紹介されている:

https://atmarkit.itmedia.co.jp/ait/articles/1903/08/news028.html

#ref(ソフトウェア/CopyQ/スクリーンショット 2024-08-26 213447.png,,50%);
~

> 過去にコピーまたは切り取りしたデータを貼り付けできる「クリップボードの履歴」機能の使い方を紹介する。「履歴」機能を使えば、クリップボードに保存した過去のデータを利用したり、よく使うデータをクリップボードに保存しておき必要に応じて呼び出したりすることができる。
> 2023年08月18日 05時00分 公開
> [小林章彦,デジタルアドバンテージ]

* 問題点 [#v12918b5]

クリップボード履歴、という機能はとても便利そうなのだけれど、

パスワードや個人情報をコピーした履歴が長時間残ってしまうのは困る。

そう考えると Windows 標準の機能をそのまま使うわけにはいかない・・・

* 実現したい機能 [#v1a95a7d]

- 履歴にアクセスできるのは便利そう
- でもそんなに昔のコピー履歴にアクセスする必要はないので 30 分くらい経ったら消えてくれていい
- スクリーンセーバーが起動したり、ロック画面が表示されたら履歴を消去してほしい
- ただし、よく使う内容は履歴と別に保存しておいて、スニペットとして使いたい

そんなソフトはないかと探しました

* CopyQ というソフト [#b5b43093]

#ref(copyq-logo.png,around,right);

https://copyq.readthedocs.io/en/latest/

これは Windows だけじゃなく Mac OS や Linux 上でも動く、オープンソースのクリップボード履歴管理アプリとして有名なもの。

クリップボード履歴の機能だけでなく、スニペット的に使える内容を複数のタブに分類して保存しておいたりもできて便利そう。

標準では自動的に履歴を消す機能はないけれど、JavaScript 的な独自のスクリプト言語で標準動作をカスタマイズしたり、追加の機能を実装したりできるので、それを使えば自動消去に対応できそう。

** 基本的な使い方 [#l69a1f00]

- コピーした内容は自動的に CopyQ の履歴に入る
- タスクトレイのアイコンを左クリックするとメイン画面が表示される
-- そのままキー入力するとクリップボード内容を検索可能
-- 上下矢印キーで選択して ENTER で貼り付け

** メイン画面表示のショートカットを設定 [#n8b0446c]

わざわざタスクトレーアイコンをクリックするのは面倒なのでショートカット設定は必須。

タスクトレーアイコンの右クリックから [設定] を選択

[ショートカット] の [メインウィンドウの表示切り替え] の + をクリックして、
例えば Ctrl + Alt + C を割り当てる。

すると、他のアプリを使用中でも Ctrl + Alt + C で CopyQ が立ち上がるようになる。

*** ショートカットキーの選択 [#z58f4bf3]

CopyQ のショートカット機能では Winキー は選択できないので Win + V にはできない

というか、Windows がそれを許していない?

そうなると、

- Ctrl + Shift + V はテキスト形式で張り付け
- Ctrl + Alt + V はエクセルで形式を選択して貼り付け

なので、V 関連は使いづらい。

Ctrl + Alt + C は他であまり使われてなさそうだしいいかな、と。

** スニペット機能 [#s8d4b214]

メインウィンドウの [タブ] メニューから新しくタブを追加して、
そこにスニペットとして使う内容を追加するのが良さそう。

- 左右の矢印キーで表示するタブを変更できる

#ref(ソフトウェア/CopyQ/スクリーンショット 2024-08-26 220951.png,,75%);
~
このように各項目の行数が多くて一覧性が悪い場合には、
設定で 「アイテムをシンプルに表示」 をチェックしておくと
#ref(ソフトウェア/CopyQ/スクリーンショット 2024-08-26 221333.png,,75%);
~
このように見やすくなる。
#ref(ソフトウェア/CopyQ/スクリーンショット 2024-08-26 221607.png,,75%);

* クリップボード履歴の自動消去 [#i74ca3a5]

- 作業中に30分以上前の古い履歴は削除する
- ロック画面が表示されたら、ピン止めされておらず、タグもついていないクリップボード履歴はすべて削除する
- スクリーンセーバーの設定を、スクリーンセーバーからの復帰時にロック画面へ飛ぶようにしておく

とすることで、クリップボード履歴の機能を使いつつも、
機密性の高い情報がクリップボード履歴に長時間残ってしまう可能性を減らせるはず。

** クリップボード履歴にコピーした時刻を持たせる [#a55cfb75]

「古い履歴」を消すにはそれがいつコピーされたかという時刻の情報を持たなければならない。

CopyQ のスクリプト例にほとんどそのまま使えるコードがあった。~
https://copyq.readthedocs.io/en/latest/command-examples.html#show-copy-time

このコードのタグの区切り文字のカンマの後ろにあったスペースを除去した。

 var tags = str(data(tagsMime)) + ', ' + time

を

 var tags = str(data(tagsMime)) + ',' + time

ということ。

そうしてできたコードがこれ:

 [Command]
 Automatic=true
 Command="
     copyq:
     var time = dateString('yyyy-MM-dd hh:mm:ss')
     setData('application/x-copyq-user-copy-time', time)
 
     var tagsMime = 'application/x-copyq-tags'
     var tags = str(data(tagsMime)) + ',' + time
     setData(tagsMime, tags)"
 Icon=\xf017
 Name=Store Copy Time

使い方は、

- このコードをコピーしてから CopyQ のメインウィンドウを表示する
- F6 を押すとコマンドウィンドウが現れる
- Ctrl + V で張り付けると Store Copy Time という項目が追加される

Automatic=true の指定があるため、このコードはクリップボードへデータがコピーされるたびに呼び出される。

- 時刻を表す文字列は "2024-01-01 01:01:01" の形式
- application/x-copyq-user-copy-time タイプの情報としてクリップボードに入れる
- 同時に、タグとしても同じデータを付けておく(これは表示用)

** 時刻で選別して古いものを消すコマンドを実装する [#vde4b93b]

これが Auto Delete 相当の機能になる

上と同様の手順で以下を張り付ける:

 [Command]
 Name="removeOldItems(millisec=0)"
 Command="
     copyq:
     global.removeOldItems = function(millisec=0) {
       // 全消去時にはクリップボードの中身も消す
       if(!millisec) copy('') // なぜか消えない時がある???
 
       // 現在時刻より millisec だけ昔の時刻を表す文字列を作る
       var old = new Date(Date.now()-millisec)
       var str = ''
       str += ('000' + old.getFullYear()).slice(-4)
       str += '-' + ('0' + (old.getMonth() + 1)).slice(-2)
       str += '-' +('0' + old.getDate()).slice(-2)
       str += ' ' +  ('0' + old.getHours()).slice(-2)
       str += ':' + ('0' + old.getMinutes()).slice(-2)
       str += ':' + ('0' + old.getSeconds()).slice(-2)
 
       // 1つ目のタブに切り替える
       // 1つ目のタブがクリップボード履歴であると仮定している
       var save = selectedTab()
       tab(tab()[0])
       var i = size() - 1 // 履歴情報を後ろから順に確認
       while(i >= 0){
         // 時刻情報が30分前より古く、ピン止めや時刻以外のタグがなければ消す
         var time = getItem(i)['application/x-copyq-user-copy-time']
         if(time && time < str && !plugins.itempinned.isPinned(i)) {
           if(!plugins.itemtags.tags(i).find((tag)=>tag!=time)) {
             remove(i)
           }
         }
         i-- // 次へ
       }
       tab(save) // タブを元に戻す
     }
     "
 IsScript=true

すると、removeOldItems(millisec=0) という項目が追加される。

この項目は [スクリプト] に指定されており、内部では
global という名のグローバル変数プールに removeOldItems という関数を追加している。

このように追加した関数は、他のスクリプトから呼び出せるほか、コマンドライン引数の中からも実行が可能になる。

で、肝心の関数の中身は、
- 現在時刻から millisec で指定されただけ過去の時刻を元に "2000-01-01 00:00:00" 形式の文字列を作る
- 1つめのタブ(これがクリップボード履歴に相当する)の項目を後ろから順に見ていく
-- 後ろから見るのは項目を消去したときにおかしくならないようにするため
-- 'application/x-copyq-user-copy-time' の情報を取り出して、時刻を比較し古いものだけを処理
-- ピン止めされておらず、時刻以外のタグが付いていなければ消去する
- 何も残らなければ、つまり最新の除法でさえ古いものであれば、クリップボード自体もクリアする
- millisec を省略すると 0 を指定したのと同じになるため、常にすべての履歴が消去される

** クリップボードへのコピーがあった時に呼び出す [#l6ae7e0e]

クリップボードへコピーがあるたびに、30分以上前の履歴を消せるよう removeOldItems を呼び出す。

 [Command]
 Automatic=true
 Command="
     copyq:
     removeOldItems(30*60*1000)  // 30 min
 "
 Icon=\xf12d
 Name=Clear Old History

クリップボードへのコピーを行わないと消えないので本当はちょっと不満なのだけれど、
まあそこまで厳密にしなくても?

履歴一覧の表示前に呼び出されるコールバックがあればそこに記述したいのだけれどなあ。

(どうしてもやりたければ下でタスクスケジューラを利用した方法を紹介している)
*** アイコンの文字コード [#y75a0718]

上記の Clear Old History のスクリプトには消しゴムマークのアイコンを付けたのだけれど、
CopyQ の「選択したコマンドをコピー」でコピーすると、

 

となって、現状ではこれはブラウザ上では文字化けしてしまった。

https://ao-system.net/entity/ こちらのサイトで html エンティティに変換したところ、

 \xf12d

と表記すればよいことが分かった。

** Windows のロック画面が表示されたらクリップボードを空にする [#x0b6055c]

- ピン止め・タグ付けされていないすべての履歴を消す
- クリップボード自体も空にする

これは引数無しで removeOldItems() を呼び出せばいいのだけれど、

「Windows のロック画面(ログイン画面)が表示されたら特定のスクリプトを実行する」という設定は CopyQ にはない

そこで Wimdows 標準の「タスクスケジューラ」から CopyQ を呼び出す形で対応する。

ロックされたら copyq.exe に --eval "removeOldItems()" を付けて呼び出せばいい。

*** タスクスケジューラを起動 [#fe5c60d7]

スタートボタンを押して task と入れればタスクスケジューラが見つかるはず。

#ref(ソフトウェア/CopyQ/スクリーンショット 2024-08-26 231836.png,,50%);

*** タスクを作成&名前を付ける [#def2b7f9]

#ref(ソフトウェア/CopyQ/スクリーンショット 2024-08-26 232052.png,,50%);
~

#ref(ソフトウェア/CopyQ/スクリーンショット 2024-08-26 232148.png,,50%);

*** トリガーを「ワークステーション ロック時」にする ← アンロック時にした方が良いかも [#p40cd113]

トリガータブで「新規」
#ref(ソフトウェア/CopyQ/スクリーンショット 2024-08-26 232209.png,,50%);
~

「ワークステーション ロック時」としてOK
#ref(ソフトウェア/CopyQ/スクリーンショット 2024-08-26 232308.png,,50%);
→ これ、「ワークステーション アンロック時」としないと CopyQ の履歴は消せてもクリップボードの中身は消せなかった [[(参照)>#e8da74c7]]
~

トリガーが追加された
#ref(ソフトウェア/CopyQ/スクリーンショット 2024-08-26 232332.png,,50%);

*** 操作で CopyQ を呼び出す [#p4e87780]

[操作] タブで [新規]
#ref(ソフトウェア/CopyQ/スクリーンショット 2024-08-26 232348.png,,50%);
~
[プログラム] にフルパスで copyq.exe を指定、引数に --eval "removeOldItems()" を指定~
#ref(ソフトウェア/CopyQ/スクリーンショット 2024-08-26 232519.png,,50%);
~
正しく項目が追加された
#ref(ソフトウェア/CopyQ/スクリーンショット 2024-08-26 232537.png,,50%);

*** 条件で「AC 接続時のみ」のチェックを外す [#dc76a19e]

#ref(ソフトウェア/CopyQ/スクリーンショット 2024-08-26 232617.png,,50%);

*** 完成 [#u3c2dfef]

これで Windows のロック時に CopyQ の履歴とクリップボード内容が消去されるようになった
これで Windows のロック時(アンロック時)に CopyQ の履歴とクリップボード内容が消去されるようになった

すばらしい

** スクリーンセーバーの再開時にロック画面を表示する [#s0d6de0a]

こうしておけば、席から離れるとしばらくしてクリップボードの履歴が消えることになる。

デスクトップの右クリックから [個人用設定]

#ref(ソフトウェア/CopyQ/スクリーンショット 2024-08-26 234317.png,,75%)
~
[ロック画面] から [スクリーンセーバーの設定]
#ref(ソフトウェア/CopyQ/スクリーンショット 2024-08-26 234515.png,,50%)
~
[再開時にログオン画面に戻る]にチェック
#ref(ソフトウェア/CopyQ/スクリーンショット 2024-08-26 222925.png,,50%)

** 5分おきに removeOldItems(30*60*1000) を呼び出してもいい [#a739da9b]

タスクスケジューラのトリガーには5分ごとに繰り返す、というような指定もできるので、
5分おきに removeOldItems(30*60*1000) を呼び出せば、長時間コピー操作をしていない場合にも
確実に古い履歴を消すことができる。

#ref(ソフトウェア/CopyQ/スクリーンショット 2024-08-26 234929.png,,50%)

* クリップボードデータを加工するスクリプト [#e0efb813]

コピーしたデータを CopyQ に登録したスクリプトで加工して貼り付けることができる。

定型でやってる作業があれば登録しておくと便利。

さしあたり登録したのは、

- pukiwiki のコードブロック用に「各行の先頭に指定の文字列を追加する」という機能

- 英文 pdf をズルっとコピーしたものを deepl などの翻訳機に通す前に、不必要に入ってしまった改行を取り除く機能
-- 行末がハイフンならハイフンごと消去する
-- そうでなければ空白文字1つに置き換える

の2つ。

以下のスクリプトは、

- [&Modify] というメニューのサブメニューにしてある
- M の前に & を付けてあるので "m" キーがメニューのアクセラレータキーになっている

** 行頭に文字列を挿入 [#s0053a76]

pukiwiki のコードブロックを作るために使えるようデフォルトを空白文字にしてある

 [Command]
  Name=&Modify|行頭に文字列を挿入
  Command="
      copyq:
      var replaceTo = dialog('行頭に挿入する文字列を入力してください', ' ')
      var text = str(data(mimeText))
      var newText = text.replace(/^/gm,replaceTo)
      copy(newText)
      "
  InMenu=true
  Icon=

** 改行を削除(翻訳用) [#gf1c7838]

- pdf をズルっとコピーして deepl なんかに貼る際に使う
- ハイフン + 改行 は完全除去、そうじゃなければ改行を空白に置き換え
- 本当に改行しているところまでつながっちゃうけれど仕方ないか・・・

 [Command]
  Name=&Modify|改行を削除(翻訳用)
  Command="
      copyq:
      var text = str(data(mimeText))
      var newText = text.replace(/-\\n/gm,'').replace(/\\n/gm,' ')
      copy(newText)
      "
  InMenu=true
  Icon=

* しばらくこれでやってみる [#e03e1427]

履歴やスニペット、なんとなく便利そうではあるけれど、実際にはどこまで使うことになるのか。

クリップボードデータを加工するスクリプトを走らせられるのもなんとなく便利そう。

- すべての行頭に " " を挿入して pukiwiki にコードブロックとして張り付けるとか
- pdf からコピーした、改行だらけの英文から不要な改行を消去して、翻訳ソフトに突っ込みやすくするとか

今まで秀丸のマクロを使ってた変換を CopyQ だけで済ませられる可能性が高い?

しばらくこれでやってみよう。

万一それらがそこまで役に立たなくても、これまではクリップボードにコピーされたデータ自体、場合によっては長時間残ってしまっていたのだけれど、上記の手順でPCのロック時に確実に消えるようにできただけでも収穫があったはず。→ いやこれなんかうまく消えない時があるぞ?っていうかむしろたまにしか消えない。

copy('') が効くときと効かないときの差は何なのか??? → 次項参照

** ロック画面表示中に消しても効果がないのかも [#e8da74c7]

「ワークステーション ロック時」をトリガーにしてスクリプトを起動した場合、CopyQ の履歴は消せてもクリップボード自体の中身が消えない(たまに消える?)ことが分かった。

どうやらロック画面表示中に消しても効果がないのかもしれない。

ロックが解除されたときに呼ぶとうまく行くみたいだった。

#ref(ソフトウェア/CopyQ/スクリーンショット 2024-08-28 205316.png,,50%);

* コメント・質問 [#a476a5a7]

#article_kcaptcha

Counter: 238 (from 2010/06/03), today: 3, yesterday: 3