Recently, I started teaching myself CE C and I need help detecting multiple keypresses. Here's my code:


Code:

int main(void)
{
    int cx = 1; // circle x position
    int cy = 1; // circle y position

    kb_key_t key;

    gfx_Begin();
    gfx_SetDrawBuffer();
    gfx_SetColor(7);

    do
    {
        kb_Scan();

        key = kb_Data[7];

        if (key == kb_Down)
        {
            cy++;
        }
        if (key == kb_Up)
        {
            cy--;
        }
        if (key == kb_Left)
        {
            cx--;
        }
        if (key == kb_Right)
        {
            cx++;
        }
        gfx_FillScreen(255);
        gfx_FillCircle(cx, cy, 10);
        gfx_SwapDraw();

    } while (kb_Data[6] != kb_Clear);

    gfx_End();

    return 0;
}


My goal is to get the green circle to move in 8 directions, but it currently only moves in 4 and when I press 2 keys at once, the circle stops moving. Any suggestions?
Since the keys you care about are all part of the same group, simply test for a combination of key values:

Code:
if (key == (kb_Down | kb_Left)) {
    cy++;
    cx--;
} // ...


The kb_* values are bits indicating the state of the named key, so it's perfectly valid to combine them in this way.
Thanks for the help, Tari. That makes a lot of sense!
Also, how would I test for a combination of key values in a different group?
I'm no expert in C, but for detecting a combination of keys across different groups, you can try something like this:

Code:
kb_Scan();
if (kb_IsDown(kb_KeyCos) && kb_IsDown(kb_KeyMul)) {
    // do something when the cosine and multiplication keys are pressed simultaneously
    // you can keep chaining more keys in the if statement's condition
}

There's probably a more elegant way of doing this. The CE toolchain's documentation has more information, including the names for the keys.
Idea
Actually...
There is a more elegant way of doing this: using variadic functions.

Code:
#include <stdarg.h>
#include <stdbool.h>

#include <graphx.h>
#include <keypadc.h>
#include <tice.h>

int are_keys_pressed(int num_keys, ...) {
    kb_Scan();
    va_list keys;
    va_start(keys, num_keys);
    for (int c = 0; c < num_keys; c++) {
        kb_lkey_t key = (kb_lkey_t) va_arg(keys, kb_lkey_t);
        if (kb_IsDown(key)) {
            continue;
        }
        // if a key is *not* pressed down, end the function early and return false
        va_end(keys);
        return false;
    }

    // if we got through all of the keys without returning false,
    // then we return true.

    va_end(keys);
    return true;
}

int main() {
    gfx_Begin();
    do {
        // if the math, sin, left bracket, 9, and subtraction keys are pressed all at the same time
        // turn the screen white
        // otherwise, keep the screen black
        if (are_keys_pressed(5, kb_KeyMath, kb_KeySin, kb_KeyLParen, kb_Key9, kb_KeySub)) {
            gfx_FillScreen(0xff);
        } else {
            gfx_FillScreen(0x00);
        }
    } while (!kb_IsDown(kb_KeyClear));
    gfx_End();
    return 0;
}

Tested this in CEmu and with my physical calc. Works like a charm. Very Happy
The code for the are_keys_pressed() function itself is pretty ugly. If I have the time, I'll see if I can turn this into a more maintainable snippet.
Other than that, just pass the number of keys you wish to detect, and then the long values of the keys (note that they start with "kb_Key", not "kb_"), and the function will return true if and only if all of those keys are simultaneously pressed.

On an interesting note: it was quite difficult to get the keys pressed in CEmu, because of the way my laptop keyboard is wired. (this article explains: https://www.sjbaker.org/wiki/index.php?title=Keyboards_Are_Evil) The calculator itself seems to have no problems with detecting simultaneous keypresses.
kb_Data[7] is a bitfield that contains one bit for each key in that group. So, if you're holding the down arrow, it would contain 0b0001 (1), if you're holding the left arrow, it would contain 0b0010 (2), and if you're holding both, it would contain 0b0011 (3).

I assume that you don't want to handle an "up-left diagonal" case separately from the up and left cases (which is what most of the other "solutions" are doing), but instead, want the up case to work regardless of which other keys are pressed.

The trivial solution to that is to change key == kb_Down to key & kb_Down. This does a bitwise and of the bitfield with the specific bit for the down key, so the rest of the bits get ignored.

Of course, the "idiomatic" solution is to avoid using kb_Data directly entirely and just use kb_IsDown. For example, instead of doing key == kb_Down, use kb_IsDown(kb_KeyDown).

If you do at some point want to require two keys to be held at the same time, you can just AND two kb_IsDown macros together, as Candledark mentioned.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement