1 /*
2  * barrier -- mouse and keyboard sharing utility
3  * Copyright (C) 2012-2016 Symless Ltd.
4  * Copyright (C) 2003 Chris Schoeneman
5  *
6  * This package is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * found in the file LICENSE that should have accompanied this file.
9  *
10  * This package is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #pragma once
20 
21 #include "barrier/KeyState.h"
22 #include "common/stdmap.h"
23 #include "common/stdvector.h"
24 #include "XWindowsImpl.h"
25 
26 #if X_DISPLAY_MISSING
27 #    error X11 is required to build barrier
28 #else
29 #    include <X11/Xlib.h>
30 #    if HAVE_X11_EXTENSIONS_XTEST_H
31 #        include <X11/extensions/XTest.h>
32 #    else
33 #        error The XTest extension is required to build barrier
34 #    endif
35 #    if HAVE_XKB_EXTENSION
36 #        include <X11/extensions/XKBstr.h>
37 #    endif
38 #endif
39 
40 class IEventQueue;
41 
42 //! X Windows key state
43 /*!
44 A key state for X Windows.
45 */
46 class XWindowsKeyState : public KeyState {
47 public:
48     typedef std::vector<int> KeycodeList;
49     enum {
50         kGroupPoll       = -1,
51         kGroupPollAndSet = -2
52     };
53 
54     XWindowsKeyState(IXWindowsImpl* impl, Display*, bool useXKB,
55                      IEventQueue* events);
56     XWindowsKeyState(IXWindowsImpl* impl, Display*, bool useXKB,
57                      IEventQueue* events, barrier::KeyMap& keyMap);
58     ~XWindowsKeyState();
59 
60     //! @name modifiers
61     //@{
62 
63     //! Set active group
64     /*!
65     Sets the active group to \p group.  This is the group returned by
66     \c pollActiveGroup().  If \p group is \c kGroupPoll then
67     \c pollActiveGroup() will really poll, but that's a slow operation
68     on X11.  If \p group is \c kGroupPollAndSet then this will poll the
69     active group now and use it for future calls to \c pollActiveGroup().
70     */
71     void                setActiveGroup(SInt32 group);
72 
73     //! Set the auto-repeat state
74     /*!
75     Sets the auto-repeat state.
76     */
77     void                setAutoRepeat(const XKeyboardState&);
78 
79     //@}
80     //! @name accessors
81     //@{
82 
83     //! Convert X modifier mask to barrier mask
84     /*!
85     Returns the barrier modifier mask corresponding to the X modifier
86     mask in \p state.
87     */
88     KeyModifierMask        mapModifiersFromX(unsigned int state) const;
89 
90     //! Convert barrier modifier mask to X mask
91     /*!
92     Converts the barrier modifier mask to the corresponding X modifier
93     mask.  Returns \c true if successful and \c false if any modifier
94     could not be converted.
95     */
96     bool                mapModifiersToX(KeyModifierMask, unsigned int&) const;
97 
98     //! Convert barrier key to all corresponding X keycodes
99     /*!
100     Converts the barrier key \p key to all of the keycodes that map to
101     that key.
102     */
103     void                mapKeyToKeycodes(KeyID key,
104                             KeycodeList& keycodes) const;
105 
106     //@}
107 
108     // IKeyState overrides
109     virtual bool        fakeCtrlAltDel();
110     virtual KeyModifierMask
111                         pollActiveModifiers() const;
112     virtual SInt32        pollActiveGroup() const;
113     virtual void        pollPressedKeys(KeyButtonSet& pressedKeys) const;
114 
115 protected:
116     // KeyState overrides
117     virtual void        getKeyMap(barrier::KeyMap& keyMap);
118     virtual void        fakeKey(const Keystroke& keystroke);
119 
120 private:
121     void                init(Display* display, bool useXKB);
122     void                updateKeysymMap(barrier::KeyMap&);
123     void                updateKeysymMapXKB(barrier::KeyMap&);
124     bool                hasModifiersXKB() const;
125     int                    getEffectiveGroup(KeyCode, int group) const;
126     UInt32                getGroupFromState(unsigned int state) const;
127 
128     static void            remapKeyModifiers(KeyID, SInt32,
129                             barrier::KeyMap::KeyItem&, void*);
130 
131 private:
132     struct XKBModifierInfo {
133     public:
134         unsigned char    m_level;
135         UInt32            m_mask;
136         bool            m_lock;
137     };
138 
139 #ifdef TEST_ENV
140 public: // yuck
141 #endif
142     typedef std::vector<KeyModifierMask> KeyModifierMaskList;
143 
144 private:
145     typedef std::map<KeyModifierMask, unsigned int> KeyModifierToXMask;
146     typedef std::multimap<KeyID, KeyCode> KeyToKeyCodeMap;
147     typedef std::map<KeyCode, unsigned int> NonXKBModifierMap;
148     typedef std::map<UInt32, XKBModifierInfo> XKBModifierMap;
149 
150     IXWindowsImpl* m_impl;
151 
152     Display*            m_display;
153 #if HAVE_XKB_EXTENSION
154     XkbDescPtr            m_xkb;
155 #endif
156     SInt32                m_group;
157     XKBModifierMap        m_lastGoodXKBModifiers;
158     NonXKBModifierMap    m_lastGoodNonXKBModifiers;
159 
160     // X modifier (bit number) to barrier modifier (mask) mapping
161     KeyModifierMaskList    m_modifierFromX;
162 
163     // barrier modifier (mask) to X modifier (mask)
164     KeyModifierToXMask    m_modifierToX;
165 
166     // map KeyID to all keycodes that can synthesize that KeyID
167     KeyToKeyCodeMap        m_keyCodeFromKey;
168 
169     // autorepeat state
170     XKeyboardState        m_keyboardState;
171 
172 #ifdef TEST_ENV
173 public:
group()174     SInt32                  group() const { return m_group; }
group(const SInt32 & group)175     void                    group(const SInt32& group) { m_group = group; }
modifierFromX()176     KeyModifierMaskList& modifierFromX() { return m_modifierFromX; }
177 #endif
178 };
179