AFsoft WebSite(エーエフソフト・ウェブサイト)
 

オペレーティング・システムについて

プログラミングについて
ホームページについて
キャドについて
電子カタログについて
書籍・雑誌
イベント
リンク集
DelphiXE3 [FMX] キーボード 2014/06/10
 
前回は、クリップボードについて記述しました。
今回は、キーボードのキーについて見ていきます。
キーボードのキー処理については、既に、[3D-FMX] 3Dアプリケーションテスト(2)(3) にて少し記述しています。
 
VCLアプリケーションでは、コントロールのイベントとして、OnKeyDown・OnKeyPress・OnKeyUp がありました。以下、ヘルプ(VCL)より。
OnKeyDown コントロールにフォーカスがあるときにユーザーがキーを押すと発生します。
 
OnKeyDown イベント ハンドラを使用すると、キーが押された際に発生する、特殊な処理を指定することができます。 OnKeyDown ハンドラは、キーボード キー(ファンクション キーや、SHIFT、ALT、CTRL キーと通常のキーとの組み合わせ、も含まれる)のほか、マウスボタンの押下にも応答します。
 
メモ: TCheckBox は、矢印キーについては、OnKeyDown イベントを発生させません。
 
OnKeyDown は、Vcl.Controls.TKeyEvent 型のイベント ハンドラです。 パラメータの説明については、TKeyEvent を参照してください。
OnKeyPress キーが押されたときに発生します。
 
OnKeyPress イベント ハンドラを使用すると、1 文字のキーを押したときの結果として何かを発生させます。
 
OnKeyPress イベント ハンドラの Key パラメータはChar 型で、OnKeyPress イベントは押されたキーの ASCII 文字を登録します。ASCII Char 値(たとえば SHIFT キーや F1キー)に対応しないキーは、OnKeyPress イベントを生成しません。キーの組み合わせ(たとえば SHIFT+A など)では、OnKeyPress イベントを 1 つだけ生成します。(たとえば、SHIFT+A と押したときの結果は、Caps Lock がオフのときの Key の値が「A」になります。)ASCII 以外のキー、またはキーの組み合わせに応答するには、OnKeyDown もしくは OnKeyUp イベント ハンドラを使用します。
OnKeyUp ユーザーが、押したキーを離した際に発生します。
 
OnKeyUp イベント ハンドラを使用すると、キーが離された際に発生する、特殊な処理を指定することができます。 OnKeyUp ハンドラは、すべてのキーボード キー(文字を表すキーや、ファンクション キー、SHIFT、ALT、CTRL キーと通常のキーとの組み合わせ、など)に応答します。
 
Key が #0 に設定されている場合、それ以降の OnKeyUp イベントの処理は行われません。
 
OnKeyUp は、Vcl.Controls.TKeyEvent 型のイベント ハンドラです。 パラメータの説明については、TKeyEvent を参照してください。
アプリケーションは、すべてのキーについて、ユーザーがキーを押すと Windows の WM_KEYDOWN メッセージを受け取ります。このメッセージは、間接的に OnKeyDown イベントを生成します。Key パラメータを #0に設定すると、メッセージはそれ以上処理されなくなります。ただし、文字を生成するキーでは、Windows は WM_CHAR も生成します。OnKeyDown イベントが発生した時点で、そのキーの WM_CHAR メッセージは既にメッセージ キューに置かれています。Key を #0 に設定しても、メッセージの配信は停止されず、OnKeyPress イベントが発生します。Key を #0 に設定すると、OnKeyPress は文字を表さないキー以外にも発生します。文字を表すキーについては、OnKeyPress が発生し続けます。
 
