ゲームエフェクトデザイナーのブログ | A Real-Time VFX Artist's Blog

About Making Materials on UE, Making Tools with C#, etc

C# スペースやEnterキーでボタンを反応させない

ボタンを押すと、TabStopを無効にしていたとしてもそのボタンにフォーカスが移りますが、するとスペースキーやEnterキーを押すとそのボタンをクリックするという困った仕様があります。
これは大体の場合に問題ですし、特にスペースキーを何かの機能のショートカットキーとして使いたい場合に厄介です。

例えば、スペースキーを押しっぱなしするとカーソルガ手のひらのアイコンになって、スクロールバーが出ているコントロールのスクロールを制御できる機能(Photoshopの手のひらツールみたいな)を実装したいと思った時に困りました。

標準のボタンではフォーカスを無効にするプロパティは表に出ておらず、ボタンコントロールを継承して無効に設定したボタンを作ってやる必要があるようです。
そこでこちらの記事と質問サイトを参考に試してみました。
フォーカスを受け取らないボタンを作成する - C#プログラミング
フォームが来ないボタン

結果から言うとダメだったのですが、一応試した際のコードを載せておきます。

試してみた時のフォームの外観はこちらのような感じ。
「button1」と「picturebox1」を配置した状態です。
f:id:moko_03_25:20200314193557p:plain

▼Form1.cs

using System;
using System.Windows.Forms;

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

	public partial class NoFocusedButton : Button
	{
		public NoFocusedButton() : base()
		{
			SetStyle(ControlStyles.Selectable, false);
		}
	}
}


▼Form1.Designer.cs のButton1の生成部分をこちらのように書き換えてみたもの。

/// <summary>
/// デザイナー サポートに必要なメソッドです。このメソッドの内容を
/// コード エディターで変更しないでください。
/// </summary>
private void InitializeComponent()
{
	this.button1 = new Sample_Sample_NoFocusedButton.NoFocusedButton();
	this.panel1 = new System.Windows.Forms.Panel();
	this.pictureBox1 = new System.Windows.Forms.PictureBox();
	this.panel1.SuspendLayout();
	((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
	this.SuspendLayout();


コメントで書かれているようにForm1.Designer.cs の内容をコードエディタで変更するのは良くないようなので、ユーザコントロールとして新規追加してビルドし、フォームデザイナ上に配置してあげる方が良いと思います。


さて、こちらは「試してダメだった」のですが、じゃあどうやって解決したかというと、下記のコードのようにアクティブコントロールNull を設定してやることでフォーカスを解除しました。
ちょっと強引な方法ですが、フォーカスが解除されて問題ない状況なら有効ではと思います。そもそもTabキーでフォーカスを変えられない別のコントロール(この事例だとpicturebox1)にフォーカスを移してやるのでもうまくいきました。

▼Form1.cs

using System;
using System.Windows.Forms;

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

		private void Button1_Click(object sender, EventArgs e)
		{
			ActiveControl = null;
		}
	}
}


スマートではないですが、とりあえずそんな方法もあるということで。。
何か良い解決法をご存じの方はコメント欄で教えていただけると助かります!