[win32] - how build a combinekeys() function?

Pages: 12
i need some advices for build a combinekeys() function.

1
2
3
4
void CombineKeys(int key1, int key2,...)
{
    
}

is for be used, normaly, with keys messages.
but i need more advices, please.
how these works:
1 - if the key1 was pressed then key1 is 'true';
2 - test if key1 is 'true' and if the key2 was pressed. if key2(or other keys) was not pressed... then go back and start from begining.
(is like the games way.. the combination keys)
Do you mean like a key sequence? Like how in a fighting game, they have to press Left,Left,Attack to do a special move?


You can't do this in a single function because the keystrokes will be done at different times. You'll need to keep a history of all the keys the user pressed and then examine that history to see if they pressed the necessary keys in the right order.


But before I get into code examples... I want to make sure I'm understanding the problem correctly. Is this what you are trying to do?
yes... and i more or less know how to do ;)
the night make me think ;)
let me ask 1 thing with these function: how can i test if is the last parameter?
(i usee C++11)
now i will do the function correctly, but i need to know how i know what is the last parameter for return a boolean value instead void ;)
Last edited on
heres the funtion almost completed:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
bool CombineKeys(int key1, int key2,int...keyn)
{
    static bool PreviousKeyPressed=false;
    static DWORD StartTimer = GetTickCount();
    if((GetAsyncKeyState(key1) & 0x8000) and PreviousKeyPressed==false)
    {
        PreviousKeyPressed=true;
    }
    else if((GetAsyncKeyState(key2) & 0x8000) and PreviousKeyPressed==true)
    {
        PreviousKeyPressed=true;
    }
    else if((GetAsyncKeyState(keyn) & 0x8000) and PreviousKeyPressed==true)
    {
        PreviousKeyPressed=true;
    }
    else if((GetAsyncKeyState(lastkey) & 0x8000) and PreviousKeyPressed==true)
    {
        return true;
    }
    else if(GetTickCount() < (startTime + 2000)) //2 seconds
    {
        PreviousKeyPressed=false;
    }
    else
    {
        PreviousKeyPressed=false;
    }
    return false;
}

