Top > プログラミング > .NET Tips> Enterキーを押した時、まるでTabキーを押したかのように、次のコントロールにフォーカスを移す

Enterキーを押した時、まるでTabキーを押したかのように、次のコントロールにフォーカスを移す」への評価、コメント

評価

良い / 悪い = 15 / 6 (「良い」の割合 = 0.714 , 人気度 = 0.944

評価する

コメント一覧


評価の理由
匿名 2020/06/2 (Tue) 21:52:10
評価:良い
知りたいことが理解できました。ありがとうございます。

評価の理由
tom 2017/03/1 (Wed) 14:28:36
評価:良い
It is very helpful to me. Thanks

通常のコメント
管理人 2015/06/24 (Wed) 00:41:44
> 「KeyDownイベントを使用する方法」ではTABを2回押した時と同じになりました(2つ移動してしまう)。「ProcessDialogKeyメソッドとProcessTabKeyメソッドを使用する方法」ではうまくいきました。

私が試した限りでは、KeyDownイベントの方法でも正常に動作しました。KeyDownイベントハンドラを重複して追加していたり、ProcessDialogKeyメソッドの方法と併用しているということはないでしょうか?

通常のコメント
匿名 2015/05/14 (Thu) 07:58:45
「KeyDownイベントを使用する方法」ではTABを2回押した時と同じになりました(2つ移動してしまう)。「ProcessDialogKeyメソッドとProcessTabKeyメソッドを使用する方法」ではうまくいきました。VS2013で2.0と4.5で試しました。

評価の理由
匿名 2015/01/4 (Sun) 00:22:53
評価:良い
keyDownとkeyUpの違いがよくわかりました

通常のコメント
管理人 2014/11/14 (Fri) 01:31:13
>> Shiftキーが押されていてもいなくても「SendKeys.Send("{TAB}")」とするだけでよかったのかもしれません。

> なるほど確かに、確認したところ、期待する動作が確認できました。

ご確認いただき、ありがとうございました。間違ったサンプルでご迷惑をおかけしてしまい、申し訳ありませんでした。記事は近いうちに修正させていただきます。また何かありましたら、よろしくお願いいたします。

通常のコメント
たきる 2014/11/13 (Thu) 15:21:45
> Shiftキーが押されていてもいなくても「SendKeys.Send("{TAB}")」とするだけでよかったのかもしれません。

なるほど確かに、確認したところ、期待する動作が確認できました。

APIを直接呼び出すのと挙動が違ったので不思議に思ってたのですが、なるほど、サンプルではShiftが押された時には+をつけてSendKeys.Send()してましたね。

ProcessDialogKey()内で、SendKeys.Send("{TAB}")を利用して制御するのが最もベストですね。
長々とお付き合いいただき、ありがとうございました。

通常のコメント
管理人 2014/11/13 (Thu) 01:22:48
> あんな面倒なことしなくても、keybd_eventで十分でした。

ご報告ありがとうございます。教えていただいたコードを拝見して気が付いたのですが、そもそも私の記事のSendKeysを使ったサンプルが間違えており、Shiftキーが押されていてもいなくても「SendKeys.Send("{TAB}")」とするだけでよかったのかもしれません。実際私が試した限りでは、それでうまく行きました。試していただけると、幸いです。

通常のコメント
たきる 2014/11/12 (Wed) 13:37:15
あんな面倒なことしなくても、keybd_eventで十分でした。
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern uint keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);

protected override bool ProcessDialogKey(Keys keyData)
{
if (((keyData & Keys.KeyCode) == Keys.Return) &&
((keyData & (Keys.Alt | Keys.Control)) == Keys.None))
{
var vk = (byte)0x0009; // VK_TAB
keybd_event(vk, 0, (uint)0, UIntPtr.Zero);
return true;
}

return base.ProcessDialogKey(keyData);
}

通常のコメント
たきる 2014/11/12 (Wed) 11:40:14
以下で出来ました。未リファクタですがご参考まで。

