今回もネタ記事です。SHOWROOMで50カウントできるアプリをつくります。
Contents
SHOWROOMの50カウントって何?
SHOWROOMはアイドルやタレントがライブ配信して視聴者とコミュニケーションを楽しむ仮想ライブ空間です。AKBグループや坂道シリーズなどのアイドルだけでなく、LIVE、お笑い、JUNON、アニメ、バーチャルキャラクターなど多彩なジャンルで番組を配信しています。
SHOWROOMでは視聴者が配信者にコメントやギフトアイテムを送ることができます。これによって配信を盛り上がらせることができるだけでなく、視聴者の承認欲求を満たすことができます。SNSを毎日更新してもイマイチ承認欲求を満たすことができない方はSHOWROOMに参加することをおすすめします。配信者または視聴者として配信に参加することで普段の満たされない承認欲求を手っ取り早く満たすことができるのです。
無料でできる人助け 「星」と「カウント」
自分が応援したい配信者のためにできることとしてギフティングがあります。有料のアイテムを投げることができない方は無料で手に入る星を手に入れて投げましょう。こんなささやかなことであっても感謝してもらえます。そして普段の満たされない承認欲求がみたされ、しばし幸せな気持ちになれるのです(ネタ記事なので我ながらメチャクチャを書いています)。
無料で配信者を支援することができる手段として大きなものとして「星」がありますが、もうひとつの重要な手段としてカウント枠があります。これは50回限定ではありますがコメントをすることで配信者にポイントを送ることができるのです。無料でできる人助けです。自分と相手の相互のために星とカウントは忘れずにやっておきましょう。
カウントとは?
カウントはコメントで1~50までの数字を入力し送信するだけです。終わったら配信者に「50カウント終了」と報告すると喜んでもらえます。ただ1~50まで手作業で入力するのは面倒臭いと思いませんか? プログラミングをやっているのであればここは簡単にやってしまう方法を考えましょう。スパム的なことさえしなければ何の問題もありません。
これから50カウントできるアプリをつくります。サーバーに50カウントをしているかのようなデータを送りつけるのはスパム的に思います。そこで自分のパソコンを自動で操作して50カウントします。「1」キーを押してEnterキーを押す、しばらく待ってから「2」キーを押してEnterキーを押す、これを50になるまで続けます。
俺様はタッチタイピングができるぜ!と数字キーとEnterキーを連続して押していると「しばらく待ってから送信してください」というメッセージが出て送信を拒否されるので、そのときはしばらく(2秒くらい)待ちましょう。
グローバルキーフックをつかって自動カウントする
ではどうすればクリック一発でそんな自動操作ができるのか? グローバルキーフックをすればよいのです。【ネタ】実はペーストしただけなのに一文字ずつ入力しているように見せるアプリで作成したKeyboardHookクラスとKeyEventArgクラスをそのまま使います。なので、KeyboardHookクラスとKeyEventArgクラスは省略します。リンク先のページを参照してください。
コンストラクタを示します。フォームを最前面に表示されるようにするとともに、KeyboardHookオブジェクトを生成してキーが押下されたときのイベントハンドラを追加しています。同時にフックされているかを示すIsHookプロパティをfalseにしています。
デザイナでボタンをフォームに1つだけ貼り付けておきます。
初期化
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public partial class Form1 : Form {     KeyboardHook keyboardHook = new KeyboardHook();     public Form1()     {         InitializeComponent();         this.TopMost = true;         keyboardHook.KeyDownEvent += KeyboardHook_KeyDownEvent1; ;         IsHook = false;     } } | 
グローバルキーフックと解除
IsHookプロパティが定義されている部分を示します。trueがセットされたらグローバルキーフックをして、falseがセットされたら解除しています。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public partial class Form1 : Form {     bool _isHook = false;     bool IsHook     {         set         {             _isHook = value;             button1.Enabled = !_isHook;             if(_isHook)                 keyboardHook.Hook();             else                 keyboardHook.UnHook();         }         get         {             return _isHook;         }     } } | 
ボタンがクリックされたらグローバルキーフックをします。
| 1 2 3 4 5 6 7 8 9 10 | public partial class Form1 : Form {     private void button1_Click(object sender, EventArgs e)     {         if (IsHook)             return;         IsHook = true;     } } | 
キー押下時の処理
グローバルキーフックされている状態でキーが押されたらカウントを開始します。「1」キーが押されたらカウントスタートです。またグローバルキーフックする場合は解除するための手段を用意しておかないいけません。そうでないと想定外のことがおきたとき収拾がつかなくなります。ここではQキーを押したらアプリケーションそのものを終了させています。
グローバルキーフックをして「1」キーが押されたらカウントスタートさせているわけですが、そのあと「1」キーを押してEnterキーを押す、しばらく待ってから「2」キーを押してEnterキーを押すという動作を繰り返しています。処理を行なっている最中に「1」キーが押下されることもあるわけですが、そのときに新たな処理が開始されないようにisAllowフラグで処理が二重に開始されないように制御しています。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | public partial class Form1 : Form {     KeysConverter kc = new KeysConverter();     Random _random = new Random();     bool isAllow = true;     private async void KeyboardHook_KeyDownEvent1(object sender, KeyEventArg e)     {         // Qキーを押したら終了         if (kc.ConvertToString(e.KeyCode) == "Q")         {             Application.Exit();             return;         }         // 「1」キーを押したらカウントスタート         if (kc.ConvertToString(e.KeyCode) == "1")         {             // 処理が二重に開始されないようにする             if (!isAllow)                 return;             int interval = 2000;             isAllow = false;             {                 e.IsCancel = true; // 「1」キーが押下されたら本来の動作をさせずに以下の処理を実行する                 for (int i = 0; i < 50; i++)                 {                     await Task.Delay(interval); // 2秒待つ                     string s = (i + 1).ToString() + "{Enter}"; // 数字キーを押下した後Enterキーを押下する                     SendKeys.SendWait(s);                 }                 await Task.Delay(interval);                 IsHook = false; // グローバルキーフックを解除する             }             isAllow = true;         }     }     // 終了するときはアンフックする     protected override void OnFormClosing(FormClosingEventArgs e)     {         keyboardHook.UnHook();     } } | 
順番をランダムに変更してカウントする
ところでカウントは1から順に50まで順番にしなければならないわけではないそうです。だったらこれはジョークアプリだし、順番をランダムにできないかと考えたくなるものです。
実際に順番をランダムにして50カウントすることはできるのですが、実際にどこまで完了しているのかがわかりにくいです。またカウントしている最中に他のところをクリックするとおかしなことになります。というのはこのアプリはSendKeys.SendWaitメソッドを使っています。デスクトップやエクスプローラでアプリのアイコンが選択されている状態でEnterキーを押下するとそのアプリが起動してしまうのです。望んでいないアプリが突然起動して・・・ということは避けないといけません。
そこでプログレスバーを表示してどこまで処理が進行しているのかが視覚的にわかるようにしています。またカウントを開始するときと終了したときにコメントを送ることができるようにしてみました。

一番下にあるのはプログレスバーです。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public partial class Form1 : Form {     public Form1()     {         InitializeComponent();         this.TopMost = true;         keyboardHook.KeyDownEvent += KeyboardHook_KeyDownEvent2;         textBoxBefore.Text = "50カウント開始";         textBoxAfter.Text = "50カウント完了";         IsHook = false;     } } | 
GetNumberListメソッドは1から50までの整数をランダムに格納したリストを作成します。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | public partial class Form1 : Form {     List<int> GetNumberList()     {         List<int> list;         int[] vs1 = {                     1, 2, 3, 4, 5, 6, 7,8,9,10,                     11, 12, 13, 14, 15, 16, 17,18,19,20,                     21, 22, 23, 24, 25, 26, 27,28,29,30,                     31, 32, 33, 34, 35, 36, 37,38,39,40,                     41, 42, 43, 44, 45, 46, 47,48,49,50,                 };         List<int> vs2 = new List<int>(vs1);         Random random = new Random();         if (!checkBox1.Checked)             list = new List<int>(vs1);         else         {             list = new List<int>();             while (true)             {                 int r = random.Next(vs2.Count);                 int num = vs2[r];                 vs2.RemoveAt(r);                 list.Add(num);                 if (vs2.Count == 0)                     break;             }         }         return list;     } } | 
そして「1」キーが押下されたときにカウントを開始します。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | public partial class Form1 : Form {     private async void KeyboardHook_KeyDownEvent2(object sender, KeyEventArg e)     {         // Qキーを押したら終了         if (kc.ConvertToString(e.KeyCode) == "Q")         {             Application.Exit();             return;         }         // 1キーを押したらカウントスタート         if (kc.ConvertToString(e.KeyCode) == "1")         {             if (!isAllow)                 return;             int interval = 2000;             isAllow = false;             {                 e.IsCancel = true;                 if (textBoxBefore.Text != "")                 {                     await Task.Delay(interval);                     Clipboard.SetText(textBoxBefore.Text);                     SendKeys.SendWait("^v{Enter}");                 }                 List<int> list = GetNumberList();                 progressBar1.Value = 0;                 progressBar1.Maximum = list.Count;                 foreach(int i in list)                 {                     // きっちり2秒待機するのは不自然なので最大で+0.6秒ずらす                     await Task.Delay(interval + _random.Next(600));                     string s = i.ToString() + "{Enter}";                     SendKeys.SendWait(s);                     progressBar1.Value++;                 }                 if (textBoxAfter.Text != "")                 {                     await Task.Delay(interval);                     Clipboard.SetText(textBoxAfter.Text);                     SendKeys.SendWait("^v{Enter}");                 }                 IsHook = false;                 progressBar1.Value = 0;             }             isAllow = true;         }     } } | 
