how to simplify this

cebasso
cebasso used Ask the Experts™
on
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
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
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
NOTE:
Sounds like you need the virtual key code constant represented in your TShiftstate variable. Using integer(ssShift), integer(ssAlt), etc. won't work as it will return the ordinal value of the set item. i.e. Shift will return 0, alt will return 1, etc. I'm pretty sure this is not what you want.

if you need the virtual key value, use something like this:
var kc: integer;
...
kc:= 0;
if ssShift in AShiftState then kc:= kc OR VK_SHIFT;
if ssCtrl in AShiftState then kc:= kc OR VK_CONTROL;
if ssALT in AShiftState then kc:= kc OR VK_MENU;

if you need to use it for mouse messages, use something like this:
if ssShift in AShiftState then kc:= kc OR MK_SHIFT;
if ssCtrl in AShiftState then kc:= kc OR MK_CONTROL;
//alt not supported in mouse message, you would have to use something like GetKeyState to determine it

Emmanuel PASQUIERFreelance Project Manager
Top Expert 2010

Commented:
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

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial