C#のキー入力を取得する方法|KeyDown・KeyPress・ショートカット実装まで解説

はじめに

C#でアプリケーションを作っていると、「Enterキーが押されたら検索する」「Escキーで画面を閉じる」「Ctrl + Sで保存する」「矢印キーでキャラクターを動かす」といったキー入力処理が必要になる場面があります。

C#のキー入力取得は、作成するアプリの種類によって書き方が変わります。WinFormsではKeyDownKeyPressKeyUpなどのイベントを使い、WPFではKeyDownPreviewKeyDown、コンソールアプリではConsole.ReadKeyを使います。

また、同じ「キー入力」といっても、押されたキーそのものを取得したい場合と、入力された文字を取得したい場合では使うイベントが異なります。たとえば、Enterキーや矢印キー、Ctrlキーとの組み合わせを判定したいならKeyDownが向いています。一方、TextBoxに入力された文字を制限したい場合はKeyPressが便利です。

この記事では、C#でキー入力を取得する基本から、WinForms・WPF・コンソールアプリでの実装方法、ショートカットキーの作り方、よくあるエラーの対処法まで解説します。

1. C#でキー入力を取得する基本

C#でキー入力を取得する方法は、アプリケーションの種類や目的によって変わります。

キーが押された瞬間を取得したいのか、入力された文字を取得したいのか、フォーム全体でキーを受け取りたいのか、特定のTextBoxだけで処理したいのかによって、使うイベントやプロパティを選ぶ必要があります。

まずは、C#で扱えるキー入力の種類と、それぞれの用途を整理しておきましょう。

1-1. C#で取得できるキー入力の種類

C#で取得できるキー入力は、大きく分けると次のようになります。

種類主な用途
通常キーA、B、1、2など文字入力、入力制限
特殊キーEnter、Esc、Tab、BackSpaceなど確定、キャンセル、削除
方向キー↑、↓、←、→移動、選択
修飾キーShift、Ctrl、Altショートカット
組み合わせキーCtrl + S、Shift + Enterなど保存、改行、検索など

たとえば、Enterキーが押されたかどうかを判定する場合は、押されたキーを判定する処理が必要です。

C#
if (e.KeyCode == Keys.Enter)
{
MessageBox.Show("Enterキーが押されました");
}

一方、入力された文字が数字かどうかを判定する場合は、キーそのものではなく文字を取得します。

C#
if (!char.IsDigit(e.KeyChar))
{
e.Handled = true;
}

このように、C#のキー入力処理では「キーを判定する」のか「文字を判定する」のかを分けて考えることが重要です。

1-2. キー入力取得が使われる主な場面

C#でキー入力を取得する処理は、さまざまな場面で使われます。

代表的な例は次のとおりです。

場面実装例
フォーム操作Enterで検索、Escで閉じる
入力制限数字のみ入力可能にする
ショートカットCtrl + Sで保存する
ゲーム・ツール矢印キーで移動する
業務アプリF1でヘルプ、F5で更新
コンソールアプリキー入力でメニューを選択する

特に業務アプリでは、マウス操作だけでなくキーボード操作を用意しておくと、作業効率が大きく上がります。

たとえば、保存ボタンをクリックするだけでなく、Ctrl + Sでも同じ保存処理を実行できるようにしておくと、ユーザーにとって使いやすいアプリになります。

1-3. WinForms・WPF・コンソールアプリでの違い

C#のキー入力取得は、アプリケーションの種類によって書き方が異なります。

アプリの種類主な取得方法特徴
WinFormsKeyDown、KeyPress、KeyUpイベントベースで扱いやすい
WPFKeyDown、PreviewKeyDown、Keyboard.Modifiersルーティングイベントを使う
コンソールアプリConsole.ReadKeyシンプルに1キーずつ取得できる

WinFormsでは、フォームやTextBoxなどのコントロールに対してイベントを設定します。

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
MessageBox.Show("Enterキー");
}
}

WPFでは、System.Windows.Input.Keyを使ってキーを判定します。

C#
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
MessageBox.Show("Enterキー");
}
}

コンソールアプリでは、Console.ReadKeyを使います。

C#
ConsoleKeyInfo keyInfo = Console.ReadKey();

if (keyInfo.Key == ConsoleKey.Enter)
{
Console.WriteLine("Enterキー");
}

同じC#でも、WinForms、WPF、コンソールでは使うクラスやプロパティが違うため、開発しているアプリの種類に合わせて実装する必要があります。

1-4. この記事で解説するキー入力処理の全体像

この記事では、次の順番でC#のキー入力取得を解説します。

まず、WinFormsでよく使われるKeyDownKeyPressKeyUpの違いを確認します。次に、EnterキーやEscキー、矢印キー、Ctrlキーとの組み合わせを判定する方法を紹介します。

その後、数字のみ入力可能にする方法や、ショートカットキーを実装する方法、フォーム全体でキー入力を受け取る方法を解説します。

さらに、WPFとコンソールアプリでのキー入力取得方法も取り上げます。

最後に、キー入力処理でよくある「KeyDownが反応しない」「矢印キーが取得できない」「日本語入力中に想定通り動かない」といったつまずきや、実用的なコード例を紹介します。

2. WinFormsでキー入力を取得する方法

WinFormsでキー入力を取得する場合、主に次の3つのイベントを使います。

イベント発生タイミング主な用途
KeyDownキーが押されたときEnter、Esc、ショートカット判定
KeyPress文字が入力されたとき数字のみ入力、文字入力制限
KeyUpキーが離されたとき押しっぱなし解除、状態リセット

それぞれ役割が異なるため、目的に応じて使い分けましょう。

2-1. KeyDownイベントでキーが押された瞬間を取得する

KeyDownイベントは、キーが押された瞬間に発生します。

Enterキー、Escキー、矢印キー、ファンクションキー、CtrlやShiftとの組み合わせを判定したい場合に使います。

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
MessageBox.Show("Enterキーが押されました");
}
}

フォームでKeyDownを使う場合は、デザイナーのイベント一覧からKeyDownを設定するか、コードでイベントを登録します。

C#
public Form1()
{
InitializeComponent();

this.KeyDown += Form1_KeyDown;
}

ただし、TextBoxなどのコントロールにフォーカスがある場合、フォームのKeyDownが発生しないことがあります。その場合は、後述するKeyPreviewを使います。

2-2. KeyUpイベントでキーが離されたタイミングを取得する

KeyUpイベントは、押していたキーが離されたタイミングで発生します。

たとえば、矢印キーを押している間だけオブジェクトを移動し、キーを離したら停止するような処理で使えます。

