どこかで見たものを再現 興味を持ったものなんでもつくってみる その覚え書とアイテム置き場

C#プログラミングの覚え書き。
  1. グローバルフックを実装する。
  2. フォームを表示させずにタスクトレイにアイコンを表示する。
 
C#に慣れることを兼ねて、つぎのようなアプリを作成する。
  • テンキーから入力すると押したキーの数字が発声される。
  • そこそこの速さで入力しても反応よく音声が再生される。
  • タスクトレイ常駐型。

タスクトレイのスクリーンキャプチャ
(アプリ名はNumKeyVoiceとつけた)

フォーカスがどこにあってもキーが押されれば発声する。

デモ音声:円周率を入力したときの発声
キーボード イベントをフックする
 これを実現するには、グローバルフックを実装する必要があるようだ。
 自力では難しいので検索。海外のサイトでライブラリにしてあるのを発見。
  RamGec Tools collection

 コード内コメント行に記載してあるコピーライトと利用要件を書いておけば
 自由に使ってよいとある。

 使い方は簡単
 キーダウンイベントを捉えたいのでkeyboardHook.csをプロジェクトに追加する。
 ライブラリのインスタンスを生成してソメッドでイベントとコールバック関数を
 定義したらキーボードイベントをキャプチャできる。

 その部分の記述は
RamGecTools.KeyboardHook keyboardHook = new RamGecTools.KeyboardHook();

keyboardHook.KeyDown += new RamGecTools.KeyboardHook.KeyboardHookCallback(keyboardHook_KeyDown);
keyboardHook.Install();
 これだけ、たったの3行で完了、すばらしく便利です。

 終了時に keyboardHook.Uninstall(); で解放する。

 あとは
private void keyboardHook_KeyDown(RamGecTools.KeyboardHook.VKeys key)
{
    // ライブラリに列挙されたキーコードがkeyで受け取れる。
}
 MouseHook.csを使えばマウスイベントをキャプチャできる。
フォームを表示させずにトレイアイコンを表示する
 DOBON.NET パラメータを指定せずにApplication.Runを呼び出す方法を参考にした。

 C#のWindowsフォームアプリケーションのテンプレートでは
 Program.cs の Main()で下記のように記述されている。

  Application.Run(new Form1()); フォームを表示してアプリケーション開始する。

 ここを Application.Run に Form1 を渡さないようにすると
  new Form1();
  Application.Run();
 これでフォームを表示しないでアプリケーション開始できる。
タスクトレイアイコンを右クリックでメニュ表示させる。
 NotifyIconとContextMenuStripツールを使う。
 
 NotifyIconにアイコンを設定
  当然だがアイコンを設定しないとタスクトレイには表示されない。
  フォームもタスクバーも表示されていないので終了操作にも困る。

 NotifyIconにContextMenuStripを設定
  タスクトレイにアイコンが表示されていてもContextMenuStripを設定しないと
  アイコンを右クリックしてもイベントが発生しない。

 終了イベントでの処理
  NotifyIconのVisibleプロパティをfalseにしてタスクトレイから消す。
  Application.Exit(); で終了。
  
ここまでがポイント。
あとは特筆するテクニックなどはないです。手順をまとめると
  • Windowsフォームアプリケーションのテンプレートでプロジェクトをつくる。

  • keyboardHook.csをプロジェクトに追加

  • 音声リソースを準備
  '0〜9', '.', '+', '-', '*', '/'の15種のWAVをリソースに追加。

  • アイコンリソースを準備
  icoファイルをリソースに追加。


  • NotifyIconとContextMenuStripをForm1に配置


  • NotifyIcon1にアイコンとContextMenuStrip1を設定

  • ContextMenuStrip1の設定
   メインキーでの発声
   テンキーでの発声(CheckedをTrueに)
   アプリ終了
  3項目ともダブルクリックしてイベントハンドラーを生成

  • Program.csの編集
   new Form();
   Application.Run();

  • 参照設定の追加
   Microsoft.DirectX
   Microsoft.DirectX.DirectSound
   (ついでにいらない参照を削除した。)
 
  • プロジェクトのプロパティ設定
   アプリケーション -> アイコン指定
   ビルド -> プラットホームターゲットを'x86'に設定


  • フォームのコーディング
using System; 
using System.Windows.Forms; 
using Microsoft.DirectX; 
using Microsoft.DirectX.DirectSound; 
 
namespace NumKeyVoice 
{ 
    public partial class Form1 : Form 
    { 
        private 
            RamGecTools.KeyboardHook keyboardHook = new RamGecTools.KeyboardHook(); 
            BufferDescription desc = new BufferDescription(); 
            Device dev = null; 
            SecondaryBuffer[] sBuf; 
 
        public Form1() 
        { 
            InitializeComponent(); 
            DirectSoundSetting(); 
            keyboardHook.KeyDown += 
            new RamGecTools.KeyboardHook.KeyboardHookCallback(keyboardHook_KeyDown); 
            keyboardHook.Install(); 
        } 

