LPARAM is a 32-bit integer. Each bit can be either set (1) or clear (0).
Using hexadecimal numbers is easier to deal with binary because it more closely resembles binary. 1 hex digit directly corresponds to 4 binary digits. Here's a quick chart of hex numbers and their binary equivalents:
HEX BINARY
================
0x01 00000001
0x02 00000010
0x04 00000100
0x08 00001000
0x10 00010000
0x20 00100000
0x40 01000000
0x80 10000000
|
The "low" bit is the bit furthest to the right. That is "bit 0". Bit bit to the left of that is bit 1. To the left of that is bit 2, and so on.
Each bit has a "weight" of 2
n, where n is the bit number. So...
bit 0 has a weight of 2
0=1
bit 1 has a weight of 2
1=2
bit 2 has a weight of 2
2=4
bit 3 has a weight of 2
3=8
etc
HEX BIN
============
0x0 0000 (0)
0x1 0001 (1)
0x2 0010 (2)
0x3 0011 (2 + 1)
0x4 0100 (4)
0x5 0101 (4 + 1)
0x6 0110 (4 + 2)
0x7 0111 (4 + 2 + 1)
0x8 1000 (8)
0x9 1001 (8 + 1)
0xA 1010 (8 + 2)
0xB 1011 (8 + 2 + 1)
0xC 1100 (8 + 4)
0xD 1101 (8 + 4 + 1)
0xE 1110 (8 + 4 + 2)
0xF 1111 (8 + 4 + 2 + 1)
^^^^
||||
|||\___bit 0 (weight of 1)
|||
||\___bit 1 (weight of 2)
||
|\___bit 2 (weight of 4)
|
\___bit 3 (weight of 8)
|
So as you can see, the binary value of 0101 is a value of 5... because bits 0 and 2 are set. Which means the value is:
2
0 + 2
2
= 1 + 4
= 5
With that in mind... the binary operators AND (&), OR (|), and complement (~) are frequently used to pull out individual bits from a value. Each operation is performed on each bit in the values. See below for examples:
OR takes 2 bits, and if either one of them are set, the result is set. Otherwise the result is clear.
0 OR 0 = 0
0 OR 1 = 1
1 OR 0 = 1
1 OR 1 = 1
Therefore... 0x26 | 0x44 == 0x66 because:
0x26 = 00100110
0x44 = 01000100
OR ========
0x66 01100110
|
OR is frequently used to set specific bits, because any bit OR 1 will result in 1:
1 2 3 4 5 6 7 8 9
|
myval = myval | 0x04; // set bit 2
/* because:
myval = xxxxxxxx (can be anything)
0x04 = 00000100
OR ========
xxxxx1xx (x bits remain unchanged... bit 2 forced to be set)
*/
|
AND takes 2 bits, and if both one of them are set, the result is set. Otherwise the result is clear.
0 AND 0 = 0
0 AND 1 = 0
1 AND 0 = 0
1 AND 1 = 1
Therefore... 0x26 & 0x44 == 0x04 because:
0x26 = 00100110
0x44 = 01000100
AND ========
0x04 00000100
|
AND is frequently used to isolate bits you are interested in by forcing other bits to be clear.... because any bit AND 0 will result in 0:
1 2 3 4 5 6 7 8 9
|
myval = myval & 0x04; // isolate bit 2
/* because:
myval = xxxxxxxx (can be anything)
0x04 = 00000100
AND ========
00000x00 (bit 2 remains unchanged... all other bits forced to 0)
*/
|
COMPLEMENT takes 1 bit, and just flips it. So if it was clear, it is set, and if it was set, it is cleared.
~0 = 1
~1 = 0
Therefore... ~0x04 == 0xFB (assuming 8-bit value) because:
0x04 = 00000100
COMP ========
0xFB 11111011 (all bits flipped)
|
COMPLEMENT is frequently used with AND to clear specific bits. Kind of like the opposite of an OR operation:
1 2 3 4 5 6 7 8 9 10 11 12
|
myval = myval & ~0x04; // clear bit 2
/* because:
0x04 = 00000100
COMP ========
11111011
11111011
myval = xxxxxxxx
AND ========
xxxxx0xx (all bits unchanged except for bit 2, which is forced clear)
*/
|
This is why... when you use GetAsyncKeyState... you should always AND with 0x8000. Since the keystate is stored in bit 15... that is probably the only bit you are interested in. All the other bits mean something else:
1 2 3 4 5 6 7 8 9
|
int foo = GetAsyncKeyState( VK_ESCAPE ); // get the key state
// key state is in bit 15 only .. other bits means other stuff
// so isolate bit 15 with an AND operation:
if( foo & 0x8000 ) // is bit 15 set?
{
// if yes, the key is pressed
}
|
For the LPARAM in WM_KEYDOWN, you can use AND to isolate the bits you are interested in. So if you want to look at the repeat count (which is in bits 0-15):
|
int repeatcount = lParam & 0x0000FFFF; // isolate the low 16 bits by forcing all other bits to be clear
|
To get the scan code (in bits 16-23), you'd do the same thing, but you'd want to shift the bits over as well:
1 2 3
|
int scancode = lParam & 0x00FF0000; // isolate bits 16-23
scancode >>= 16; // then shift all bits to the right 16 places
// this turns 0x00FF0000 into 0x000000FF
|