Link to home
Start Free TrialLog in
Avatar of cebasso
cebassoFlag for United States of America

asked on

how to simplify this

Hello,

Shift: TShiftState;

TShiftState = set of (ssShift, ssAlt, ssCtrl,
    ssLeft, ssRight, ssMiddle, ssDouble);

Ok, but its not compatible with others languages like C++
So i need to make it compatible in my Param, like

TMyParam = packed record
  kbShift: DWORD;
end;

I'm doing in this way...

if ssShift in Shift then
kbShift := Integer(ssShift);
if ssAlt in Shift then
kbShift := kbShift or Integer(ssAlt);
if ssCtrl in Shift then
kbShift := kbShift or Integer(ssCtrl);
//for each type i need to do it, but maybe a loop can do this?
...

So i can call the reverse way like

if ssCtrl in kbShift then
...

But, i think there is a better way to do that... i tried to loop but no success

kbShift := -1;
for i := Low(TShiftState) to High(TShiftState) do
if (TShiftState(i) in Shift) then
kbShift := kbShift or TShiftState(i);
...

not work! hehe

Some idea?

Regards,
Carlos
Avatar of javierjat
javierjat
Flag of Argentina image

I dont know wich version of Delphi you are using, but there is some option on Delphi 2007.

See tha link.

http://delphi.about.com/od/delphitips2007/qt/for_in_set.htm
ASKER CERTIFIED SOLUTION
Avatar of Pierre Cornelius
Pierre Cornelius
Flag of South Africa image

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
PierreC is right about the virtual key codes bitmask. For this specific topic you'd better stick to windows constants, and his way is the only way to do that correctly.

Now, you just hinted an approach that might be useful for other needs, that is : how to translate a set into a numeric value for use in other languages
Here is how to do so
the principle will work for all kind of sets, with one limitation : no more than 32 possible values for the set elements (64 when Delphi will allow for 64bits compiling).
but you'll need specific translator functions for each kind
Type
 TMyEnumType=(ev1,ev2,ev3,ev4);
 TMyEnumSet=Set of TMyEnumType;

function EnumSetToNumeric(es:TMyEnumSet):Cardinal;
Var
 ev:TMyEnumType;
begin
 Result:=0;
 for ev:=Low(TMyEnumType) to High(TMyEnumType) do
  if ev in es
   Then Result:=Result Or (1 SHL Integer(ev));
// The trick here is to use the binary SHIFT operator
// to translate 0=>1 , 1=>2 , 2=>4 etc...
end;

function NumericToEnumSet(Num:Cardinal):TMyEnumSet;
Var
 ev:TMyEnumType;
begin
 Result:=[];
 for ev:=Low(TMyEnumType) to High(TMyEnumType) do
  if (Num And (1 SHL Integer(ev)))>0
   Then Result:=Result+[ev];
end;

// this is just to format a value in binary string representation
function IntToBin ( value: Cardinal; digits: integer ): string;
begin
 result := StringOfChar ( '0', digits ) ;
  while value > 0 do begin
   if ( value and 1 ) = 1 then result [ digits ] := '1';
   dec ( digits ) ;
   value := value shr 1;
  end;
end;

// Demo : 
 ShowMessage(
  IntToBin( EnumSetToNumeric([ev2,ev4]) ,
            Integer(High(TMyEnumType))+1 // calculate the maximum significant bits
          )
 );

Open in new window

Hi cebasso,

see if the following code helps you:

var
  kbShift: DWORD;
  ss: TShiftState;


procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  { Copy ShiftState Bits to kbShift }
  CopyMemory(@kbShift, @Shift, SizeOf(Shift));
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  { Copy kbShift bits to ss (TShiftState} }
  CopyMemory(@ss, @kbShift, SizeOf(ss));
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  { Test against ss }
  if ssCtrl in ss then
    showmessage('Control');
end;
Try this:

kbShift:=PByte(@Shift)^

Regards,
  Joan-Ramon