Reverted to Xlib event handling since XCB event handling just breaks too many things.

This commit is contained in:
binary1248 2015-07-29 13:58:48 +02:00 committed by Lukas Dürrenberger
parent 7c179193e6
commit 561eb82f14
6 changed files with 250 additions and 915 deletions

View File

@ -30,8 +30,6 @@
#include <SFML/Window/Unix/ScopedXcbPtr.hpp> #include <SFML/Window/Unix/ScopedXcbPtr.hpp>
#include <X11/keysym.h> #include <X11/keysym.h>
#include <cassert> #include <cassert>
#include <cstdlib>
#include <algorithm>
#include <map> #include <map>
@ -43,108 +41,6 @@ namespace
typedef std::map<std::string, xcb_atom_t> AtomMap; typedef std::map<std::string, xcb_atom_t> AtomMap;
AtomMap atoms; AtomMap atoms;
bool mapBuilt = false;
xcb_keycode_t firstKeycode = 255;
xcb_keycode_t lastKeycode = 0;
// We use a simple array instead of a map => constant time lookup
// xcb_keycode_t can only contain 256 distinct values
xcb_keysym_t keysymMap[256];
xcb_keysym_t keysymToLower(xcb_keysym_t keysym)
{
switch(keysym >> 8)
{
// Latin 1
case 0:
{
if ((keysym >= XK_A) && (keysym <= XK_Z))
return keysym + (XK_a - XK_A);
else if ((keysym >= XK_Agrave) && (keysym <= XK_Odiaeresis))
return keysym + (XK_agrave - XK_Agrave);
else if ((keysym >= XK_Ooblique) && (keysym <= XK_Thorn))
return keysym + (XK_oslash - XK_Ooblique);
break;
}
// Latin 2
case 1:
{
if (keysym == XK_Aogonek)
return XK_aogonek;
else if (keysym >= XK_Lstroke && keysym <= XK_Sacute)
return keysym + (XK_lstroke - XK_Lstroke);
else if (keysym >= XK_Scaron && keysym <= XK_Zacute)
return keysym + (XK_scaron - XK_Scaron);
else if (keysym >= XK_Zcaron && keysym <= XK_Zabovedot)
return keysym + (XK_zcaron - XK_Zcaron);
else if (keysym >= XK_Racute && keysym <= XK_Tcedilla)
return keysym + (XK_racute - XK_Racute);
break;
}
// Latin 3
case 2:
{
if (keysym >= XK_Hstroke && keysym <= XK_Hcircumflex)
return keysym + (XK_hstroke - XK_Hstroke);
else if (keysym >= XK_Gbreve && keysym <= XK_Jcircumflex)
return keysym + (XK_gbreve - XK_Gbreve);
else if (keysym >= XK_Cabovedot && keysym <= XK_Scircumflex)
return keysym + (XK_cabovedot - XK_Cabovedot);
break;
}
// Latin 4
case 3:
{
if (keysym >= XK_Rcedilla && keysym <= XK_Tslash)
return keysym + (XK_rcedilla - XK_Rcedilla);
else if (keysym == XK_ENG)
return XK_eng;
else if (keysym >= XK_Amacron && keysym <= XK_Umacron)
return keysym + (XK_amacron - XK_Amacron);
break;
}
// Cyrillic
case 6:
{
if (keysym >= XK_Serbian_DJE && keysym <= XK_Serbian_DZE)
return keysym - (XK_Serbian_DJE - XK_Serbian_dje);
else if (keysym >= XK_Cyrillic_YU && keysym <= XK_Cyrillic_HARDSIGN)
return keysym - (XK_Cyrillic_YU - XK_Cyrillic_yu);
break;
}
// Greek
case 7:
{
if (keysym >= XK_Greek_ALPHAaccent && keysym <= XK_Greek_OMEGAaccent)
return keysym + (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
else if (keysym >= XK_Greek_ALPHA && keysym <= XK_Greek_OMEGA)
return keysym + (XK_Greek_alpha - XK_Greek_ALPHA);
break;
}
// Armenian
case 0x14:
{
if (keysym >= XK_Armenian_AYB && keysym <= XK_Armenian_fe) {
return (keysym | 1);
}
break;
}
default:
{
break;
}
}
return keysym;
}
} }
namespace sf namespace sf
@ -268,89 +164,6 @@ xcb_atom_t getAtom(const std::string& name, bool onlyIfExists)
return reply->atom; return reply->atom;
} }
////////////////////////////////////////////////////////////
const xcb_keysym_t* getKeysymMap()
{
if (!mapBuilt)
buildKeysymMap();
return keysymMap;
}
////////////////////////////////////////////////////////////
void buildKeysymMap()
{
// Open a connection with the X server
xcb_connection_t* connection = sf::priv::OpenConnection();
firstKeycode = xcb_get_setup(connection)->min_keycode;
lastKeycode = xcb_get_setup(connection)->max_keycode;
sf::priv::ScopedXcbPtr<xcb_generic_error_t> error(NULL);
sf::priv::ScopedXcbPtr<xcb_get_keyboard_mapping_reply_t> keyboardMapping(xcb_get_keyboard_mapping_reply(
connection,
xcb_get_keyboard_mapping(
connection,
firstKeycode,
lastKeycode - firstKeycode + 1
),
&error
));
sf::priv::CloseConnection(connection);
if (error || !keyboardMapping)
{
sf::err() << "Failed to get keyboard mapping" << std::endl;
return;
}
uint8_t keysymsPerKeycode = keyboardMapping->keysyms_per_keycode;
if (!keysymsPerKeycode)
{
sf::err() << "Error: No keysyms per keycode" << std::endl;
return;
}
const xcb_keysym_t* keysyms = xcb_get_keyboard_mapping_keysyms(keyboardMapping.get());
if (!keysyms)
{
sf::err() << "Failed to get keyboard mapping keysyms" << std::endl;
return;
}
xcb_keycode_t range = lastKeycode - firstKeycode + 1;
std::fill(keysymMap, keysymMap + 256, XK_VoidSymbol);
for (xcb_keycode_t i = firstKeycode; ; ++i)
{
const xcb_keysym_t* keysym = &keysyms[(i - firstKeycode) * keysymsPerKeycode];
if ((keysymsPerKeycode == 1) || (keysym[1] == XCB_NO_SYMBOL))
{
keysymMap[i] = keysymToLower(keysym[0]);
if (i == lastKeycode)
break;
continue;
}
keysymMap[i] = keysym[0];
if (i == lastKeycode)
break;
}
mapBuilt = true;
}
} // namespace priv } // namespace priv
} // namespace sf } // namespace sf

View File

@ -116,23 +116,6 @@ xcb_window_t XCBDefaultRootWindow(xcb_connection_t* connection);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
xcb_atom_t getAtom(const std::string& name, bool onlyIfExists = false); xcb_atom_t getAtom(const std::string& name, bool onlyIfExists = false);
////////////////////////////////////////////////////////////
/// \brief Get the keycode to keysym map
///
/// Contains 255 values. Use the keycode as the index
/// into the array to retrieve its keysym.
///
/// \return Keycode to keysym map
///
////////////////////////////////////////////////////////////
const xcb_keysym_t* getKeysymMap();
////////////////////////////////////////////////////////////
/// \brief Build the keysym map
///
////////////////////////////////////////////////////////////
void buildKeysymMap();
} // namespace priv } // namespace priv
} // namespace sf } // namespace sf

View File

