How to Handle Key Press Events in C++

How to handle key press events in C++

You won't find anything in the standard library for that. It's all platform-dependent. In Windows, you have functions like GetAsyncKeyState to get the state of a key on the keyboard for example.

SDL and SFML both have platform-independent event handling.

How to handle key press event in console application

For console application you can do this, the do while loop runs untill you press x

public class Program
{
public static void Main()
{

ConsoleKeyInfo keyinfo;
do
{
keyinfo = Console.ReadKey();
Console.WriteLine(keyinfo.Key + " was pressed");
}
while (keyinfo.Key != ConsoleKey.X);
}
}

This will only work if your console application has focus. If you want to gather system wide key press events you can use windows hooks

Key pressed and key released interrupts in C

You cannot do this in a portable manner. Terminals (and emulators of those such as xterm) give you only the key that was pressed, not the release events. Graphical user interfaces often provide the ability to receive separate press- and release-events.

Terminal emulators running in a graphical environment compose those events into individual characters. As read in the graphical environment, those are key symbols, which may contain characters. In addition to the press- and release-events for the key events themselves, you can have modifiers such as shift-, control- and meta-modifiers which are separate events. If you run xev, you can see these separate events.

After composing these events into a character, the terminal emulator may send it to your application as a series of data bytes, e.g., in UTF-8 encoding. When you use getch(), the ncurses library reads those bytes, and puts it together again into a character. In between those two (the terminal emulator and application) are the pseudo-terminal and its translation, which both terminal emulator and application must manipulate.

If you are not running in a graphical environment, there are (not always) other ways than graphical applications such as xev which can read directly the key press/release events. The Linux console supports that. See for example the links cited in Receiving key press and key release events in Linux terminal applications?

Catch a key-press event

You can refer to this solution. This may help you. Your question is quite confusing but here you can get more general information about Key event handling.

Implementing a KeyPress Event in C with Multiple Threads

The multi-threaded approach I mentioned in the comments, that has a separate thread to fetch and enqueue keys, being designed not to drop keys, isn't trivial. It requires some C skills and some UNIX knowledge. I implemented a working skeleton that runs, so you can see what's involved.

To test this, save the file as, let's say, dispatch.c

$ cc -o dispatch dispatch.c
$ ./dispatch

Sample output:

$ ./dispatch

Key 'a' pressed...

... Thread T3 pulled key 'a' from queue

... Thread T1 pulled key 'a' from queue

... Thread T2 pulled key 'a' from queue

Key 'b' pressed...

... Thread T2 pulled key 'b' from queue

... Thread T1 pulled key 'b' from queue

Key 'c' pressed...

... Thread T3 pulled key 'c' from queue

... Thread T1 pulled key 'c' from queue

Key 'd' pressed...

... Thread T2 pulled key 'd' from queue

... Thread T3 pulled key 'd' from queue

Key 'z' pressed...

... Thread T2 pulled key 'z' from queue

... Thread T1 pulled key 'z' from queue

... Thread T3 pulled key 'z' from queue

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <strings.h>
#include <string.h>
#include <termios.h>
#include <sys/types.h>

typedef struct keyQueue {
struct keyQueue *next;
char key;
} keyQueue_t;

typedef struct ThreadInfo {
pthread_t tid; /* thread id */
pthread_mutex_t kqmutex; /* protects key queue from race condition between threads */
keyQueue_t kqhead; /* input keys queued to this thread */
char *keys; /* keys this thread responds to */
char *name; /* name of this thread */
} threadInfo_t;

static struct termios origtc, newtc;

threadInfo_t threads[] = {
{ 0, PTHREAD_MUTEX_INITIALIZER, { NULL, '\0' }, "abcez", "Thread T1" },
{ 0, PTHREAD_MUTEX_INITIALIZER, { NULL, '\0' }, "abdfz", "Thread T2" },
{ 0, PTHREAD_MUTEX_INITIALIZER, { NULL, '\0' }, "acdgz", "Thread T3" }
};

void *service(void *arg) {
char key;
threadInfo_t *t = &threads[(int)arg]; // get pointer to thread
for(;;) {
pthread_mutex_lock(&t->kqmutex); // lock other threads out while we tamper
key = '\0'; // initialize key to NULL
if (t->kqhead.next != NULL) { // Anything queued up for us?
keyQueue_t *kq = t->kqhead.next; // if so get ptr to key pkt
key = kq->key; // fetch key from pkt
t->kqhead.next = kq->next; // Point to next key in queue (or NULL if no more queued up).
free(kq);
}
pthread_mutex_unlock(&t->kqmutex); // unlock key queue
if (key != '\0') { // if we got a key, log it
printf("... %s pulled key '%c' from queue\n", t->name, key);
}
// ⇓ usleep() probably more practical as 1-sec too long for most cases
sleep(1); // sleep so we don't loop too fast eating CPU
}
return NULL;
}

