トップへ(mam-mam.net/)

タッチキーボード(スクリーンキーボード,ソフトウェアキーボード)を作成 ~Delphiソースコード集

検索:

タッチキーボード(スクリーンキーボード,ソフトウェアキーボード)を作成 ~Delphiソースコード集

日本語のタッチキーボード(スクリーンキーボード,ソフトウェアキーボード)を作成します。

Delphiでタッチキーボードを作成

タッチキーボードを作成するにはCreateParamsをオーバーライドしてウィンドウがフォーカスを持たないようにする必要があります。
また、使用するコントロールもフォーカスを持たないもの(TSpeedButtonやTBitBtnなど)を使う必要があります。

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs , Vcl.Buttons;

type
  TForm1 = class(TForm)
  private
    { Private 宣言 }
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  public
    { Public 宣言 }
  end;

implementation

{$R *.dfm}

procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.ExStyle :=
    (Params.ExStyle
    or WS_EX_NOACTIVATE  //アクティブにならないウィンドウ
    or WS_EX_TOPMOST     //常に手前に配置
    ) 
    // and (not WS_EX_APPWINDOW)    //タスクバーに配置しない
    ;
end;

キーボードのキーを押すには「keybd_event」API関数を使用します。
procedure keybd_event(bVk: Byte; bScan: Byte; dwFlags: DWORD; dwExtraInfo: UIntPtr); stdcall;

プロジェクトの作成と画面設計

[ファイル]⇒[新規作成]⇒[VCL フォーム アプリケーション -Delphi]をクリックし、新規プロジェクトを作成します。
画面設計は完了です。

Delphiでタッチキーボードを作成

ソースコードの記述

キーボードから「F12」キーを押してコードエディタに切り替えます。
以下ソースコードをコピー&ペーストして貼り付けます。

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs , Vcl.Buttons;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
    IsShift:Boolean;
    procedure BtnClick(Sender: TObject);
    procedure SetKeyBoard();
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  public
    { Public 宣言 }
  end;

  TVKeybd=record
    C,S:String;
    K:Byte;
    W:Integer;
    SB:TSpeedButton;
  end;