@ -32,34 +32,6 @@
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#include <xcb/xcb.h> #include <xcb/xcb.h>
#include <X11/keysym.h> #include <X11/keysym.h>
#include <cstdlib>
////////////////////////////////////////////////////////////
// Private data
////////////////////////////////////////////////////////////
namespace
{
bool mapBuilt = false;
// We use a simple array instead of a map => constant time lookup
xcb_keycode_t keycodeMap[sf::Keyboard::KeyCount];
xcb_keycode_t getKeycode(xcb_keysym_t keysym)
{
const xcb_keysym_t* keysymMap = sf::priv::getKeysymMap();
for (xcb_keycode_t i = 0; ; ++i)
{
if (keysymMap[i] == keysym)
return i;
if (i == 255)
break;
}
return 255;
}
}
namespace sf namespace sf
@ -69,15 +41,125 @@ namespace priv
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool InputImpl::isKeyPressed(Keyboard::Key key) bool InputImpl::isKeyPressed(Keyboard::Key key)
{ {
if (!mapBuilt) // Get the corresponding X11 keysym
buildMap(); KeySym keysym = 0;
switch (key)
{
case Keyboard::A: keysym = XK_A; break;
case Keyboard::B: keysym = XK_B; break;
case Keyboard::C: keysym = XK_C; break;
case Keyboard::D: keysym = XK_D; break;
case Keyboard::E: keysym = XK_E; break;
case Keyboard::F: keysym = XK_F; break;
case Keyboard::G: keysym = XK_G; break;
case Keyboard::H: keysym = XK_H; break;
case Keyboard::I: keysym = XK_I; break;
case Keyboard::J: keysym = XK_J; break;
case Keyboard::K: keysym = XK_K; break;
case Keyboard::L: keysym = XK_L; break;
case Keyboard::M: keysym = XK_M; break;
case Keyboard::N: keysym = XK_N; break;
case Keyboard::O: keysym = XK_O; break;
case Keyboard::P: keysym = XK_P; break;
case Keyboard::Q: keysym = XK_Q; break;
case Keyboard::R: keysym = XK_R; break;
case Keyboard::S: keysym = XK_S; break;
case Keyboard::T: keysym = XK_T; break;
case Keyboard::U: keysym = XK_U; break;
case Keyboard::V: keysym = XK_V; break;
case Keyboard::W: keysym = XK_W; break;
case Keyboard::X: keysym = XK_X; break;
case Keyboard::Y: keysym = XK_Y; break;
case Keyboard::Z: keysym = XK_Z; break;
case Keyboard::Num0: keysym = XK_0; break;
case Keyboard::Num1: keysym = XK_1; break;
case Keyboard::Num2: keysym = XK_2; break;
case Keyboard::Num3: keysym = XK_3; break;
case Keyboard::Num4: keysym = XK_4; break;
case Keyboard::Num5: keysym = XK_5; break;
case Keyboard::Num6: keysym = XK_6; break;
case Keyboard::Num7: keysym = XK_7; break;
case Keyboard::Num8: keysym = XK_8; break;
case Keyboard::Num9: keysym = XK_9; break;
case Keyboard::Escape: keysym = XK_Escape; break;
case Keyboard::LControl: keysym = XK_Control_L; break;
case Keyboard::LShift: keysym = XK_Shift_L; break;
case Keyboard::LAlt: keysym = XK_Alt_L; break;
case Keyboard::LSystem: keysym = XK_Super_L; break;
case Keyboard::RControl: keysym = XK_Control_R; break;
case Keyboard::RShift: keysym = XK_Shift_R; break;
case Keyboard::RAlt: keysym = XK_Alt_R; break;
case Keyboard::RSystem: keysym = XK_Super_R; break;
case Keyboard::Menu: keysym = XK_Menu; break;
case Keyboard::LBracket: keysym = XK_bracketleft; break;
case Keyboard::RBracket: keysym = XK_bracketright; break;
case Keyboard::SemiColon: keysym = XK_semicolon; break;
case Keyboard::Comma: keysym = XK_comma; break;
case Keyboard::Period: keysym = XK_period; break;
case Keyboard::Quote: keysym = XK_dead_acute; break;
case Keyboard::Slash: keysym = XK_slash; break;
case Keyboard::BackSlash: keysym = XK_backslash; break;
case Keyboard::Tilde: keysym = XK_dead_grave; break;
case Keyboard::Equal: keysym = XK_equal; break;
case Keyboard::Dash: keysym = XK_minus; break;
case Keyboard::Space: keysym = XK_space; break;
case Keyboard::Return: keysym = XK_Return; break;
case Keyboard::BackSpace: keysym = XK_BackSpace; break;
case Keyboard::Tab: keysym = XK_Tab; break;
case Keyboard::PageUp: keysym = XK_Prior; break;
case Keyboard::PageDown: keysym = XK_Next; break;
case Keyboard::End: keysym = XK_End; break;
case Keyboard::Home: keysym = XK_Home; break;
case Keyboard::Insert: keysym = XK_Insert; break;
case Keyboard::Delete: keysym = XK_Delete; break;
case Keyboard::Add: keysym = XK_KP_Add; break;
case Keyboard::Subtract: keysym = XK_KP_Subtract; break;
case Keyboard::Multiply: keysym = XK_KP_Multiply; break;
case Keyboard::Divide: keysym = XK_KP_Divide; break;
case Keyboard::Left: keysym = XK_Left; break;
case Keyboard::Right: keysym = XK_Right; break;
case Keyboard::Up: keysym = XK_Up; break;
case Keyboard::Down: keysym = XK_Down; break;
case Keyboard::Numpad0: keysym = XK_KP_0; break;
case Keyboard::Numpad1: keysym = XK_KP_1; break;
case Keyboard::Numpad2: keysym = XK_KP_2; break;
case Keyboard::Numpad3: keysym = XK_KP_3; break;
case Keyboard::Numpad4: keysym = XK_KP_4; break;
case Keyboard::Numpad5: keysym = XK_KP_5; break;
case Keyboard::Numpad6: keysym = XK_KP_6; break;
case Keyboard::Numpad7: keysym = XK_KP_7; break;
case Keyboard::Numpad8: keysym = XK_KP_8; break;
case Keyboard::Numpad9: keysym = XK_KP_9; break;
case Keyboard::F1: keysym = XK_F1; break;
case Keyboard::F2: keysym = XK_F2; break;
case Keyboard::F3: keysym = XK_F3; break;
case Keyboard::F4: keysym = XK_F4; break;
case Keyboard::F5: keysym = XK_F5; break;
case Keyboard::F6: keysym = XK_F6; break;
case Keyboard::F7: keysym = XK_F7; break;
case Keyboard::F8: keysym = XK_F8; break;
case Keyboard::F9: keysym = XK_F9; break;
case Keyboard::F10: keysym = XK_F10; break;
case Keyboard::F11: keysym = XK_F11; break;
case Keyboard::F12: keysym = XK_F12; break;
case Keyboard::F13: keysym = XK_F13; break;
case Keyboard::F14: keysym = XK_F14; break;
case Keyboard::F15: keysym = XK_F15; break;
case Keyboard::Pause: keysym = XK_Pause; break;
default: keysym = 0; break;
}
// Sanity checks // Sanity checks
if (key < 0 || key >= sf::Keyboard::KeyCount) if (key < 0 || key >= sf::Keyboard::KeyCount)
return false; return false;
// Open a connection with the X server
Display* display = OpenDisplay();
// Convert to keycode // Convert to keycode
xcb_keycode_t keycode = keycodeMap[key]; xcb_keycode_t keycode = XKeysymToKeycode(display, keysym);
CloseDisplay(display);
ScopedXcbPtr<xcb_generic_error_t> error(NULL); ScopedXcbPtr<xcb_generic_error_t> error(NULL);
@ -316,115 +398,6 @@ Vector2i InputImpl::getTouchPosition(unsigned int /*finger*/, const Window& /*re
return Vector2i(); return Vector2i();
} }
////////////////////////////////////////////////////////////
void InputImpl::buildMap()
{
keycodeMap[sf::Keyboard::A] = getKeycode(XK_a);
keycodeMap[sf::Keyboard::B] = getKeycode(XK_b);
keycodeMap[sf::Keyboard::C] = getKeycode(XK_c);
keycodeMap[sf::Keyboard::D] = getKeycode(XK_d);
keycodeMap[sf::Keyboard::E] = getKeycode(XK_e);
keycodeMap[sf::Keyboard::F] = getKeycode(XK_f);
keycodeMap[sf::Keyboard::G] = getKeycode(XK_g);
keycodeMap[sf::Keyboard::H] = getKeycode(XK_h);
keycodeMap[sf::Keyboard::I] = getKeycode(XK_i);
keycodeMap[sf::Keyboard::J] = getKeycode(XK_j);
keycodeMap[sf::Keyboard::K] = getKeycode(XK_k);
keycodeMap[sf::Keyboard::L] = getKeycode(XK_l);
keycodeMap[sf::Keyboard::M] = getKeycode(XK_m);
keycodeMap[sf::Keyboard::N] = getKeycode(XK_n);
keycodeMap[sf::Keyboard::O] = getKeycode(XK_o);
keycodeMap[sf::Keyboard::P] = getKeycode(XK_p);
keycodeMap[sf::Keyboard::Q] = getKeycode(XK_q);
keycodeMap[sf::Keyboard::R] = getKeycode(XK_r);
keycodeMap[sf::Keyboard::S] = getKeycode(XK_s);
keycodeMap[sf::Keyboard::T] = getKeycode(XK_t);
keycodeMap[sf::Keyboard::U] = getKeycode(XK_u);
keycodeMap[sf::Keyboard::V] = getKeycode(XK_v);
keycodeMap[sf::Keyboard::W] = getKeycode(XK_w);
keycodeMap[sf::Keyboard::X] = getKeycode(XK_x);
keycodeMap[sf::Keyboard::Y] = getKeycode(XK_y);
keycodeMap[sf::Keyboard::Z] = getKeycode(XK_z);
keycodeMap[sf::Keyboard::Num0] = getKeycode(XK_KP_Insert);
keycodeMap[sf::Keyboard::Num1] = getKeycode(XK_KP_End);
keycodeMap[sf::Keyboard::Num2] = getKeycode(XK_KP_Down);
keycodeMap[sf::Keyboard::Num3] = getKeycode(XK_KP_Page_Down);
keycodeMap[sf::Keyboard::Num4] = getKeycode(XK_KP_Left);
keycodeMap[sf::Keyboard::Num5] = getKeycode(XK_KP_Begin);
keycodeMap[sf::Keyboard::Num6] = getKeycode(XK_KP_Right);
keycodeMap[sf::Keyboard::Num7] = getKeycode(XK_KP_Home);
keycodeMap[sf::Keyboard::Num8] = getKeycode(XK_KP_Up);
keycodeMap[sf::Keyboard::Num9] = getKeycode(XK_KP_Page_Up);
keycodeMap[sf::Keyboard::Escape] = getKeycode(XK_Escape);
keycodeMap[sf::Keyboard::LControl] = getKeycode(XK_Control_L);
keycodeMap[sf::Keyboard::LShift] = getKeycode(XK_Shift_L);
keycodeMap[sf::Keyboard::LAlt] = getKeycode(XK_Alt_L);
keycodeMap[sf::Keyboard::LSystem] = getKeycode(XK_Super_L);
keycodeMap[sf::Keyboard::RControl] = getKeycode(XK_Control_R);
keycodeMap[sf::Keyboard::RShift] = getKeycode(XK_Shift_R);
keycodeMap[sf::Keyboard::RAlt] = getKeycode(XK_Alt_R);
keycodeMap[sf::Keyboard::RSystem] = getKeycode(XK_Super_R);
keycodeMap[sf::Keyboard::Menu] = getKeycode(XK_Menu);
keycodeMap[sf::Keyboard::LBracket] = getKeycode(XK_bracketleft);
keycodeMap[sf::Keyboard::RBracket] = getKeycode(XK_bracketright);
keycodeMap[sf::Keyboard::SemiColon] = getKeycode(XK_semicolon);
keycodeMap[sf::Keyboard::Comma] = getKeycode(XK_comma);
keycodeMap[sf::Keyboard::Period] = getKeycode(XK_period);
keycodeMap[sf::Keyboard::Quote] = getKeycode(XK_apostrophe);
keycodeMap[sf::Keyboard::Slash] = getKeycode(XK_slash);
keycodeMap[sf::Keyboard::BackSlash] = getKeycode(XK_backslash);
keycodeMap[sf::Keyboard::Tilde] = getKeycode(XK_grave);
keycodeMap[sf::Keyboard::Equal] = getKeycode(XK_equal);
keycodeMap[sf::Keyboard::Dash] = getKeycode(XK_minus);
keycodeMap[sf::Keyboard::Space] = getKeycode(XK_space);
keycodeMap[sf::Keyboard::Return] = getKeycode(XK_Return);
keycodeMap[sf::Keyboard::BackSpace] = getKeycode(XK_BackSpace);
keycodeMap[sf::Keyboard::Tab] = getKeycode(XK_Tab);
keycodeMap[sf::Keyboard::PageUp] = getKeycode(XK_Prior);
keycodeMap[sf::Keyboard::PageDown] = getKeycode(XK_Next);
keycodeMap[sf::Keyboard::End] = getKeycode(XK_End);
keycodeMap[sf::Keyboard::Home] = getKeycode(XK_Home);
keycodeMap[sf::Keyboard::Insert] = getKeycode(XK_Insert);
keycodeMap[sf::Keyboard::Delete] = getKeycode(XK_Delete);
keycodeMap[sf::Keyboard::Add] = getKeycode(XK_KP_Add);
keycodeMap[sf::Keyboard::Subtract] = getKeycode(XK_KP_Subtract);
keycodeMap[sf::Keyboard::Multiply] = getKeycode(XK_KP_Multiply);
keycodeMap[sf::Keyboard::Divide] = getKeycode(XK_KP_Divide);
keycodeMap[sf::Keyboard::Left] = getKeycode(XK_Left);
keycodeMap[sf::Keyboard::Right] = getKeycode(XK_Right);
keycodeMap[sf::Keyboard::Up] = getKeycode(XK_Up);
keycodeMap[sf::Keyboard::Down] = getKeycode(XK_Down);
keycodeMap[sf::Keyboard::Numpad0] = getKeycode(XK_KP_0);
keycodeMap[sf::Keyboard::Numpad1] = getKeycode(XK_KP_1);
keycodeMap[sf::Keyboard::Numpad2] = getKeycode(XK_KP_2);
keycodeMap[sf::Keyboard::Numpad3] = getKeycode(XK_KP_3);
keycodeMap[sf::Keyboard::Numpad4] = getKeycode(XK_KP_4);
keycodeMap[sf::Keyboard::Numpad5] = getKeycode(XK_KP_5);
keycodeMap[sf::Keyboard::Numpad6] = getKeycode(XK_KP_6);
keycodeMap[sf::Keyboard::Numpad7] = getKeycode(XK_KP_7);
keycodeMap[sf::Keyboard::Numpad8] = getKeycode(XK_KP_8);
keycodeMap[sf::Keyboard::Numpad9] = getKeycode(XK_KP_9);
keycodeMap[sf::Keyboard::F1] = getKeycode(XK_F1);
keycodeMap[sf::Keyboard::F2] = getKeycode(XK_F2);
keycodeMap[sf::Keyboard::F3] = getKeycode(XK_F3);
keycodeMap[sf::Keyboard::F4] = getKeycode(XK_F4);
keycodeMap[sf::Keyboard::F5] = getKeycode(XK_F5);
keycodeMap[sf::Keyboard::F6] = getKeycode(XK_F6);
keycodeMap[sf::Keyboard::F7] = getKeycode(XK_F7);
keycodeMap[sf::Keyboard::F8] = getKeycode(XK_F8);
keycodeMap[sf::Keyboard::F9] = getKeycode(XK_F9);
keycodeMap[sf::Keyboard::F10] = getKeycode(XK_F10);
keycodeMap[sf::Keyboard::F11] = getKeycode(XK_F11);
keycodeMap[sf::Keyboard::F12] = getKeycode(XK_F12);
keycodeMap[sf::Keyboard::F13] = getKeycode(XK_F13);
keycodeMap[sf::Keyboard::F14] = getKeycode(XK_F14);
keycodeMap[sf::Keyboard::F15] = getKeycode(XK_F15);
keycodeMap[sf::Keyboard::Pause] = getKeycode(XK_Pause);
mapBuilt = true;
}
} // namespace priv } // namespace priv
} // namespace sf } // namespace sf

View File

@ -158,12 +158,6 @@ public:
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
static Vector2i getTouchPosition(unsigned int finger, const Window& relativeTo); static Vector2i getTouchPosition(unsigned int finger, const Window& relativeTo);
////////////////////////////////////////////////////////////
/// \brief Build the SFML to X11 keymap
///
////////////////////////////////////////////////////////////
static void buildMap();
}; };
} // namespace priv } // namespace priv

View File

@ -47,14 +47,6 @@
#include <string> #include <string>
#include <cstring> #include <cstring>
// So we don't have to require xcb dri2 to be present
#define XCB_DRI2_BUFFER_SWAP_COMPLETE 0
#define XCB_DRI2_INVALIDATE_BUFFERS 1
// So we don't have to require xcb xkb to be present
#define XCB_XKB_NEW_KEYBOARD_NOTIFY 0
#define XCB_XKB_MAP_NOTIFY 1
#ifdef SFML_OPENGL_ES #ifdef SFML_OPENGL_ES
#include <SFML/Window/EglContext.hpp> #include <SFML/Window/EglContext.hpp>
typedef sf::priv::EglContext ContextType; typedef sf::priv::EglContext ContextType;
@ -73,18 +65,19 @@ namespace
sf::Mutex allWindowsMutex; sf::Mutex allWindowsMutex;
sf::String windowManagerName; sf::String windowManagerName;
bool mapBuilt = false;
// We use a simple array instead of a map => constant time lookup
// xcb_keycode_t can only contain 256 distinct values
sf::Keyboard::Key sfKeyMap[256];
static const unsigned long eventMask = XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_BUTTON_PRESS | static const unsigned long eventMask = XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION |
XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_KEY_PRESS |
XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_STRUCTURE_NOTIFY |
XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW; XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW;
// Filter the events received by windows (only allow those matching a specific window)
Bool checkEvent(::Display*, XEvent* event, XPointer userData)
{
// Just check if the event matches the window
return event->xany.window == reinterpret_cast< ::Window >(userData);
}
// Find the name of the current executable // Find the name of the current executable
std::string findExecutableName() std::string findExecutableName()
{ {
@ -245,124 +238,6 @@ namespace
return true; return true;
} }
xcb_query_extension_reply_t getXExtension(const std::string& name)
{
xcb_connection_t* connection = sf::priv::OpenConnection();
sf::priv::ScopedXcbPtr<xcb_generic_error_t> error(NULL);
sf::priv::ScopedXcbPtr<xcb_query_extension_reply_t> extension(xcb_query_extension_reply(
connection,
xcb_query_extension(
connection,
name.size(),
name.c_str()
),
&error
));
// Close the connection with the X server
sf::priv::CloseConnection(connection);
if (error || !extension || !extension->present)
{
xcb_query_extension_reply_t reply;
std::memset(&reply, 0, sizeof(reply));
return reply;
}
return *extension.get();
}
void dumpXcbExtensions()
{
xcb_connection_t* connection = sf::priv::OpenConnection();
sf::priv::ScopedXcbPtr<xcb_generic_error_t> error(NULL);
// Check if the RandR extension is present
sf::priv::ScopedXcbPtr<xcb_list_extensions_reply_t> extensions(xcb_list_extensions_reply(
connection,
xcb_list_extensions(
connection
),
&error
));
if (error || !extensions)
{
// Close the connection with the X server
sf::priv::CloseConnection(connection);
sf::err() << "Couldn't get list of X extensions" << std::endl;
return;
}
xcb_str_iterator_t iter = xcb_list_extensions_names_iterator(extensions.get());
sf::err() << "X Extensions:" << std::endl;
while (iter.rem)
{
std::string name(xcb_str_name(iter.data), xcb_str_name_length(iter.data));
sf::priv::ScopedXcbPtr<xcb_generic_error_t> error(NULL);
// Check if the RandR extension is present
sf::priv::ScopedXcbPtr<xcb_query_extension_reply_t> extension(xcb_query_extension_reply(
connection,
xcb_query_extension(
connection,
name.size(),
name.c_str()
),
&error
));
if (error || !extension || !extension->present)
{
sf::err() << "\t" << name << " - Failed to query" << std::endl;
continue;
}
int firstEvent = extension->first_event;
sf::err() << "\t" << name << " - First event: " << firstEvent << std::endl;
iter.data += xcb_str_name_length(iter.data) + 1;
--iter.rem;
}
// Close the connection with the X server
sf::priv::CloseConnection(connection);
}
void dumpUnhandledEvent(uint8_t type)
{
static std::vector<uint8_t> types;
// Check if we already reported this type
if (std::find(types.begin(), types.end(), type) != types.end())
return;
// Insert it if new
types.push_back(type);
static bool dumpedExtensions = false;
if (!dumpedExtensions)
{
dumpXcbExtensions();
dumpedExtensions = true;
}
sf::err() << "Unhandled event type: " << (static_cast<int>(type) & ~0x80) << std::endl
<< "Report this to the SFML maintainers if possible" << std::endl;
}
xcb_keysym_t getKeysymFromKeycode(xcb_keycode_t keycode)
{
return sf::priv::getKeysymMap()[keycode];
}
sf::Keyboard::Key keysymToSF(xcb_keysym_t symbol) sf::Keyboard::Key keysymToSF(xcb_keysym_t symbol)
{ {
switch (symbol) switch (symbol)
@ -473,27 +348,6 @@ namespace
return sf::Keyboard::Unknown; return sf::Keyboard::Unknown;
} }
void buildMap()
{
for (xcb_keycode_t i = 0; ; ++i)
{
sfKeyMap[i] = keysymToSF(getKeysymFromKeycode(i));
if (i == 255)
break;
}
mapBuilt = true;
}
sf::Keyboard::Key keycodeToSF(xcb_keycode_t keycode)
{
if (!mapBuilt)
buildMap();
return sfKeyMap[keycode];
}
} }
@ -529,7 +383,6 @@ m_fullscreen (false)
ewmhSupported(); ewmhSupported();
m_screen = XCBDefaultScreen(m_connection); m_screen = XCBDefaultScreen(m_connection);
XSetEventQueueOwner(m_display, XCBOwnsEventQueue);
// Save the window handle // Save the window handle
m_window = handle; m_window = handle;
@ -583,7 +436,6 @@ m_fullscreen ((style & Style::Fullscreen) != 0)
ewmhSupported(); ewmhSupported();
m_screen = XCBDefaultScreen(m_connection); m_screen = XCBDefaultScreen(m_connection);
XSetEventQueueOwner(m_display, XCBOwnsEventQueue);
// Compute position and size // Compute position and size
int left = m_fullscreen ? 0 : (m_screen->width_in_pixels - mode.width) / 2; int left = m_fullscreen ? 0 : (m_screen->width_in_pixels - mode.width) / 2;
@ -737,105 +589,10 @@ WindowHandle WindowImplX11::getSystemHandle() const
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplX11::processEvents() void WindowImplX11::processEvents()
{ {
// Key repeat workaround: If key repeat is enabled, XCB will spawn two XEvent event;
// events for each repeat interval: key release and key press. Both have while (XCheckIfEvent(m_display, &event, &checkEvent, reinterpret_cast<XPointer>(m_window)))
// the same timestamp and key code. We are holding back the release event
// to check for the matching key press event and if so, discard the release
// event.
xcb_generic_event_t* event = NULL;
xcb_key_release_event_t* lastKeyReleaseEvent = NULL;
uint8_t eventType = 0;
if (!m_xcbEvents.empty())
{ {
event = m_xcbEvents.front(); processEvent(event);
m_xcbEvents.pop_front();
}
else
{
event = xcb_poll_for_event(m_connection);
}
while (event)
{
eventType = event->response_type & ~0x80;
// Key was pressed and one has been released prior to that.
if (eventType == XCB_KEY_PRESS && lastKeyReleaseEvent)
{
// If the key press event matches the held back key release event,
// then we have a key repeat and discard the held back release
// event.
if (lastKeyReleaseEvent->time == reinterpret_cast<xcb_key_press_event_t*>(event)->time &&
lastKeyReleaseEvent->detail == reinterpret_cast<xcb_key_press_event_t*>(event)->detail)
{
free(lastKeyReleaseEvent);
lastKeyReleaseEvent = NULL;
// If key repeat is disabled, discard the matching key press event as well
if (!m_keyRepeat)
{
free(event);
if (!m_xcbEvents.empty())
{
event = m_xcbEvents.front();
m_xcbEvents.pop_front();
}
else
{
event = xcb_poll_for_event(m_connection);
}
continue;
}
}
}
// If there's still a key release event held back, process it now.
if (lastKeyReleaseEvent)
{
if (processEvent(reinterpret_cast<xcb_generic_event_t*>(lastKeyReleaseEvent)))
free(lastKeyReleaseEvent);
lastKeyReleaseEvent = NULL;
}
if (eventType == XCB_KEY_RELEASE)
{
// Check if we're in charge of the key release
if (!passEvent(event, reinterpret_cast<xcb_key_release_event_t*>(event)->event))
{
// Remember this key release event.
lastKeyReleaseEvent = reinterpret_cast<xcb_key_release_event_t*>(event);
event = NULL; // For safety reasons.
}
}
else
{
if (processEvent(event))
free(event);
}
if (!m_xcbEvents.empty())
{
event = m_xcbEvents.front();
m_xcbEvents.pop_front();
}
else
{
event = xcb_poll_for_event(m_connection);
}
}
// Process any held back release event.
if (lastKeyReleaseEvent)
{
if (processEvent(reinterpret_cast<xcb_generic_event_t*>(lastKeyReleaseEvent)))
free(lastKeyReleaseEvent);
lastKeyReleaseEvent = NULL;
} }
} }
@ -1847,28 +1604,57 @@ void WindowImplX11::cleanup()
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent) bool WindowImplX11::processEvent(XEvent windowEvent)
{ {
// This function implements a workaround to properly discard
// repeated key events when necessary. The problem is that the
// system's key events policy doesn't match SFML's one: X server will generate
// both repeated KeyPress and KeyRelease events when maintaining a key down, while
// SFML only wants repeated KeyPress events. Thus, we have to:
// - Discard duplicated KeyRelease events when KeyRepeatEnabled is true
// - Discard both duplicated KeyPress and KeyRelease events when KeyRepeatEnabled is false
// Detect repeated key events
// (code shamelessly taken from SDL)
if (windowEvent.type == KeyRelease)
{
// Check if there's a matching KeyPress event in the queue
XEvent nextEvent;
if (XPending(m_display))
{
// Grab it but don't remove it from the queue, it still needs to be processed :)
XPeekEvent(m_display, &nextEvent);
if (nextEvent.type == KeyPress)
{
// Check if it is a duplicated event (same timestamp as the KeyRelease event)
if ((nextEvent.xkey.keycode == windowEvent.xkey.keycode) &&
(nextEvent.xkey.time - windowEvent.xkey.time < 2))
{
// If we don't want repeated events, remove the next KeyPress from the queue
if (!m_keyRepeat)
XNextEvent(m_display, &nextEvent);
// This KeyRelease is a repeated event and we don't want it
return false;
}
}
}
}
// Convert the X11 event to a sf::Event // Convert the X11 event to a sf::Event
switch (windowEvent->response_type & ~0x80) switch (windowEvent.type)
{ {
// Destroy event // Destroy event
case XCB_DESTROY_NOTIFY: case DestroyNotify:
{ {
if (passEvent(windowEvent, reinterpret_cast<xcb_destroy_notify_event_t*>(windowEvent)->window))
return false;
// The window is about to be destroyed: we must cleanup resources // The window is about to be destroyed: we must cleanup resources
cleanup(); cleanup();
break; break;
} }
// Gain focus event // Gain focus event
case XCB_FOCUS_IN: case FocusIn:
{ {
if (passEvent(windowEvent, reinterpret_cast<xcb_focus_in_event_t*>(windowEvent)->event))
return false;
// Update the input context // Update the input context
if (m_inputContext) if (m_inputContext)
XSetICFocus(m_inputContext); XSetICFocus(m_inputContext);
@ -1909,11 +1695,8 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
} }
// Lost focus event // Lost focus event
case XCB_FOCUS_OUT: case FocusOut:
{ {
if (passEvent(windowEvent, reinterpret_cast<xcb_focus_out_event_t*>(windowEvent)->event))
return false;
// Update the input context // Update the input context
if (m_inputContext) if (m_inputContext)
XUnsetICFocus(m_inputContext); XUnsetICFocus(m_inputContext);
@ -1925,56 +1708,51 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
} }
// Resize event // Resize event
case XCB_CONFIGURE_NOTIFY: case ConfigureNotify:
{ {
if (passEvent(windowEvent, reinterpret_cast<xcb_configure_notify_event_t*>(windowEvent)->window)) // ConfigureNotify can be triggered for other reasons, check if the size has actually changed
return false; if ((windowEvent.xconfigure.width != m_previousSize.x) || (windowEvent.xconfigure.height != m_previousSize.y))
// X notifies about "window configuration events", which also includes moving a window only. Check
// for a different size and only spawn a Resized event when it differs.
xcb_configure_notify_event_t* e = reinterpret_cast<xcb_configure_notify_event_t*>(windowEvent);
if (e->width != m_previousSize.x || e->height != m_previousSize.y)
{ {
m_previousSize.x = e->width;
m_previousSize.y = e->height;
Event event; Event event;
event.type = Event::Resized; event.type = Event::Resized;
event.size.width = e->width; event.size.width = windowEvent.xconfigure.width;
event.size.height = e->height; event.size.height = windowEvent.xconfigure.height;
pushEvent(event); pushEvent(event);
m_previousSize.x = windowEvent.xconfigure.width;
m_previousSize.y = windowEvent.xconfigure.height;
} }
break; break;
} }
// Close event // Close event
case XCB_CLIENT_MESSAGE: case ClientMessage:
{ {
if (passEvent(windowEvent, reinterpret_cast<xcb_client_message_event_t*>(windowEvent)->window))
return false;
xcb_client_message_event_t* e = reinterpret_cast<xcb_client_message_event_t*>(windowEvent);
static xcb_atom_t wmProtocols = getAtom("WM_PROTOCOLS"); static xcb_atom_t wmProtocols = getAtom("WM_PROTOCOLS");
// Handle window manager protocol messages we support // Handle window manager protocol messages we support
if (e->type == wmProtocols) if (windowEvent.xclient.message_type == wmProtocols)
{ {
static xcb_atom_t wmDeleteWindow = getAtom("WM_DELETE_WINDOW"); static xcb_atom_t wmDeleteWindow = getAtom("WM_DELETE_WINDOW");
static xcb_atom_t netWmPing = ewmhSupported() ? getAtom("_NET_WM_PING", true) : XCB_ATOM_NONE; static xcb_atom_t netWmPing = ewmhSupported() ? getAtom("_NET_WM_PING", true) : XCB_ATOM_NONE;
if ((e->format == 32) && (e->data.data32[0]) == static_cast<long>(wmDeleteWindow)) if ((windowEvent.xclient.format == 32) && (windowEvent.xclient.data.l[0]) == static_cast<long>(wmDeleteWindow))
{ {
// Handle the WM_DELETE_WINDOW message // Handle the WM_DELETE_WINDOW message
Event event; Event event;
event.type = Event::Closed; event.type = Event::Closed;
pushEvent(event); pushEvent(event);
} }
else if (netWmPing && (e->format == 32) && (e->data.data32[0]) == static_cast<long>(netWmPing)) else if (netWmPing && (windowEvent.xclient.format == 32) && (windowEvent.xclient.data.l[0]) == static_cast<long>(netWmPing))
{ {
xcb_client_message_event_t event;
// Handle the _NET_WM_PING message, send pong back to WM to show that we are responsive // Handle the _NET_WM_PING message, send pong back to WM to show that we are responsive
e->window = XCBDefaultRootWindow(m_connection); event.response_type = XCB_CLIENT_MESSAGE;
event.format = windowEvent.xclient.format;
event.window = XCBDefaultRootWindow(m_connection);
event.type = windowEvent.xclient.message_type;
std::memcpy(event.data.data8, windowEvent.xclient.data.b, 20);
ScopedXcbPtr<xcb_generic_error_t> pongError(xcb_request_check( ScopedXcbPtr<xcb_generic_error_t> pongError(xcb_request_check(
m_connection, m_connection,
@ -1983,7 +1761,7 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
0, 0,
XCBDefaultRootWindow(m_connection), XCBDefaultRootWindow(m_connection),
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
reinterpret_cast<char*>(e) reinterpret_cast<char*>(&event)
) )
)); ));
@ -1995,33 +1773,27 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
} }
// Key down event // Key down event
case XCB_KEY_PRESS: case KeyPress:
{ {
if (passEvent(windowEvent, reinterpret_cast<xcb_key_press_event_t*>(windowEvent)->event)) // Get the keysym of the key that has been pressed
return false; static XComposeStatus keyboard;
char buffer[32];
xcb_key_press_event_t* e = reinterpret_cast<xcb_key_press_event_t*>(windowEvent); KeySym symbol;
XLookupString(&windowEvent.xkey, buffer, sizeof(buffer), &symbol, &keyboard);
// Fill the event parameters // Fill the event parameters
// TODO: if modifiers are wrong, use XGetModifierMapping to retrieve the actual modifiers mapping // TODO: if modifiers are wrong, use XGetModifierMapping to retrieve the actual modifiers mapping
Event event; Event event;
event.type = Event::KeyPressed; event.type = Event::KeyPressed;
event.key.code = keycodeToSF(e->detail); event.key.code = keysymToSF(symbol);
event.key.alt = e->state & XCB_MOD_MASK_1; event.key.alt = windowEvent.xkey.state & Mod1Mask;
event.key.control = e->state & XCB_MOD_MASK_CONTROL; event.key.control = windowEvent.xkey.state & ControlMask;
event.key.shift = e->state & XCB_MOD_MASK_SHIFT; event.key.shift = windowEvent.xkey.state & ShiftMask;
event.key.system = e->state & XCB_MOD_MASK_4; event.key.system = windowEvent.xkey.state & Mod4Mask;
pushEvent(event); pushEvent(event);
XEvent fakeEvent;
fakeEvent.type = KeyPress;
fakeEvent.xany.display = m_display;
fakeEvent.xany.window = e->event;
fakeEvent.xkey.state = e->state;
fakeEvent.xkey.keycode = e->detail;
// Generate a TextEntered event // Generate a TextEntered event
if (!XFilterEvent(&fakeEvent, None)) if (!XFilterEvent(&windowEvent, None))
{ {
#ifdef X_HAVE_UTF8_STRING #ifdef X_HAVE_UTF8_STRING
if (m_inputContext) if (m_inputContext)
@ -2031,7 +1803,7 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
int length = Xutf8LookupString( int length = Xutf8LookupString(
m_inputContext, m_inputContext,
&fakeEvent.xkey, &windowEvent.xkey,
reinterpret_cast<char*>(keyBuffer), reinterpret_cast<char*>(keyBuffer),
sizeof(keyBuffer), sizeof(keyBuffer),
NULL, NULL,
@ -2056,7 +1828,7 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
{ {
static XComposeStatus status; static XComposeStatus status;
char keyBuffer[16]; char keyBuffer[16];
if (XLookupString(&fakeEvent.xkey, keyBuffer, sizeof(keyBuffer), NULL, &status)) if (XLookupString(&windowEvent.xkey, keyBuffer, sizeof(keyBuffer), NULL, &status))
{ {
Event textEvent; Event textEvent;
textEvent.type = Event::TextEntered; textEvent.type = Event::TextEntered;
@ -2070,52 +1842,47 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
} }
// Key up event // Key up event
case XCB_KEY_RELEASE: case KeyRelease:
{ {
if (passEvent(windowEvent, reinterpret_cast<xcb_key_release_event_t*>(windowEvent)->event)) // Get the keysym of the key that has been pressed
return false; char buffer[32];
KeySym symbol;
xcb_key_release_event_t* e = reinterpret_cast<xcb_key_release_event_t*>(windowEvent); XLookupString(&windowEvent.xkey, buffer, 32, &symbol, NULL);
// Fill the event parameters // Fill the event parameters
Event event; Event event;
event.type = Event::KeyReleased; event.type = Event::KeyReleased;
event.key.code = keycodeToSF(e->detail); event.key.code = keysymToSF(symbol);
event.key.alt = e->state & XCB_MOD_MASK_1; event.key.alt = windowEvent.xkey.state & Mod1Mask;
event.key.control = e->state & XCB_MOD_MASK_CONTROL; event.key.control = windowEvent.xkey.state & ControlMask;
event.key.shift = e->state & XCB_MOD_MASK_SHIFT; event.key.shift = windowEvent.xkey.state & ShiftMask;
event.key.system = e->state & XCB_MOD_MASK_4; event.key.system = windowEvent.xkey.state & Mod4Mask;
pushEvent(event); pushEvent(event);
break; break;
} }
// Mouse button pressed // Mouse button pressed
case XCB_BUTTON_PRESS: case ButtonPress:
{ {
if (passEvent(windowEvent, reinterpret_cast<xcb_button_press_event_t*>(windowEvent)->event))
return false;
xcb_button_press_event_t* e = reinterpret_cast<xcb_button_press_event_t*>(windowEvent);
// XXX: Why button 8 and 9? // XXX: Why button 8 and 9?
// Because 4 and 5 are the vertical wheel and 6 and 7 are horizontal wheel ;) // Because 4 and 5 are the vertical wheel and 6 and 7 are horizontal wheel ;)
xcb_button_t button = e->detail; unsigned int button = windowEvent.xbutton.button;
if ((button == XCB_BUTTON_INDEX_1) || if ((button == Button1) ||
(button == XCB_BUTTON_INDEX_2) || (button == Button2) ||
(button == XCB_BUTTON_INDEX_3) || (button == Button3) ||
(button == 8) || (button == 8) ||
(button == 9)) (button == 9))
{ {
Event event; Event event;
event.type = Event::MouseButtonPressed; event.type = Event::MouseButtonPressed;
event.mouseButton.x = e->event_x; event.mouseButton.x = windowEvent.xbutton.x;
event.mouseButton.y = e->event_y; event.mouseButton.y = windowEvent.xbutton.y;
switch(button) switch(button)
{ {
case XCB_BUTTON_INDEX_1: event.mouseButton.button = Mouse::Left; break; case Button1: event.mouseButton.button = Mouse::Left; break;
case XCB_BUTTON_INDEX_2: event.mouseButton.button = Mouse::Middle; break; case Button2: event.mouseButton.button = Mouse::Middle; break;
case XCB_BUTTON_INDEX_3: event.mouseButton.button = Mouse::Right; break; case Button3: event.mouseButton.button = Mouse::Right; break;
case 8: event.mouseButton.button = Mouse::XButton1; break; case 8: event.mouseButton.button = Mouse::XButton1; break;
case 9: event.mouseButton.button = Mouse::XButton2; break; case 9: event.mouseButton.button = Mouse::XButton2; break;
} }
@ -2125,49 +1892,44 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
} }
// Mouse button released // Mouse button released
case XCB_BUTTON_RELEASE: case ButtonRelease:
{ {
if (passEvent(windowEvent, reinterpret_cast<xcb_button_release_event_t*>(windowEvent)->event)) unsigned int button = windowEvent.xbutton.button;
return false; if ((button == Button1) ||
(button == Button2) ||
xcb_button_release_event_t* e = reinterpret_cast<xcb_button_press_event_t*>(windowEvent); (button == Button3) ||
xcb_button_t button = e->detail;
if ((button == XCB_BUTTON_INDEX_1) ||
(button == XCB_BUTTON_INDEX_2) ||
(button == XCB_BUTTON_INDEX_3) ||
(button == 8) || (button == 8) ||
(button == 9)) (button == 9))
{ {
Event event; Event event;
event.type = Event::MouseButtonReleased; event.type = Event::MouseButtonReleased;
event.mouseButton.x = e->event_x; event.mouseButton.x = windowEvent.xbutton.x;
event.mouseButton.y = e->event_y; event.mouseButton.y = windowEvent.xbutton.y;
switch(button) switch(button)
{ {
case XCB_BUTTON_INDEX_1: event.mouseButton.button = Mouse::Left; break; case Button1: event.mouseButton.button = Mouse::Left; break;
case XCB_BUTTON_INDEX_2: event.mouseButton.button = Mouse::Middle; break; case Button2: event.mouseButton.button = Mouse::Middle; break;
case XCB_BUTTON_INDEX_3: event.mouseButton.button = Mouse::Right; break; case Button3: event.mouseButton.button = Mouse::Right; break;
case 8: event.mouseButton.button = Mouse::XButton1; break; case 8: event.mouseButton.button = Mouse::XButton1; break;
case 9: event.mouseButton.button = Mouse::XButton2; break; case 9: event.mouseButton.button = Mouse::XButton2; break;
} }
pushEvent(event); pushEvent(event);
} }
else if ((button == XCB_BUTTON_INDEX_4) || (button == XCB_BUTTON_INDEX_5)) else if ((button == Button4) || (button == Button5))
{ {
Event event; Event event;
event.type = Event::MouseWheelMoved; event.type = Event::MouseWheelMoved;
event.mouseWheel.delta = (button == XCB_BUTTON_INDEX_4) ? 1 : -1; event.mouseWheel.delta = (button == Button4) ? 1 : -1;
event.mouseWheel.x = e->event_x; event.mouseWheel.x = windowEvent.xbutton.x;
event.mouseWheel.y = e->event_y; event.mouseWheel.y = windowEvent.xbutton.y;
pushEvent(event); pushEvent(event);
event.type = Event::MouseWheelScrolled; event.type = Event::MouseWheelScrolled;
event.mouseWheelScroll.wheel = Mouse::VerticalWheel; event.mouseWheelScroll.wheel = Mouse::VerticalWheel;
event.mouseWheelScroll.delta = (button == XCB_BUTTON_INDEX_4) ? 1 : -1; event.mouseWheelScroll.delta = (button == Button4) ? 1 : -1;
event.mouseWheelScroll.x = e->event_x; event.mouseWheelScroll.x = windowEvent.xbutton.x;
event.mouseWheelScroll.y = e->event_y; event.mouseWheelScroll.y = windowEvent.xbutton.y;
pushEvent(event); pushEvent(event);
} }
else if ((button == 6) || (button == 7)) else if ((button == 6) || (button == 7))
@ -2176,37 +1938,28 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
event.type = Event::MouseWheelScrolled; event.type = Event::MouseWheelScrolled;
event.mouseWheelScroll.wheel = Mouse::HorizontalWheel; event.mouseWheelScroll.wheel = Mouse::HorizontalWheel;
event.mouseWheelScroll.delta = (button == 6) ? 1 : -1; event.mouseWheelScroll.delta = (button == 6) ? 1 : -1;
event.mouseWheelScroll.x = e->event_x; event.mouseWheelScroll.x = windowEvent.xbutton.x;
event.mouseWheelScroll.y = e->event_y; event.mouseWheelScroll.y = windowEvent.xbutton.y;
pushEvent(event); pushEvent(event);
} }
break; break;
} }
// Mouse moved // Mouse moved
case XCB_MOTION_NOTIFY: case MotionNotify:
{ {
if (passEvent(windowEvent, reinterpret_cast<xcb_motion_notify_event_t*>(windowEvent)->event))
return false;
xcb_motion_notify_event_t* e = reinterpret_cast<xcb_motion_notify_event_t*>(windowEvent);
Event event; Event event;
event.type = Event::MouseMoved; event.type = Event::MouseMoved;
event.mouseMove.x = e->event_x; event.mouseMove.x = windowEvent.xmotion.x;
event.mouseMove.y = e->event_y; event.mouseMove.y = windowEvent.xmotion.y;
pushEvent(event); pushEvent(event);
break; break;
} }
// Mouse entered // Mouse entered
case XCB_ENTER_NOTIFY: case EnterNotify:
{ {
if (passEvent(windowEvent, reinterpret_cast<xcb_enter_notify_event_t*>(windowEvent)->event)) if (windowEvent.xcrossing.mode == NotifyNormal)
return false;
xcb_enter_notify_event_t* enterNotifyEvent = reinterpret_cast<xcb_enter_notify_event_t*>(windowEvent);
if (enterNotifyEvent->mode == NotifyNormal)
{ {
Event event; Event event;
event.type = Event::MouseEntered; event.type = Event::MouseEntered;
@ -2216,14 +1969,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
} }
// Mouse left // Mouse left
case XCB_LEAVE_NOTIFY: case LeaveNotify:
{ {
if (passEvent(windowEvent, reinterpret_cast<xcb_leave_notify_event_t*>(windowEvent)->event)) if (windowEvent.xcrossing.mode == NotifyNormal)
return false;
xcb_leave_notify_event_t* leaveNotifyEvent = reinterpret_cast<xcb_leave_notify_event_t*>(windowEvent);
if (leaveNotifyEvent->mode == NotifyNormal)
{ {
Event event; Event event;
event.type = Event::MouseLeft; event.type = Event::MouseLeft;
@ -2233,152 +1981,15 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
} }
// Parent window changed // Parent window changed
case XCB_REPARENT_NOTIFY: case ReparentNotify:
{ {
if (passEvent(windowEvent, reinterpret_cast<xcb_reparent_notify_event_t*>(windowEvent)->window))
return false;
// Catch reparent events to properly apply fullscreen on // Catch reparent events to properly apply fullscreen on
// some "strange" window managers (like Awesome) which // some "strange" window managers (like Awesome) which
// seem to make use of temporary parents during mapping // seem to make use of temporary parents during mapping
if (m_fullscreen) if (m_fullscreen)
switchToFullscreen(); switchToFullscreen();
xcb_flush(m_connection); // Discard remaining events XSync(m_display, True); // Discard remaining events
break;
}
// The stuff that might pop up but we don't care about
// Whitelist more when necessary
// Window visibility changed (hide/unhide)
case XCB_MAP_NOTIFY:
case XCB_UNMAP_NOTIFY:
{
break;
}
// Handle the rest
default:
{
uint8_t responseType = windowEvent->response_type & ~0x80;
// Handle any extension events first
// SHAPE
// Ubuntu's Unity desktop environment makes use of the
// Compiz compositing window manager
// Compiz seems to send SHAPE events to windows even if they
// did not specifically select those events
// We ignore those events here in order to not generate warnings
static xcb_query_extension_reply_t shapeExtension = getXExtension("SHAPE");
if (shapeExtension.present && (responseType == shapeExtension.first_event))
break;
// DRI2
static xcb_query_extension_reply_t driExtension = getXExtension("DRI2");
if (driExtension.present)
{
// Because we are using the XCB event queue instead of the Xlib event
// queue, Mesa breaks a bit (VSync among other things) because DRI2 still
// expects certain Xlib events to come its way. We work around this by
// emulating the old Xlib event queue for these specific wire events.
// Sources (retrieved 27 Mar 2015):
// http://wrl.illest.net/post/45342765813/code-tip-glx-and-xcbownseventqueue
// https://bugs.freedesktop.org/show_bug.cgi?id=42131
// https://bugs.freedesktop.org/show_bug.cgi?id=35945
// Mesa src/glx/dri2.c
// QtBase src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp
// QtBase Commit bb22b4965070409df4658f16fdf549f0362e8a9c
// Qt Change-Id I3b4ef3f6e3efbae25f49f161e229e9b15e951778
// QtBase Commit 13c5c81cfa934c9b610720fe79e07465b00ebc8d
// Qt Change-Id Ia93eb8be1cbbc3d8ae7913a934c195af6b5ec538
// QtBase Commit decb88693c8a7f0c073889b91151f01a850e3adf
// Qt Change-Id Ic466ff26487937b03f072a57e0ee4df335492a5f
if ((responseType == driExtension.first_event + XCB_DRI2_BUFFER_SWAP_COMPLETE) ||
(responseType == driExtension.first_event + XCB_DRI2_INVALIDATE_BUFFERS))
{
// DRI2 BufferSwapComplete and InvalidateBuffers
// We lock/unlock the display to protect against concurrent access
XLockDisplay(m_display);
typedef Bool (*wireEventHandler)(Display*, XEvent*, xEvent*);
// Probe for any handlers that are registered for this event type
wireEventHandler handler = XESetWireToEvent(m_display, responseType, 0);
if (handler)
{
// Restore the previous handler if one was registered
XESetWireToEvent(m_display, responseType, handler);
XEvent event;
windowEvent->sequence = LastKnownRequestProcessed(m_display);
// Pretend to be the Xlib event queue
handler(m_display, &event, reinterpret_cast<xEvent*>(windowEvent));
}
XUnlockDisplay(m_display);
return true;
}
}
// XKEYBOARD
// When the X server sends us XKEYBOARD events, it means that
// the user probably changed the layout of their keyboard
// We update our keymaps in that case
static xcb_query_extension_reply_t xkeyboardExtension = getXExtension("XKEYBOARD");
if (xkeyboardExtension.present && (responseType == xkeyboardExtension.first_event))
{
// We do this so we don't have to include the xkb header for the struct declaration
uint8_t xkbType = reinterpret_cast<const uint8_t*>(windowEvent)[1];
// We only bother rebuilding our maps if the xkb mapping actually changes
if ((xkbType == XCB_XKB_NEW_KEYBOARD_NOTIFY) || (xkbType == XCB_XKB_MAP_NOTIFY))
{
// keysym map
buildKeysymMap();
// keycode to SFML
buildMap();
// SFML to keycode
InputImpl::buildMap();
// XInputMethod expects keyboard mapping changes to be propagated to it
// Same idea here as with the DRI2 events above
// We lock/unlock the display to protect against concurrent access
XLockDisplay(m_display);
typedef Bool (*wireEventHandler)(Display*, XEvent*, xEvent*);
// Probe for any handlers that are registered for this event type
wireEventHandler handler = XESetWireToEvent(m_display, responseType, 0);
if (handler)
{
// Restore the previous handler if one was registered
XESetWireToEvent(m_display, responseType, handler);
XEvent event;
windowEvent->sequence = LastKnownRequestProcessed(m_display);
// Pretend to be the Xlib event queue
handler(m_display, &event, reinterpret_cast<xEvent*>(windowEvent));
}
XUnlockDisplay(m_display);
}
break;
}
// Print any surprises to stderr (would be nice if people report when this happens)
dumpUnhandledEvent(responseType);
break; break;
} }
} }
@ -2386,33 +1997,6 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
return true; return true;
} }
////////////////////////////////////////////////////////////
bool WindowImplX11::passEvent(xcb_generic_event_t* windowEvent, xcb_window_t window)
{
// Check if this is our event
if (window == m_window)
return false;
Lock lock(allWindowsMutex);
// If we are the only window, there is nobody else to pass to
if (allWindows.size() == 1)
return false;
for (std::vector<WindowImplX11*>::iterator i = allWindows.begin(); i != allWindows.end(); ++i)
{
if ((*i)->m_window == window)
{
(*i)->m_xcbEvents.push_back(windowEvent);
return true;
}
}
// It seems nobody wants the event, we'll just handle it ourselves
return false;
}
} // namespace priv } // namespace priv
} // namespace sf } // namespace sf

View File

@ -301,18 +301,7 @@ private:
/// \return True if the event was processed, false if it was discarded /// \return True if the event was processed, false if it was discarded
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool processEvent(xcb_generic_event_t* windowEvent); bool processEvent(XEvent windowEvent);
////////////////////////////////////////////////////////////
/// \brief Pass an incoming event to another window
///
/// \param windowEvent Event which is being processed
/// \param window Window to pass to
///
/// \return True if the event was passed to another window, false if it is destined for the current window
///
////////////////////////////////////////////////////////////
bool passEvent(xcb_generic_event_t* windowEvent, xcb_window_t window);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
@ -323,7 +312,6 @@ private:
xcb_screen_t* m_screen; ///< Screen identifier xcb_screen_t* m_screen; ///< Screen identifier
XIM m_inputMethod; ///< Input method linked to the X display XIM m_inputMethod; ///< Input method linked to the X display
XIC m_inputContext; ///< Input context used to get unicode input in our window XIC m_inputContext; ///< Input context used to get unicode input in our window
std::deque<xcb_generic_event_t*> m_xcbEvents; ///< Events that were received in another window's loop
bool m_isExternal; ///< Tell whether the window has been created externally or by SFML bool m_isExternal; ///< Tell whether the window has been created externally or by SFML
xcb_randr_get_screen_info_reply_t m_oldVideoMode; ///< Video mode in use before we switch to fullscreen xcb_randr_get_screen_info_reply_t m_oldVideoMode; ///< Video mode in use before we switch to fullscreen
Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hidding, we must create a transparent one Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hidding, we must create a transparent one