CopyQ を使ってクリップボード履歴を管理する の履歴(No.4)
更新概要†
Windows は標準で Win + V キーでクリップボード履歴を利用できる。
便利そうではあるのだけれど、パスワードなどの情報が長時間にわたって履歴に残ってしまうと気持ちが悪いので気軽には使えない・・・
そこでクリップボード履歴とスニペットの管理 を CopyQ というフリーソフトで行うことにして、ログイン画面が表示されたら自動的にクリップボード内容を消去する機能を持たせることにした。
スニペット機能とは?
頻出のフレーズを CopyQ に登録しておいて、
そこから選んで張り付けられる
目次†
Windows では標準で Winキー + V でクリップボード履歴にアクセスできる†
例えばこの記事でも紹介されている:
https://atmarkit.itmedia.co.jp/ait/articles/1903/08/news028.html
過去にコピーまたは切り取りしたデータを貼り付けできる「クリップボードの履歴」機能の使い方を紹介する。「履歴」機能を使えば、クリップボードに保存した過去のデータを利用したり、よく使うデータをクリップボードに保存しておき必要に応じて呼び出したりすることができる。
2023年08月18日 05時00分 公開
[小林章彦,デジタルアドバンテージ]
問題点†
クリップボード履歴、という機能はとても便利そうなのだけれど、
パスワードや個人情報をコピーした履歴が長時間残ってしまうのは困る。
そう考えると Windows 標準の機能をそのまま使うわけにはいかない・・・
実現したい機能†
- 履歴にアクセスできるのは便利そう
 - でもそんなに昔のコピー履歴にアクセスする必要はないので 30 分くらい経ったら消えてくれていい
 - スクリーンセーバーが起動したり、ロック画面が表示されたら履歴を消去してほしい
 - ただし、よく使う内容は履歴と別に保存しておいて、スニペットとして使いたい
 
そんなソフトはないかと探しました
CopyQ というソフト†
https://copyq.readthedocs.io/en/latest/
これは Windows だけじゃなく Mac OS や Linux 上でも動く、オープンソースのクリップボード履歴管理アプリとして有名なもの。
クリップボード履歴の機能だけでなく、スニペット的に使える内容を複数のタブに分類して保存しておいたりもできて便利そう。
標準では自動的に履歴を消す機能はないけれど、Java Script 的な独自のスクリプト言語で標準動作をカスタマイズしたり、追加の機能を実装したりできるので、それを使えば自動消去に対応できそう。
基本的な使い方†
- コピーした内容は自動的に CopyQ の履歴に入る
 - タスクトレイのアイコンを左クリックするとメイン画面が表示される
- そのままキー入力するとクリップボード内容を検索可能
 - 上下矢印キーで選択して ENTER で貼り付け
 
 
メイン画面表示のショートカットを設定†
わざわざタスクトレーアイコンをクリックするのは面倒なのでショートカット設定は必須。
タスクトレーアイコンの右クリックから [設定] を選択
[ショートカット] の [メインウィンドウの表示切り替え] の + をクリックして、 例えば Ctrl + Alt + C を割り当てる。
すると、他のアプリを使用中でも Ctrl + Alt + C で CopyQ が立ち上がるようになる。
ショートカットキーの選択†
CopyQ のショートカット機能では Winキー は選択できないので Win + V にはできない
というか、Windows がそれを許していない?
そうなると、
- Ctrl + Shift + V はテキスト形式で張り付け
 - Ctrl + Alt + V はエクセルで形式を選択して貼り付け
 
なので、V 関連は使いづらい。
Ctrl + Alt + C は他であまり使われてなさそうだしいいかな、と。
スニペット機能†
メインウィンドウの [タブ] メニューから新しくタブを追加して、 そこにスニペットとして使う内容を追加するのが良さそう。
- 左右の矢印キーで表示するタブを変更できる
 
このように各項目の行数が多くて一覧性が悪い場合には、
設定で 「アイテムをシンプルに表示」 をチェックしておくと
このように見やすくなる。
クリップボード履歴の自動消去†
- 作業中に30分以上前の古い履歴は削除する
 - ロック画面が表示されたら、ピン止めされておらず、タグもついていないクリップボード履歴はすべて削除する
 - スクリーンセーバーの設定を、スクリーンセーバーからの復帰時にロック画面へ飛ぶようにしておく
 
とすることで、クリップボード履歴の機能を使いつつも、 機密性の高い情報がクリップボード履歴に長時間残ってしまう可能性を減らせるはず。
クリップボード履歴にコピーした時刻を持たせる†
「古い履歴」を消すにはそれがいつコピーされたかという時刻の情報を持たなければならない。
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 タイプの情報としてクリップボードに入れる
 - 同時に、タグとしても同じデータを付けておく(これは表示用)
 
時刻で選別して古いものを消すコマンドを実装する†
これが Auto Delete 相当の機能になる
上と同様の手順で以下を張り付ける:
[Command]
Name="removeOldItems(millisec=0)"
Command="
    copyq:
    global.removeOldItems = function(millisec=0) {
      // 現在時刻より 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) // タブを元に戻す
      // 全消去時にはクリップボードの中身も消す
      if(!millisec) copy('') // なぜか消えない時がある???
    }
    "