var
  Form1: TForm1;
  kbd : array[0..5] of array[0..14] of TVKeybd = (
    (
      (C:'ESC'; S:'ESC'; K:VK_ESCAPE; W:60),
      (C:'F1'; S:'F1'; K:VK_F1; W:60),
      (C:'F2'; S:'F2'; K:VK_F2; W:60),
      (C:'F3'; S:'F3'; K:VK_F3; W:60),
      (C:'F4'; S:'F4'; K:VK_F4; W:60),
      (C:'F5'; S:'F5'; K:VK_F5; W:60),
      (C:'F6'; S:'F6'; K:VK_F6; W:60),
      (C:'F7'; S:'F7'; K:VK_F7; W:60),
      (C:'F8'; S:'F8'; K:VK_F8; W:60),
      (C:'F9'; S:'F9'; K:VK_F9; W:60),
      (C:'F10'; S:'F10'; K:VK_F10; W:60),
      (C:'F11'; S:'F11'; K:VK_F11; W:60),
      (C:'F12'; S:'F12'; K:VK_F12; W:60),
      (C:'Prt'; S:'Prt'; K:VK_SNAPSHOT; W:60),
      (C:''; S:''; K:0; W:0)
    ),(
      (C:'漢字'; S:'漢字'; K:255; W:60),
      (C:'1'; S:'!'; K:Ord('1'); W:60),
      (C:'2'; S:'"'; K:Ord('2'); W:60),
      (C:'3'; S:'#'; K:Ord('3'); W:60),
      (C:'4'; S:'$'; K:Ord('4'); W:60),
      (C:'5'; S:'%'; K:Ord('5'); W:60),
      (C:'6'; S:'&&'; K:Ord('6'); W:60),
      (C:'7'; S:''''; K:Ord('7'); W:60),
      (C:'8'; S:'('; K:Ord('8'); W:60),
      (C:'9'; S:')'; K:Ord('9'); W:60),
      (C:'0'; S:''; K:Ord('0'); W:60),
      (C:'-'; S:'='; K:VK_OEM_MINUS; W:60),
      (C:'^'; S:'~'; K:VK_OEM_7; W:60),
      (C:'\'; S:'|'; K:VK_OEM_5; W:60),
      (C:'BS'; S:'BS'; K:VK_BACK; W:60)
    ),(
      (C:'Tab'; S:'Tab'; K:VK_TAB; W:60),
      (C:'q'; S:'Q'; K:Ord('Q'); W:60),
      (C:'w'; S:'W'; K:Ord('W'); W:60),
      (C:'e'; S:'E'; K:Ord('E'); W:60),
      (C:'r'; S:'R'; K:Ord('R'); W:60),
      (C:'t'; S:'T'; K:Ord('T'); W:60),
      (C:'y'; S:'Y'; K:Ord('Y'); W:60),
      (C:'u'; S:'U'; K:Ord('U'); W:60),
      (C:'i'; S:'I'; K:Ord('I'); W:60),
      (C:'o'; S:'O'; K:Ord('O'); W:60),
      (C:'p'; S:'P'; K:Ord('P'); W:60),
      (C:'@'; S:'`'; K:VK_OEM_3; W:60),
      (C:'['; S:'{'; K:VK_OEM_4; W:60),
      (C:'Ent'; S:'Ent'; K:VK_RETURN; W:120),
      (C:''; S:''; K:0; W:0)
    ),(
      (C:'Cap'; S:'Cap'; K:VK_CAPITAL; W:60),
      (C:'a'; S:'A'; K:Ord('A'); W:60),
      (C:'s'; S:'S'; K:Ord('S'); W:60),
      (C:'d'; S:'D'; K:Ord('D'); W:60),
      (C:'f'; S:'F'; K:Ord('F'); W:60),
      (C:'g'; S:'G'; K:Ord('G'); W:60),
      (C:'h'; S:'H'; K:Ord('H'); W:60),
      (C:'j'; S:'J'; K:Ord('J'); W:60),
      (C:'k'; S:'K'; K:Ord('K'); W:60),
      (C:'l'; S:'L'; K:Ord('L'); W:60),
      (C:';'; S:'+'; K:VK_OEM_PLUS; W:60),
      (C:':'; S:'*'; K:VK_OEM_1; W:60),
      (C:']'; S:'}'; K:VK_OEM_6; W:60),
      (C:''; S:''; K:0; W:0),
      (C:''; S:''; K:0; W:0)
    ),(
      (C:'Shift'; S:'Shift'; K:VK_SHIFT; W:60),
      (C:'z'; S:'Z'; K:Ord('Z'); W:60),
      (C:'x'; S:'X'; K:Ord('X'); W:60),
      (C:'c'; S:'C'; K:Ord('C'); W:60),
      (C:'v'; S:'V'; K:Ord('V'); W:60),
      (C:'b'; S:'B'; K:Ord('B'); W:60),
      (C:'n'; S:'N'; K:Ord('N'); W:60),
      (C:'m'; S:'M'; K:Ord('M'); W:60),
      (C:','; S:'<'; K:VK_OEM_COMMA; W:60),
      (C:'.'; S:'>'; K:VK_OEM_PERIOD; W:60),
      (C:'/'; S:'?'; K:VK_OEM_2; W:60),
      (C:'\'; S:'_'; K:VK_OEM_102; W:60),
      (C:''; S:''; K:0; W:0),
      (C:''; S:''; K:0; W:0),
      (C:''; S:''; K:0; W:0)
    ),(
      (C:'Del'; S:'Del'; K:VK_DELETE; W:60),
      (C:'Ins'; S:'Ins'; K:VK_INSERT; W:60),
      (C:'Space'; S:'Space'; K:VK_SPACE; W:180),
      (C:'←'; S:'←'; K:VK_LEFT; W:60),
      (C:'↑'; S:'↑'; K:VK_UP; W:60),
      (C:'↓'; S:'↓'; K:VK_DOWN; W:60),
      (C:'→'; S:'→'; K:VK_RIGHT; W:60),
      (C:'Home'; S:'Home'; K:VK_HOME; W:60),
      (C:'End'; S:'End'; K:VK_END; W:60),
      (C:'Up'; S:'Up'; K:VK_PRIOR; W:60),
      (C:'Dn'; S:'Dn'; K:VK_NEXT; W:60),
      (C:''; S:''; K:0; W:0),
      (C:''; S:''; K:0; W:0),
      (C:''; S:''; K:0; W:0),
      (C:''; S:''; K:0; W:0)
    )
  );

Const
  IMC_GETOPENSTATUS=$5;
  IMC_SETOPENSTATUS=$6;

implementation

{$R *.dfm}

uses Winapi.Imm;

{ TForm1 }

procedure TForm1.SetKeyBoard;
var x,y:Integer;
    CapsLockState:SmallInt;
begin
  // CAPS LOCKの状態を取得
  CapsLockState := (GetKeyState(VK_CAPITAL) AND 1);
  for y := Low(kbd) to High(kbd) do
  begin
    for x := Low(kbd[y]) to High(kbd[y]) do
    begin
      if kbd[y][x].C='Shift' then
      begin
        if IsShift then        
          kbd[y][x].SB.Font.Color:=clRed
        else
          kbd[y][x].SB.Font.Color:=clBlack;
      end
      else if kbd[y][x].C='Cap' then
      begin
        if CapsLockState=1 then
          kbd[y][x].SB.Font.Color:=clRed
        else
          kbd[y][x].SB.Font.Color:=clBlack;
      end;

      if IsShift then
      begin
        if (CapsLockState=1) and (Length(kbd[y][x].S)=1) then
          kbd[y][x].SB.Caption:=LowerCase(kbd[y][x].S)
        else
          kbd[y][x].SB.Caption:=kbd[y][x].S;
      end
      else
      begin
        if (CapsLockState=1) and (Length(kbd[y][x].S)=1) then
          kbd[y][x].SB.Caption:=UpperCase(kbd[y][x].C)
        else
          kbd[y][x].SB.Caption:=kbd[y][x].C;
      end;
    end;
  end;
end;

procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.ExStyle :=
    (Params.ExStyle
    or WS_EX_NOACTIVATE  //アクティブにならないウィンドウ
    or WS_EX_TOPMOST     //常に手前に配置
    ) 
    // and (not WS_EX_APPWINDOW)    //タスクバーに配置しない
    ;
end;

procedure TForm1.FormCreate(Sender: TObject);
var x,y,w:Integer;
    sb:TSpeedButton;
begin
  Self.ClientWidth := 60*15;
  Self.ClientHeight := 60*6;
  IsShift:=False;
  for y := Low(kbd) to High(kbd) do
  begin
    w:=0;
    for x := Low(kbd[y]) to High(kbd[y]) do
    begin
      if kbd[y][x].C<>'' then
      begin
        sb:=TSpeedButton.Create(Self);
        sb.Parent:=Self;
        sb.Width:=kbd[y][x].W;
        if kbd[y][x].C='Ent' then
          sb.Height:=120
        else
          sb.Height:=60;
        sb.Font.Height:=-16;
        sb.Left:=w;
        sb.Top:=y*60;
        sb.Tag:=x+(y shl 8);
        sb.OnClick:=BtnClick;
        kbd[y][x].SB:=sb;
        inc(w, kbd[y][x].W);
      end;
    end;
  end;
  SetKeyBoard();
end;

procedure TForm1.BtnClick(Sender: TObject);
var sb:TSpeedButton;
    h,hIME:HWND;
    meStatus:NativeInt;
    Key:Byte;
    ScanCode:Cardinal;
    x,y:Byte;
begin
  sb:=TSpeedButton(Sender);
  y:=(sb.Tag shr 8);
  x:=(sb.Tag and $FF);

  if kbd[y][x].K=255 then
  begin
    //フォアグラウンドウィンドウを取得
    h:=GetForegroundWindow();
    //IMEクラスの既定のウィンドウハンドルを取得
    hIME:=ImmGetDefaultIMEWnd(h);
    if hIME<>0 then
    begin
      meStatus := SendMessage(hIME, WM_IME_CONTROL, IMC_GETOPENSTATUS, 0);
      if meStatus=1 then
        SendMessage(hIME, WM_IME_CONTROL, IMC_SETOPENSTATUS, 0)
      else
        SendMessage(hIME, WM_IME_CONTROL, IMC_SETOPENSTATUS, 1);
    end;
  end
  else if kbd[y][x].K=VK_SHIFT then
  begin
    IsShift:=not IsShift;
    SetKeyBoard();
  end
  else
  begin
    if IsShift then
    begin
      ScanCode:=MapVirtualKey(VK_SHIFT, MAPVK_VK_TO_VSC);
      keybd_event(VK_SHIFT,ScanCode,0,0);
    end;
    Key:=kbd[y][x].K;
    ScanCode:=MapVirtualKey(Key, MAPVK_VK_TO_VSC);
    keybd_event(Key,ScanCode,0,0);
    keybd_event(Key,ScanCode,KEYEVENTF_KEYUP,0);
    if IsShift then
    begin
      ScanCode:=MapVirtualKey(VK_SHIFT, MAPVK_VK_TO_VSC);
      keybd_event(VK_SHIFT,ScanCode,KEYEVENTF_KEYUP,0);
    end;
    if Key=VK_CAPITAL then
      SetKeyBoard();
  end;
end;

end.

イベントプロパティの設定

キーボードから「F12」キーを押してデザインエディタに切り替えます。
左上ペイン「構造」から「Form1」をクリックします。
左下ペイン「オブジェクト インスペクタ」から「イベント」タブをクリックし「OnCreate」イベントプロパティに「FormCreate」を設定します。

Delphiでタッチキーボードを作成

プロジェクト オプションの設定

「プロジェクト」⇒「オプション」をクリックします。
左上ペイン「アプリケーション」⇒「マニフェスト」を選択します。
「DPIの認識」の設定を「なし」に設定し「保存」ボタンをクリックします。

Delphiでタッチキーボードを作成

「実行」⇒「実行」をクリックすると、コンパイルして実行されます。