パソコンに入力されたキーを表示する【C#】

# 動機

今回はボタン一つで何か処理をする・表示するというものではなく、キーボードから入力されたキー情報をデスクトップアプリ上に表示させようと思います。

動機は、キーロガーを実装することで、今後私が計画している便利アプリに組み込めるのではないかと思ったためです。

本アプリは WindowsFormsApp で作成しました。

# 過去の記事（WpfApp）

> 参考 1：[ノートパソコンの画面の明るさをボタン一つで変更する【C#】](https://qiita.com/kewpie134134/items/d81461aab1ab1b9a26af)
> 参考 2：[ノートパソコンの画面の音量をボタン一つで変更する【C#】](https://qiita.com/kewpie134134/items/22acfa606071fbc22018#mainwindowxamlcs)
> 参考 3：[ノートパソコンの画面のバッテリー状況をボタン一つで取得する【C#】](https://qiita.com/kewpie134134/items/744d52aea14662732c6c)
> 参考 4：[ノートパソコンの画面の通信料状況をボタン一つで取得する【C#】](https://qiita.com/kewpie134134/items/8b1f7e709a1483b84cf0)
> 参考 5：[ノートパソコンで現在使用中のアプリをボタン一つで把握する【C#】](https://qiita.com/kewpie134134/items/bb9fc6d2efd03237e31f)
> 参考 6: [ノートパソコンで現在使用中のオーディオ機器情報をボタン一つで取得する【C#】](https://qiita.com/kewpie134134/items/c3e0c22f3d3e29dedd1a)
> 参考 7：[パソコンのユーザー情報取得やアプリ起動・終了、ディスプレイ画面の切替などを、ボタンを作って動かす【C#】](https://qiita.com/kewpie134134/items/d70feef6319949120389)

# 過去の記事（WindowsFormsApp）

> 参考 1：[パソコンに接続しているディスプレイ情報をボタン一つで取得する【C#】](https://qiita.com/kewpie134134/items/bbdc49dc38fe84a48c1a)

# イメージ画像

UI はプロトタイプのため、特にこだわりはありません。

キーボードから入力された文字が表示されるだけの、シンプルな UI となっております。

今回のアプリでは、キーボードから入力された文字（アルファベット、数字、Ctrl キー、Shift キー、alt キーなど）が、本アプリ上に表示されます。

![key_logger.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407150/066edfe6-610e-bce2-7a43-11d62e1a6058.gif)

# ソース

## Form1.Designer.cs

```Form1.Designer.cs

namespace WindowsFormsApp1
{
    partial class Form1
    {
        /// <summary>
        /// 必要なデザイナー変数です。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// 使用中のリソースをすべてクリーンアップします。
        /// </summary>
        /// <param name="disposing">マネージド リソースを破棄する場合は true を指定し、その他の場合は false を指定します。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows フォーム デザイナーで生成されたコード

        /// <summary>
        /// デザイナー サポートに必要なメソッドです。このメソッドの内容を
        /// コード エディターで変更しないでください。
        /// </summary>
        private void InitializeComponent()
        {
            this.labelKey = new System.Windows.Forms.Label();
            this.labelShift = new System.Windows.Forms.Label();
            this.labelCtrl = new System.Windows.Forms.Label();
            this.labelAlt = new System.Windows.Forms.Label();
            this.label1 = new System.Windows.Forms.Label();
            this.label2 = new System.Windows.Forms.Label();
            this.SuspendLayout();
            //
            // labelKey
            //
            this.labelKey.AutoSize = true;
            this.labelKey.Font = new System.Drawing.Font("MS UI Gothic", 48F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(128)));
            this.labelKey.Location = new System.Drawing.Point(426, 37);
            this.labelKey.Name = "labelKey";
            this.labelKey.Size = new System.Drawing.Size(226, 80);
            this.labelKey.TabIndex = 0;
            this.labelKey.Text = "label1";
            this.labelKey.Click += new System.EventHandler(this.labelKey_Click);
            //
            // labelShift
            //
            this.labelShift.AutoSize = true;
            this.labelShift.Font = new System.Drawing.Font("MS UI Gothic", 48F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(128)));
            this.labelShift.Location = new System.Drawing.Point(426, 172);
            this.labelShift.Name = "labelShift";
            this.labelShift.Size = new System.Drawing.Size(226, 80);
            this.labelShift.TabIndex = 1;
            this.labelShift.Text = "label2";
            this.labelShift.Click += new System.EventHandler(this.labelShift_Click);
            //
            // labelCtrl
            //
            this.labelCtrl.AutoSize = true;
            this.labelCtrl.Font = new System.Drawing.Font("MS UI Gothic", 48F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(128)));
            this.labelCtrl.Location = new System.Drawing.Point(426, 252);
            this.labelCtrl.Name = "labelCtrl";
            this.labelCtrl.Size = new System.Drawing.Size(226, 80);
            this.labelCtrl.TabIndex = 2;
            this.labelCtrl.Text = "label3";
            this.labelCtrl.Click += new System.EventHandler(this.labelCtrl_Click);
            //
            // labelAlt
            //
            this.labelAlt.AutoSize = true;
            this.labelAlt.Font = new System.Drawing.Font("MS UI Gothic", 48F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(128)));
            this.labelAlt.Location = new System.Drawing.Point(426, 332);
            this.labelAlt.Name = "labelAlt";
            this.labelAlt.Size = new System.Drawing.Size(226, 80);
            this.labelAlt.TabIndex = 3;
            this.labelAlt.Text = "label4";
            this.labelAlt.Click += new System.EventHandler(this.labelAlt_Click);
            //
            // label1
            //
            this.label1.AutoSize = true;
            this.label1.Font = new System.Drawing.Font("MS UI Gothic", 19.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(128)));
            this.label1.Location = new System.Drawing.Point(106, 69);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(305, 34);
            this.label1.TabIndex = 4;
            this.label1.Text = "キーボード入力文字：";
            //
            // label2
            //
            this.label2.AutoSize = true;
            this.label2.Font = new System.Drawing.Font("MS UI Gothic", 19.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(128)));
            this.label2.Location = new System.Drawing.Point(74, 293);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(337, 34);
            this.label2.TabIndex = 5;
            this.label2.Text = "Ctrl, Shift or Alt 判定：";
            //
            // Form1
            //
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(800, 450);
            this.Controls.Add(this.label2);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.labelAlt);
            this.Controls.Add(this.labelCtrl);
            this.Controls.Add(this.labelShift);
            this.Controls.Add(this.labelKey);
            this.Name = "Form1";
            this.Text = "Form1";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.Label labelKey;
        private System.Windows.Forms.Label labelShift;
        private System.Windows.Forms.Label labelCtrl;
        private System.Windows.Forms.Label labelAlt;
        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.Label label2;
    }
}
```

## Form1.cs

```Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            labelKey.Text = "";
            labelShift.Text = "";
            labelCtrl.Text = "";
            labelAlt.Text = "";
        }

        KeyboardHook keyboardHook = new KeyboardHook();

        protected override void OnLoad(EventArgs e)
        {
            keyboardHook.KeyDownEvent += KeyboardHook_KeyDownEvent;
            keyboardHook.KeyUpEvent += KeyboardHook_KeyUpEvent;
            keyboardHook.Hook();
        }

        // A-Zキーが押されているときは非0が入る
        int AtoZ = 0;

        private void KeyboardHook_KeyDownEvent(object sender, KeyEventArg e)
        {
            KeysConverter kc = new KeysConverter();

            if (e.KeyCode >= 65 && e.KeyCode <= 90)
            {
                AtoZ = e.KeyCode;
                labelKey.Text = kc.ConvertToString(e.KeyCode);
            }
            else if (e.KeyCode == 160 || e.KeyCode == 161)
                labelShift.Text = "Shift";
            else if (e.KeyCode == 162 || e.KeyCode == 163)
                labelCtrl.Text = "Ctrl";
            else if (e.KeyCode == 164 || e.KeyCode == 165)
                labelAlt.Text = "Alt";
            else
                labelKey.Text = kc.ConvertToString(e.KeyCode);
        }

        private void KeyboardHook_KeyUpEvent(object sender, KeyEventArg e)
        {
            KeysConverter kc = new KeysConverter();

            if (e.KeyCode >= 65 && e.KeyCode <= 90 && AtoZ == e.KeyCode)
            {
                AtoZ = 0;
                labelKey.Text = "";
            }
            else if (e.KeyCode == 160 || e.KeyCode == 161)
                labelShift.Text = "";
            else if (e.KeyCode == 162 || e.KeyCode == 163)
                labelCtrl.Text = "";
            else if (e.KeyCode == 164 || e.KeyCode == 165)
                labelAlt.Text = "";
            else if (AtoZ == 0)
                labelKey.Text = "";
            else
                labelKey.Text = kc.ConvertToString(AtoZ);
        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            keyboardHook.UnHook();
        }

        private void labelAlt_Click(object sender, EventArgs e)
        {

        }

        private void labelShift_Click(object sender, EventArgs e)
        {

        }

        private void labelKey_Click(object sender, EventArgs e)
        {

        }

        private void labelCtrl_Click(object sender, EventArgs e)
        {

        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }
    }

    class KeyboardHook
    {
        protected const int WH_KEYBOARD_LL = 0x000D;
        protected const int WM_KEYDOWN = 0x0100;
        protected const int WM_KEYUP = 0x0101;
        protected const int WM_SYSKEYDOWN = 0x0104;
        protected const int WM_SYSKEYUP = 0x0105;

        [StructLayout(LayoutKind.Sequential)]
        public class KBDLLHOOKSTRUCT
        {
            public uint vkCode;
            public uint scanCode;
            public KBDLLHOOKSTRUCTFlags flags;
            public uint time;
            public UIntPtr dwExtraInfo;
        }

        [Flags]
        public enum KBDLLHOOKSTRUCTFlags : uint
        {
            KEYEVENTF_EXTENDEDKEY = 0x0001,
            KEYEVENTF_KEYUP = 0x0002,
            KEYEVENTF_SCANCODE = 0x0008,
            KEYEVENTF_UNICODE = 0x0004,
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook, KeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        private delegate IntPtr KeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

        private KeyboardProc proc;
        private IntPtr hookId = IntPtr.Zero;

        public void Hook()
        {
            if (hookId == IntPtr.Zero)
            {
                proc = HookProcedure;
                using (var curProcess = Process.GetCurrentProcess())
                {
                    using (ProcessModule curModule = curProcess.MainModule)
                    {
                        hookId = SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
                    }
                }
            }
        }

        public void UnHook()
        {
            UnhookWindowsHookEx(hookId);
            hookId = IntPtr.Zero;
        }

        public IntPtr HookProcedure(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 && (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN))
            {
                var kb = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
                var vkCode = (int)kb.vkCode;
                OnKeyDownEvent(vkCode);
            }
            else if (nCode >= 0 && (wParam == (IntPtr)WM_KEYUP || wParam == (IntPtr)WM_SYSKEYUP))
            {
                var kb = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
                var vkCode = (int)kb.vkCode;
                OnKeyUpEvent(vkCode);
            }
            return CallNextHookEx(hookId, nCode, wParam, lParam);
        }

        public delegate void KeyEventHandler(object sender, KeyEventArg e);
        public event KeyEventHandler KeyDownEvent;
        public event KeyEventHandler KeyUpEvent;

        protected void OnKeyDownEvent(int keyCode)
        {
            KeyDownEvent?.Invoke(this, new KeyEventArg(keyCode));
        }
        protected void OnKeyUpEvent(int keyCode)
        {
            KeyUpEvent?.Invoke(this, new KeyEventArg(keyCode));
        }

    }

    public class KeyEventArg : EventArgs
    {
        public int KeyCode { get; }

        public KeyEventArg(int keyCode)
        {
            KeyCode = keyCode;
        }
    }
}
```

# おわりに

今回はボタン一つで何かする、というものではなかったのですが、今後の便利アプリにうまい具合に組み込めていければいいなと思っています。

誰かのお役に立てれば幸いです。