IsScript=true
すると、removeOldItems(millisec=0) という項目が追加される。
この項目は [スクリプト] に指定されており、内部では global という名のグローバル変数プールに removeOldItems という関数を追加している。
このように追加した関数は、他のスクリプトから呼び出せるほか、コマンドライン引数の中からも実行が可能になる。
で、肝心の関数の中身は、
- 現在時刻から millisec で指定されただけ過去の時刻を元に "2000-01-01 00:00:00" 形式の文字列を作る
 - 1つめのタブ(これがクリップボード履歴に相当する)の項目を後ろから順に見ていく
- 後ろから見るのは項目を消去したときにおかしくならないようにするため
 - 'application/x-copyq-user-copy-time' の情報を取り出して、時刻を比較し古いものだけを処理
 - ピン止めされておらず、時刻以外のタグが付いていなければ消去する
 
 - 何も残らなければ、つまり最新の除法でさえ古いものであれば、クリップボード自体もクリアする
 - millisec を省略すると 0 を指定したのと同じになるため、常にすべての履歴が消去される
 
クリップボードへのコピーがあった時に呼び出す†
クリップボードへコピーがあるたびに、30分以上前の履歴を消せるよう removeOldItems を呼び出す。
[Command]
Automatic=true
Command="
    copyq:
    removeOldItems(30*60*1000)  // 30 min
"
Icon=\xf12d
Name=Clear Old History
クリップボードへのコピーを行わないと消えないので本当はちょっと不満なのだけれど、 まあそこまで厳密にしなくても?
履歴一覧の表示前に呼び出されるコールバックがあればそこに記述したいのだけれどなあ。
(どうしてもやりたければ下でタスクスケジューラを利用した方法を紹介している)
アイコンの文字コード†
上記の Clear Old History のスクリプトには消しゴムマークのアイコンを付けたのだけれど、 CopyQ の「選択したコマンドをコピー」でコピーすると、
となって、現状ではこれはブラウザ上では文字化けしてしまった。
https://ao-system.net/entity/ こちらのサイトで html エンティティに変換したところ、
\xf12d
と表記すればよいことが分かった。
Windows のロック画面が表示されたらクリップボードを空にする†
- ピン止め・タグ付けされていないすべての履歴を消す
 - クリップボード自体も空にする
 
これは引数無しで removeOldItems() を呼び出せばいいのだけれど、
「Windows のロック画面(ログイン画面)が表示されたら特定のスクリプトを実行する」という設定は CopyQ にはない
そこで Wimdows 標準の「タスクスケジューラ」から CopyQ を呼び出す形で対応する。
ロックされたら copyq.exe に --eval "removeOldItems()" を付けて呼び出せばいい。
タスクスケジューラを起動†
スタートボタンを押して task と入れればタスクスケジューラが見つかるはず。
タスクを作成&名前を付ける†
トリガーを「ワークステーション ロック時」にする†
トリガータブで「新規」
「ワークステーション ロック時」としてOK
トリガーが追加された
操作で CopyQ を呼び出す†
[操作] タブで [新規]
[プログラム] にフルパスで copyq.exe を指定、引数に --eval "removeOldItems()" を指定
正しく項目が追加された
条件で「AC 接続時のみ」のチェックを外す†
完成†
これで Windows のロック時に CopyQ の履歴とクリップボード内容が消去されるようになった
すばらしい
スクリーンセーバーの再開時にロック画面を表示する†
デスクトップの右クリックから [個人用設定]
[ロック画面] から [スクリーンセーバーの設定]
[再開時にログオン画面に戻る]にチェック
5分おきに removeOldItems(30*60*1000) を呼び出してもいいけれど†
タスクスケジューラのトリガーには5分ごとに繰り返す、というような指定もできるので、 5分おきに removeOldItems(30*60*1000) を呼び出せば、長時間コピー操作をしていない場合にも 確実に古い履歴を消すことができる。
できるけど・・・ロック画面で消えてくれるならそこまでする必要もない・・・かな???
しばらくこれでやってみる†
履歴やスニペット、なんとなく便利そうではあるけれど、実際にはどこまで使うことになるのか。
クリップボードデータを加工するスクリプトを走らせられるのもなんとなく便利そう。
- すべての行頭に " " を挿入して pukiwiki にコードブロックとして張り付けるとか
 - pdf からコピーした、改行だらけの英文から不要な改行を消去して、翻訳ソフトに突っ込みやすくするとか
 
今まで秀丸のマクロを使ってた変換を CopyQ だけで済ませられる可能性が高い?
しばらくこれでやってみよう。
万一それらがそこまで役に立たなくても、これまではクリップボードにコピーされたデータ自体、場合によっては長時間残ってしまっていたのだけれど、上記の手順でPCのロック時に確実に消えるようにできただけでも収穫があったはず。→ いやこれなんかうまく消えない時があるぞ?っていうかむしろたまにしか消えない。
copy('') が効くときと効かないときの差は何なのか???


