C#
private bool isMovingRight = false;

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Right)
{
isMovingRight = true;
}
}

private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Right)
{
isMovingRight = false;
}
}

KeyDownだけで処理すると、キーを押しっぱなしにしたときに同じ処理が連続で実行されます。キーを離したタイミングを検知したい場合は、KeyUpを組み合わせると扱いやすくなります。

2-3. KeyPressイベントで文字入力を取得する

KeyPressイベントは、文字として入力された内容を取得するときに使います。

たとえば、TextBoxに数字だけ入力させたい場合に便利です。

C#
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsDigit(e.KeyChar) && e.KeyChar != (char)Keys.Back)
{
e.Handled = true;
}
}

e.KeyCharには、実際に入力された文字が入ります。

C#
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
MessageBox.Show($"入力された文字: {e.KeyChar}");
}

ただし、KeyPressでは矢印キーやファンクションキーなど、文字入力に関係しないキーは取得できない場合があります。

2-4. KeyDown・KeyPress・KeyUpの違い

KeyDownKeyPressKeyUpは似ていますが、発生するタイミングと用途が異なります。

イベント発生タイミング取得しやすい情報向いている処理
KeyDownキーが押された瞬間キーコード、修飾キーショートカット、特殊キー判定
KeyPress文字が入力されたとき入力文字入力制限、文字チェック
KeyUpキーが離された瞬間キーコード押下状態の解除

たとえば、Enterキーで処理を実行したい場合はKeyDownを使います。

C#
if (e.KeyCode == Keys.Enter)
{
ExecuteSearch();
}

数字以外を入力できないようにしたい場合はKeyPressを使います。

C#
if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar))
{
e.Handled = true;
}

キーを離したときに状態を戻したい場合はKeyUpを使います。

C#
if (e.KeyCode == Keys.Space)
{
isJumping = false;
}

2-5. KeyEventArgsとKeyPressEventArgsの使い分け

KeyDownKeyUpではKeyEventArgsを使います。

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
}

KeyEventArgsでは、次のような情報を取得できます。

プロパティ内容
e.KeyCode押されたキー
e.KeyDataキーと修飾キーの組み合わせ
e.ModifiersCtrl、Shift、Altなどの修飾キー
e.ControlCtrlキーが押されているか
e.ShiftShiftキーが押されているか
e.AltAltキーが押されているか
e.Handledイベントを処理済みにする
e.SuppressKeyPress後続のキー入力処理を抑制する

一方、KeyPressではKeyPressEventArgsを使います。

C#
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
}

KeyPressEventArgsでは、主にe.KeyCharを使います。

プロパティ内容
e.KeyChar入力された文字
e.Handled入力をキャンセルする

キーそのものを判定したいならKeyEventArgs、入力文字を判定したいならKeyPressEventArgsを使うと覚えておくと分かりやすいです。

3. KeyDownイベントの使い方

KeyDownイベントは、C#のキー入力取得で最もよく使われるイベントのひとつです。

Enterキー、Escキー、矢印キー、Ctrl + Sなどのショートカットキーを判定する場合は、基本的にKeyDownを使います。

3-1. KeyDownイベントの基本コード

WinFormsでフォームのKeyDownイベントを使う基本コードは次のとおりです。

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
MessageBox.Show("Enterキーが押されました");
}
}

フォーム全体でキー入力を受け取りたい場合は、KeyPreviewtrueにします。

C#
public Form1()
{
InitializeComponent();

this.KeyPreview = true;
this.KeyDown += Form1_KeyDown;
}

KeyPreviewtrueにすると、フォーム上のTextBoxやButtonなどのコントロールより先に、フォーム側でキーイベントを受け取れるようになります。

3-2. Enterキー・Escキー・矢印キーを判定する方法

Enterキーを判定するには、e.KeyCodeKeys.Enterを比較します。

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
MessageBox.Show("Enterキーです");
}
}

EscキーはKeys.Escapeで判定します。

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
this.Close();
}
}

矢印キーは、Keys.UpKeys.DownKeys.LeftKeys.Rightを使います。

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Up:
label1.Top -= 5;
break;

case Keys.Down:
label1.Top += 5;
break;

case Keys.Left:
label1.Left -= 5;
break;

case Keys.Right:
label1.Left += 5;
break;
}
}

このように、KeyDownでは特殊キーも扱いやすいため、操作系の処理に向いています。

3-3. e.KeyCode・e.KeyData・e.Modifiersの違い

KeyDownでよく使うプロパティに、e.KeyCodee.KeyDatae.Modifiersがあります。

それぞれの違いは次のとおりです。

プロパティ内容
e.KeyCode押されたメインのキーS、Enter、Escape
e.KeyDataメインキーと修飾キーの組み合わせCtrl + S
e.ModifiersCtrl、Shift、Altなどの修飾キーControl、Shift

たとえば、単純にSキーが押されたかどうかを判定するならe.KeyCodeを使います。

C#
if (e.KeyCode == Keys.S)
{
MessageBox.Show("Sキー");
}

Ctrl + Sを判定するなら、e.KeyDataを使うと簡潔に書けます。

C#
if (e.KeyData == (Keys.Control | Keys.S))
{
SaveFile();
}

または、e.KeyCodee.Modifiersを分けて判定することもできます。

C#
if (e.KeyCode == Keys.S && e.Modifiers == Keys.Control)
{
SaveFile();
}

複数の修飾キーを組み合わせる場合は、HasFlagを使うと分かりやすくなります。

C#
if (e.KeyCode == Keys.S &&
e.Modifiers.HasFlag(Keys.Control) &&
e.Modifiers.HasFlag(Keys.Shift))
{
SaveAsFile();
}

3-4. Shift・Ctrl・Altとの組み合わせを判定する方法

Ctrlキー、Shiftキー、Altキーとの組み合わせを判定する場合は、e.Controle.Shifte.Altを使う方法もあります。

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.S)
{
SaveFile();
}

if (e.Shift && e.KeyCode == Keys.Enter)
{
MessageBox.Show("Shift + Enter");
}

if (e.Alt && e.KeyCode == Keys.F4)
{
MessageBox.Show("Alt + F4");
}
}

e.Controlなどを使うと、条件が読みやすくなります。

ただし、複数の修飾キーを厳密に判定したい場合は、e.Modifiersを使うほうが適しています。

C#
if (e.KeyCode == Keys.S &&
e.Modifiers == (Keys.Control | Keys.Shift))
{
SaveAsFile();
}

この書き方では、CtrlとShiftが押されていて、Altなど余計な修飾キーが押されていない場合だけ処理されます。