このようなキーの処理方法には利点があります。文字(改行復帰の #13、Ctrl + C の #3 などの制御文字を含む)だけを処理するコードは、OnKeyPress イベントを使用する必要があります。文字を生成しないキーを処理するコードは、 OnKeyDown イベントを使用する必要があります。
OnKeyDownは、キーコード的な扱い、OnKeyPressは、押した文字内容的な扱い、というのもありましたが、改行キー判定で、OnKeyDownを利用するとBEEP音が鳴って難儀する、というのはありました。
 
あと、フォームには、KeyPreview プロパティがありました。
フォームがアクティブコントロールより前にキーボードイベントを受け取るかどうかを指定します。
 
KeyPreview プロパティが true の場合,キーボードイベントはアクティブコントロールで発生する前にフォームで発生します。(アクティブコントロールは ActiveControl プロパティによって指定されます)
 
KeyPreview が false の場合,キーボードイベントはアクティブコントロールでのみ発生します。
 
Tab,BackTab,矢印キーなどの移動キーは,キーボードイベントを発生させないので KeyPreview の影響を受けません。同様に,ボタンにフォーカスがある場合や,その Default プロパティが true の場合は,キーボードイベントを発生させないので,Enter キーは KeyPreview の影響を受けません。
 
KeyPreview のデフォルト値は false です。
 
 
それでは、FireMonkey(FMX) の場合を見てみると、フォームやボタン、エディット等のコントロールには、OnKeyDown・OnKeyUpイベントはありますが、OnKeyPressイベントというものはありません。OnKeyDown に統一したのでしょう。あと、フォームに KeyPreview プロパティというのはありません。
procedure TForm1.Edit1KeyDown(Sender: TObject;
 var Key: Word; var KeyChar: Char; Shift: TShiftState);
begin
 
end;
 
procedure TForm1.Edit1KeyUp(Sender: TObject;
 var Key: Word; var KeyChar: Char; Shift: TShiftState);
begin
 
end;
Key は、キーボードのキーを示します。
KeyChar は、文字コードを示します。
Shift は、指定されたキーがフォーカスのあるコントロールで押された際に、どのシフト キー(SHIFT、CTRL、ALT)が押されていたかを示します。
コントロールは、どのキー ダウン メッセージにも応じて、KeyDown を呼び出します。その際、メッセージ パラメータは、キー コード、文字コード、シフト キーの状態にデコードされ、それぞれ、Key、KeyChar、Shift の各パラメータとして渡されます。
System.Classes.TShiftState
type TShiftState = set of (ssShift, ssAlt, ssCtrl, ssLeft, ssRight, ssMiddle, ssDouble, ssTouch, ssPen, ssCommand);
Alt、Ctrl、Shift キー、マウス ボタン、またはタッチ デバイスの状態を示します。
TShiftState 型は、キーイベント ハンドラおよびマウスイベント ハンドラによって使用され、イベントが発生したときの Alt キー、Ctrl キー、および Shift キーの状態、マウスボタンまたはアタッチされたタッチデバイスの状態を判断します。次の状態を示すフラグセットです。
意味
ssShiftShift キーが押されています。
ssAltAlt キーが押されています。
ssCtrlCtrl キーが押されています。
ssLeftマウスの左ボタンが押されています。
ssRightマウスの右ボタンが押されています。
ssMiddleマウスのホイール ボタンが押されています。
ssDoubleマウス ボタンがダブルクリックされた。
ssTouchユーザーがタッチ画面に指をあてています。
ssPenペンがタブレット表面に触れています。
ssCommandCMD(Mac 上でのみ)が押されています。
Key値は、仮想キーを扱う場合に利用します。仮想キーは、「System.UITypes」にて登録されている vk〜〜 という定数です。
 
下図のように、エディット(Edit)ボタン(Button)ラベル(Label)を配置します。

Edit1 の OnKeyDown・OnKeyUp イベントハンドラを下記のようにします。
procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word;
 var KeyChar: Char; Shift: TShiftState);
begin
   Label1.Text := '[Edit1] ' + KeyChar ;
   if (Key = vkLEFT)  then Label1.Text := '[Edit1] ' + '←';
   if (Key = vkRIGHT) then Label1.Text := '[Edit1] ' + '→';
   key := 0 ;
   KeyChar := #0 ;
end;

procedure TForm1.Edit1KeyUp(Sender: TObject; var Key: Word;
 var KeyChar: Char;  Shift: TShiftState);
begin
   Label2.Text := '[Edit1] ' + KeyChar ;
   if (Key = vkLEFT)  then Label2.Text := '[Edit1] ' + '←';
   if (Key = vkRIGHT) then Label2.Text := '[Edit1] ' + '→';
   key := 0 ;
   KeyChar := #0 ;
end;
保存・コンパイル(ビルド)・実行します。

Edit1 にフォーカス移動した状態で「a」と入力
 
Edit1 にフォーカスがない状態では、ラベル内容の変化はありません。なお、この状態では、Edit1 で文字入力を行う事は出来ません。文字入力を行いたい場合は、
key := 0 ;
KeyChar := #0 ;
の部分は削除(又はコメント化)して下さい。
 
次に、フォーム Form1 の OnKeyDown・OnKeyUp イベントハンドラを記述してみます。
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
 var KeyChar: Char; Shift: TShiftState);
begin
   Label1.Text := '[Form] ' + KeyChar ;
   if (Key = vkLEFT)  then Label1.Text := '[Form] ' + '←';
   if (Key = vkRIGHT) then Label1.Text := '[Form] ' + '→';
   key := 0 ;
   KeyChar := #0 ;
end;

procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word;
 var KeyChar: Char; Shift: TShiftState);
