Может ли 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;

но я действительно не знаю, как это будет выглядеть для двух ключей).

Спасибо за вашу помощь!


person user2281387    schedule 22.04.2013    source источник


Ответы (2)


Есть два случая, о которых следует знать.

Некоторые специальные клавиши называются клавишами-модификаторами, и они приводят к установке бита модификатора в event->state, поэтому вы можете проверить, например, if (event->state & GDK_CONTROL_MASK).

Только несколько общих модификаторов устанавливают флаг таким образом. Для других клавиш вам нужно будет самостоятельно отслеживать отдельные события нажатия и отпускания, что позволит вам определить, нажата ли еще одна клавиша, когда приходит другая. Сигналы виджета — это событие нажатия клавиши и событие отпускания клавиши.

Могут быть и другие факторы, вызывающие проблемы для вас, хороший подход — создать небольшой автономный компилируемый тестовый пример из одного файла, показывающий проблему. Вы можете понять это, просто создав тестовый пример, но если нет, тестовый пример поможет другим помочь вам. (Поскольку они могут использовать его для воспроизведения проблемы.)

person Havoc P    schedule 22.04.2013
comment
Спасибо. Я попытаюсь настроить тестовый пример и посмотреть, смогу ли я заставить его распознавать две нажатые клавиши. Похоже, вы говорите, что если одна клавиша удерживается, а затем нажимается другая, то для второй клавиши генерируется другой сигнал события нажатия клавиши, что, я полагаю, верно, но я действительно не думал об этом. Так что, возможно, я могу попытаться заставить его работать, отслеживая состояние нажатия/отпускания для каждой клавиши с отдельными переменными. Раньше я просто кормил программу следующим нажатием клавиши для каждого события нажатия клавиши, используя переменную с именем «ключ». Так что, может быть, мне нужны переменные "keyleft", "keyright" и "keyz"... - person user2281387; 22.04.2013
comment
Обновление: Да, это было именно так. Я создал переменные для отслеживания каждого ключа отдельно, и теперь это прекрасно работает. Спасибо! - person user2281387; 22.04.2013

клавиатура так не работает: каждая клавиша генерирует отдельное прерывание, которое будет генерировать отдельное системное событие оконной системы, поэтому вам придется сохранять состояние самостоятельно.

некоторые клавиши фактически являются специальными и действуют как модификаторы других клавиш: 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;
}
person ebassi    schedule 22.04.2013