3-5. KeyDownが発生しないときの原因と対処法

KeyDownイベントを書いたのに反応しない場合、主な原因は次のとおりです。

原因対処法
フォームにフォーカスがない対象コントロールのイベントを使う
TextBoxにフォーカスがあるKeyPreviewをtrueにする
イベントが登録されていないデザイナーまたはコードで登録する
矢印キーやTabキーが処理されないPreviewKeyDownを使う
ボタンなどがキーを先に処理しているフォーム側の処理方法を見直す

フォーム全体でキー入力を受け取りたい場合は、まずKeyPreviewを確認しましょう。

C#
public Form1()
{
InitializeComponent();

this.KeyPreview = true;
this.KeyDown += Form1_KeyDown;
}

また、矢印キーやTabキーは、コントロールによってはフォーカス移動などに使われるため、通常のKeyDownで期待通り取得できないことがあります。

その場合は、PreviewKeyDownを使います。

C#
private void button1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode == Keys.Left || e.KeyCode == Keys.Right)
{
e.IsInputKey = true;
}
}

4. KeyPressイベントの使い方

KeyPressイベントは、入力された文字を取得したいときに使います。

特に、TextBoxで「数字のみ入力可能にする」「英字のみ入力可能にする」「特定の文字を禁止する」といった入力制限を実装する場合に便利です。

4-1. KeyPressイベントの基本コード

TextBoxのKeyPressイベントを使う基本コードは次のとおりです。

C#
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
MessageBox.Show($"入力された文字: {e.KeyChar}");
}

e.KeyCharには、入力された文字が入ります。

たとえば、ユーザーがAを入力すると、e.KeyCharには'A'が入ります。1を入力すると、'1'が入ります。

イベントはデザイナーから登録してもよいですし、コードで登録しても構いません。

C#
public Form1()
{
InitializeComponent();

textBox1.KeyPress += textBox1_KeyPress;
}

4-2. 入力された文字をe.KeyCharで取得する方法

KeyPressでは、e.KeyCharを使って入力文字を取得します。

C#
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
char inputChar = e.KeyChar;

MessageBox.Show(inputChar.ToString());
}

入力された文字をチェックして、条件に合わない場合はe.Handled = trueにします。

C#
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == '@')
{
e.Handled = true;
}
}

e.Handled = trueにすると、その文字入力はキャンセルされます。

4-3. 数字のみ・英字のみ入力を許可する方法

数字のみ入力可能にするには、char.IsDigitを使います。

C#
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar))
{
e.Handled = true;
}
}

char.IsControlを許可しているのは、BackSpaceなどの制御キーを使えるようにするためです。

英字のみ入力可能にする場合は、char.IsLetterを使います。

C#
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsLetter(e.KeyChar) && !char.IsControl(e.KeyChar))
{
e.Handled = true;
}
}

英数字のみ許可したい場合は、char.IsLetterOrDigitを使います。

C#
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsLetterOrDigit(e.KeyChar) && !char.IsControl(e.KeyChar))
{
e.Handled = true;
}
}

小数点を許可したい場合は、.も条件に追加します。

C#
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
TextBox textBox = sender as TextBox;

if (char.IsDigit(e.KeyChar) || char.IsControl(e.KeyChar))
{
return;
}

if (e.KeyChar == '.' && !textBox.Text.Contains("."))
{
return;
}

e.Handled = true;
}

4-4. BackSpaceなど制御キーを考慮する方法

入力制限を実装するときに忘れやすいのが、BackSpaceなどの制御キーです。

たとえば、次のように数字以外を禁止すると、BackSpaceも使えなくなってしまいます。

C#
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsDigit(e.KeyChar))
{
e.Handled = true;
}
}

これでは、入力した文字を削除できなくなります。

そのため、通常はchar.IsControlを使って制御キーを許可します。

C#
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar))
{
e.Handled = true;
}
}

また、BackSpaceだけを個別に許可することもできます。

C#
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsDigit(e.KeyChar) && e.KeyChar != (char)Keys.Back)
{
e.Handled = true;
}
}

ただし、BackSpace以外にもDelete、Enter、Tabなどの制御キーを考慮する場面があるため、基本的にはchar.IsControlを使うほうが扱いやすいです。

4-5. KeyPressで取得できないキーに注意する

KeyPressは文字入力を扱うイベントです。そのため、すべてのキーを取得できるわけではありません。

たとえば、次のようなキーはKeyPressでは扱いにくい、または取得できない場合があります。

キーKeyPressでの扱い
矢印キー取得しにくい
F1〜F12取得しにくい
Ctrlキー単体文字ではないため不向き
Shiftキー単体文字ではないため不向き
Altキー単体文字ではないため不向き
Tabキーフォーカス移動に使われることが多い

これらのキーを判定したい場合は、KeyDownを使います。

C#
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.F1)
{
MessageBox.Show("F1キー");
}
}

KeyPressは、入力文字を扱うときに使うイベントだと考えると分かりやすいです。

5. ショートカットキーを実装する方法

C#でショートカットキーを実装する場合は、基本的にKeyDownイベントを使います。

代表的なショートカットキーには、次のようなものがあります。

ショートカット処理例
Ctrl + S保存
Ctrl + O開く
Ctrl + N新規作成
Ctrl + F検索
Escキャンセル
F5更新

ショートカットキーを実装するときは、既存の操作との競合や、TextBox入力中の動作にも注意が必要です。

5-1. Ctrl + Sなどのショートカットキーを判定する

Ctrl + Sを判定する基本コードは次のとおりです。

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.S)
{
SaveFile();
}
}

private void SaveFile()
{
MessageBox.Show("保存しました");
}

フォーム全体でショートカットキーを有効にしたい場合は、KeyPreviewtrueにします。

C#
public Form1()
{
InitializeComponent();

this.KeyPreview = true;
this.KeyDown += Form1_KeyDown;
}

e.KeyDataを使うと、次のようにも書けます。

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyData == (Keys.Control | Keys.S))
{
SaveFile();
}
}

処理後にキー入力を抑制したい場合は、e.SuppressKeyPress = trueを設定します。

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.S)
{
SaveFile();
e.SuppressKeyPress = true;
}
}

5-2. Ctrl + C・Ctrl + Vなど既存操作との競合に注意する

ショートカットキーを実装するときは、既存の標準操作と競合しないように注意しましょう。

特に、次のショートカットはTextBoxなどで標準的に使われています。

ショートカット標準操作
Ctrl + Cコピー
Ctrl + X切り取り
Ctrl + V貼り付け
Ctrl + A全選択
Ctrl + Z元に戻す

