Может ли GDK/GTK распознавать две клавиши, нажатые одновременно?
Поэтому я пытаюсь разработать игру в стиле платформы, писать на C и использовать GTK в качестве своего графического инструментария. Прямо сейчас у меня есть программа, которая размещает три блока на экране. Две из них являются платформами, а третий можно перемещать в боковом направлении, нажимая клавиши со стрелками влево / вправо. (Я пока не рисовал спрайтов, поэтому сейчас героем моей игры является синий прямоугольник). Я также реализовал прыжки, нажав клавишу "z", и вы можете прыгать и приземляться на платформы.
Тем не менее, двигаться в поперечном направлении во время прыжков довольно сложно. Я полагаю, что это потому, что моя программа не распознает две клавиши, нажатые одновременно, поэтому вам нужно отпустить стрелку влево или вправо, нажать z, а затем отпустить z и снова нажать стрелку вправо или влево, чтобы двигаться в боковом направлении, находясь в воздухе. Я хотел бы иметь возможность удерживать левую или правую и одновременно нажимать z, чтобы герой подпрыгнул в боковом направлении.
Справочное руководство GDK ссылается на "gdk/gdkkeysyms.h" (который в моей системе находится по адресу /usr/include/gtk-3.0/gdk/gdkkeysyms.h) для получения списка кодов ключей GDK, но не дает никаких руководство по использованию двух клавиш одновременно. Может ли GTK/GDK распознать событие, когда одновременно нажимаются две клавиши (GDK, GTK, в зависимости от того, что мне мешает, где находится граница между ними, но я полагаю, что это тема для другого вопроса...)? Как бы вы применили это? (Для одного ключа вы получаете код, делая что-то вроде
key = event->keyval;
но я не знаю, как это будет выглядеть для двух ключей).
Спасибо за вашу помощь!
2 ответа
Есть два случая, о которых нужно знать.
Некоторые специальные клавиши называются клавишами-модификаторами, и они приводят к установке бита-модификатора в event->state
так что вы можете проверить if (event->state & GDK_CONTROL_MASK)
например.
Только несколько распространенных модификаторов устанавливают флаг таким образом. Для других клавиш вам нужно будет самостоятельно отслеживать отдельные события нажатия и отпускания, что позволит вам определить, нажата ли еще одна клавиша, когда прибывает другая. Сигналы виджета - это событие нажатия клавиши и событие освобождения клавиши.
Могут быть и другие факторы, вызывающие у вас проблемы, хороший подход - создать небольшой одиночный скомпилированный тестовый пример с одним файлом, показывающий проблему. Вы можете понять это, просто сделав контрольный пример, но если нет, то контрольный пример поможет другим помочь вам. (Так как они могут использовать это, чтобы воспроизвести проблему.)
Клавиатура не работает таким образом: каждая клавиша генерирует отдельное прерывание, которое генерирует отдельное системное событие управления окнами, поэтому вы должны сохранять состояние самостоятельно.
некоторые клавиши являются специальными и действуют как модификаторы других клавиш: Control, Shift, Alt, являются модификаторами, и поэтому обрабатываются по-разному - т.е., если они нажаты, их состояние будет записано в структуру данных события отдельно от фактической клавиши. будучи нажатым. тем не менее, они также будут генерировать отдельные ключевые события.
Вы можете просто вести запись нажатия клавиш и позже проверять, поддерживается ли состояние, например:
static gboolean is_a_pressed = FALSE;
static gboolean is_b_pressed = FALSE;
static gboolean on_key_press (GtkWidget *w, GdkEvent *e)
{
/* acquire key A */
if (e->key.symbol == GDK_KEY_a)
is_a_pressed = TRUE;
/* acquire key B */
if (e->key.symbol == GDK_KEY_b)
is_b_pressed = TRUE;
/* both keys have been pressed */
if (is_a_pressed && is_b_pressed)
do_something_amazing ();
/* let the event propagate further */
return GDK_EVENT_PROPAGATE;
}
static gboolean on_key_release (GtkWidget *w, GdkEvent *e)
{
/* release key A */
if (e->key.symbol == GDK_KEY_a)
is_a_pressed = FALSE;
/* release key B */
if (e->key.symbol == GDK_KEY_b)
is_b_pressed = FALSE;
return GDK_EVENT_PROPAGATE;
}