begin
   Label2.Text := '[Form] ' + KeyChar ;
   if (Key = vkLEFT)  then Label2.Text := '[Form] ' + '←';
   if (Key = vkRIGHT) then Label2.Text := '[Form] ' + '→';
   key := 0 ;
   KeyChar := #0 ;
end;
保存・コンパイル(ビルド)・実行します。

Edit1にフォーカスが無い状態で、「a」入力

Edit1 にフォーカス移動

Edit1にフォーカスがある状態で、「a」入力
親であるフォーム Form1 が先にイベント処理されてしまう
様子だけれども実際の文字入力は行われていない?
 
フォーム Form1 側のイベントハンドラ内の
key := 0 ;
KeyChar := #0 ;
の部分を削除(又はコメント化)しても変化はありません。
Edit1にフォーカスがあっても、Edit1 のイベントハンドラが正常処理した様子はありませんが、文字入力も出来ていません。
 
次に、エディット Edit1 側のイベントハンドラ内の
key := 0 ;
KeyChar := #0 ;
の部分を削除(又はコメント化)してみます。すると、

Edit1にフォーカスがある状態で文字入力すれば Edit1 への入力は出来るようになります。が、イベントハンドラが正常処理した様子はありません。しかし、フォーム Form1 の OnKeyDown イベントハンドラはキー入力した文字内容を受け取っていない様子ですが、キーコードは受け取っているようです。また、OnKeyUp イベントハンドラのほうは、キー入力した文字内容とキーコードの両方を受け取っている様子です。
 
はい、よく分からない状況ですね。こういった重複するようなプログラミングは、誤動作の原因となる可能性が高いので、やめておいた方がいいですね。
 
エディットには OnKeyDown・OnKeyUp イベントのほか、OnTyping イベントというものもあるようです。
OnTyping この編集コントロールに入力している際に発生します。
OnTyping イベント ハンドラを記述すると、この編集コントロールに入力した際に、特定のアクションを実行させることができます。 文字を入力すると、Typing プロパティもまた True に設定されます。
という事で、フォーム Form1 側の OnKeyDown・OnKeyUp イベントハンドラを削除し、エディット Edit1 の OnTyping イベントハンドラを下記のようにしてみました。
procedure TForm1.Edit1Typing(Sender: TObject);
begin
 Label2.Text := '*';
end;
保存・コンパイル(ビルド)・実行します。

キーを押している間は、「*」が表示されます


キーを離すと OnKeyUp イベントハンドラが実行されます
 
 
VCLアプリケーション時は、長いループ時に、Escapeキーを押したら中断をしたい、というような処理を記述する際、よく、ループ内に
if ((GetAsyncKeyState(VK_ESCAPE) and $8000) > 0) then
 {中止用のコード}
のような文を記述していましたが、この関数は、WindowsAPI ですので、FireMonkey(FMX) で WindowsAPI を使うことは出来ませんから、フォームやコントロールの OnKeyDown イベントでキー処理するよう考えた方がよさそうです。
 
 
次に、VCLアプリケーションの場合、[Touch]内に、タッチキーボード(ソフトウェアキーボード)の機能がありましたが、FireMonkey(FMX)にはありません。まぁ、タブレットを使用していれば、タブレットの機能でタッチキーボードは表示されるのでしょうけれども…。
 
ボタン Button1 の OnClickイベントハンドラを下記のようにしてみます。
procedure TForm1.Button1Click(Sender: TObject);
var
   kb : IFMXVirtualKeyboardService ;
begin
   kb := IFMXVirtualKeyboardService(
      TPlatformServices.Current.GetPlatformService(
         IFMXVirtualKeyboardService));
   kb.ShowVirtualKeyboard(Edit1);
end;
保存・コンパイル(ビルド)・実行します。

ボタンをクリックします


タッチキーボードが表示されます。


フォーム内のエディットをクリックして
フォーカスを移動した状態で、タッチキーボード上のキーを
タッチ/クリックすると、エディット内にその文字が
入力されていきます。
 
こういう記述方法で良いのかどうかは分かりませんが、取り敢えず動いてはいるようです。タッチディスプレイやタブレット等での動作確認はしていませんけれども……。
 
 
バッチファイル
BASIC
C言語のお勉強
拡張子な話
DOSプログラム
Delphi
>Dehi入門編
>Delphi2010
>DelphiXE3
▲2014/06/09
 2014/06/10
▼2014/06/11
 
シェアウェア
Script!World
データベース
 
お問い合わせ 
本サイトはリンクフリーです
リンクバナー
(C)Copyright 1999-2015. By AFsoft All Rights Reserved.