たとえば、TextBox入力中にCtrl + Cをアプリ独自の処理に割り当ててしまうと、ユーザーがテキストをコピーできなくなる可能性があります。

そのため、TextBoxにフォーカスがある場合は標準操作を優先するなどの工夫が必要です。

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (this.ActiveControl is TextBox)
{
return;
}

if (e.Control && e.KeyCode == Keys.S)
{
SaveFile();
e.SuppressKeyPress = true;
}
}

また、貼り付け操作を制限したい場合は、KeyDownだけでなくTextBoxの入力後チェックも組み合わせると安全です。

5-3. 複数キーの組み合わせを分かりやすく管理する方法

ショートカットキーが増えてくると、if文が増えて読みにくくなります。

その場合は、switchや辞書を使って管理すると分かりやすくなります。

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyData)
{
case Keys.Control | Keys.S:
SaveFile();
e.SuppressKeyPress = true;
break;

case Keys.Control | Keys.O:
OpenFile();
e.SuppressKeyPress = true;
break;

case Keys.Control | Keys.N:
NewFile();
e.SuppressKeyPress = true;
break;

case Keys.F5:
RefreshData();
e.SuppressKeyPress = true;
break;
}
}

private void SaveFile()
{
MessageBox.Show("保存");
}

private void OpenFile()
{
MessageBox.Show("開く");
}

private void NewFile()
{
MessageBox.Show("新規作成");
}

private void RefreshData()
{
MessageBox.Show("更新");
}

ショートカットがさらに多い場合は、辞書で管理する方法もあります。

C#
private Dictionary<Keys, Action> shortcuts;

public Form1()
{
InitializeComponent();

this.KeyPreview = true;

shortcuts = new Dictionary<Keys, Action>
{
{ Keys.Control | Keys.S, SaveFile },
{ Keys.Control | Keys.O, OpenFile },
{ Keys.Control | Keys.N, NewFile },
{ Keys.F5, RefreshData }
};

this.KeyDown += Form1_KeyDown;
}

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (shortcuts.TryGetValue(e.KeyData, out Action action))
{
action();
e.SuppressKeyPress = true;
}
}

このようにすると、ショートカットと処理の対応関係が分かりやすくなります。

5-4. メニューやボタン処理にショートカットを紐づける方法

ショートカットキーで実行する処理は、ボタンやメニューのクリック処理と共通化するのがおすすめです。

たとえば、保存ボタンのクリック処理がある場合、ショートカット側で同じ処理を呼び出します。

C#
private void buttonSave_Click(object sender, EventArgs e)
{
SaveFile();
}

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.S)
{
SaveFile();
e.SuppressKeyPress = true;
}
}

private void SaveFile()
{
MessageBox.Show("保存しました");
}

このように共通メソッドにまとめておくと、ボタン操作とキーボード操作で処理内容がずれることを防げます。

MenuStripを使っている場合は、ShortcutKeysプロパティを設定する方法もあります。

C#
saveToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.S;

メニュー項目のクリックイベントに保存処理を設定しておけば、Ctrl + Sで同じ処理を実行できます。

C#
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
SaveFile();
}

WinFormsでメニューを使っている場合は、ShortcutKeysを使うと簡単にショートカットを設定できます。

5-5. アプリ全体でショートカットキーを有効にする方法

フォーム内のどのコントロールにフォーカスがあってもショートカットキーを有効にしたい場合は、KeyPreviewを使います。

C#
public Form1()
{
InitializeComponent();

this.KeyPreview = true;
}

そのうえで、フォームのKeyDownイベントにショートカット処理を書きます。

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.S)
{
SaveFile();
e.SuppressKeyPress = true;
}

if (e.KeyCode == Keys.Escape)
{
this.Close();
}
}

ただし、アプリ全体といっても、これは基本的に現在のフォーム内での処理です。アプリケーションが非アクティブな状態でもキーを取得したい場合は、グローバルホットキーの仕組みが必要になります。

通常の業務アプリやフォーム操作では、まずKeyPreviewKeyDownで対応するのが一般的です。

6. フォーム全体でキー入力を受け取る方法

WinFormsでフォーム全体のキー入力を受け取りたい場合は、KeyPreviewプロパティを使います。

TextBoxやButtonなどのコントロールにフォーカスがあると、通常はそのコントロールがキーイベントを受け取ります。フォーム側で先にキー入力を処理したい場合は、KeyPreviewtrueに設定します。

6-1. KeyPreviewプロパティを使う方法

KeyPreviewを使う基本コードは次のとおりです。

C#
public Form1()
{
InitializeComponent();

this.KeyPreview = true;
this.KeyDown += Form1_KeyDown;
}

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
this.Close();
}
}

KeyPreviewtrueの場合、キーイベントはまずフォームに送られ、その後にフォーカスのあるコントロールへ送られます。

そのため、フォーム全体でEscキーやCtrl + Sなどを処理したい場合に便利です。

6-2. TextBoxなど入力コントロールにフォーカスがある場合の挙動

TextBoxにフォーカスがある場合、文字入力やコピー、貼り付けなどの操作はTextBox側で処理されます。

KeyPreviewtrueにしていればフォーム側でもキーイベントを受け取れますが、すべてをフォーム側で処理してしまうと、TextBox本来の操作を邪魔してしまう場合があります。

たとえば、TextBox入力中のCtrl + Aは通常「全選択」です。これをアプリ独自の処理に使うと、ユーザーが困る可能性があります。

そのため、入力コントロールにフォーカスがある場合は、処理を分けるとよいでしょう。

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (this.ActiveControl is TextBox)
{
if (e.KeyCode == Keys.Escape)
{
this.ActiveControl = null;
e.SuppressKeyPress = true;
}

return;
}

if (e.Control && e.KeyCode == Keys.S)
{
SaveFile();
e.SuppressKeyPress = true;
}
}

この例では、TextBox入力中は通常のショートカット処理を避けています。

6-3. PreviewKeyDownイベントを使うケース

WinFormsでは、矢印キーやTabキーなどが通常の入力キーとして扱われないことがあります。

たとえば、Buttonにフォーカスがある状態で矢印キーを取得したい場合、KeyDownだけでは反応しないことがあります。

その場合は、PreviewKeyDownイベントを使います。

C#
private void button1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode == Keys.Up ||
e.KeyCode == Keys.Down ||
e.KeyCode == Keys.Left ||
e.KeyCode == Keys.Right)
{
e.IsInputKey = true;
}
}

private void button1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Left)
{
MessageBox.Show("左キー");
}
}

