Link to home
Start Free TrialLog in
Avatar of vaguemax
vaguemax

asked on

Keboard input

How can I tell the difference between when the user presses the left shift key as opposed to the right shift key.
Avatar of ahalya
ahalya
Flag of Canada image

Use GetkeyboardState WinAPI.

here is part of the help file:

This gives the status of the SHIFT, CTRL, or ALT keys without distinguishing between left and right. An application can also use the following virtual-key code constants as indices to distinguish between the left and right instances of those keys:

VK_LSHIFT      VK_RSHIFT
VK_LCONTROL      VK_RCONTROL
VK_LMENU      VK_RMENU

Avatar of vaguemax
vaguemax

ASKER

Key codes don't go with getkeyboardstate, they go with getKeyState(Version 1 does not have VK_LSHIFT)  
getkeyboardstate does return an array of values but I can't tell which ones go with the shift & control keys
This sample is from the Borland Technical help file:


Title      : Handling Special Keys and Direct Memory AccessProduct      
{
Toggle Controls: -- allow you to check to see if a certain key
was pressed or to turn off or on a certain key, such as
activating the Num-Lock key.

MemW[0000:$0417]
number   bit
    1     0  - Right Shift
    2     1  - Left Shift
    4     2  - Ctrl
    8     3  - Alt
   16     4  - Scroll Lock
   32     5  - Num Lock
   64     6  - Caps Lock
  128     7  - Insert
  256     8  -
  512     9  -
 1024    10  - Sys Req
 2048    11  -
 4096    12  - Scroll Lock Pressed

 8192    13  - Num Lock Pressed
16384    14  - Caps Lock Pressed
32768    15  - Insert Pressed

Other memory locations that can be accessed to get/put
information.

Clock ticks: MemW[$0040:$006C] updates every 58ms.
Clear Key Buffer: MemW[0000:$041A] := MemW[0000:$041C].

Color Address: $B800:0000; Mono Address: $B000:0000.

Print Screen: inline ($CD/$05).
}

{ example }
program TrapAlt;
 Uses
   Dos, Crt;
 Var
   i:char;
 Function alt:boolean;
 Begin

   if MemW[0000:$0417] and 8<>0 then
     begin
      alt:=true;
      repeat
       if keypressed then
         begin
           alt:=false;
           exit;
         end;
      until MemW[0000:$0417] and 8=0;
     end
     else
      alt:=false;
  End;

Begin
 clrscr;
  repeat
   if keypressed then
     begin
       writeln('non alt');
       i:=readkey;
     end;
   if alt then writeln('Alt key pressed');
  until (i=#13);
End.
I don't want to use DOS mode functions.  They are rarely reliable.
I also want to detect left and right CTRL keys
procedure TForm1.Button1Click(Sender: TObject);
var FKey: TkeyboardState;
begin
GetkeyboardState(FKey);
if (FKey[VK_LSHIFT]=128) or (FKey[VK_LSHIFT]=129) then
  showmessage('Left Shift is pressed now');

if (FKey[VK_RSHIFT]=128) or (FKey[VK_RSHIFT]=129) then
  showmessage('Right Shift is pressed now');

if (FKey[VK_LCONTROL]=128) or (FKey[VK_LCONTROL]=129) then
  showmessage('Left Control is pressed now');

if (FKey[VK_RCONTROL]=128) or (FKey[VK_RCONTROL]=129) then
  showmessage('Right Control is pressed now');

end;

VK_LSHIFT, VK_RSHIFT, VK_LCONTROL and VK_RCONTROL are not available for Delphi 1.0.  This may work if I could get the Hex codes for these constants.
I have tried a routine that on keypress did getkeyboardstate, then looped through all of the positions.  The only one with a high order bit was 16.  This occurs with both left and right shift keys.
ASKER CERTIFIED SOLUTION
Avatar of ronit051397
ronit051397

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
It works, but I don't know what its doing.  I am having trouble integrating this into my existing program.  Probably because I'm using the KeyDown and KeyPress events.
This will not work with any other input control.

I don't understand the comment.
If you add a combobox or textbox onto the form this code does not execute, even with keypreview on.
The reason for this behavior is that when the focus is on a control that can be focused such as TEdit (not such as TLabel), then this control is receiving the keyboard messages and not the form. Notice that this code refers to the form's messages
only.(TForm.somthing...)
However, If you need to refer to these messages in the application level, that is to have the ability to handle any massages that are sent to your application, then write the
following code instead.
This code is using TApplication.something and is solving the 'focused controls' problem.

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure AppMessage(var Msg: TMsg; var Handled: Boolean);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}
procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
function Power(FBasis, FDegree: Word): LongInt;
begin
  Result:=Round(Exp(FDegree*Ln(FBasis)));
end;
begin
  with Msg do
  if Message=WM_KEYDOWN then
  begin
    if wParam=VK_CONTROL then
    begin
      if (lParam) and (Power(2,24))<>0 then
        showmessage('Right Control is pressed')
      else
        showmessage('Left Control is pressed')
    end;

    if wParam=VK_SHIFT then
    begin
      if (lParam) and (Power(2,18))<>0 then
        showmessage('Right Shift is pressed')
      else
        showmessage('Left Shift is pressed')
    end;
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Application.OnMessage := AppMessage;
end;

end.

I have tried using this code as well as several permutations and I can not get it to work at all.  The form does absoulutely nothing.  Probably a programmer density problem, but I cant help it.
This code is working. I tested it after I put several controls on the form. Test on a new form without extra code.
Now, This is very bizzar:
When you copy and paste the code as it is, the OnMessage event doesn't work at all, not just for this case, but for any other messages.
In order to get this to work, write (not copy and paste!!!) every thing that is needed from the above code, except the code inside the onMessage event, This code you can copy and paste.
This should work cause I tested it. Let me know weather it's working or not.
Probabely, sometimes when you copy and paste, some code is getting 'dirty'. Years ago, I have had the same problem with
Microsoft Access. I couldn't copy and paste and I had to rewrite the code.
I typed the code instead of copying and it works great now.  Thanks for the help.