即使Key:= 0,仍然会发出“叮”声

时间:2014-06-19 18:46:54

标签: delphi

我有一个有趣的问题经常被问到,但我发现他们给出的解决方案不起作用......

我在Win 7上使用Delphi XE3。

我一直都知道在FormKeyDown或FormKeyPress中,您可以将Key设置为0或#0以指示键已被处理(因此,对于无效按键,它不应发出“ding”声音。)< / p>

我做了以下事情:

  1. 新的VCL申请
  2. 表格KeyPreview:= true
  3. 添加一些事件处理程序(见下文)
  4. 运行
  5. Alt + T键 (发出叮当声)
  6. 我成功检测到Alt + T并将Key设置为0. Form OnKeyPress和Form OnKeyUp不会触发。这对我来说并不奇怪,因为我把Key设置为0。

    令人惊讶的是,它在OnKeyDown完成后仍会发出“叮”声。

    我怎么能阻止它这样做呢?

    在某些调试中,似乎有一条消息WM_SYSKEYDOWN导致这种情况发生。

    谢谢!

    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
    
    type
      TForm1 = class(TForm)
        procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
        procedure FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
        procedure FormKeyPress(Sender: TObject; var Key: Char);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.DFM}
    
    procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    begin
      if (key=ord('T')) and (shift=[ssAlt]) then
        key:=0;
    end;
    
    procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
    begin
      showmessage('keypress');
    end;
    
    procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
    begin
      showmessage('keyup');
    end;
    
    end.
    
    
    object Form1: TForm1
      Left = 267
      Top = 163
      Caption = 'Form1'
      ClientHeight = 565
      ClientWidth = 654
      Color = clBtnFace
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -11
      Font.Name = 'MS Sans Serif'
      Font.Style = []
      KeyPreview = True
      OldCreateOrder = False
      Position = poScreenCenter
      ShowHint = True
      OnKeyDown = FormKeyDown
      OnKeyPress = FormKeyPress
      OnKeyUp = FormKeyUp
      PixelsPerInch = 96
      TextHeight = 13
    end
    

2 个答案:

答案 0 :(得分:2)

WM_SYSCHAR消息转换后,从已发布的队列中删除WM_SYSKEYDOWN消息(因此称为'ding')。

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var
  Msg: TMsg;
begin
  if (key=ord('T')) and (shift=[ssAlt]) then begin
    PeekMessage(Msg, 0, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE);
    key:=0;
  end;
end;


您无法在表单级别处理WM_SYSCHAR(除非将其发布到表单本身),因为VCL没有“SysKeyPreview”功能。但是,如果您不希望它“T”不是“T”,并且这与应用程序中的所有/大多数表单相关,您可能会发现在应用程序级别处理消息更方便。这也不需要设置KeyPreview

procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
begin
  if Msg.message = WM_SYSCHAR then begin
    if Char(Msg.wParam) in ['f','F','g','t','T'] then
      Handled := True;
  end;
end;

注意,如果您对这些密钥没有任何特殊处理,您最好放弃“叮”,否则用户将缺乏这些密钥组合不起任何作用的反馈。

答案 1 :(得分:0)

出于向后兼容的原因,我不得不使我的小巧,简单 工具应用程序以响应“ ALT-N”,“ ALT-S”,“ ALT-E”和“ ALT-D”按键。 如果我在FormKeyDown中处理这些问题,它会发出令人讨厌的“哔”或“叮”声。 问题是通过使用FormShortCut事件解决的。

procedure TForm1.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
{Instead of FormKeyDown event, use FormShortCut event.
Form's KeyPreview can be set to False or True.}
begin
    if (GetKeyState(VK_MENU) < 0) then
    case Msg.CharCode of
        Ord('N'): Label1.Caption := 'ALT-N';
        Ord('S'): Label1.Caption := 'ALT-S';
        Ord('E'): Label1.Caption := 'ALT-E';
        Ord('D'): Label1.Caption := 'ALT-D';
    end
end;