3

When the cursor is e.g. in a Edit field, pressing and releasing the Alt key (without pressing any other key) causes the Edit field to lose the focus. This happens also with any other focused control. How can this be prevented in a Delphi program for any focused control?

user1580348
  • 5,721
  • 4
  • 43
  • 105
  • 10
    Stop trying to fix things that aren't problems. *All* Windows programs behave that way. When you press Alt, the menu gets activated. If your window doesn't have a main menu, then the window many is activated (the one you get by clicking the icon in the upper left corner). You can see this by using the arrow keys to navigate your window's menus. The solution to this is better user education, not to try altering your program's behavior from all the others. When focus is stolen, simply press Alt again, or Esc, to cancel menu mode. – Rob Kennedy May 30 '13 at 05:47
  • Intercepting all the windows messages and filtering away those that open the menu. But you have many chances to totally break the program with this. If your users are dumb, better make a big baner for them, that would show when they opened menu, so they would know they have to go back to input box. – Arioch 'The May 30 '13 at 09:17
  • 1
    @Rob Kennedy I understand your speech for Windows conformity, and generally I agree with you. However, there can be very special situations where preventing the Alt key from stealing the focus can be useful. Meanwhile I've found a solution: In the OnKeyDown event handler of the control where you want to avoid losing focus with the Alt key write: `if Shift = [ssAlt] then Key := 0;`. – user1580348 May 30 '13 at 10:35
  • 3
    this would kill all Alt+something hotkeys, perhaps some AltGr-based umlaut characters would no more be accessible – Arioch 'The May 30 '13 at 11:28
  • 1
    As I said: In "very special situations" (where Alt+something is not needed). – user1580348 May 30 '13 at 15:06
  • How will the user access the menu and/or the system menu? Are you going to force them to use the mouse? – David Heffernan May 31 '13 at 07:35
  • This can be very useful for in-house apps. For example I have a DirectX game editor where it is useful to use either Alt, shift or control (to toggle some stuff on the map, to make selections, to move layers, etc), and where the main menu is of less importance. In that case, using the mouse to use menus is not even an annoyance. It would, however, be confusing if this was a public app with a standard look that does not behave as a user expects. – Eric Fortier Feb 02 '17 at 08:28

2 Answers2

5

A better way to do this with fewer unintended consequences is to be extremely precise about it - I would suggest :

In your form, override WndProc :

TForm1 = class(TForm)
  Edit1: TEdit;
private
   FSuppress : boolean;
protected
   procedure WndProc(var Message : TMessage); override;
end;

And implement like this :

procedure TForm1.WndProc(var Message : TMessage);
begin
  if (Message.Msg = WM_SYSCOMMAND) and
     (Message.WParam = SC_KEYMENU) and
     FSuppress then Exit;

  inherited WndProc(Message);
end;

This is the windows message for a system command and the specific WParam that indicates it is for retrieving the menu triggered by keystroke. Set FSuppress on any controls you wish to keep focus :

procedure TForm1.Edit1Enter(Sender: TObject);
begin
  FSuppress := true;
end;

procedure TForm1.Edit1Exit(Sender: TObject);
begin
  FSuppress := false;
end;

This will not disable the ALT key, but will disable, specifically, the activation of the menu while Edit1 has focus. Critically, shortcuts like ALT + F4 to exit the program or ALT+TAB to switch windows will still work.

I agree with most of the comments, however, in that this is probably not the best solution to the LCD of your user base. You're essentially crippling the program for competent users to pander to the failings of the incompetent ones. Perhaps make it an option like Windows sticky-keys or accessibility options for variously disabled persons.

J...
  • 30,968
  • 6
  • 66
  • 143
  • Just for reference, both of the constants you suggest defining are already defined in `Windows.pas`, and have been since at least Delphi 2. Since this is in a unit for a VCL form, `Windows` is already in the uses clause and the declarations are redundant. – Ken White May 31 '13 at 02:37
  • @KenWhite I thought so... error insight claimed they were unknown so I just added them in. Sometimes I think error insight needs to underline itself. – J... May 31 '13 at 09:35
  • Thanks, this is a perfect solution. And as I already said: This is for a very special situation. Of course I've changed the variable name. – user1580348 May 31 '13 at 19:38
0
procedure SendKey_ALT;
begin
    keybd_event(VK_MENU, MapVirtualKey(VK_MENU, 0), 0, 0);
    keybd_event(VK_MENU, MapVirtualKey(VK_MENU, 0), KEYEVENTF_KEYUP, 0);
end;

Call the above procedure in your FormCreate() method. This will solve the problem.