6

I've built a custom control that I'm trying to send input to. It will accept mouse input and report MouseDown, MouseMove and MouseUp correctly, but for whatever reason, it won't accept keyboard input. When I click on it, it doesn't receive focus, and any keys I press get interpreted by whatever control had the focus already.

This is probably something really simple. The first place I thought to look was in the ControlStyle property, but the only thing I can see in the helpfile about keyboard input is csNoStdEvents, which disables it, and my control doesn't have that. So what do I need to do to make it so my control can receive input focus?

Mason Wheeler
  • 82,511
  • 50
  • 270
  • 477

5 Answers5

8

A few things to try:

  • On MouseDown, call Windows.SetFocus(Handle). In my experience, the WinAPI function SetFocus often works better than the VCL's SetFocus method.
  • In response to the WM_GETDLGCODE message, reply with Message.Result := Message.Result or DLGC_WANTCHARS or DLGC_WANTARROWS or DLGC_WANTTAB or DLGC_WANTALLKEYS;
Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
  • Thanks. It was either accept yours or Lars's, because you both had the answer to putting SetFocus inside MouseDown, and that worked. I picked yours because of the WM_GETDLGCODE thing, which I also ended up needing since I need to trap the arrow keys specifically. – Mason Wheeler May 13 '10 at 18:53
  • Isn't it enough to ask for just `DLGC_WANTALLKEYS`? – David Heffernan Apr 19 '11 at 12:49
  • @Andreas Why not? My interpretation of the documentation is clearly wrong. – David Heffernan Apr 19 '11 at 12:51
  • 1
    @David: You have to ask Microsoft. All I know is that `DLGC_WANTARROWS or DLGC_WANTTAB or DLGC_WANTALLKEYS` is not the same thing as `DLGC_WANTALLKEYS`. Of course, from a mathematical point of view (just look at the numerical values), this is trivial, but the OS also treats these two values differently. So, no, you need to add tab and arrows separately. See http://stackoverflow.com/questions/5070573/how-do-i-make-my-custom-treeview-accept-the-enter-key for instance. – Andreas Rejbrand Apr 19 '11 at 12:55
  • @Andreas Thanks. As I happens I only want `DLGC_WANTARROWS` but I always like to understand what I'm doing, even if such enlightenment is only ever fleeting! – David Heffernan Apr 19 '11 at 12:58
5

Could it be as simple as calling SetFocus on mouse down?

procedure TYourCustomControl.MouseDown(Button: TMouseButton; Shift: TShiftState; X: Integer; Y: Integer);
begin
  inherited;

  if CanFocus then
    SetFocus;
end;
Lars Truijens
  • 42,837
  • 6
  • 126
  • 143
2

Do you have WS_TABSTOP set? You don't have input focus without that, I believe. But this is based on a recollection from nearly 10 years ago, when I was writing my own syntax-highlighting code editor, for which I have long since lost the source.

{TWinControl.}TabStop := True; ought to do. A quick test app with a do-nothing component derived from TWinControl and displaying a dialog for key events seems to show that it makes all the difference.

Barry Kelly
  • 41,404
  • 5
  • 117
  • 189
1

I've checked the code for my control and I can't see anything that might stop this working. Are you calling "inherited" in the Create procedure?

I do handle the following, but nothing special:

procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
procedure WMKillFocus(var Message: TWMKillFocus); message WM_KILLFOCUS;
procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;

procedure KeyDown(var Key: Word; Shift: TShiftState); override;
mj2008
  • 6,647
  • 2
  • 38
  • 56
0

Is the keystroke available at form level? That is, is KeyPreview turned on, and can you see the keystroke in the form's OnKeypress event? You can follow it from there in the debugger. Is the control (as Dan indicated) suitable for keyboard input? For instance, a TLabel, although it displays text, is a graphical control.