PreviewKeyDowne.IsInputKey = trueを設定すると、そのキーを入力キーとして扱えるようになります。

6-4. フォーカスによってキーイベントが動かないときの対処法

キーイベントが動かない場合は、まずフォーカスを確認しましょう。

WinFormsでは、キー入力は基本的にフォーカスを持っているコントロールに送られます。

対処法としては、次のようなものがあります。

状況対処法
フォームのKeyDownが動かないKeyPreviewをtrueにする
TextBoxだけで処理したいTextBoxのKeyDownを使う
矢印キーが取得できないPreviewKeyDownを使う
ButtonにフォーカスがあるButtonのキーイベントを確認する
イベント自体が呼ばれないイベント登録を確認する

イベント登録が漏れている場合もよくあります。

C#
this.KeyDown += Form1_KeyDown;

デザイナーでイベントを設定したつもりでも、メソッド名を変更した後に関連付けが外れていることがあります。動かないときは、まずイベントが本当に登録されているか確認しましょう。

6-5. 特定コントロールだけキー入力を無効化する方法

特定のTextBoxでキー入力を無効化したい場合は、KeyPressKeyDownで入力をキャンセルします。

文字入力を禁止するだけなら、KeyPresse.Handled = trueにします。

C#
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}

ショートカットや特殊キーも含めて制御したい場合は、KeyDownを使います。

C#
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
e.SuppressKeyPress = true;
}

ただし、すべてのキーを無効にすると、コピーや選択、削除などもできなくなります。読み取り専用にしたいだけなら、ReadOnlyプロパティを使うほうが自然です。

C#
textBox1.ReadOnly = true;

ユーザーに入力させたくないが文字の選択やコピーは許可したい場合は、ReadOnlyを使うのがおすすめです。

7. WPFでキー入力を取得する方法

WPFでも、キー入力を取得するにはKeyDownKeyUpを使います。

ただし、WinFormsとは名前空間やキーの判定方法が異なります。WPFでは、System.Windows.Input.KeyKeyboard.Modifiersを使います。

また、WPFにはルーティングイベントという仕組みがあり、PreviewKeyDownを使うと、通常のKeyDownより前にキー入力を処理できます。

7-1. WPFのKeyDownイベントの基本

WPFでWindowのKeyDownイベントを使う例は次のとおりです。

XML
<Window x:Class="SampleApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="300"
Width="400"
KeyDown="Window_KeyDown">
<Grid>
<TextBox Width="200" Height="30" />
</Grid>
</Window>

コードビハインドでは、次のように書きます。

C#
using System.Windows;
using System.Windows.Input;

private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
MessageBox.Show("Enterキーが押されました");
}
}

WPFでは、キー判定にKeys.EnterではなくKey.Enterを使います。

7-2. e.Keyで押されたキーを判定する方法

WPFのKeyDownでは、e.Keyを使って押されたキーを判定します。

C#
private void Window_KeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.Enter:
MessageBox.Show("Enter");
break;

case Key.Escape:
this.Close();
break;

case Key.Up:
MessageBox.Show("Up");
break;

case Key.Down:
MessageBox.Show("Down");
break;
}
}

WinFormsではe.KeyCode == Keys.Enterと書きますが、WPFではe.Key == Key.Enterです。

また、IMEや特殊な入力状態ではe.Keye.SystemKeyを意識する必要がある場合もあります。Altキーとの組み合わせなどで期待通り取得できない場合は、e.SystemKeyも確認しましょう。

C#
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.SystemKey == Key.F4)
{
MessageBox.Show("Alt + F4");
}
}

7-3. Keyboard.ModifiersでCtrl・Shift・Altを判定する方法

WPFでCtrl、Shift、Altなどの修飾キーを判定するには、Keyboard.Modifiersを使います。

Ctrl + Sを判定する例です。

C#
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.S)
{
SaveFile();
e.Handled = true;
}
}

private void SaveFile()
{
MessageBox.Show("保存しました");
}

Shift + Enterを判定する場合は、次のように書きます。

C#
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (Keyboard.Modifiers == ModifierKeys.Shift && e.Key == Key.Enter)
{
MessageBox.Show("Shift + Enter");
}
}

Ctrl + Shift + Sのように複数の修飾キーを使う場合は、ビット演算で組み合わせます。

C#
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (Keyboard.Modifiers == (ModifierKeys.Control | ModifierKeys.Shift) &&
e.Key == Key.S)
{
SaveAsFile();
e.Handled = true;
}
}

7-4. PreviewKeyDownで事前にキー入力を処理する方法

WPFでは、PreviewKeyDownを使うと、通常のKeyDownより前にキー入力を処理できます。

XML
<Window x:Class="SampleApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="300"
Width="400"
PreviewKeyDown="Window_PreviewKeyDown">
<Grid>
<TextBox Width="200" Height="30" />
</Grid>
</Window>

コードビハインドは次のようになります。

C#
private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
this.Close();
e.Handled = true;
}
}

PreviewKeyDownは、TextBoxなどのコントロールがキー入力を処理する前に呼ばれます。

そのため、画面全体でEscキーを処理したい場合や、特定のキー入力を事前に止めたい場合に便利です。

7-5. WinFormsとの書き方の違い

WinFormsとWPFでは、キー入力の考え方は似ていますが、使用する型やプロパティが異なります。

内容WinFormsWPF
キー判定Keys.EnterKey.Enter
イベント引数KeyEventArgsKeyEventArgs
修飾キーe.Controle.ModifiersKeyboard.Modifiers
入力前処理PreviewKeyDownPreviewKeyDown
処理済み設定e.Handlede.SuppressKeyPresse.Handled

WinFormsではKeyPreviewを使ってフォーム全体でキー入力を受け取ることが多いですが、WPFではPreviewKeyDownやコマンド機能を使うことも多いです。

ショートカットキーを本格的に管理したい場合は、WPFのInputBindingsCommandを使う方法もあります。

XML
<Window.InputBindings>
<KeyBinding Key="S"
Modifiers="Control"
Command="{Binding SaveCommand}" />
</Window.InputBindings>

簡単なキー判定ならKeyDown、画面全体のショートカットやMVVM構成ではInputBindingsを使うとよいでしょう。

8. コンソールアプリでキー入力を取得する方法

コンソールアプリでキー入力を取得する場合は、Console.ReadKeyを使います。

Console.ReadLineはEnterキーが押されるまで文字列を入力しますが、Console.ReadKeyは1キーずつ入力を取得できます。

そのため、メニュー選択や簡単なショートカット風の処理に向いています。

8-1. Console.ReadKeyでキー入力を取得する

