Detect autoreapeat in xcb plugin.

Until now QKeyEvent::isAutoRepeat() would always return false.

Change-Id: I7771bc7a7ec848ef280f99bada0a26eda188604e
Reviewed-by: Jørgen Lind <jorgen.lind@nokia.com>
This commit is contained in:
Samuel Rødal 2012-01-06 15:03:24 +01:00 committed by Qt by Nokia
parent a98741516c
commit 0ba89ed91f
3 changed files with 85 additions and 3 deletions

View File

@ -340,7 +340,7 @@ public:
xcb_generic_event_t *checkEvent(int type);
template<typename T>
inline xcb_generic_event_t *checkEvent(const T &checker);
inline xcb_generic_event_t *checkEvent(T &checker);
typedef bool (*PeekFunc)(xcb_generic_event_t *);
void addPeekFunc(PeekFunc f);
@ -428,7 +428,7 @@ private:
#define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display()))
template<typename T>
xcb_generic_event_t *QXcbConnection::checkEvent(const T &checker)
xcb_generic_event_t *QXcbConnection::checkEvent(T &checker)
{
QXcbEventArray *eventqueue = m_reader->lock();

View File

@ -907,6 +907,7 @@ QString QXcbKeyboard::translateKeySym(xcb_keysym_t keysym, uint xmodifiers,
QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection)
: QXcbObject(connection)
, m_autorepeat_code(0)
{
m_key_symbols = xcb_key_symbols_alloc(xcb_connection());
setupModifiers();
@ -1020,6 +1021,62 @@ void QXcbKeyboard::setMask(uint sym, uint mask)
// #define XCB_KEYBOARD_DEBUG
class KeyChecker
{
public:
KeyChecker(xcb_window_t window, xcb_keycode_t code, xcb_timestamp_t time)
: m_window(window)
, m_code(code)
, m_time(time)
, m_error(false)
, m_release(true)
{
}
bool check(xcb_generic_event_t *ev)
{
if (m_error || !ev)
return false;
int type = ev->response_type & ~0x80;
if (type != XCB_KEY_PRESS && type != XCB_KEY_RELEASE)
return false;
xcb_key_press_event_t *event = (xcb_key_press_event_t *)ev;
if (event->event != m_window || event->detail != m_code) {
m_error = true;
return false;
}
if (type == XCB_KEY_PRESS) {
m_error = !m_release || event->time - m_time > 10;
return !m_error;
}
if (m_release) {
m_error = true;
return false;
}
m_release = true;
m_time = event->time;
return false;
}
bool release() const { return m_release; }
xcb_timestamp_t time() const { return m_time; }
private:
xcb_window_t m_window;
xcb_keycode_t m_code;
xcb_timestamp_t m_time;
bool m_error;
bool m_release;
};
void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycode_t code,
quint16 state, xcb_timestamp_t time)
{
@ -1062,8 +1119,32 @@ void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycod
return;
}
bool isAutoRepeat = false;
if (type == QEvent::KeyPress) {
if (m_autorepeat_code == code) {
isAutoRepeat = true;
m_autorepeat_code = 0;
}
} else {
// look ahead for auto-repeat
KeyChecker checker(((QXcbWindow *)window->handle())->xcb_window(), code, time);
xcb_generic_event_t *event = connection()->checkEvent(checker);
if (event) {
isAutoRepeat = true;
free(event);
}
m_autorepeat_code = isAutoRepeat ? code : 0;
}
QWindowSystemInterface::handleExtendedKeyEvent(window, time, type, qtcode, modifiers,
code, 0, state, string.left(count));
code, 0, state, string.left(count), isAutoRepeat);
if (isAutoRepeat && type == QEvent::KeyRelease) {
// since we removed it from the event queue using checkEvent we need to send the key press here
QWindowSystemInterface::handleExtendedKeyEvent(window, time, QEvent::KeyPress, qtcode, modifiers,
code, 0, state, string.left(count), isAutoRepeat);
}
}
#ifdef XCB_USE_XLIB

View File

@ -86,6 +86,7 @@ private:
uint m_caps_lock_mask;
xcb_key_symbols_t *m_key_symbols;
xcb_keycode_t m_autorepeat_code;
};
QT_END_NAMESPACE