【问题标题】:Still getting the "ding" sound even though Key:=0即使 Key:=0 仍然会发出“叮”的声音
【发布时间】:2014-06-19 18:46:54
【问题描述】:

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

我在 Win 7 上使用 Delphi XE3。

我一直明白,在 FormKeyDown 或 FormKeyPress 中,您可以将 Key 设置为 0 或 #0 以表示该键已被处理(因此它不应该为无效的按键发出“叮”的声音)。

我做了以下事情:

  1. 新的 VCL 应用程序
  2. Form KeyPreview:=true
  3. 添加一些事件处理程序(见下文)
  4. 运行
  5. Alt+T (发出叮声)

我成功检测到 Alt+T 并将 Key 设置为 0。Form OnKeyPress 和 Form OnKeyUp 不会触发。这对我来说并不奇怪,因为我将 K​​ey 设置为 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

【问题讨论】:

  • 您是否尝试过简单地捕获WM_SYKEY... 消息? WM_KEY...WM_SYSKEY... 是不同的消息集。您正在使用的事件处理程序是针对 WM_KEY... 消息触发的,而不是 WM_SYSKEY... 消息。
  • 如果您的应用没有附加到 alt+t 的加速器,它应该 ding
  • 删除了我的回答;它不能正常工作!

标签: delphi


【解决方案1】:

在从WM_SYSKEYDOWN 消息翻译后,从已经发布的队列中删除WM_SYSCHAR 消息(因此称为“叮”)。

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”,而且这与您的应用程序中的所有/大多数表单相关,您可能会发现在应用程序级别处理消息更方便。这也不需要设置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;


注意,如果你没有对这些按键做任何特殊处理,最好不要发出“叮”的声音,否则用户会缺乏这些按键组合没有任何用途的反馈。

【讨论】:

    【解决方案2】:

    出于向后兼容性的原因,我不得不让我的小而简单 工具应用程序以响应“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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-11
      • 1970-01-01
      • 2021-04-30
      • 2019-06-30
      相关资源
      最近更新 更多