[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

protected override bool ProcessDialogKey(Keys keyData)
{
if (((keyData & Keys.KeyCode) == Keys.Return) &&
((keyData & (Keys.Alt | Keys.Control)) == Keys.None))
{
var msg = (uint)0x0100; // WM_KEYDOWN
var wParam = new IntPtr(0x0009); // VK_TAB
var lParam = IntPtr.Zero;
PostMessage(this._getActiveControl(this).Handle, msg, wParam, lParam);
return true;
}
return base.ProcessDialogKey(keyData);
}

// 現在フォーカスを得ているコントロールを取得
private Control _getActiveControl(ContainerControl cc)
{
var control = ((ContainerControl)cc).ActiveControl;

if (control.Focused) { return control; }

return this._getActiveControl((ContainerControl)control);
}

通常のコメント
たきる 2014/11/10 (Mon) 10:02:42
> SplitContainerのProcessDialogKeyをオーバーライドして同様のことを行うと、うまくいくようです

ありがとうございます。
確認したところ、期待通りの動作をしました。

オーバーライドに委ねると、恐らくContainerControlを継承しているコントロールをすべてそうしなければならないのではないかと懸念していましたが、PropertyGrid、ToolStripContainer、ToolStripPanel、UpDownBase、UserControlは問題ないようです。

全コントロールを試したわけではありませんが、SplitContainerだけが曲者のようです。
正直、Formのオーバーライドだけで済ませたいところですが、GetNextControl()、SelectNextControl()による荒業をしないとダメそうでバグの温床になりそうだし、要件にあるなら、ご提示いただいた方法がベストかもですね。

私の方でも、もし今後、より良い方法論が見つかりましたら、ご連絡させていただきます。

通常のコメント
管理人 2014/11/10 (Mon) 01:08:59
> 問題があるのは、SplitContainerでした。

ご報告ありがとうございます。私も試してみましたが、おっしゃるとおりでした。ProcessTabKeyまたはSelectNextControlを使ってフォーカスを移動させると、うまく行きませんでした。

SplitContainerのProcessDialogKeyをオーバーライドして同様のことを行うと、うまくいくようです。ただしこの場合、ProcessTabKeyがTrueを返した時だけ「return true」とし、それ以外では「return base.ProcessDialogKey(keyData)」とする必要があります。

public class SplitContainerEx : SplitContainer
{
protected override bool ProcessDialogKey(Keys keyData)
{
if (((keyData & Keys.KeyCode) == Keys.Return) &&
((keyData & (Keys.Alt | Keys.Control)) == Keys.None))
{
if (this.ProcessTabKey((keyData & Keys.Shift) != Keys.Shift))
{
return true;
}
}
return base.ProcessDialogKey(keyData);
}
}

> Shift+Enter押下時にも、一度は正しく動作しますが、Shiftキーを離さず連続してEnterを押しても、Shiftが認識されず、Enterの動作をしてしまいます。

私も試してみましたが、そうなりました。SendKeys.Sendは厳しいかもしれませんね...

もっと良い方法が見つかりましたら、また報告させていただきます。

通常のコメント
たきる 2014/11/7 (Fri) 15:11:35
> Panelの内外関係なく次のコントロールにフォーカスが移動し、問題ありませんでした。そちらではうまくいかないでしょうか?

すみません、いくつか検証した結果、GroupBox、TabControl、Panelは問題ないようでした。
問題があるのは、SplitContainerでした。

C# 2012 .NET Framework 4.5

【ProcessDialogKeyメソッドとProcessTabKeyメソッドを使用する方法】
SplitContainer内の最初のコントロールにフォーカスが移ったあと、更にEnterを押すと、SplitContainer外の次のコントロールにフォーカスしてしまいます。
(Tab押下は、SplitContainer内の終端コントロールまで遷移したら、SplitContainer外のコントロールへ遷移する)

【Tabキーを押した時と同じ動作をさせる別の方法 - SendKeys.Send()】
Enter押下時は正しく動作します。
Shift+Enter押下時にも、一度は正しく動作しますが、Shiftキーを離さず連続してEnterを押しても、Shiftが認識されず、Enterの動作をしてしまいます。
(都度、Shiftを押し直せば期待する動作をしますが、Shift+Tabは、都度Shiftを押す必要がないので、すべての挙動が同じとは言い切れません。)

SendKeys.Send()の挙動で、なんとかShiftを認識させることができればベストなんですが・・・。
なにかお知恵を拝借できたら幸いです。

通常のコメント
管理人 2014/11/6 (Thu) 00:55:58
> パネルなどのコンテナ内と外にコントロールが存在するとTabキー通りの遷移をしません。

「ProcessDialogKeyメソッドとProcessTabKeyメソッドを使用する方法」で試してみました。プロパティを変更していないフォームにPanelコントロールを配置して、その中と外にTexoBoxコントロールを配置しました。この場合は、Enterキーを押すと、Panelの内外関係なく次のコントロールにフォーカスが移動し、問題ありませんでした。そちらではうまくいかないでしょうか?

通常のコメント
匿名 2014/11/5 (Wed) 16:02:08
パネルなどのコンテナ内と外にコントロールが存在するとTabキー通りの遷移をしません。
SendKeys.Send("{TAB}")は試していませんが・・・。

通常のコメント
管理人 2014/07/7 (Mon) 23:47:47
> 以下の方法はどうでしょうか。

ご提案いただいた方法を追加させていただき、これを一番目の方法とさせていただきました。ありがとうございました。

通常のコメント
ありげ~ 2014/04/18 (Fri) 16:39:18
以下の方法はどうでしょうか。

(System.Windows.Forms.Form を継承したクラスで)
Protected Overrides Function ProcessDialogKey(keyData As System.Windows.Forms.Keys) As Boolean
Dim ret As Boolean
If (((Keys.Enter = keyData) OrElse ((Keys.Enter Or Keys.Shift) = keyData)) AndAlso (Me.AcceptButton Is Nothing)) Then
ret = Me.ProcessTabKey(Keys.None = (keyData And Keys.Shift))
Else
ret = MyBase.ProcessDialogKey(keyData)
End If
Return (ret)
End Function

IME、メッセージボックス、テキストボックスともに対処できます。

通常のコメント
管理人 2010/12/1 (Wed) 04:09:11
> vb2005で確認しましたが、Me.KeyPreview = Trueを記述するだけ、ButtonコントロールにFocusがある時のEnterキーをFrom1_KeyDownイベントは拾えます。

.NET Framework 2.0と4.0で確認しましたが、やはりButtonコントロールではKeyDownイベントが発生しませんでした。

> messageboxで「ok」ボタン等をEnterを押下した場合、From1_KeyUpイベンドでEnterを取得してしまいます。

> この方法で漢字を入力するときIMEで変換中にEnterキーが捕捉されてしまい次のコントロールに移動するのを防ぐにはにはどうすればよいのか?

記事に追記させていただきます。ご報告ありがとうございました。

通常のコメント
IMI 2010/01/22 (Fri) 12:10:31
私もIMEで変換時とMsgBoxのEnterを拾ってしまい
防ぐ方法がわかりません。

通常のコメント
YOSHI 2008/09/2 (Tue) 11:45:33
この方法で
漢字を入力するとき
IMEで変換中にEnterキーが捕捉されてしまい
次のコントロールに移動するのを
防ぐにはにはどうすればよいのか?

通常のコメント
mimimi 2008/01/28 (Mon) 13:09:11
vb2005で確認しましたが、Me.KeyPreview = True

を記述するだけ、ButtonコントロールにFocusがある
時のEnterキーをFrom1_KeyDownイベントは拾えます。
また上記記載の方法では、messageboxで「ok」ボタン等
をEnterを押下した場合、From1_KeyUpイベンドでEnter
を取得してしまいます。

コメントの投稿

[説明]