int main() {

/* Fire up threads */
for (long i = 0; i < sizeof (threads) / sizeof (threadInfo_t); i++) {
if (pthread_create(&threads[i].tid, NULL, service, (void *)i) < 0) {
perror("pthread_create()");
exit(-1);
}
}

tcgetattr(0, &origtc); // get orig tty settings
newtc = origtc; // copy them
newtc.c_lflag &= ~ICANON; // put in '1 key mode'
newtc.c_lflag &= ~ECHO; // turn off echo

for(;;) {
tcsetattr(0, TCSANOW, &newtc); // echo off 1-key read mode
char c = getchar(); // get single key immed.
tcsetattr(0, TCSANOW, &origtc); // settings back to normal
printf("Key '%c' pressed...\n", c); // show user what we got
for (int i = 0; i < sizeof (threads) / sizeof (threadInfo_t); i++) {
threadInfo_t *t = &threads[i]; // get shorthand ptr to thread
if (strchr(t->keys, c) != NULL) { // this thread listens for this key
pthread_mutex_lock(&t->kqmutex); // lock other threads out while we tamper
keyQueue_t *kq = calloc(sizeof (struct keyQueue), 1); // allocate pkt
kq->key = c; // stash key there
keyQueue_t *kptr = &t->kqhead; // get pointer to queue head
while(kptr->next != NULL) // find first empty slot
kptr = kptr->next;
kptr->next = kq; // enqueue key packet to thread
pthread_mutex_unlock(&t->kqmutex); // unlock key queue
}
}
}
}

This code starts three threads, t1, t2, t3, which each have a 'key queue' structure on them, as well as a char * field keys. keys is a string containing the characters (keys) the thread is 'interested in'.

The keyboard keys listed in the string are duplicated in the threads string so that one key can be consumed by more than one thread in some cases. For example, all the threads listen to 'a' and 'z', two threads listen to 'b', another two to 'c', another pair of threads are interested in 'd', and finally 'e', 'f', and 'g' have only one thread listening, respectively.

The main loop reads keys without echo and captures keys immediately (e.g. without the user having to hit return). When a key is entered, it loops through the thread info to find out which threads are interested in the pressed key and enqueues the key (in a packet) to the respective thread(s).

The threads are in their own loop, sleeping one second in between loops. When they wake up they check their queue to see if there are any keys queued. If there are they pull it from the queue and say they pulled that key from the queue.

Because of the delay in each thread's polling/work loop (e.g. before the threads wake up and check their respective queues), there's time for you to enter multiple things on the keyboard to get queued up to the threads, and then the threads will dequeue them the enqueue keys one at a time at 1 second intervals.

In real life the program would use a much shorter sleep, but would put something in there to keep each thread from needlessly hogging a lot of CPU time.

Kind of fun to run it and see it in action.

*Note: calloc() is used instead of malloc() because unlike malloc(), calloc() initializes the memory returned to all 0's. It's a nice trick.

How to make a keypress form event in C#

You have several errors in your code.

MainWindow.KeyPress = new KeyPressEventArgs(Form_KeyPress);

1) KeyPress has KeyPressEventHandler type. Not KeyPressEventArgs. In C# classes which called ...EventArgs are usually used as special objects that contains data about a raised event and them are inherited from EventArgs system class. And classes which called ...EventHandlers are usually define wrapper for delegates and called events.

2) So KeyPress is event. If you want to subscribe this event you should use += operator. And method that you want to specify as handler should have signature void(object, KeyPressEventArgs). Typical signature for events is void(object, ...EventArgs)

private void Form_KeyPress(object sender, System.Windows.Forms.KeyEventArgs e)

3) As I said this method has wrong signature (KeyPressEventArgs instead KeyEventArgs).

4) It should be static. You can not use non-static class members in static method.

So your code should look like this:

    class PracticeEvent
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
Form MainWindow = new Form();
MainWindow.Text = "Practice";
MainWindow.MaximizeBox = false;
MainWindow.MinimizeBox = false;
MainWindow.FormBorderStyle = FormBorderStyle.FixedSingle;
MainWindow.StartPosition = FormStartPosition.CenterScreen;
MainWindow.Size = new Size(1000, 700);
MainWindow.KeyPreview = true;
MainWindow.KeyPress += Form_KeyPress;
MainWindow.ShowDialog();
}

private static void Form_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
if (e.KeyChar == 'a')
{
MessageBox.Show("You pressed the A key.");
}
}
}

Use listeners in C# is not good practice, but some frameworks use it. Usually events and callbacks is used.

And my last advice. May be you want to use the KeyDown event? The KeyPress is used for working with char input.



Related Topics



Leave a reply



Submit