How do I use low-level 8 bit flags as conditionals?
Asked Answered
D

5

6

In my keyboard hook, each keypress gets a flag that states if it was injected or not. http://msdn.microsoft.com/en-us/library/ms644967(VS.85).aspx

I've distilled a KBDLLHOOKSTRUCT from the lParam. I can access kbd.flags.XXX. I just don't know how to convert this 8bit flag into an if (injected) {... type conditional that I know how to use.

If one of you smart computer-science types would help me out I'd really appreciate it.

    private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        KBDLLHOOKSTRUCT kbd = new KBDLLHOOKSTRUCT();
        Marshal.PtrToStructure(lParam, kbd);

        //if (injected) {...

Cheers!

Discovery answered 16/1, 2010 at 1:16 Comment(0)
B
7

You need to bitwise-and it with a mask. For example, the injected bit is bit 4. That's binary 00010000, hex 0x10. So you bitwise-and it with 0x10, and see if anything's left:

bool isInjected = ((kbd.flags & 0x10) != 0);

(Of course, as per Andrew's answer, it would be a good idea to define a LLKHF_INJECTED constant for this rather than including the hex value directly in your code!)

Becerra answered 16/1, 2010 at 1:22 Comment(8)
This (and others here that I've tried) is throwing a A first chance exception of type 'System.ArgumentException' occurred in foofoo.exe Seems to be messing up the previous keyboard hook code I had as well. What gives? It's also not compiling unless I add parentheses: bool isInjected = ((kbd.flags & LLKHF_INJECTED) != 0);... is that changing the code?Discovery
The extra parens aren't changing the code -- they just fix my silly precedence error. Answer updated.Becerra
No idea where the ArgumentException is coming from, as you are only reading from the flags field. Is an exception actually being thrown or is it just a debug message about a first-chance exception (i.e. caught and handled internally within the CLR)? If the former, what's the stack trace of the exception? Do you still get it if you just Console.WriteLine(kbd.flags)? Once you've looked into these, you might want to create a separate question because it's probably not related to the pure bit-twiddling question "how do I use bitwise flags in C#?", more likely a marshalling issue.Becerra
Also, you'll probably need to post your KBDLLHOOKSTRUCT declaration for us to figure out the exception and hook code issue.Becerra
ooo I think I figured out where it is... I have that KBD struct declaration and PtrToStruct Marshalling up in the original question, and then later have int trueKeyPressed = Marshal.ReadInt32(lParam);... I think the two Marshal commands on lParam are messing each other up or something. Does that make sense? Removing the first one makes the second one work again. Anyway, I'll try to figure this out later tonight. Thanks!Discovery
Hmm, I don't see why a Marshal.ReadInt32(lParam) would mess up the Marshal.PtrToStructure. But you can't argue with a fix that works! *grin* Besides, the ReadInt32 is redundant once you've read the whole block into a struct: you can get the value direct from the struct. Congratulations on figuring it out!Becerra
Yeah, it's weird... it's not that it's like overwriting the lParam or anything, but rather that the statement Marshal.PtrToStructure(lParam, kbd); is what's causing the error. If I have that line in there, 2 exceptions are thrown per key press and none of my event code that the keyboard hook is feeding is executed at all.Discovery
New question for this problem: #2080368Discovery
S
11

.NET supports this with the [Flags] attribute:

[Flags]
enum KbdHookFlags {
  Extended = 0x01,
  Injected = 0x10,
  AltPressed = 0x20,
  Released = 0x80
}

Sample usage:

  KBDLLHOOKSTRUCT info = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
  if ((info.flags & KbdHookFlags.Released) == KbdHookFlags.Released) {
    // Key was released
    // etc..
  }
Szymanowski answered 16/1, 2010 at 1:42 Comment(0)
B
7

You need to bitwise-and it with a mask. For example, the injected bit is bit 4. That's binary 00010000, hex 0x10. So you bitwise-and it with 0x10, and see if anything's left:

bool isInjected = ((kbd.flags & 0x10) != 0);

(Of course, as per Andrew's answer, it would be a good idea to define a LLKHF_INJECTED constant for this rather than including the hex value directly in your code!)

Becerra answered 16/1, 2010 at 1:22 Comment(8)
This (and others here that I've tried) is throwing a A first chance exception of type 'System.ArgumentException' occurred in foofoo.exe Seems to be messing up the previous keyboard hook code I had as well. What gives? It's also not compiling unless I add parentheses: bool isInjected = ((kbd.flags & LLKHF_INJECTED) != 0);... is that changing the code?Discovery
The extra parens aren't changing the code -- they just fix my silly precedence error. Answer updated.Becerra
No idea where the ArgumentException is coming from, as you are only reading from the flags field. Is an exception actually being thrown or is it just a debug message about a first-chance exception (i.e. caught and handled internally within the CLR)? If the former, what's the stack trace of the exception? Do you still get it if you just Console.WriteLine(kbd.flags)? Once you've looked into these, you might want to create a separate question because it's probably not related to the pure bit-twiddling question "how do I use bitwise flags in C#?", more likely a marshalling issue.Becerra
Also, you'll probably need to post your KBDLLHOOKSTRUCT declaration for us to figure out the exception and hook code issue.Becerra
ooo I think I figured out where it is... I have that KBD struct declaration and PtrToStruct Marshalling up in the original question, and then later have int trueKeyPressed = Marshal.ReadInt32(lParam);... I think the two Marshal commands on lParam are messing each other up or something. Does that make sense? Removing the first one makes the second one work again. Anyway, I'll try to figure this out later tonight. Thanks!Discovery
Hmm, I don't see why a Marshal.ReadInt32(lParam) would mess up the Marshal.PtrToStructure. But you can't argue with a fix that works! *grin* Besides, the ReadInt32 is redundant once you've read the whole block into a struct: you can get the value direct from the struct. Congratulations on figuring it out!Becerra
Yeah, it's weird... it's not that it's like overwriting the lParam or anything, but rather that the statement Marshal.PtrToStructure(lParam, kbd); is what's causing the error. If I have that line in there, 2 exceptions are thrown per key press and none of my event code that the keyboard hook is feeding is executed at all.Discovery
New question for this problem: #2080368Discovery
M
2

Use the bitwise AND operator to check if the relevant bit is set in the flags variable:

if (kbd.flags & LLKHF_INJECTED)
{
    ...
}
Multiform answered 16/1, 2010 at 1:22 Comment(1)
Won't compile. In C#, the if expression has to be a bool; kbd.flags & LLKHF_INJECTED is an int. (It would work in C/C++ though.)Becerra
T
2

You need to check that the bitflag is set. Easy to do with bitwise operations. The documentation states that bit four is used for the injected flag, bit 4 (or 5 if you count the first bit as 1) equals 16, so you can do a bitwise AND against the flag.

if ((kbd.flags & 16) == 16)
{
    FireTorpedoes();
}

You can learn more about bitwise operations here:

Tum answered 16/1, 2010 at 1:23 Comment(2)
Bit 4 equals 16. (Bit 4 is the fifth bit, counting from 0 to 7.)Aylesbury
Good call, didn't see that they were zero indexed in the docs.Tum
D
2

The reason everyone is saying to use a bitwise & and then compare to zero or the flag:

  0111 1000        // kbd.flags 
& 0001 0000        // Injected
          =
  0001 0000        // (!= 0 or ==Injected)
Dehisce answered 16/1, 2010 at 9:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.