Console.ReadKeyの基本コードは次のとおりです。

C#
Console.WriteLine("何かキーを押してください");

ConsoleKeyInfo keyInfo = Console.ReadKey();

Console.WriteLine();
Console.WriteLine($"押されたキー: {keyInfo.Key}");

Console.ReadKeyは、キーが押されるまで処理を待機します。

押されたキーの情報はConsoleKeyInfoとして取得できます。

8-2. 押されたキーをConsoleKeyで判定する

押されたキーを判定するには、keyInfo.Keyを使います。

C#
ConsoleKeyInfo keyInfo = Console.ReadKey();

if (keyInfo.Key == ConsoleKey.Enter)
{
Console.WriteLine("Enterキーが押されました");
}

メニュー選択の例です。

C#
Console.WriteLine("メニューを選択してください");
Console.WriteLine("1: 新規作成");
Console.WriteLine("2: 保存");
Console.WriteLine("3: 終了");

ConsoleKeyInfo keyInfo = Console.ReadKey(true);

switch (keyInfo.Key)
{
case ConsoleKey.D1:
case ConsoleKey.NumPad1:
Console.WriteLine("新規作成");
break;

case ConsoleKey.D2:
case ConsoleKey.NumPad2:
Console.WriteLine("保存");
break;

case ConsoleKey.D3:
case ConsoleKey.NumPad3:
Console.WriteLine("終了");
break;
}

数字キーは、キーボード上部の数字キーとテンキーで値が異なります。両方に対応したい場合は、ConsoleKey.D1ConsoleKey.NumPad1の両方を判定します。

8-3. 入力文字を画面に表示しない方法

Console.ReadKey()をそのまま使うと、押したキーが画面に表示されます。

表示したくない場合は、引数にtrueを指定します。

C#
ConsoleKeyInfo keyInfo = Console.ReadKey(true);

パスワード入力や、メニュー選択でキーを画面に表示したくない場合に使います。

C#
Console.WriteLine("キーを押してください");

ConsoleKeyInfo keyInfo = Console.ReadKey(true);

Console.WriteLine($"選択されたキー: {keyInfo.Key}");

8-4. Enterなしでキー入力を受け取る方法

Console.ReadLineではEnterキーを押すまで入力が確定しません。

一方、Console.ReadKeyを使うと、Enterなしで1キーずつ取得できます。

C#
Console.WriteLine("Escキーで終了します");

while (true)
{
ConsoleKeyInfo keyInfo = Console.ReadKey(true);

if (keyInfo.Key == ConsoleKey.Escape)
{
break;
}

Console.WriteLine($"{keyInfo.Key} が押されました");
}

ゲーム風の操作や、簡単なメニュー操作ではConsole.ReadKeyが便利です。

矢印キーも取得できます。

C#
ConsoleKeyInfo keyInfo = Console.ReadKey(true);

if (keyInfo.Key == ConsoleKey.UpArrow)
{
Console.WriteLine("上キー");
}
else if (keyInfo.Key == ConsoleKey.DownArrow)
{
Console.WriteLine("下キー");
}

8-5. コンソールアプリでショートカット風の処理を作る方法

ConsoleKeyInfoには、CtrlやShift、Altなどの修飾キー情報も含まれます。

Ctrl + Sを判定する例です。

C#
Console.WriteLine("Ctrl + Sで保存、Escで終了");

while (true)
{
ConsoleKeyInfo keyInfo = Console.ReadKey(true);

if (keyInfo.Key == ConsoleKey.Escape)
{
break;
}

if (keyInfo.Key == ConsoleKey.S &&
keyInfo.Modifiers.HasFlag(ConsoleModifiers.Control))
{
Console.WriteLine("保存しました");
}
}

Shiftキーとの組み合わせも判定できます。

C#
if (keyInfo.Key == ConsoleKey.Enter &&
keyInfo.Modifiers.HasFlag(ConsoleModifiers.Shift))
{
Console.WriteLine("Shift + Enter");
}

ただし、コンソール環境やOS、ターミナルによっては、一部のキー組み合わせが期待通り取得できない場合があります。特にAltキーや一部のショートカットは、ターミナル側で処理されることがあります。

9. キー入力処理でよくあるエラー・つまずき

C#のキー入力処理では、コード自体は間違っていないのにイベントが発生しない、想定と違うキーが取得される、同じ処理が何度も実行されるといった問題がよくあります。

ここでは、特につまずきやすいポイントと対処法を紹介します。

9-1. KeyDownイベントが反応しない

KeyDownイベントが反応しない場合、まず確認するべきなのは次の点です。

確認項目内容
イベント登録KeyDownイベントが正しく紐づいているか
フォーカスキー入力を受け取るコントロールにフォーカスがあるか
KeyPreviewフォーム全体で受け取りたい場合trueになっているか
コントロール側の処理TextBoxやButtonが先に処理していないか

フォームでキー入力を受け取りたい場合は、KeyPreviewを設定します。

C#
this.KeyPreview = true;

イベント登録も確認しましょう。

C#
this.KeyDown += Form1_KeyDown;

デザイナーでイベントを登録している場合、メソッド名を変更したときに関連付けが外れることがあります。動かないときは、プロパティウィンドウのイベント一覧も確認してください。

9-2. 矢印キーやTabキーが取得できない

矢印キーやTabキーは、フォーカス移動やコントロール操作に使われるため、通常のキーイベントで取得しにくい場合があります。

この場合は、PreviewKeyDownで入力キーとして扱うように指定します。

C#
private void button1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode == Keys.Up ||
e.KeyCode == Keys.Down ||
e.KeyCode == Keys.Left ||
e.KeyCode == Keys.Right ||
e.KeyCode == Keys.Tab)
{
e.IsInputKey = true;
}
}

その後、KeyDownで処理します。

C#
private void button1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Tab)
{
MessageBox.Show("Tabキー");
}
}

ただし、Tabキーは本来フォーカス移動に使われるキーです。無効化すると操作性に影響するため、必要な場面だけで使いましょう。

9-3. TextBox入力中にショートカットが効かない

TextBoxにフォーカスがあると、TextBoxがキー入力を先に処理することがあります。

フォーム全体でショートカットを受け取りたい場合は、KeyPreviewtrueにします。

C#
this.KeyPreview = true;

それでもうまくいかない場合は、TextBox側のKeyDownにも処理を追加します。

C#
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.S)
{
SaveFile();
e.SuppressKeyPress = true;
}
}

ただし、TextBox入力中はコピーや貼り付けなどの標準ショートカットも使われます。Ctrl + CCtrl + Vなどを独自処理に割り当てる場合は、ユーザーの操作性を損なわないように注意しましょう。

9-4. 日本語入力中のキー判定が期待通りにならない

日本語入力中、つまりIMEが有効な状態では、キー入力の扱いが英数字入力時と異なることがあります。

たとえば、KeyDownではキーが押されたことを取得できても、実際に入力される文字は変換確定後に決まります。そのため、KeyDownだけで日本語の入力文字を正確に判定しようとすると、期待通りにならない場合があります。

入力された最終的な文字列を確認したい場合は、TextChangedイベントを使う方法もあります。

C#
private void textBox1_TextChanged(object sender, EventArgs e)
{
string text = textBox1.Text;
}

日本語を含む入力制限をしたい場合は、KeyPressだけで完全に制御しようとせず、入力後にTextChangedや検証処理でチェックする方法も検討しましょう。

C#
private void textBox1_Leave(object sender, EventArgs e)
{
if (textBox1.Text.Length > 10)
{
MessageBox.Show("10文字以内で入力してください");
}
}

IMEが関係する入力では、「キーが押された瞬間」ではなく「入力結果」を基準にチェックするほうが安定します。

9-5. 同じ処理が何度も実行されてしまう

KeyDownは、キーを押しっぱなしにすると連続で発生します。

そのため、次のようなコードでは、Enterキーを押し続けたときに処理が何度も実行されます。

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
ExecuteProcess();
}
}

1回だけ実行したい場合は、フラグを使います。

C#
private bool isEnterPressed = false;

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter && !isEnterPressed)
{
isEnterPressed = true;
ExecuteProcess();
}
}

private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
isEnterPressed = false;
}
}

また、ボタン処理などで二重実行を防ぎたい場合は、処理中フラグを使う方法もあります。

C#
private bool isProcessing = false;

private void ExecuteProcess()
{
if (isProcessing)
{
return;
}

try
{
isProcessing = true;

// 実行したい処理
}
finally
{
isProcessing = false;
}
}

10. C#のキー入力取得でよく使う実装例

ここでは、C#のキー入力処理でよく使う実装例を紹介します。

実際のアプリでそのまま使いやすいように、WinFormsを中心にコードを掲載します。

10-1. Enterキーでボタン処理を実行する

Enterキーでボタンと同じ処理を実行したい場合は、共通メソッドを作るのがおすすめです。

C#
private void buttonSearch_Click(object sender, EventArgs e)
{
Search();
}

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
Search();
e.SuppressKeyPress = true;
}
}

private void Search()
{
MessageBox.Show("検索処理を実行しました");
}

フォーム全体でEnterキーを受け取りたい場合は、KeyPreviewを設定します。

C#
public Form1()
{
InitializeComponent();

this.KeyPreview = true;
}

TextBoxでEnterキーを押したときだけ検索したい場合は、TextBoxのKeyDownを使います。

C#
private void textBoxKeyword_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
Search();
e.SuppressKeyPress = true;
}
}

10-2. Escキーでフォームを閉じる

Escキーでフォームを閉じる場合は、KeyDownKeys.Escapeを判定します。

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
this.Close();
}
}

フォーム全体でEscキーを受け取りたい場合は、KeyPreviewtrueにします。

C#
public Form1()
{
InitializeComponent();

this.KeyPreview = true;
}

また、WinFormsではCancelButtonプロパティを使って、Escキーでキャンセルボタンを実行する方法もあります。

C#
this.CancelButton = buttonCancel;

キャンセルボタンのクリックイベントに閉じる処理を書いておけば、Escキーでも同じ処理を実行できます。

C#
private void buttonCancel_Click(object sender, EventArgs e)
{
this.Close();
}

10-3. 矢印キーでオブジェクトを移動する

矢印キーでラベルや画像などを移動する例です。

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
int move = 5;

switch (e.KeyCode)
{
case Keys.Up:
pictureBox1.Top -= move;
break;

case Keys.Down:
pictureBox1.Top += move;
break;

case Keys.Left:
pictureBox1.Left -= move;
break;

case Keys.Right:
pictureBox1.Left += move;
break;
}
}

フォーム全体で矢印キーを受け取りたい場合は、KeyPreviewを設定します。

C#
public Form1()
{
InitializeComponent();

this.KeyPreview = true;
}

ただし、ボタンなどにフォーカスがある場合、矢印キーがフォーカス移動に使われることがあります。その場合は、PreviewKeyDownを使って入力キーとして扱います。

C#
private void Form1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode == Keys.Up ||
e.KeyCode == Keys.Down ||
e.KeyCode == Keys.Left ||
e.KeyCode == Keys.Right)
{
e.IsInputKey = true;
}
}

10-4. 数字以外の入力を禁止する

TextBoxで数字以外の入力を禁止するには、KeyPressを使います。

C#
private void textBoxNumber_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar))
{
e.Handled = true;
}
}

小数点を許可する場合は、次のようにします。

C#
private void textBoxNumber_KeyPress(object sender, KeyPressEventArgs e)
{
TextBox textBox = sender as TextBox;

if (char.IsDigit(e.KeyChar) || char.IsControl(e.KeyChar))
{
return;
}

if (e.KeyChar == '.' && !textBox.Text.Contains("."))
{
return;
}

e.Handled = true;
}

マイナス記号も許可する場合は、先頭に1つだけ入力できるようにします。

C#
private void textBoxNumber_KeyPress(object sender, KeyPressEventArgs e)
{
TextBox textBox = sender as TextBox;

if (char.IsDigit(e.KeyChar) || char.IsControl(e.KeyChar))
{
return;
}

if (e.KeyChar == '-' && textBox.SelectionStart == 0 && !textBox.Text.Contains("-"))
{
return;
}

if (e.KeyChar == '.' && !textBox.Text.Contains("."))
{
return;
}

e.Handled = true;
}

ただし、貼り付け操作ではKeyPressを通らないケースもあります。確実に数値チェックをしたい場合は、入力後にint.TryParsedecimal.TryParseで検証しましょう。

C#
if (!decimal.TryParse(textBoxNumber.Text, out decimal value))
{
MessageBox.Show("数値を入力してください");
}

10-5. Ctrl + Sで保存処理を実行する

Ctrl + Sで保存処理を実行する例です。

C#
public Form1()
{
InitializeComponent();

this.KeyPreview = true;
this.KeyDown += Form1_KeyDown;
}

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.S)
{
SaveFile();
e.SuppressKeyPress = true;
}
}

private void SaveFile()
{
MessageBox.Show("保存しました");
}

