Link to home
Start Free TrialLog in
Avatar of enigmasolutions

asked on

Interpret ASCII Char from Word variable in OnKeyDown event

I have a grid and I am trapping the OnKeyDown event.

I am trying to detect when the user either hits the Insert key or the letter A or the backslash key.

So in my OnKeyDown evnet I have the code

if Key=VK_Insert then
  Showmessage('Insert key was hit - this works!!!');
if Char(Key)='A' then
  Showmessage('A key was hit - this works!!!');
if Char(Key)='\' then
  Showmessage('Backslash key was hit');

Why does the test for the backslash key fail?

I note that when I hit the backslash then key=220 but Ord('\')=92.  Strange!

I prefer to use OnKeyDown because it is the first event and I can set the Key:=#0 to kill the keystroke and I can test virtual keys.  I can't do this with OnKeyPress.
Avatar of Emmanuel PASQUIER
Flag of France image

Link to home
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Also, you should say
  if Key=ord('A')
instead of
  if Char(Key)='A'

because otherwise it would ignore the top half of the word if it's not an ASCII character code (or maybe throw an exception if you have range-checking on, I'm not sure about that).

But that isn't your problem here.
Avatar of enigmasolutions



Good answer, I get the point.

Actually I started hunting through StdCtrls.pas and Controls.pas to see how Delphi (or Windows) converts keys into characters.  It got ugly fast!

The bottom line is... too hard.  I will use BOTH events for my purposes.

epasquier, you get the points.

But, for the record, I bet there would be a Windows API call that could convert a key into a char.  
I will leave this question open for a day or two to see if anyone works it out.

i wanted to trap the backslash and convert it to an Insert key.

Thats why I wanted to use OnKeyDown
Link to home
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
It worked but I couldn't trick my application into thinking the Insert key was pressed.

Thanks for your input.

Although I ended up using my own solution.
you can emulate Key stroke at your application form level :
procedure PostKeyExHWND(hWindow: HWnd; key: Word; const shift: TShiftState=[]; specialkey: Boolean=False);
 * Procedure PostKeyEx
 * Parameters:
 *  hWindow: target window to be send the keystroke
 *  key    : virtual keycode of the key to send. For printable
 *           keys this is simply the ANSI code (Ord(character)).
 *  shift  : state of the modifier keys. This is a set, so you
 *           can set several of these keys (shift, control, alt,
 *           mouse buttons) in tandem. The TShiftState type is
 *           declared in the Classes Unit.
 *  specialkey: normally this should be False. Set it to True to
 *           specify a key on the numeric keypad, for example.
 *           If this parameter is true, bit 24 of the lparam for
 *           the posted WM_KEY* messages will be set.
 * Description:
 *  This procedure sets up Windows key state array to correctly
 *  reflect the requested pattern of modifier keys and then posts
 *  a WM_KEYDOWN/WM_KEYUP message pair to the target window. Then
 *  Application.ProcessMessages is called to process the messages
 *  before the keyboard state is restored.
 * Error Conditions:
 *  May fail due to lack of memory for the two key state buffers.
 *  Will raise an exception in this case.
 * NOTE:
 *  Setting the keyboard state will not work across applications
 *  running in different memory spaces on Win32 unless AttachThreadInput
 *  is used to connect to the target thread first.
 *Created: 02/21/96 16:39:00 by P. Below
  TBuffers = array [0..1] of TKeyboardState;
  pKeyBuffers: ^TBuffers;
  lParam: LongInt;

  procedure check(b:Boolean);
   if Not b
    then ShowMessage(IntToStr(GetLastError));
  (* check if the target window exists *)
  if IsWindow(hWindow) then
    (* set local variables to default values *)
    pKeyBuffers := nil;
    lParam := MakeLong(0, MapVirtualKey(key, 0));

    (* modify lparam if special key requested *)
    if specialkey then
      lParam := lParam or $1000000;

    (* allocate space for the key state buffers *)
      (* Fill buffer 1 with current state so we can later restore it.
         Null out buffer 0 to get a "no key pressed" state. *)
      FillChar(pKeyBuffers^[0], SizeOf(TKeyboardState), 0);

      (* set the requested modifier keys to "down" state in the buffer*)
      if ssShift in shift then
        pKeyBuffers^[0][VK_SHIFT] := $80;
      if ssAlt in shift then
        (* Alt needs special treatment since a bit in lparam needs also be set *)
        pKeyBuffers^[0][VK_MENU] := $80;
        lParam := lParam or $20000000;
      if ssCtrl in shift then
        pKeyBuffers^[0][VK_CONTROL] := $80;
      if ssLeft in shift then
        pKeyBuffers^[0][VK_LBUTTON] := $80;
      if ssRight in shift then
        pKeyBuffers^[0][VK_RBUTTON] := $80;
      if ssMiddle in shift then
        pKeyBuffers^[0][VK_MBUTTON] := $80;

      (* make out new key state array the active key state map *)
      (* post the key messages *)
      if ssAlt in Shift then
        check(PostMessage(hWindow, WM_SYSKEYDOWN, key, lParam));
        check(PostMessage(hWindow, WM_SYSKEYUP, key, Cardinal(lParam) or $C0000000));
        check(PostMessage(hWindow, WM_KEYDOWN, key, lParam));
        check(PostMessage(hWindow, WM_KEYUP, key, Cardinal(lParam) or $C0000000));
      (* process the messages *)

      (* restore the old key state map *)
      (* free the memory for the key state buffers *)
      if pKeyBuffers <> nil then
    end; { If }
end; { PostKeyEx }

Open in new window


That completes the topic all round.

Thank you.
If those answers satisfied you much, you can consider raising the point value ;o)