mirror of
https://github.com/SFML/SFML.git
synced 2024-11-28 22:31:09 +08:00
Reverted to Xlib event handling since XCB event handling just breaks too many things.
This commit is contained in:
parent
7c179193e6
commit
561eb82f14
@ -30,8 +30,6 @@
|
||||
#include <SFML/Window/Unix/ScopedXcbPtr.hpp>
|
||||
#include <X11/keysym.h>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
|
||||
@ -43,108 +41,6 @@ namespace
|
||||
|
||||
typedef std::map<std::string, xcb_atom_t> AtomMap;
|
||||
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
|
||||
@ -268,89 +164,6 @@ xcb_atom_t getAtom(const std::string& name, bool onlyIfExists)
|
||||
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 sf
|
||||
|
@ -116,23 +116,6 @@ xcb_window_t XCBDefaultRootWindow(xcb_connection_t* connection);
|
||||
////////////////////////////////////////////////////////////
|
||||
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 sf
|
||||
|
@ -32,34 +32,6 @@
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <xcb/xcb.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
|
||||
@ -69,15 +41,125 @@ namespace priv
|
||||
////////////////////////////////////////////////////////////
|
||||
bool InputImpl::isKeyPressed(Keyboard::Key key)
|
||||
{
|
||||
if (!mapBuilt)
|
||||
buildMap();
|
||||
// Get the corresponding X11 keysym
|
||||
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
|
||||
if (key < 0 || key >= sf::Keyboard::KeyCount)
|
||||
return false;
|
||||
|
||||
// Open a connection with the X server
|
||||
Display* display = OpenDisplay();
|
||||
|
||||
// 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);
|
||||
|
||||
@ -316,115 +398,6 @@ Vector2i InputImpl::getTouchPosition(unsigned int /*finger*/, const Window& /*re
|
||||
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 sf
|
||||
|
@ -158,12 +158,6 @@ public:
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static Vector2i getTouchPosition(unsigned int finger, const Window& relativeTo);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Build the SFML to X11 keymap
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void buildMap();
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
@ -47,14 +47,6 @@
|
||||
#include <string>
|
||||
#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
|
||||
#include <SFML/Window/EglContext.hpp>
|
||||
typedef sf::priv::EglContext ContextType;
|
||||
@ -73,18 +65,19 @@ namespace
|
||||
sf::Mutex allWindowsMutex;
|
||||
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 |
|
||||
XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION |
|
||||
XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_KEY_PRESS |
|
||||
XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_STRUCTURE_NOTIFY |
|
||||
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
|
||||
std::string findExecutableName()
|
||||
{
|
||||
@ -245,124 +238,6 @@ namespace
|
||||
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)
|
||||
{
|
||||
switch (symbol)
|
||||
@ -473,27 +348,6 @@ namespace
|
||||
|
||||
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();
|
||||
|
||||
m_screen = XCBDefaultScreen(m_connection);
|
||||
XSetEventQueueOwner(m_display, XCBOwnsEventQueue);
|
||||
|
||||
// Save the window handle
|
||||
m_window = handle;
|
||||
@ -583,7 +436,6 @@ m_fullscreen ((style & Style::Fullscreen) != 0)
|
||||
ewmhSupported();
|
||||
|
||||
m_screen = XCBDefaultScreen(m_connection);
|
||||
XSetEventQueueOwner(m_display, XCBOwnsEventQueue);
|
||||
|
||||
// Compute position and size
|
||||
int left = m_fullscreen ? 0 : (m_screen->width_in_pixels - mode.width) / 2;
|
||||
@ -737,105 +589,10 @@ WindowHandle WindowImplX11::getSystemHandle() const
|
||||
////////////////////////////////////////////////////////////
|
||||
void WindowImplX11::processEvents()
|
||||
{
|
||||
// Key repeat workaround: If key repeat is enabled, XCB will spawn two
|
||||
// events for each repeat interval: key release and key press. Both have
|
||||
// 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())
|
||||
XEvent event;
|
||||
while (XCheckIfEvent(m_display, &event, &checkEvent, reinterpret_cast<XPointer>(m_window)))
|
||||
{
|
||||
event = m_xcbEvents.front();
|
||||
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;
|
||||
processEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
switch (windowEvent->response_type & ~0x80)
|
||||
switch (windowEvent.type)
|
||||
{
|
||||
// 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
|
||||
cleanup();
|
||||
break;
|
||||
}
|
||||
|
||||
// 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
|
||||
if (m_inputContext)
|
||||
XSetICFocus(m_inputContext);
|
||||
@ -1909,11 +1695,8 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
}
|
||||
|
||||
// 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
|
||||
if (m_inputContext)
|
||||
XUnsetICFocus(m_inputContext);
|
||||
@ -1925,56 +1708,51 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
}
|
||||
|
||||
// Resize event
|
||||
case XCB_CONFIGURE_NOTIFY:
|
||||
case ConfigureNotify:
|
||||
{
|
||||
if (passEvent(windowEvent, reinterpret_cast<xcb_configure_notify_event_t*>(windowEvent)->window))
|
||||
return false;
|
||||
|
||||
// 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)
|
||||
// ConfigureNotify can be triggered for other reasons, check if the size has actually changed
|
||||
if ((windowEvent.xconfigure.width != m_previousSize.x) || (windowEvent.xconfigure.height != m_previousSize.y))
|
||||
{
|
||||
m_previousSize.x = e->width;
|
||||
m_previousSize.y = e->height;
|
||||
|
||||
Event event;
|
||||
event.type = Event::Resized;
|
||||
event.size.width = e->width;
|
||||
event.size.height = e->height;
|
||||
event.size.width = windowEvent.xconfigure.width;
|
||||
event.size.height = windowEvent.xconfigure.height;
|
||||
pushEvent(event);
|
||||
|
||||
m_previousSize.x = windowEvent.xconfigure.width;
|
||||
m_previousSize.y = windowEvent.xconfigure.height;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// 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");
|
||||
|
||||
// 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 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
|
||||
Event event;
|
||||
event.type = Event::Closed;
|
||||
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
|
||||
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(
|
||||
m_connection,
|
||||
@ -1983,7 +1761,7 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
0,
|
||||
XCBDefaultRootWindow(m_connection),
|
||||
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
|
||||
case XCB_KEY_PRESS:
|
||||
case KeyPress:
|
||||
{
|
||||
if (passEvent(windowEvent, reinterpret_cast<xcb_key_press_event_t*>(windowEvent)->event))
|
||||
return false;
|
||||
|
||||
xcb_key_press_event_t* e = reinterpret_cast<xcb_key_press_event_t*>(windowEvent);
|
||||
// Get the keysym of the key that has been pressed
|
||||
static XComposeStatus keyboard;
|
||||
char buffer[32];
|
||||
KeySym symbol;
|
||||
XLookupString(&windowEvent.xkey, buffer, sizeof(buffer), &symbol, &keyboard);
|
||||
|
||||
// Fill the event parameters
|
||||
// TODO: if modifiers are wrong, use XGetModifierMapping to retrieve the actual modifiers mapping
|
||||
Event event;
|
||||
event.type = Event::KeyPressed;
|
||||
event.key.code = keycodeToSF(e->detail);
|
||||
event.key.alt = e->state & XCB_MOD_MASK_1;
|
||||
event.key.control = e->state & XCB_MOD_MASK_CONTROL;
|
||||
event.key.shift = e->state & XCB_MOD_MASK_SHIFT;
|
||||
event.key.system = e->state & XCB_MOD_MASK_4;
|
||||
event.key.code = keysymToSF(symbol);
|
||||
event.key.alt = windowEvent.xkey.state & Mod1Mask;
|
||||
event.key.control = windowEvent.xkey.state & ControlMask;
|
||||
event.key.shift = windowEvent.xkey.state & ShiftMask;
|
||||
event.key.system = windowEvent.xkey.state & Mod4Mask;
|
||||
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
|
||||
if (!XFilterEvent(&fakeEvent, None))
|
||||
if (!XFilterEvent(&windowEvent, None))
|
||||
{
|
||||
#ifdef X_HAVE_UTF8_STRING
|
||||
if (m_inputContext)
|
||||
@ -2031,7 +1803,7 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
|
||||
int length = Xutf8LookupString(
|
||||
m_inputContext,
|
||||
&fakeEvent.xkey,
|
||||
&windowEvent.xkey,
|
||||
reinterpret_cast<char*>(keyBuffer),
|
||||
sizeof(keyBuffer),
|
||||
NULL,
|
||||
@ -2056,7 +1828,7 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
{
|
||||
static XComposeStatus status;
|
||||
char keyBuffer[16];
|
||||
if (XLookupString(&fakeEvent.xkey, keyBuffer, sizeof(keyBuffer), NULL, &status))
|
||||
if (XLookupString(&windowEvent.xkey, keyBuffer, sizeof(keyBuffer), NULL, &status))
|
||||
{
|
||||
Event textEvent;
|
||||
textEvent.type = Event::TextEntered;
|
||||
@ -2070,52 +1842,47 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
}
|
||||
|
||||
// Key up event
|
||||
case XCB_KEY_RELEASE:
|
||||
case KeyRelease:
|
||||
{
|
||||
if (passEvent(windowEvent, reinterpret_cast<xcb_key_release_event_t*>(windowEvent)->event))
|
||||
return false;
|
||||
|
||||
xcb_key_release_event_t* e = reinterpret_cast<xcb_key_release_event_t*>(windowEvent);
|
||||
// Get the keysym of the key that has been pressed
|
||||
char buffer[32];
|
||||
KeySym symbol;
|
||||
XLookupString(&windowEvent.xkey, buffer, 32, &symbol, NULL);
|
||||
|
||||
// Fill the event parameters
|
||||
Event event;
|
||||
event.type = Event::KeyReleased;
|
||||
event.key.code = keycodeToSF(e->detail);
|
||||
event.key.alt = e->state & XCB_MOD_MASK_1;
|
||||
event.key.control = e->state & XCB_MOD_MASK_CONTROL;
|
||||
event.key.shift = e->state & XCB_MOD_MASK_SHIFT;
|
||||
event.key.system = e->state & XCB_MOD_MASK_4;
|
||||
event.key.code = keysymToSF(symbol);
|
||||
event.key.alt = windowEvent.xkey.state & Mod1Mask;
|
||||
event.key.control = windowEvent.xkey.state & ControlMask;
|
||||
event.key.shift = windowEvent.xkey.state & ShiftMask;
|
||||
event.key.system = windowEvent.xkey.state & Mod4Mask;
|
||||
pushEvent(event);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// 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?
|
||||
// Because 4 and 5 are the vertical wheel and 6 and 7 are horizontal wheel ;)
|
||||
xcb_button_t button = e->detail;
|
||||
if ((button == XCB_BUTTON_INDEX_1) ||
|
||||
(button == XCB_BUTTON_INDEX_2) ||
|
||||
(button == XCB_BUTTON_INDEX_3) ||
|
||||
unsigned int button = windowEvent.xbutton.button;
|
||||
if ((button == Button1) ||
|
||||
(button == Button2) ||
|
||||
(button == Button3) ||
|
||||
(button == 8) ||
|
||||
(button == 9))
|
||||
{
|
||||
Event event;
|
||||
event.type = Event::MouseButtonPressed;
|
||||
event.mouseButton.x = e->event_x;
|
||||
event.mouseButton.y = e->event_y;
|
||||
event.mouseButton.x = windowEvent.xbutton.x;
|
||||
event.mouseButton.y = windowEvent.xbutton.y;
|
||||
switch(button)
|
||||
{
|
||||
case XCB_BUTTON_INDEX_1: event.mouseButton.button = Mouse::Left; break;
|
||||
case XCB_BUTTON_INDEX_2: event.mouseButton.button = Mouse::Middle; break;
|
||||
case XCB_BUTTON_INDEX_3: event.mouseButton.button = Mouse::Right; break;
|
||||
case Button1: event.mouseButton.button = Mouse::Left; break;
|
||||
case Button2: event.mouseButton.button = Mouse::Middle; break;
|
||||
case Button3: event.mouseButton.button = Mouse::Right; break;
|
||||
case 8: event.mouseButton.button = Mouse::XButton1; break;
|
||||
case 9: event.mouseButton.button = Mouse::XButton2; break;
|
||||
}
|
||||
@ -2125,49 +1892,44 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
}
|
||||
|
||||
// Mouse button released
|
||||
case XCB_BUTTON_RELEASE:
|
||||
case ButtonRelease:
|
||||
{
|
||||
if (passEvent(windowEvent, reinterpret_cast<xcb_button_release_event_t*>(windowEvent)->event))
|
||||
return false;
|
||||
|
||||
xcb_button_release_event_t* e = reinterpret_cast<xcb_button_press_event_t*>(windowEvent);
|
||||
|
||||
xcb_button_t button = e->detail;
|
||||
if ((button == XCB_BUTTON_INDEX_1) ||
|
||||
(button == XCB_BUTTON_INDEX_2) ||
|
||||
(button == XCB_BUTTON_INDEX_3) ||
|
||||
unsigned int button = windowEvent.xbutton.button;
|
||||
if ((button == Button1) ||
|
||||
(button == Button2) ||
|
||||
(button == Button3) ||
|
||||
(button == 8) ||
|
||||
(button == 9))
|
||||
{
|
||||
Event event;
|
||||
event.type = Event::MouseButtonReleased;
|
||||
event.mouseButton.x = e->event_x;
|
||||
event.mouseButton.y = e->event_y;
|
||||
event.mouseButton.x = windowEvent.xbutton.x;
|
||||
event.mouseButton.y = windowEvent.xbutton.y;
|
||||
switch(button)
|
||||
{
|
||||
case XCB_BUTTON_INDEX_1: event.mouseButton.button = Mouse::Left; break;
|
||||
case XCB_BUTTON_INDEX_2: event.mouseButton.button = Mouse::Middle; break;
|
||||
case XCB_BUTTON_INDEX_3: event.mouseButton.button = Mouse::Right; break;
|
||||
case Button1: event.mouseButton.button = Mouse::Left; break;
|
||||
case Button2: event.mouseButton.button = Mouse::Middle; break;
|
||||
case Button3: event.mouseButton.button = Mouse::Right; break;
|
||||
case 8: event.mouseButton.button = Mouse::XButton1; break;
|
||||
case 9: event.mouseButton.button = Mouse::XButton2; break;
|
||||
}
|
||||
pushEvent(event);
|
||||
}
|
||||
else if ((button == XCB_BUTTON_INDEX_4) || (button == XCB_BUTTON_INDEX_5))
|
||||
else if ((button == Button4) || (button == Button5))
|
||||
{
|
||||
Event event;
|
||||
|
||||
event.type = Event::MouseWheelMoved;
|
||||
event.mouseWheel.delta = (button == XCB_BUTTON_INDEX_4) ? 1 : -1;
|
||||
event.mouseWheel.x = e->event_x;
|
||||
event.mouseWheel.y = e->event_y;
|
||||
event.mouseWheel.delta = (button == Button4) ? 1 : -1;
|
||||
event.mouseWheel.x = windowEvent.xbutton.x;
|
||||
event.mouseWheel.y = windowEvent.xbutton.y;
|
||||
pushEvent(event);
|
||||
|
||||
event.type = Event::MouseWheelScrolled;
|
||||
event.mouseWheelScroll.wheel = Mouse::VerticalWheel;
|
||||
event.mouseWheelScroll.delta = (button == XCB_BUTTON_INDEX_4) ? 1 : -1;
|
||||
event.mouseWheelScroll.x = e->event_x;
|
||||
event.mouseWheelScroll.y = e->event_y;
|
||||
event.mouseWheelScroll.delta = (button == Button4) ? 1 : -1;
|
||||
event.mouseWheelScroll.x = windowEvent.xbutton.x;
|
||||
event.mouseWheelScroll.y = windowEvent.xbutton.y;
|
||||
pushEvent(event);
|
||||
}
|
||||
else if ((button == 6) || (button == 7))
|
||||
@ -2176,37 +1938,28 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
event.type = Event::MouseWheelScrolled;
|
||||
event.mouseWheelScroll.wheel = Mouse::HorizontalWheel;
|
||||
event.mouseWheelScroll.delta = (button == 6) ? 1 : -1;
|
||||
event.mouseWheelScroll.x = e->event_x;
|
||||
event.mouseWheelScroll.y = e->event_y;
|
||||
event.mouseWheelScroll.x = windowEvent.xbutton.x;
|
||||
event.mouseWheelScroll.y = windowEvent.xbutton.y;
|
||||
pushEvent(event);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// 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.type = Event::MouseMoved;
|
||||
event.mouseMove.x = e->event_x;
|
||||
event.mouseMove.y = e->event_y;
|
||||
event.mouseMove.x = windowEvent.xmotion.x;
|
||||
event.mouseMove.y = windowEvent.xmotion.y;
|
||||
pushEvent(event);
|
||||
break;
|
||||
}
|
||||
|
||||
// Mouse entered
|
||||
case XCB_ENTER_NOTIFY:
|
||||
case EnterNotify:
|
||||
{
|
||||
if (passEvent(windowEvent, reinterpret_cast<xcb_enter_notify_event_t*>(windowEvent)->event))
|
||||
return false;
|
||||
|
||||
xcb_enter_notify_event_t* enterNotifyEvent = reinterpret_cast<xcb_enter_notify_event_t*>(windowEvent);
|
||||
|
||||
if (enterNotifyEvent->mode == NotifyNormal)
|
||||
if (windowEvent.xcrossing.mode == NotifyNormal)
|
||||
{
|
||||
Event event;
|
||||
event.type = Event::MouseEntered;
|
||||
@ -2216,14 +1969,9 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
}
|
||||
|
||||
// Mouse left
|
||||
case XCB_LEAVE_NOTIFY:
|
||||
case LeaveNotify:
|
||||
{
|
||||
if (passEvent(windowEvent, reinterpret_cast<xcb_leave_notify_event_t*>(windowEvent)->event))
|
||||
return false;
|
||||
|
||||
xcb_leave_notify_event_t* leaveNotifyEvent = reinterpret_cast<xcb_leave_notify_event_t*>(windowEvent);
|
||||
|
||||
if (leaveNotifyEvent->mode == NotifyNormal)
|
||||
if (windowEvent.xcrossing.mode == NotifyNormal)
|
||||
{
|
||||
Event event;
|
||||
event.type = Event::MouseLeft;
|
||||
@ -2233,152 +1981,15 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
}
|
||||
|
||||
// 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
|
||||
// some "strange" window managers (like Awesome) which
|
||||
// seem to make use of temporary parents during mapping
|
||||
if (m_fullscreen)
|
||||
switchToFullscreen();
|
||||
|
||||
xcb_flush(m_connection); // 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);
|
||||
|
||||
XSync(m_display, True); // Discard remaining events
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2386,33 +1997,6 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
||||
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 sf
|
||||
|
@ -301,18 +301,7 @@ private:
|
||||
/// \return True if the event was processed, false if it was discarded
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool processEvent(xcb_generic_event_t* 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);
|
||||
bool processEvent(XEvent windowEvent);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
@ -323,7 +312,6 @@ private:
|
||||
xcb_screen_t* m_screen; ///< Screen identifier
|
||||
XIM m_inputMethod; ///< Input method linked to the X display
|
||||
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
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user