ПрограммированиеФорумОбщее

Linux: XKeyEvent - повтор нажатия при удерживании

#0
18:53, 12 апр 2010

Программирование под Linux.
в иксах (X11) при нажатии клавиши я получаю событие XKeyEvent с кодом клавиши, состоянием модификаторов (Ctrl, Alt) и прочей информацией. Но я так и не нашел информацию о том, была ли эта клавиша реально нажата, или это многократный авто-повтор при удерживании.

для сравнения: в WinAPI с событием WM_KEYDOWN приходит параметр lParam, один из битов которого как раз является флагом - "нажато руками" или "повтор при удерживании":

if (lParam & 0x40000000) {
  // повтор при удерживании
}
else {
 // нажато руками
};

А как быть с иксами?
параметром auto_repeat_mode, устанавливамый в XKeyboardControl, здесь воспользоваться не удастся: мне не надо отключать повторы, мне надо определять их.

#1
19:03, 12 апр 2010

попробуй сохрани предыдущее состояние клавиши...

если предыдущее false и новое true => нажата

если предыдущее true и новое true => зажата

если предыдущее true и новое false => отжата

если предыдущее false и новое false => ничего

думаю так...

#2
19:08, 12 апр 2010

хм, и правда :) массив keymap я свой уже сделал, а использовать его для этой цели не подумал. спасибо, попробую.

всё же странно, что API не предусматривает такой, казалось бы важный, флаг. ничего не упустили?

#3
23:48, 12 апр 2010

Неа, так не прокатит.
При удерживании сыпятся сообщения и о нажатии (KeyPress), и об отпускании (KeyRelease), то есть никак невозможно отличить ручное многократное нажатие от автоматического.

Еще идеи? всё же кажется, что API должен предусматривать разницу...

#4
0:17, 13 апр 2010

ALPINE
> Еще идеи?
Ну, можно еще позвать XQueryKeymap(), и узнать действительное состояние кнопки.

#5
5:58, 13 апр 2010

RPGman
> Ну, можно еще позвать XQueryKeymap(), и узнать действительное состояние кнопки.
я с никсами не знаком, но рискну предположить, что не очень верная идея. сообщенияже наверняка асинхронные?
т.е. допустим FPS = 10 (100мс). за это время мы действительно несколько раз нажали и отпустили клавишу (ну например удаляем несколько введенных символов). и что покажет функция возвращающая реальное состояние клавиши - уже не поможет определить - нажали несколько раз или один и удержали.

#6
6:34, 13 апр 2010

Нажимаешь на кнопку чаще десяти раз в секунду? Сурово. Школа ниндзя?

По теме - что-то мне подсказывает, что это было бы логически неправильно и так делать нельзя. Нужны только физические события - отключай повтор.

#7
11:00, 13 апр 2010

Kloun
> рискну предположить, что не очень верная идея
keltar
> Нужны только физические события - отключай повтор.
Вы не поняли.
Суть - по приходу события KeyRelease зовем XQueryKeymap(), она возвращает битовый массив состояний кнопок - нажата/отжата. Если для кейкода в событии KeyRelease состояние кнопки "нажата" - то это стопудофф автоповтор, и этот ивент можно спокойно проигнорировать.

#8
11:50, 13 апр 2010

Я добился методом тыка, но оно отлично работает!

 While XPending(Display) > 0 do begin
      XNextEvent ( Display, @Event );
      if Event._type = KeyRelease then begin
        scancode:= DivineScanCode(event);
        //defeat the auto-repeat feature!
        GotNext:= No;
        ItsAutoRepeat:= No;
        if XPending(Display) > 0 then begin
          GotNext:= Yes;
          XNextEvent ( Display, @NextEvent );
          ItsAutoRepeat:= (NextEvent._type = KeyPress) and (NextEvent.xkey.keycode = Event.xkey.keycode) and (NextEvent.xkey.time = Event.xkey.time);
        end;
        if f_KeyState[scancode] and not ItsAutoRepeat then begin
          f_KeyState[scancode]:= false;
          OnRelease(scancode);
        end;
        if GotNext then Event:= NextEvent;
      end;

      case Event._type of
        KeyPress: begin
...

Короче, в каждом эвенте отпускания считываем следующий эвент. Если следующий - эвент нажатия, с идентичным временем и идентичной клавишей - решаем что это автоповтор, и игнорируем оба. Иначе обрабатывем следующий как положено

#9
19:20, 13 апр 2010

Суть - по приходу события KeyRelease зовем XQueryKeymap(), она возвращает битовый массив состояний кнопок - нажата/отжата.

я думаю, что и при авто-повторе биты будут прыгать, имитируя как раз-таки нажатость-отжатость. и по ним мы ничего не узнаем.

я с никсами не знаком, но рискну предположить, что не очень верная идея. сообщенияже наверняка асинхронные?
т.е. допустим FPS = 10 (100мс). за это время мы действительно несколько раз нажали и отпустили клавишу <...>

...и в следующем фрейме мы получили несколько пар событий KeyPress/KeyRelease и успешно обработали все по очереди. потеряно ничего не будет.

в каждом эвенте отпускания считываем следующий эвент. Если следующий - эвент нажатия, <...>

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

#10
20:04, 13 апр 2010

XAutoRepeatOff никак нельзя?

#11
20:14, 13 апр 2010

ALPINE
> я думаю, что и при авто-повторе биты будут прыгать
А не надо думать-гадать. Загляни в glut, и что делает glutIgnoreKeyRepeat().

ПрограммированиеФорумОбщее

Тема в архиве.