the lastkey isn't declared, because i don't know how can i detect it :(
can you help me on that?
Last edited on
finally something:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
bool CombineKeys(std::initializer_list<int> keys)
{
    static bool PreviousKeyPressed=false;
    static DWORD StartTimer = GetTickCount();
    int i=0;

    for(i = 0; i != (int)keys.size(); i++)
    {
        if((GetAsyncKeyState(keys(i)) & 0x8000) and PreviousKeyPressed==false)
        {
            PreviousKeyPressed=true;
        }
        else if((GetAsyncKeyState(keys(i)) & 0x8000) and PreviousKeyPressed==true)
        {
            PreviousKeyPressed=true;
        }
        else if((i==(int)keys.size()) && (GetAsyncKeyState(i) & 0x8000) and PreviousKeyPressed==true)
        {
            return true;
        }
        else if(GetTickCount() < (StartTimer + 2000))//2 seconds
        {
            PreviousKeyPressed=false;
        }
        else
        {
            PreviousKeyPressed=false;
        }
    }
    return false;
}

but i get an error in these line:
if((GetAsyncKeyState(keys(i)) & 0x8000) and PreviousKeyPressed==false)
"error: no match for call to '(std::initializer_list<int>) (int&)"
what means these error?
finally i put it to work:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
int GetAllKeyPressed()
{
    int key=0;
    bool FirstKey=false;

    for(int i=0; i<256; i++)
    {
        if(GetAsyncKeyState(i) & 0x8000)
        {
            if(FirstKey==false)
            {
                key=i;
                FirstKey=true;
            }
            else
            {
                key=key & i;
            }
        }
    }
    return key;
}

bool CombineKeys(std::vector<int> const keys)
{
    static bool PreviousKeyPressed=false;
    static DWORD StartTimer = GetTickCount();
    static int i=0;

        //test if the 1st key was pressed
        //if((GetAsyncKeyState(keys[0]) & 0x8000) && PreviousKeyPressed==false)
        if((GetAllKeyPressed()==keys[0]) && PreviousKeyPressed==false)
        {
            SetWindowText(a,"hi");
            i=0;
            PreviousKeyPressed=true;
            StartTimer = GetTickCount();
            i++;
        }
        //test if the StartTimer have 2 seconds
        else if (GetTickCount() - StartTimer >= 2000)//now i put the timer here ;)
        {

            StartTimer =GetTickCount();
            PreviousKeyPressed=false;
            i=0;
        }
        //test if the last key was pressed
        //else if((i==(int)keys.size()-1) && (GetAsyncKeyState(keys[(int)keys.size()-1]) & 0x8000) && PreviousKeyPressed==true)
        else if((i==(int)keys.size()-1) && (GetAllKeyPressed()==keys[(int)keys.size()-1]) && PreviousKeyPressed==true)
        {
            PreviousKeyPressed=false;
            i=0;
            StartTimer=0;
            return true;

        }
        //test if the next key was pressed
        //else if((GetAsyncKeyState(keys[i]) & 0x8000) && PreviousKeyPressed==true)
        else if((GetAllKeyPressed()==keys[i]) && PreviousKeyPressed==true)
        {
            PreviousKeyPressed=true;
            StartTimer = GetTickCount();
            i++;
        }

        else
        {
            PreviousKeyPressed=false;
            StartTimer = GetTickCount();
            i=0;
        }

    return false;
}

#define CombinationKeys(...) CombineKeys({__VA_ARGS__})

//heres a tested sample:
if(CombinationKeys('A' & 'S', VK_LEFT, 'C', 'B'))
        {
            MessageBox(NULL,"hi","hi",MB_OK);
        }

i need ask anotherthing: these 2 functions are great. but i need be more complex like:

CombinationKeys('A' & ('S'|'W'), VK_LEFT, 'C', 'B')

but i don't get the right results.. i have test it but the ' & ('S'|'W')' is ignored :(
can anyone advice me, please?
Last edited on
'A' & ('S'|'W')

This does not do what you expect. & and | are bitwise operators, meaning they perform an operation on each bit in the given values.

I explain how these operators work in this thread:
http://www.cplusplus.com/forum/beginner/72705/#msg387899

In your case... this is happening:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
char        byte        binary
______________________________________
'A'  ==     0x41 ==     01000001
'S'  ==     0x53 ==     01010011
'W'  ==     0x57 ==     01010111



'S' | 'W' == 'W'
because:

'S' = 0x53 = 01010011
'W' = 0x57 = 01010111
             ========  <- bitwise OR
'W' = 0x57 = 01010111


'A' & ('W') == 'A'
because:

'A' = 0x41 = 01000001
'W' = 0x57 = 01010111
             ========  <- bitwise AND
'A' = 0x41 = 01000001


Therefore... CombinationKeys('A' & ('S' | 'W'));
is exactly the same as: CombinationKeys('A');

I also have no idea what you're doing on line 17. & Makes no sense there.





But really -- this problem aside... I think you're entire approach is flawed. If you want to look for key sequences, you'll need to record a history of key presses. I don't see you doing that here... you're just taking a snapshot of the keyboard once. This will only let you see the current state of the keyboard... it will not let you see the keyboard history.


Trying to combine all the keys into a single object might be useful... I just think you're doing it wrong. This is something that probably should be made into a class.
sorry. but see these:

'A' & ('S' | 'W')
gives a value.. imagine that it's 'x'.

now see these:
the GetAllKeyPressed() function combine all pressed keys with '&' bit operator. and give me a value('y').
my objective is test if the 'x' is igual a 'y'.
but seems that i have some problems with my GetAllKeyPressed() function. can you tell me what i did wrong with function?
'A' & ('S' | 'W')
gives a value.. imagine that it's 'x'.


I don't have to imagine what the value is. I already know it's 'A'.

Try this:

1
2
if( 'A' == ('A' & ('S' | 'W')) )
    cout << "This will print" << endl;


You misunderstand bitwise operators. You can't just treat any value as a flag and attempt to "combine" them. It only works with bits. See the thread I linked to previously:

http://www.cplusplus.com/forum/beginner/72705/#msg387899

You simply cannot combine all possible keys into 1 value. There are 100+ different keys on a keyboard. That's too many to cram into a single simple var.


EDIT:

but seems that i have some problems with my GetAllKeyPressed() function. can you tell me what i did wrong with function?


It's less that there's a problem with your function... and more that there's a conceptual problem with what you're trying to do. A 'CombineKeys' function doesn't really make a lot of sense.

Is this for checking for an input key sequence? Like if the user presses Left,Left,S to do a special move?
Last edited on
i see what you mean.. sorry about that confusion..
so what you can advice me?
Disch told you to build your own queue, say 5 elements max. When user press a key you receive a message, store that in the queue; when you receive another key press check if some amount of time has passed (in that case empty the queue and proceed to treat all key pressed before as simple keys events -> be careful about delay chosen, it is usually very short).

If not, proceed to combo action and empty the queue. If the user presses a "wrong" key not allocated for a combo empty the queue and proceed to process simple keys events.
sorry Disch.. i didn't answer these:
"Is this for checking for an input key sequence? Like if the user presses Left,Left,S to do a special move?"
yes...
heres the new code(without '|' or '&'... like you said it's a big number for 1 variable):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//test if a key\combination keys is pressed
bool AreAllKeysPressed(const std::vector<int> &keys)
{
    int state = 0x8000;
    for (int key:keys)
    {
        state &= GetAsyncKeyState(key);
    }

    return (state & 0x8000) != 0;
}

bool CombineKeys(std::vector<std::vector<int>> const &keys)
{
    static bool PreviousKeyPressed=false;
    static DWORD StartTimer = GetTickCount();
    static int i;

        //test if the 1st key\combination key is pressed        
        if((AreAllKeysPressed(keys[0])==true) && PreviousKeyPressed==false)
        {
            i=0;
            PreviousKeyPressed=true;
            StartTimer = GetTickCount();
            i++;
        }
        //the user only have 2 seconds for press the next key\combination key
        else if (GetTickCount() - StartTimer >= 2000)//now i put the timer here ;)
        {
            StartTimer =GetTickCount();
            PreviousKeyPressed=false;
            i=0;
        }
        //test if the previous key\combination keys was pressed
        //and the last key\combination keys
        else if((i==(int)keys.size()-1) && (AreAllKeysPressed(keys[(int)keys.size()-1])==true) && PreviousKeyPressed==true)
        {
            PreviousKeyPressed=false;
            i=0;
            StartTimer=0;
            return true;

        }
        //test if the previous key\combination keys was pressed
        //and the next key\combination keys
        else if((AreAllKeysPressed(keys[i])==true) && PreviousKeyPressed==true)
        {
            PreviousKeyPressed=true;
            StartTimer = GetTickCount();
            i++;
        }

        else
        {
            PreviousKeyPressed=false;
            StartTimer = GetTickCount();
            i=0;
        }

    return false;
}

#define CombinationKeys(...) CombineKeys({__VA_ARGS__})

//heres a sample working:
if(CombinationKeys({{'A', 'S', 'D'}, {'P'}, {'A'}, {'B'}}))
        {
            MessageBox(NULL,"hi","hi",MB_OK);
        }
//another sample don't works :(
if(CombinationKeys({{'A', 'S', 'D'}, {'P','O'}, {'A'}, {'B'}}))
        {
            MessageBox(NULL,"hi","hi",MB_OK);
        }

why the ' {'P','O'}' combination isn't working?
Line 46 seems suspect:

 
else if((AreAllKeysPressed(keys[i])==true) && PreviousKeyPressed==true)


This requires P+O be pressed at the same time. Was that what you wanted? Or did you want P or O?
in same time... is what the AreAllKeysPressed() test
i need more advice, please.
see these function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//test if a key\combination keys is pressed
bool AreAllKeysPressed(const std::vector<int> &keys)
{
    bool state = false;
    
    
    for (int key=0; key < keys.size(); key++)
    {
        if(GetAsyncKeyState(keys[key]) & 0x8000)
            state =true;            
        else
            return false;

    }
    return state;
}

i'm confused:
1 -how i know that only 1 or 2 key was pressed?
2 - how i know all keys was pressed?
my objective, with these function, is test if the user pressed all keys from 'keys' vector or some.
i'm thinking.. but i'm confused :(
i did something:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//test if a key\combination keys is pressed
bool AreAllKeysPressed(const std::vector<int> &keys)
{
    bool state = false;
    bool stateanykey=false;

    for (int key=0; key < keys.size(); key++)
    {
        if(GetAsyncKeyState(keys[key]) & 0x8000)
        {
            state =true;
            stateanykey=true;//1 or some keys was pressed
        }
        else
        {
            if(stateanykey==true)
                return -1; //if some keys was pressed then return 1
            else
                return false; //any key was pressed
        }

    }
    return state;
}

but continue with problems :(
if i press 1 key, i get true instead '-1'
bool can only be true or false. There is no '-1'.

If you cast -1 to a bool, it will be considered 'true' because it is nonzero.

You might have to change the return type of the function to an int or an enum. Or pass another parameter by reference to get more output.
i'm doing that... but i get bad results :(
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
enum AllKeyState
{
    Nokey,
    All,
    Some
};

//test if a key\combination keys is pressed
AllKeyState AreAllKeysPressed(const std::vector<int> &keys)
{
    AllKeyState keystate=Nokey;
    for (int key=0; key < keys.size(); key++)
    {
        if(GetAsyncKeyState(keys[key]) & 0x8000)
        {
            keystate=All;//1 or some keys was pressed
        }
        else
        {
            if(keystate==All)
                keystate=Some;
        }
    }
    return keystate;
}


bool CombineKeys(std::vector<std::vector<int>> const &keys)
{
    static bool PreviousKeyPressed=false;
    static DWORD StartTimer = GetTickCount();
    static DWORD PressTimer = 0;
    static int i;


        if((AreAllKeysPressed(keys[0])==Some) && PreviousKeyPressed==false)
        {
            i=0;
            SetWindowText(WindowMain,"hello");
            PreviousKeyPressed=true;
            StartTimer = GetTickCount();
            i++;
        }

i understand that i'm doing something wrong. but, for now... the AreAllKeysPressed() isn't correct, because seems not recive the right results :(
if i presse only the 1st key, i get the 'some', but not with the 2nd key :(
please i need more advices
the problem is another one. how the user can press 2 or even 3 keys in same time immediat?
i need think in these problem... but i accept sugestions. i did a delay on AreAllKeysPressed() function, but isn't enough :(
please tell me more
Keep in mind there are hardware limitations to keyboards. Even if the user presses 2 or 3 keys at the same time, they might not all register. So if you are checking for 3 keypresses and it isn't working, it might not be your code, it might be your keyboard.

I don't know if that's the problem you're having or not. I'm not sure I understand your problem.
Pages: 12