How to use window focus messages for a Delphi on-screen keyboard form

前端 未结 3 1940
感情败类
感情败类 2021-01-02 10:22

I need a built-in on screen numeric keypad in my Application. For various reasons I cannot use the TMS Software or other commercial component offerings. I\'m very happy with

3条回答
  •  别那么骄傲
    2021-01-02 10:47

    My final solution is as follows. This creates a numeric pad with a border and - yes- it does activate if the border is clicked or resized, but clicking the buttons does not steal focus from the target form / control. Simply using CreateParams did not work for me - it seemed to need the WMMouseActivate message instead.

    I've combined it with a routine that I found that posts the key to the OS, not just the focused control. Note that code below assumes some simple support from an ancestor form for setting a default size and position. Thanks for all your help.

    unit UArtScreenKeyboardForm;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      UArtBaseForm, Buttons,
      StdCtrls;
    
    type
      TArtScreenKeyboardForm = class(TArtBaseForm)
        procedure FormShow(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
        procedure FormCreate(Sender: TObject);
        procedure WMMouseActivate(var Message: TWMMouseActivate); message WM_MOUSEACTIVATE;
        procedure FormResize(Sender: TObject);
      private
        { Private declarations }
        procedure DoOnbuttonClick(ASender: TObject);
        procedure DrawButtons;
      protected
        procedure SetDefaultSizeAndPosition; override;
      public
        { Public declarations }
      end;
    
    
    
    procedure ArtScreenKeyboardForm_Show;
    procedure ArtScreenKeyboardForm_Hide;
    
    
    implementation
    
    {$R *.DFM}
    
    uses
      UArtLibrary;
    
    type
      TButtonKind = (
        bk0,
        bk1,
        bk2,
        bk3,
        bk4,
        bk5,
        bk6,
        bk7,
        bk8,
        bk9,
        bkPlus,
        bkMinus,
        bkDel,
        bkDiv,
        bkMul,
        bkEquals,
        bkDecPt,
        bkEnter );
    
    const
      ButtonCaptions : array[TButtonKind] of string = (
        '0',
        '1',
        '2',
        '3',
        '4',
        '5',
        '6',
        '7',
        '8',
        '9',
        '+',
        '-',
        'Back',
        '/',
        '*',
        '=',
        '.',
        'Enter' );
    
      ScanCodes : array[TButtonKind] of cardinal = (
        Ord( '0' ),
        Ord( '1' ),
        Ord( '2' ),
        Ord( '3' ),
        Ord( '4' ),
        Ord( '5' ),
        Ord( '6' ),
        Ord( '7' ),
        Ord( '8' ),
        Ord( '9' ),
        VK_ADD,
        VK_SUBTRACT,
        8, {BACKSPACE}
        VK_DIVIDE,
        VK_MULTIPLY,
        Ord( '=' ),
        Ord( '.' ),
        VK_RETURN );
    
    
    var
      ArtScreenKeyboardForm: TArtScreenKeyboardForm = nil;
    
    
    procedure PostKeyEx32(key: Word; const shift: TShiftState; specialkey: Boolean) ;
     {
    Parameters :
    * key : virtual keycode of the key to send. For printable keys this is simply the ANSI code (Ord(character)) .
    * shift : state of the modifier keys. This is a set, so you can set several of these keys (shift, control, alt, mouse buttons) in tandem. The TShiftState type is declared in the Classes Unit.
    * specialkey: normally this should be False. Set it to True to specify a key on the numeric keypad, for example.
    
    Description:
    Uses keybd_event to manufacture a series of key events matching the passed parameters. The events go to the control with focus. Note that for characters key is always the upper-case version of the character. Sending without any modifier keys will result in a lower-case character, sending it with [ ssShift ] will result in an upper-case character!
    }
    type
      TShiftKeyInfo = record
        shift: Byte ;
        vkey: Byte ;
      end;
    
      ByteSet = set of 0..7 ;
    
    const
      shiftkeys: array [1..3] of TShiftKeyInfo =
        ((shift: Ord(ssCtrl) ; vkey: VK_CONTROL),
        (shift: Ord(ssShift) ; vkey: VK_SHIFT),
        (shift: Ord(ssAlt) ; vkey: VK_MENU)) ;
    var
      flag: DWORD;
      bShift: ByteSet absolute shift;
      j: Integer;
    begin
      for j := 1 to 3 do
      begin
        if shiftkeys[j].shift in bShift then
          keybd_event(shiftkeys[j].vkey, MapVirtualKey(shiftkeys[j].vkey, 0), 0, 0) ;
      end;
      if specialkey then
        flag := KEYEVENTF_EXTENDEDKEY
      else
        flag := 0;
    
     keybd_event(key, MapvirtualKey(key, 0), flag, 0) ;
      flag := flag or KEYEVENTF_KEYUP;
      keybd_event(key, MapvirtualKey(key, 0), flag, 0) ;
    
     for j := 3 downto 1 do
      begin
        if shiftkeys[j].shift in bShift then
          keybd_event(shiftkeys[j].vkey, MapVirtualKey(shiftkeys[j].vkey, 0), KEYEVENTF_KEYUP, 0) ;
      end;
    end;
    
    
    
    
    procedure TArtScreenKeyboardForm.DoOnbuttonClick(ASender: TObject);
    var
      Btn : TSpeedButton;
      Kind : TButtonKind;
    begin
      Btn := ASender as TSpeedButton;
      Kind := TButtonKind(StrToIntDef( Copy( Btn.Name, 4, MaxStrLen ), 0 ));
      PostKeyEx32( ScanCodes[Kind], [], False );
    
      // As suggested also:
      //PostMessage(GetFocus, WM_KEYDOWN, Ord('A'), 0 );
      // PostMessage(GetFocus, WM_KEYDOWN, VK_NUMPAD1, MakeLong(0, MapVirtualKey(VK_NUMPAD1, 0)));
    
    
    
    end;
    
    
    
    procedure TArtScreenKeyboardForm.WMMouseActivate(var Message: TWMMouseActivate);
    begin
      Message.Result := MA_NOACTIVATE;
    end;
    
    procedure ArtScreenKeyboardForm_Show;
    begin
      If ArtScreenKeyboardForm = nil then
        begin
        ArtScreenKeyboardForm := TArtScreenKeyboardForm.Create( Application );
        ArtScreenKeyboardForm.Show;
        end;
    
     Application.ProcessMessages;
    end;
    
    
    
    
    
    procedure ArtScreenKeyboardForm_Hide;
    begin
     If ArtScreenKeyboardForm <> nil then
       begin
       ArtScreenKeyboardForm.Free;
       ArtScreenKeyboardForm := nil;
       end;
    end;
    
    
    procedure TArtScreenKeyboardForm.FormShow(Sender: TObject);
    begin
      DrawButtons;
    end;
    
    procedure TArtScreenKeyboardForm.SetDefaultSizeAndPosition;
    begin
      inherited;
      Width := 300;
      PlaceControl( Self, cpWorkAreaTopLeft );
    end;
    
    procedure TArtScreenKeyboardForm.FormClose(Sender: TObject;
      var Action: TCloseAction);
    begin
      Action := caFree;
      ArtScreenKeyboardForm := nil;
    end;
    
    
    procedure TArtScreenKeyboardForm.FormCreate(Sender: TObject);
    begin
      Constraints.MinWidth  := 200;
      Constraints.MinHeight := (120 * 5)  div 4;
    end;
    
    
    procedure TArtScreenKeyboardForm.DrawButtons;
    
      procedure AddButton( ATop, ALeft, AWidth, AHeight : integer; AKind : TButtonKind );
    
        function WidthPix( AValue : integer ) : integer;
        begin
          Result := AValue * (ClientWidth div 4);
        end;
    
        function HeightPix( AValue : integer ) : integer;
        begin
          Result := AValue * (ClientHeight div 5);
        end;
    
      var
        Button : TSpeedButton;
      begin
        Button := TSpeedButton.Create( Self );
        Button.Parent := Self;
    
        Button.Left := WidthPix( ALeft );
        Button.Top  := HeightPix( ATop );
        Button.Width := WidthPix( AWidth );
        Button.Height := HeightPix( AHeight );
        Button.Visible := True;
    
        Button.Name := Format( 'btn%d', [Ord( AKind )] );
        Button.Caption := ButtonCaptions[ AKind ];
    
        button.OnClick := DoOnbuttonClick;
      end;
    
    
    
    var
      I : integer;
    begin
      Height := (Width * 5) div 4;
    
      ApplyScreenIconTitleFontToFont( Font );
    
      Font.Size := Font.Size + ((Height-250) div 30);
    
      Font.Style := Font.Style + [fsBold];
      Font.Color := clGray;
    
      For I := ComponentCount-1 downto 0 do
        If Components[I] is TSpeedButton then
          Components[I].Free;
    
      Addbutton( 0, 0, 1, 1, bkDel      );
      Addbutton( 0, 1, 1, 1, bkEquals   );
      Addbutton( 0, 2, 1, 1, bkDiv      );
      Addbutton( 0, 3, 1, 1, bkMul      );
    
      Addbutton( 1, 0, 1, 1, bk7        );
      Addbutton( 1, 1, 1, 1, bk8        );
      Addbutton( 1, 2, 1, 1, bk9        );
      Addbutton( 1, 3, 1, 1, bkMinus    );
    
      Addbutton( 2, 0, 1, 1, bk4        );
      Addbutton( 2, 1, 1, 1, bk5        );
      Addbutton( 2, 2, 1, 1, bk6        );
      Addbutton( 2, 3, 1, 1, bkPlus     );
    
      Addbutton( 3, 0, 1, 1, bk1        );
      Addbutton( 3, 1, 1, 1, bk2        );
      Addbutton( 3, 2, 1, 1, bk3        );
      Addbutton( 3, 3, 1, 2, bkEnter    );
    
      Addbutton( 4, 0, 2, 1, bk0        );
      Addbutton( 4, 2, 1, 1, bkDecPt    );
    end;
    
    procedure TArtScreenKeyboardForm.FormResize(Sender: TObject);
    begin
      DrawButtons;
    end;
    
    initialization
    finalization
      FreeAndNil( ArtScreenKeyboardForm );
    end.
    

提交回复
热议问题