Keyboard

Beeping when <ENTER> is pressed

From: "Paul Motyer" <paulm@linuxserver.pccity.com.au>


procedure TForm1.EditKeyPress(Sender: TObject; var Key:Char);
begin
if Key = Chr(VK_RETURN) then
        begin
        Perform(WM_NEXTDLGCTL,0,0);
        key:= #0;
        end;
end;

Disable alt-tab and ctrl+esc keys

From: m.weber@public.ndh.com (Meik Weber)


procedure TurnSysKeysOff;
var
  OldVal : LongInt;
begin
  SystemParametersInfo (97, Word (True), @OldVal, 0)
end;

procedure TurnSysKeysBackOn;
var
  OldVal : LongInt;
begin
  SystemParametersInfo (97, Word (False), @OldVal, 0)
end;

How to detect arrow keys?

From: Mark Pritchard <pritchma@ozemail.com.au>

Use the KeyDown or KeyUp events, and test for VK_LEFT, VK_RIGHT etc.

Hooking keyboard

From: ilcrwfrd@aracnet.com (Iman L. Crawford)

I've seen several posts on how to hook the key board. Here's some old code I've dug up (can't remember where It came from).


library Sendkey;

uses
 SysUtils, WinTypes, WinProcs, Messages, Classes, KeyDefs;

type
  { Error codes }
  TSendKeyError = (sk_None, sk_FailSetHook, sk_InvalidToken, sk_UnknownError);

  { exceptions }
  ESendKeyError = class(Exception);
  ESetHookError = class(ESendKeyError);
  EInvalidToken = class(ESendKeyError);

  { a TList descendant that know how to dispose of its contents }
  TMessageList = class(TList)
  public
    destructor Destroy; override;
  end;

destructor TMessageList.Destroy;
var
  i: longint;
begin
  { deallocate all the message records before discarding the list }
  for i := 0 to Count - 1 do
    Dispose(PEventMsg(Items[i]));
  inherited Destroy;
end;

var
  { variables global to the DLL }
  MsgCount: word;
  MessageBuffer: TEventMsg;
  HookHandle: hHook;
  Playing: Boolean;
  MessageList: TMessageList;
  AltPressed, ControlPressed, ShiftPressed: Boolean;
  NextSpecialKey: TKeyString;

function MakeWord(L, H: Byte): Word;
{ macro creates a word from low and high bytes }
inline(
  $5A/            { pop dx }
  $58/            { pop ax }
  $8A/$E2);       { mov ah, dl }

procedure StopPlayback;
{ Unhook the hook, and clean up }
begin
  { if Hook is currently active, then unplug it }
  if Playing then
    UnhookWindowsHookEx(HookHandle);
  MessageList.Free;
  Playing := False;
end;

