C#を使った必要十分なクリップボードの監視

# 目的

業務上、特定の場所のテキストを一定の法則で置き換えて更新する作業が発生した。
本来ならpyautoguiなどを使って自動化できないか考えるところだったが、
派遣開始してからの日が浅く、納期も短いために時間のかかることはできない。

そのため、次善の策としてC#でクリップボードを監視・置き換えするアプリを作成した。

# 方法

インターネットで検索をかけると、このような[クリップボードの監視](https://wiki.clockahead.com/index.php?Coding%2F.NET%2F%A5%AF%A5%EA%A5%C3%A5%D7%A5%DC%A1%BC%A5%C9%A4%CE%B4%C6%BB%EB)方法があるらしい。
ただ、僕は今の会社に無限にいるわけでもないので、もう少しシンプルな方法で実装しておいて、他人がメンテナンスできるようにしておいたほうが良いと思った。

なので今回はシンプルに[System.Windows.Forms.Clipboardクラス](https://docs.microsoft.com/en-gb/dotnet/api/system.windows.forms.clipboard?view=net-5.0)を使ってフォームアプリケーションとして作ることにした。

なお、Clipboardクラス自体は.Net Framework1.1から対応しているようなので、
今使用可能なWindowsならバージョン依存はなく動くはずである。

# UI

下の画像のようなUIを準備した。

![クリップボード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395414/43962768-de5a-90a2-e4ed-4fc64ebaf3fd.png)

数字の書かれているラベルはcountLabel、監視中と書かれているボタンは見た目をボタンにしたcheckEnablerという名前のチェックボックス、
変換後のテキストボックスはlastText、変換前のテキストボックスはnextTextと名付けた。
また、timer1という名前のタイマも適当な間隔を指定してある。

# コード

特に難しいことは考えず、一定周期でクリップボードにテキストデータが入っているかを確認し、
テキストデータが最後に取得したテキストデータと異なっているのであれば一定の条件で処理を行っている。

数百回レベルの作業が予想されていたため、確認処理を行うたびにラベルのテキストと色を反転させて、
処理が行われているかどうかをわかりやすくした。
業務アプリだったら変換前・後のテキストをどこかに保存しておくのも有効だと思う。

```c#
using System;
using System.Drawing;
using System.Windows.Forms;

namespace ClipboardCheckApp
{
    public partial class Form1 : Form
    {

        private int checkCount;

        public int clipboardCounter
        {
            get { return checkCount; }
            private set
            {
                checkCount = value;
                // 視認性の向上。クリップボードの操作を行うたびに背景とテキストの色が反転する。
                if ((checkCount & 1) == 0)
                {
                    countLabel.BackColor = SystemColors.ControlText;
                    countLabel.ForeColor = SystemColors.Window;
                }
                else
                {
                    countLabel.ForeColor = SystemColors.ControlText;
                    countLabel.BackColor = SystemColors.Window;
                }
                countLabel.Text = checkCount.ToString();
            }
        }

        public Form1()
        {
            InitializeComponent();
            if (Clipboard.ContainsText())
            {
                lastClipboard = Clipboard.GetText();
            }
        }

        private void checkEnabler_CheckedChanged(object sender, EventArgs e)
        {
            if (checkEnabler.Checked)
            {
                checkEnabler.Text = "監視中";
            }
            else
            {
                checkEnabler.Text = "監視停止中";
            }
            timer1.Enabled = checkEnabler.Checked;
        }

        private string lastClipboard
        {
            get
            {
                return lastText.Text;
            }
            set
            {
                lastText.Text = value;
            }
        }

        private string nextClipBoard;

        private void timer1_Tick(object sender, EventArgs e)
        {
            // 適当な感覚でクリップボードを監視する。

            if (Clipboard.ContainsText())
            {
                nextClipBoard = Clipboard.GetText();
                if (lastClipboard != nextClipBoard)
                {
                    // クリップボードに対して何らかの処理を行う場所。
                    nextText.Text = nextClipBoard;
                    lastClipboard = nextClipBoard.Replace("ham", "egg");
                    Clipboard.SetText(lastClipboard);
                    clipboardCounter++;
                }
            }
        }
    }
}
```

とりあえず自分で動かしてみた限りでは問題なく動いた。