        private void DirectSoundSetting() 
        { 
            dev = new Device(); 
            dev.SetCooperativeLevel(this, CooperativeLevel.Normal); 
            sBuf = new SecondaryBuffer[15]; 
            WaveFormat wf = new WaveFormat(); 
            desc.BufferBytes = wf.AverageBytesPerSecond; 
            desc.GlobalFocus = true; 
            desc.ControlVolume = true; 
 
            sBuf[0] = new SecondaryBuffer(Properties.Resources._0, desc, dev); 
            sBuf[1] = new SecondaryBuffer(Properties.Resources._1, desc, dev); 
            sBuf[2] = new SecondaryBuffer(Properties.Resources._2, desc, dev); 
            sBuf[3] = new SecondaryBuffer(Properties.Resources._3, desc, dev); 
            sBuf[4] = new SecondaryBuffer(Properties.Resources._4, desc, dev); 
            sBuf[5] = new SecondaryBuffer(Properties.Resources._5, desc, dev); 
            sBuf[6] = new SecondaryBuffer(Properties.Resources._6, desc, dev); 
            sBuf[7] = new SecondaryBuffer(Properties.Resources._7, desc, dev); 
            sBuf[8] = new SecondaryBuffer(Properties.Resources._8, desc, dev); 
            sBuf[9] = new SecondaryBuffer(Properties.Resources._9, desc, dev); 
            sBuf[10] = new SecondaryBuffer(Properties.Resources.SLASH, desc, dev); 
            sBuf[11] = new SecondaryBuffer(Properties.Resources.ASTERISK, desc, dev); 
            sBuf[12] = new SecondaryBuffer(Properties.Resources.NO, desc, dev); 
            sBuf[13] = new SecondaryBuffer(Properties.Resources.PLUS, desc, dev); 
            sBuf[14] = new SecondaryBuffer(Properties.Resources.DOT, desc, dev); 
        } 
 
        private void keyboardHook_KeyDown(RamGecTools.KeyboardHook.VKeys key) 
        { 
            bool flag = TenKeyToolStripMenuItem.Checked; 
            string keyName = key.ToString(); 
            SecondaryBuffer buf = null; 
            int num = 0; 
            /* テンキーの判定 */ 
            if (flag) { 
                if (keyName.IndexOf("NUMP") >= 0) { 
                    num = Int32.Parse(keyName.Substring(6)); 
                } else { 
                    switch (keyName) { 
                        case "DECIMAL": num = 14; break; 
                        case "ADD": num = 13; break; 
                        case "SUBTRACT": num = 12; break; 
                        case "MULTIPLY": num = 11; break; 
                        case "DIVIDE": num = 10; break; 
                        default: flag = false; break; 
                    } 
                } 
            } 
 
            /* メインキーの判定 */ 
            if (!flag) { 
                if (MainKeyToolStripMenuItem.Checked) { 
                    string[] splitK = keyName.Split('_'); 
                    if (splitK[0].Equals("KEY")) { 
                        if (Int32.TryParse(splitK[1], out num)) flag = true; 
                    } 
                } 
            } 
 
            /* オーディオ再生 */ 
            if (flag) { 
                buf = sBuf[num]; 
                buf.SetCurrentPosition(0); 
                buf.Play(0, BufferPlayFlags.Default); 
                //buf = null; 
            } 
        } 
 
        private void MainKeyToolStripMenuItem_Click(object sender, EventArgs e) 
        { 
            MainKeyToolStripMenuItem.Checked = !MainKeyToolStripMenuItem.Checked; 
        } 
 
        private void TenKeyToolStripMenuItem_Click(object sender, EventArgs e) 
        { 
            TenKeyToolStripMenuItem.Checked = !TenKeyToolStripMenuItem.Checked; 
        } 
 
        private void CloseToolStripMenuItem_Click(object sender, EventArgs e) 
        { 
            keyboardHook.Uninstall(); 
            sBuf = null; 
            desc.Dispose(); 
            dev.Dispose(); 
            notifyIcon1.Visible = false; 
            Application.Exit(); 
        } 
    }//End of Form1 
} 
作製あとがき
エクセルに小数点以下を含む数値データーをかなりの量を入力することになった。
手書きの数字で入力ミスのリスクが高く、縦横合計みたいなものはないので
あとからチェックサムはできない。

ディスプレイを見ないで、手書きの数字だけ目で追いながらミスタイプは音声で
同時に確認できると作業の効率アップとエラーを減らせると思うのだけど...

と相談を受けたのがきっかけで「数字キーの入力を発声してくれる」みたいな
ツールきっと誰かフリーで公開しているだろうと、さらっと検索した範囲では
なかなか良いものがみつからなかった。

ポイントの情報収集に時間はかからなかったし、
主要部分はコピペコード(プログラミングの勉強にならない)なのでデバグなし。
すぐにコーディングは完了した。

入力作業の効率はかなりアップしたと喜んでもらえた。

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

管理人/副管理人のみ編集できます