1 /*
2  * barrier -- mouse and keyboard sharing utility
3  * Copyright (C) 2012-2016 Symless Ltd.
4  * Copyright (C) 2011 Nick Bolton
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 #define TEST_ENV
20 
21 #include "test/mock/barrier/MockKeyMap.h"
22 #include "test/mock/barrier/MockEventQueue.h"
23 #include "platform/XWindowsKeyState.h"
24 #include "base/Log.h"
25 
26 #define XK_LATIN1
27 #define XK_MISCELLANY
28 #include <X11/keysymdef.h>
29 
30 #if HAVE_XKB_EXTENSION
31 #    include <X11/XKBlib.h>
32 #endif
33 
34 #include "test/global/gtest.h"
35 #include "test/global/gmock.h"
36 #include <errno.h>
37 
38 class XWindowsKeyStateTests : public ::testing::Test
39 {
40 protected:
XWindowsKeyStateTests()41     XWindowsKeyStateTests() :
42         m_display(NULL)
43     {
44     }
45 
~XWindowsKeyStateTests()46     ~XWindowsKeyStateTests()
47     {
48         if (m_display != NULL) {
49             LOG((CLOG_DEBUG "closing display"));
50             XCloseDisplay(m_display);
51         }
52     }
53 
54     virtual void
SetUp()55     SetUp()
56     {
57         // open the display only once for the entire test suite
58         if (this->m_display == NULL) {
59             LOG((CLOG_DEBUG "opening display"));
60             this->m_display = XOpenDisplay(NULL);
61 
62             ASSERT_TRUE(this->m_display != NULL)
63                 << "unable to open display: " << errno;
64         }
65     }
66 
67     virtual void
TearDown()68     TearDown()
69     {
70     }
71 
72     Display* m_display;
73 };
74 
TEST_F(XWindowsKeyStateTests,setActiveGroup_pollAndSet_groupIsZero)75 TEST_F(XWindowsKeyStateTests, setActiveGroup_pollAndSet_groupIsZero)
76 {
77     MockKeyMap keyMap;
78     MockEventQueue eventQueue;
79     XWindowsKeyState keyState(new XWindowsImpl(), m_display, true, &eventQueue, keyMap);
80 
81     keyState.setActiveGroup(XWindowsKeyState::kGroupPollAndSet);
82 
83     ASSERT_EQ(0, keyState.group());
84 }
85 
TEST_F(XWindowsKeyStateTests,setActiveGroup_poll_groupIsNotSet)86 TEST_F(XWindowsKeyStateTests, setActiveGroup_poll_groupIsNotSet)
87 {
88     MockKeyMap keyMap;
89     MockEventQueue eventQueue;
90     XWindowsKeyState keyState(new XWindowsImpl(), m_display, true, &eventQueue, keyMap);
91 
92     keyState.setActiveGroup(XWindowsKeyState::kGroupPoll);
93 
94     ASSERT_LE(-1, keyState.group());
95 }
96 
TEST_F(XWindowsKeyStateTests,setActiveGroup_customGroup_groupWasSet)97 TEST_F(XWindowsKeyStateTests, setActiveGroup_customGroup_groupWasSet)
98 {
99     MockKeyMap keyMap;
100     MockEventQueue eventQueue;
101     XWindowsKeyState keyState(new XWindowsImpl(), m_display, true, &eventQueue, keyMap);
102 
103     keyState.setActiveGroup(1);
104 
105     ASSERT_EQ(1, keyState.group());
106 }
107 
TEST_F(XWindowsKeyStateTests,mapModifiersFromX_zeroState_zeroMask)108 TEST_F(XWindowsKeyStateTests, mapModifiersFromX_zeroState_zeroMask)
109 {
110     MockKeyMap keyMap;
111     MockEventQueue eventQueue;
112     XWindowsKeyState keyState(new XWindowsImpl(), m_display, true, &eventQueue, keyMap);
113 
114     int mask = keyState.mapModifiersFromX(0);
115 
116     ASSERT_EQ(0, mask);
117 }
118 
TEST_F(XWindowsKeyStateTests,mapModifiersToX_zeroMask_resultIsTrue)119 TEST_F(XWindowsKeyStateTests, mapModifiersToX_zeroMask_resultIsTrue)
120 {
121     MockKeyMap keyMap;
122     MockEventQueue eventQueue;
123     XWindowsKeyState keyState(new XWindowsImpl(), m_display, true, &eventQueue, keyMap);
124 
125     unsigned int modifiers = 0;
126     bool result = keyState.mapModifiersToX(0, modifiers);
127 
128     ASSERT_TRUE(result);
129 }
130 
TEST_F(XWindowsKeyStateTests,fakeCtrlAltDel_default_returnsFalse)131 TEST_F(XWindowsKeyStateTests, fakeCtrlAltDel_default_returnsFalse)
132 {
133     MockKeyMap keyMap;
134     MockEventQueue eventQueue;
135     XWindowsKeyState keyState(new XWindowsImpl(), m_display, true, &eventQueue, keyMap);
136 
137     bool result = keyState.fakeCtrlAltDel();
138 
139     ASSERT_FALSE(result);
140 }
141 
TEST_F(XWindowsKeyStateTests,pollActiveModifiers_defaultState_returnsZero)142 TEST_F(XWindowsKeyStateTests, pollActiveModifiers_defaultState_returnsZero)
143 {
144     MockKeyMap keyMap;
145     MockEventQueue eventQueue;
146     XWindowsKeyState keyState(new XWindowsImpl(), m_display, true, &eventQueue, keyMap);
147 
148     KeyModifierMask actual = keyState.pollActiveModifiers();
149 
150     ASSERT_EQ(0, actual);
151 }
152 
TEST_F(XWindowsKeyStateTests,pollActiveModifiers_shiftKeyDownThenUp_masksAreCorrect)153 TEST_F(XWindowsKeyStateTests, pollActiveModifiers_shiftKeyDownThenUp_masksAreCorrect)
154 {
155     MockKeyMap keyMap;
156     MockEventQueue eventQueue;
157     XWindowsKeyState keyState(new XWindowsImpl(), m_display, true, &eventQueue, keyMap);
158 
159     // set mock modifier mapping
160     std::fill(keyState.modifierFromX().begin(), keyState.modifierFromX().end(), 0);
161     keyState.modifierFromX()[ShiftMapIndex] = KeyModifierShift;
162 
163     KeyCode key = XKeysymToKeycode(m_display, XK_Shift_L);
164 
165     // fake shift key down (without using barrier)
166     XTestFakeKeyEvent(m_display, key, true, CurrentTime);
167 
168     // function under test (1st call)
169     KeyModifierMask modDown = keyState.pollActiveModifiers();
170 
171     // fake shift key up (without using barrier)
172     XTestFakeKeyEvent(m_display, key, false, CurrentTime);
173 
174     // function under test (2nd call)
175     KeyModifierMask modUp = keyState.pollActiveModifiers();
176 
177     EXPECT_TRUE((modDown & KeyModifierShift) == KeyModifierShift)
178         << "shift key not in mask - key was not pressed";
179 
180     EXPECT_TRUE((modUp & KeyModifierShift) == 0)
181         << "shift key still in mask - make sure no keys are being held down";
182 }
183 
TEST_F(XWindowsKeyStateTests,pollActiveGroup_defaultState_returnsZero)184 TEST_F(XWindowsKeyStateTests, pollActiveGroup_defaultState_returnsZero)
185 {
186     MockKeyMap keyMap;
187     MockEventQueue eventQueue;
188     XWindowsKeyState keyState(new XWindowsImpl(), m_display, true, &eventQueue, keyMap);
189 
190     SInt32 actual = keyState.pollActiveGroup();
191 
192     ASSERT_EQ(0, actual);
193 }
194 
TEST_F(XWindowsKeyStateTests,pollActiveGroup_positiveGroup_returnsGroup)195 TEST_F(XWindowsKeyStateTests, pollActiveGroup_positiveGroup_returnsGroup)
196 {
197     MockKeyMap keyMap;
198     MockEventQueue eventQueue;
199     XWindowsKeyState keyState(new XWindowsImpl(), m_display, true, &eventQueue, keyMap);
200 
201     keyState.group(3);
202 
203     SInt32 actual = keyState.pollActiveGroup();
204 
205     ASSERT_EQ(3, actual);
206 }
207 
TEST_F(XWindowsKeyStateTests,pollActiveGroup_xkb_areEqual)208 TEST_F(XWindowsKeyStateTests, pollActiveGroup_xkb_areEqual)
209 {
210 #if HAVE_XKB_EXTENSION
211     MockKeyMap keyMap;
212     MockEventQueue eventQueue;
213     XWindowsKeyState keyState(new XWindowsImpl(), m_display, true, &eventQueue, keyMap);
214 
215     // reset the group
216     keyState.group(-1);
217 
218     XkbStateRec state;
219 
220     // compare pollActiveGroup() with XkbGetState()
221     if (XkbGetState(m_display, XkbUseCoreKbd, &state) == Success) {
222         SInt32 actual = keyState.pollActiveGroup();
223 
224         ASSERT_EQ(state.group, actual);
225     }
226     else {
227         FAIL() << "XkbGetState() returned error " << errno;
228     }
229 #else
230     SUCCEED() << "Xkb extension not installed";
231 #endif
232 }
233 
234