メニューの保存処理と共通化する場合は、次のようにします。

C#
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
SaveFile();
}

private void buttonSave_Click(object sender, EventArgs e)
{
SaveFile();
}

private void SaveFile()
{
MessageBox.Show("保存しました");
}

MenuStripを使っている場合は、ShortcutKeysを設定する方法もあります。

C#
saveToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.S;

この方法なら、メニュー項目のショートカットとして自然に扱えます。

11. C#のキー入力取得に関するよくある質問

C#でキー入力を取得するときによくある疑問をまとめます。

KeyDownKeyPressの使い分けや、ショートカットキー、TextBoxでのEnterキー取得、複数キーの同時押し、グローバルホットキーについて確認しておきましょう。

11-1. KeyDownとKeyPressはどちらを使うべきか

キーそのものを判定したい場合はKeyDownを使います。

たとえば、Enterキー、Escキー、矢印キー、F1キー、Ctrl + Sなどを判定する場合です。

C#
if (e.KeyCode == Keys.Enter)
{
// Enterキーの処理
}

一方、入力された文字を判定したい場合はKeyPressを使います。

たとえば、数字のみ入力可能にする、英字のみ許可する、といった処理です。

C#
if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar))
{
e.Handled = true;
}

判断に迷った場合は、次のように考えると分かりやすいです。

やりたいこと使うイベント
Enterキーを判定したいKeyDown
Escキーを判定したいKeyDown
Ctrl + Sを判定したいKeyDown
矢印キーを判定したいKeyDown
入力文字を制限したいKeyPress
数字のみ入力させたいKeyPress
キーを離したタイミングを知りたいKeyUp

11-2. ショートカットキーの実装にはどのイベントが向いているか

ショートカットキーの実装には、基本的にKeyDownが向いています。

理由は、KeyDownでは押されたキーと修飾キーを判定しやすいからです。

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.S)
{
SaveFile();
e.SuppressKeyPress = true;
}
}

WinFormsでMenuStripを使っている場合は、ShortcutKeysプロパティを使う方法もおすすめです。

C#
saveToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.S;

WPFの場合は、KeyDownのほかにInputBindingsCommandを使う方法もあります。

XML
<Window.InputBindings>
<KeyBinding Key="S"
Modifiers="Control"
Command="{Binding SaveCommand}" />
</Window.InputBindings>

簡単な実装ならKeyDown、メニューやコマンドと連携するなら専用のショートカット機能を使うとよいでしょう。

11-3. TextBoxでEnterキーを取得するにはどうすればよいか

TextBoxでEnterキーを取得するには、TextBoxのKeyDownイベントを使います。

C#
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
MessageBox.Show("Enterキー");
e.SuppressKeyPress = true;
}
}

e.SuppressKeyPress = trueを設定すると、Enterキーによるビープ音や不要な改行を抑制できます。

複数行TextBoxの場合、Enterキーは改行として使われることがあります。改行を許可しつつ、Ctrl + Enterで確定したい場合は次のようにします。

C#
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.Enter)
{
SubmitText();
e.SuppressKeyPress = true;
}
}

フォーム全体でEnterキーを処理したい場合は、フォームのAcceptButtonプロパティを使う方法もあります。

C#
this.AcceptButton = buttonOk;

この設定をすると、Enterキーで指定したボタンのクリック処理が実行されます。

11-4. 複数キーの同時押しは取得できるか

Ctrl、Shift、Altなどの修飾キーとの組み合わせは簡単に取得できます。

C#
if (e.Control && e.KeyCode == Keys.S)
{
SaveFile();
}

Ctrl + Shift + Sのような組み合わせも取得できます。

C#
if (e.KeyCode == Keys.S &&
e.Modifiers == (Keys.Control | Keys.Shift))
{
SaveAsFile();
}

ただし、通常の文字キー同士の同時押し、たとえばAキーとDキーを同時に押しているかを判定したい場合は、押下状態を自分で管理する必要があります。

C#
private HashSet<Keys> pressedKeys = new HashSet<Keys>();

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
pressedKeys.Add(e.KeyCode);

if (pressedKeys.Contains(Keys.A) && pressedKeys.Contains(Keys.D))
{
MessageBox.Show("AとDが同時に押されています");
}
}

private void Form1_KeyUp(object sender, KeyEventArgs e)
{
pressedKeys.Remove(e.KeyCode);
}

ゲームやリアルタイム操作では、このようにKeyDownでキーを追加し、KeyUpでキーを削除する方法がよく使われます。

11-5. グローバルホットキーはC#だけで実装できるか

通常のKeyDownイベントは、アプリケーションやフォームがアクティブなときにキー入力を取得する仕組みです。

アプリが非アクティブな状態でもキー入力を取得したい場合は、グローバルホットキーを使う必要があります。

Windowsでは、Win32 APIのRegisterHotKeyをC#から呼び出して実装する方法があります。

C#
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);

[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

ただし、グローバルホットキーはOS全体に影響するため、他のアプリのショートカットと競合する可能性があります。

通常のフォーム内ショートカットで十分な場合は、KeyDownやMenuStripのShortcutKeysを使うほうが安全で簡単です。

グローバルホットキーは、常駐アプリやランチャー、スクリーンショットツールなど、アプリが非アクティブでもキー操作を受け取りたい場合に検討しましょう。

まとめ

C#でキー入力を取得する方法は、アプリケーションの種類や目的によって使い分けることが大切です。

WinFormsでは、キーが押された瞬間を取得するならKeyDown、入力された文字を取得するならKeyPress、キーが離されたタイミングを取得するならKeyUpを使います。

Enterキー、Escキー、矢印キー、Ctrl + Sなどのショートカットキーを判定したい場合は、KeyDownが基本です。入力文字を制限したい場合は、KeyPresse.KeyCharを使うと実装しやすくなります。

フォーム全体でキー入力を受け取りたい場合は、KeyPreviewtrueに設定します。ただし、TextBoxなどの入力コントロールにフォーカスがある場合は、標準操作との競合に注意が必要です。

WPFでは、e.KeyKeyboard.Modifiersを使ってキーを判定します。事前にキー入力を処理したい場合は、PreviewKeyDownが便利です。

コンソールアプリでは、Console.ReadKeyを使うことで、Enterなしで1キーずつ入力を取得できます。

キー入力処理では、「キーそのものを判定したいのか」「入力された文字を判定したいのか」を最初に整理すると、適切なイベントを選びやすくなります。C#のキー入力取得を正しく使い分けることで、ショートカット操作や入力制限、キーボード中心の快適な操作を実装できるようになります。