function Play(Code: integer; wParam: word; lParam: Longint): Longint; export;
{ This is the JournalPlayback callback function.  It is called by Windows }
{ when Windows polls for hardware events.  The code parameter indicates what }
{ to do. }
begin
  case Code of

    hc_Skip: begin
    { hc_Skip means to pull the next message out of our list. If we }
    { are at the end of the list, it's okay to unhook the JournalPlayback }
    { hook from here. }
      { increment message counter }
      inc(MsgCount);
      { check to see if all messages have been played }
      if MsgCount >= MessageList.Count then
        StopPlayback
      else
      { copy next message from list into buffer }
      MessageBuffer := TEventMsg(MessageList.Items[MsgCount]^);
      Result := 0;
    end;

    hc_GetNext: begin
    { hc_GetNext means to fill the wParam and lParam with the proper }
    { values so that the message can be played back.  DO NOT unhook }
    { hook from within here.  Return value indicates how much time until }
    { Windows should playback message.  We'll return 0 so that it's }
    { processed right away. }
      { move message in buffer to message queue }
      PEventMsg(lParam)^ := MessageBuffer;
      Result := 0  { process immediately }
    end

    else
      { if Code isn't hc_Skip or hc_GetNext, then call next hook in chain }
      Result := CallNextHookEx(HookHandle, Code, wParam, lParam);
  end;
end;

procedure StartPlayback;
{ Initializes globals and sets the hook }
begin
  { grab first message from list and place in buffer in case we }
  { get a hc_GetNext before and hc_Skip }
  MessageBuffer := TEventMsg(MessageList.Items[0]^);
  { initialize message count and play indicator }
  MsgCount := 0;
  { initialize Alt, Control, and Shift key flags }
  AltPressed := False;
  ControlPressed := False;
  ShiftPressed := False;
  { set the hook! }
  HookHandle := SetWindowsHookEx(wh_JournalPlayback, Play, hInstance, 0);
  if HookHandle = 0 then
    raise ESetHookError.Create('Couldn''t set hook')
  else
    Playing := True;
end;

procedure MakeMessage(vKey: byte; M: word);
{ procedure builds a TEventMsg record that emulates a keystroke and }
{ adds it to message list }
var
  E: PEventMsg;
begin
  New(E);                                 { allocate a message record
}
  with E^ do begin
    Message := M;                         { set message field }
    { high byte of ParamL is the vk code, low byte is the scan code }
    ParamL := MakeWord(vKey, MapVirtualKey(vKey, 0));
    ParamH := 1;                          { repeat count is 1 }
    Time := GetTickCount;                 { set time }
  end;
  MessageList.Add(E);
end;

procedure KeyDown(vKey: byte);
{ Generates KeyDownMessage }
begin
  { don't generate a "sys" key if the control key is pressed (Windows quirk) }
  if (AltPressed and (not ControlPressed) and (vKey in [Ord('A')..Ord('Z')])) or
     (vKey = vk_Menu) then
    MakeMessage(vKey, wm_SysKeyDown)
  else
    MakeMessage(vKey, wm_KeyDown);
end;

procedure KeyUp(vKey: byte);
{ Generates KeyUp message }
begin
  { don't generate a "sys" key if the control key is pressed (Windows quirk) }
  if AltPressed and (not ControlPressed) and (vKey in [Ord('A')..Ord('Z')]) then
    MakeMessage(vKey, wm_SysKeyUp)
  else
    MakeMessage(vKey, wm_KeyUp);
end;

procedure SimKeyPresses(VKeyCode: Word);
{ This function simulates keypresses for the given key, taking into }
{ account the current state of Alt, Control, and Shift keys }
begin
  { press Alt key if flag has been set }
  if AltPressed then
    KeyDown(vk_Menu);
  { press Control key if flag has been set }
  if ControlPressed then
    KeyDown(vk_Control);
  { if shift is pressed, or shifted key and control is not pressed... }
  if (((Hi(VKeyCode) and 1) <> 0) and (not ControlPressed)) or ShiftPressed then
    KeyDown(vk_Shift);    { ...press shift }
  KeyDown(Lo(VKeyCode));  { press key down }
  KeyUp(Lo(VKeyCode));    { release key }
  { if shift is pressed, or shifted key and control is not pressed... }
  if (((Hi(VKeyCode) and 1) <> 0) and (not ControlPressed)) or ShiftPressed then
    KeyUp(vk_Shift);      { ...release shift }
  { if shift flag is set, reset flag }
  if ShiftPressed then begin
    ShiftPressed := False;
  end;
  { Release Control key if flag has been set, reset flag }
  if ControlPressed then begin
    KeyUp(vk_Control);
    ControlPressed := False;
  end;
  { Release Alt key if flag has been set, reset flag }
  if AltPressed then begin
    KeyUp(vk_Menu);
    AltPressed := False;
  end;
end;

procedure ProcessKey(S: String);
{ This function parses each character in the string to create the message list }
var
  KeyCode: word;
  Key: byte;
  index: integer;
  Token: TKeyString;
begin
  index := 1;
  repeat
    case S[index] of

      KeyGroupOpen : begin
      { It's the beginning of a special token! }
        Token := '';
        inc(index);
        while S[index] <> KeyGroupClose do begin
          { add to Token until the end token symbol is encountered }
          Token := Token + S[index];
          inc(index);
          { check to make sure the token's not too long }
          if (Length(Token) = 7) and (S[index] <> KeyGroupClose) then
            raise EInvalidToken.Create('No closing brace');
        end;
        { look for token in array, Key parameter will }
        { contain vk code if successful }
        if not FindKeyInArray(Token, Key) then
          raise EInvalidToken.Create('Invalid token');
        { simulate keypress sequence }
        SimKeyPresses(MakeWord(Key, 0));
      end;

      AltKey : begin
        { set Alt flag }
        AltPressed := True;
      end;

      ControlKey : begin
        { set Control flag }
        ControlPressed := True;
      end;

      ShiftKey : begin
        { set Shift flag }
        ShiftPressed := True;
      end;

      else begin
      { A normal character was pressed }
        { convert character into a word where the high byte contains }
        { the shift state and the low byte contains the vk code }
        KeyCode := vkKeyScan(MakeWord(Byte(S[index]), 0));
        { simulate keypress sequence }
        SimKeyPresses(KeyCode);
      end;
    end;
    inc(index);
  until index > Length(S);
end;

function SendKeys(S: String): TSendKeyError; export;
{ This is the one entry point.  Based on the string passed in the S  }
{ parameter, this function creates a list of keyup/keydown messages, }
{ sets a JournalPlayback hook, and replays the keystroke messages.   }
var
  i: byte;
begin
  try
    Result := sk_None;                   { assume success }
    MessageList := TMessageList.Create;  { create list of messages }
    ProcessKey(S);                       { create messages from string
}
    StartPlayback;                       { set hook and play back messages }
  except
    { if an exception occurs, return an error code, and clean up }
    on E:ESendKeyError do begin
      MessageList.Free;
      if E is ESetHookError then
        Result := sk_FailSetHook
      else if E is EInvalidToken then
        Result := sk_InvalidToken;
    end
    else
      { Catch-all exception handler ensures than an exception }
      { doesn't walk up into application stack }
      Result := sk_UnknownError;
  end;
end;

exports
  SendKeys index 1;

begin
end

Simulating ButtonDown

From: "James D. Rofkar" <jim_rofkar%lotusnotes1@instinet.com>

Paulo Oliveira wrote: > > I have a set of buttons,(caption ='0'..'9') and I'd like to simulate the down position of the button, when the user presses the corresponding key. I.e. if user presses key '1' the button goes down on screen. How can I do this, without a new Tbutton component?

No problem Paulo:

You'll probably want to be using 10 TSpeedButton controls, or an array of them, since this button provides a "Down" property. Anyhow, set the "KeyPreview" property of your main form to "True". Then, in your "OnKeyDown" event handler, write something like this...


     case Key of
        VK_NUMPAD0: btn0.Down := True;
        VK_NUMPAD1: btn1.Down := True;
        VK_NUMPAD2: btn2.Down := True;
        VK_NUMPAD3: btn3.Down := True;
        VK_NUMPAD4: btn4.Down := True;
        VK_NUMPAD5: btn5.Down := True;
        VK_NUMPAD6: btn6.Down := True;
        VK_NUMPAD7: btn7.Down := True;
        VK_NUMPAD8: btn8.Down := True;
        VK_NUMPAD9: btn9.Down := True;
        end;

And, in your "OnKeyUp" event handler, write something like...


     case Key of
        VK_NUMPAD0: btn0.Down := False;
        VK_NUMPAD1: btn1.Down := False;
        VK_NUMPAD2: btn2.Down := False;
        VK_NUMPAD3: btn3.Down := False;
        VK_NUMPAD4: btn4.Down := False;
        VK_NUMPAD5: btn5.Down := False;
        VK_NUMPAD6: btn6.Down := False;
        VK_NUMPAD7: btn7.Down := False;
        VK_NUMPAD8: btn8.Down := False;
        VK_NUMPAD9: btn9.Down := False;
        end;

You'll want to experiment with the "AllowAllUp" property and the "GroupIndex" property to get the button response/effect you like.

Again, an array of TSpeedButtons would be the most elegant solution to this problem, since you could use the VK_ constant as the index, and make both event handlers a one line call to Button[VK_x].Down := True {or False}.

How? ENTER key instead of TAB

Here is something I picked up off Compuserve that should help.

Simon Callcott CIS: 100574,1034

Using the &tl;Enter≷ key like a &tl;Tab≷ key with Delphi Controls

The example code supplied here demonstrates how to trap the &tl;Enter≷ key and the cursor keys to provide better data entry processing.

The trick is to overide the Keypress and KeyDown events so that they process the keys the way you want. In the examples supplied I have used the &tl;Enter≷ key to move to the next control (like the &tl;Tab≷ key) and the cursor Up and Down keys to move to the previous and next controls respectively.

The Edit and EBEdit use the cursor keys as stated above, but the Combobox and the Listbox use Shift-Up and Shift-Down instead so as not to interfere with existing functionality.

The Grid control uses the &tl;Enter≷ key to move between fields, however it will not move from the last field of the last row. It is very easy to make it exit the grid at this point if you need to.

The method used to move to the next/previous control is the Windows API call SendMessage which is used to dispatch a WM_NEXTDLGCTL to the form the controls are children to. Delphi provides a function called GetParentForm to get the handle of the parent form of the control.

These simple extensions can be expanded to respond to almost any keyboard event, and I think using this method is less trouble than trapping keys in the forms OnKey events (using keypreview:=true).

Feel free to use the code as you wish, but if you discover something new please let me in on it!


{
  Edit control that reponds as if the &tl;Tab≷ key has been pressed when an
  &tl;Enter≷ key is pressed, moving to the next control.
  Very simple extension to the KeyPress event, this technique should work
  with TDBedit as well, Useful for data entry type apps.
  Less trouble than using the Keypreview function of the form to do the same
  thing.

  Please Use Freely.

  Simon Callcott  CIS: 100574, 1034
}


unit Entedit;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls;

type
  TEnterEdit = class(TEdit)
  private

  protected

    procedure KeyPress(var Key: Char); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;

  public

  published

  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TEnterEdit]);
end;

procedure TEnterEdit.KeyPress(var Key: Char);
var
   MYForm: TForm;
begin

   if Key = #13 then
   begin
       MYForm := GetParentForm( Self );
       if not (MYForm = nil ) then
           SendMessage(MYForm.Handle, WM_NEXTDLGCTL, 0, 0);
       Key := #0;
   end;

   if Key &tl;≷ #0 then inherited KeyPress(Key);

end;

procedure TEnterEdit.KeyDown(var Key: Word; Shift: TShiftState);
var
   MYForm: TForm;
   CtlDir: Word;
begin

   if (Key = VK_UP) or (Key = VK_DOWN) then
   begin
       MYForm := GetParentForm( Self );
       if Key = VK_UP then CtlDir := 1
       else CtlDir :=0;
       if not (MYForm = nil ) then
           SendMessage(MYForm.Handle, WM_NEXTDLGCTL, CtlDir, 0);
   end
   else inherited KeyDown(Key, Shift);

end;

end.

Solution 2

Q. "Is there a way to use the return key for data entry, instead of tab or the mouse?"

Ken Hale khale@oro.net Compuserve: 74633.2474

A. Use this code for an Edit's OnKeyPress event.
    procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
    begin
      If Key = #13 Then
      Begin
        SelectNext(Sender as tWinControl, True, True );
        Key := #0;
      end;
    end;

This causes Enter to behave like tab. Now, select all controls on the form you'd like to exhibit this behavior (not Buttons) and go to the Object Inspector and set their OnKeyPress handler to EditKeyPress. Now, each control you selected will process Enter as Tab. If you'd like to handle this at the form (as opposed to control) level, reset all the controls OnKeyPress properties to blank, and set the _form_'s OnKeyPress property to EditKeyPress. Then, change Sender to ActiveControl and set the form's KeyPreview property to true:


    procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
    begin
      If Key = #13 Then
      begin
        SelectNext(ActiveControl as tWinControl, True, True );
        Key := #0;
      end;
    end;

This will cause each control on the form (that can) to process Enter as Tab.

Caps Lock (and others like it) [NEW]

From: m.a.vaughan@larc.nasa.gov (Mark Vaughan)

]-How Do I turn them on? (IN A DELPHI PROGRAM OF COURSE) i have tried and asked around
try this...
procedure TMyForm.Button1Click(Sender: TObject);
  Var
    KeyState  :  TKeyboardState;
  begin
    GetKeyboardState(KeyState);
    if (KeyState[VK_NUMLOCK] = 0) then
      KeyState[VK_NUMLOCK] := 1
    else
      KeyState[VK_NUMLOCK] := 0;
    SetKeyboardState(KeyState);
  end;

for caps lock substitute VK_CAPITAL for VK_NUMLOCK.
Please email me and tell me if you liked this page.

This page has been created with