1 // KeyUtil.cc for FbTk
2 // Copyright (c) 2003 - 2006 Henrik Kinnunen (fluxgen at fluxbox dot org)
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 // DEALINGS IN THE SOFTWARE.
21 
22 // $Id: KeyUtil.cc 4199 2006-02-16 06:53:05Z mathias $
23 
24 #include "KeyUtil.hh"
25 #include "App.hh"
26 
27 #include <string>
28 
29 namespace {
30 
31 struct t_modlist{
32     char *str;
33     unsigned int mask;
operator ==__anon0cb963360111::t_modlist34     bool operator == (const char *modstr) const {
35         return  (strcasecmp(str, modstr) == 0 && mask !=0);
36     }
37 };
38 
39 const struct t_modlist modlist[] = {
40     {"SHIFT", ShiftMask},
41     {"LOCK", LockMask},
42     {"CONTROL", ControlMask},
43     {"MOD1", Mod1Mask},
44     {"MOD2", Mod2Mask},
45     {"MOD3", Mod3Mask},
46     {"MOD4", Mod4Mask},
47     {"MOD5", Mod5Mask},
48     {0, 0}
49 };
50 
51 };
52 
53 namespace FbTk {
54 
55 std::auto_ptr<KeyUtil> KeyUtil::s_keyutil;
56 
instance()57 KeyUtil &KeyUtil::instance() {
58     if (s_keyutil.get() == 0)
59         s_keyutil.reset(new KeyUtil());
60     return *s_keyutil.get();
61 }
62 
63 
KeyUtil()64 KeyUtil::KeyUtil()
65     : m_modmap(0)
66 {
67     init();
68 }
69 
init()70 void KeyUtil::init() {
71     loadModmap();
72 }
73 
~KeyUtil()74 KeyUtil::~KeyUtil() {
75     if (m_modmap)
76         XFreeModifiermap(m_modmap);
77 }
78 
loadModmap()79 void KeyUtil::loadModmap() {
80     if (m_modmap)
81         XFreeModifiermap(m_modmap);
82 
83     m_modmap = XGetModifierMapping(App::instance()->display());
84 
85     // find modifiers and set them
86     for (int i=0, realkey=0; i<8; ++i) {
87         for (int key=0; key<m_modmap->max_keypermod; ++key, ++realkey) {
88 
89             if (m_modmap->modifiermap[realkey] == 0)
90                 continue;
91 
92             KeySym ks = XKeycodeToKeysym(App::instance()->display(),
93                     m_modmap->modifiermap[realkey], 0);
94 
95             switch (ks) {
96             case XK_Caps_Lock:
97                 m_capslock = modlist[i].mask;
98                 break;
99             case XK_Scroll_Lock:
100                 m_scrolllock = modlist[i].mask;
101                 break;
102             case XK_Num_Lock:
103                 m_numlock = modlist[i].mask;
104                 break;
105             }
106         }
107     }
108 }
109 
110 
111 /**
112  Grabs a key with the modifier
113  and with numlock,capslock and scrollock
114 */
grabKey(unsigned int key,unsigned int mod)115 void KeyUtil::grabKey(unsigned int key, unsigned int mod) {
116     Display *display = App::instance()->display();
117     const unsigned int capsmod = instance().capslock();
118     const unsigned int nummod = instance().numlock();
119     const unsigned int scrollmod = instance().scrolllock();
120 
121     for (int screen=0; screen<ScreenCount(display); screen++) {
122 
123         Window root = RootWindow(display, screen);
124 
125         XGrabKey(display, key, mod,
126                  root, True,
127                  GrabModeAsync, GrabModeAsync);
128 
129         // Grab with numlock, capslock and scrlock
130 
131         //numlock
132         XGrabKey(display, key, mod|nummod,
133                  root, True,
134                  GrabModeAsync, GrabModeAsync);
135         //scrolllock
136         XGrabKey(display, key, mod|scrollmod,
137                  root, True,
138                  GrabModeAsync, GrabModeAsync);
139         //capslock
140         XGrabKey(display, key, mod|capsmod,
141                  root, True,
142                  GrabModeAsync, GrabModeAsync);
143 
144         //capslock+numlock
145         XGrabKey(display, key, mod|capsmod|nummod,
146                  root, True,
147                  GrabModeAsync, GrabModeAsync);
148 
149         //capslock+scrolllock
150         XGrabKey(display, key, mod|capsmod|scrollmod,
151                  root, True,
152                  GrabModeAsync, GrabModeAsync);
153 
154         //capslock+numlock+scrolllock
155         XGrabKey(display, key, mod|capsmod|scrollmod|nummod,
156                  root, True,
157                  GrabModeAsync, GrabModeAsync);
158 
159         //numlock+scrollLock
160         XGrabKey(display, key, mod|nummod|scrollmod,
161                  root, True,
162                  GrabModeAsync, GrabModeAsync);
163 
164     }
165 
166 }
167 
168 /**
169  @return keycode of keystr on success else 0
170 */
171 
getKey(const char * keystr)172 unsigned int KeyUtil::getKey(const char *keystr) {
173     if (!keystr)
174         return 0;
175     return XKeysymToKeycode(App::instance()->display(),
176                             XStringToKeysym(keystr));
177 }
178 
179 
180 /**
181  @return the modifier for the modstr else zero on failure.
182 */
getModifier(const char * modstr)183 unsigned int KeyUtil::getModifier(const char *modstr) {
184     if (!modstr)
185         return 0;
186 
187     // find mod mask string
188     for (unsigned int i=0; modlist[i].str !=0; i++) {
189         if (modlist[i] == modstr)
190             return modlist[i].mask;
191     }
192 
193     return 0;
194 }
195 
196 /// Ungrabs the keys
ungrabKeys()197 void KeyUtil::ungrabKeys() {
198     Display * display = App::instance()->display();
199     for (int screen=0; screen<ScreenCount(display); screen++) {
200         XUngrabKey(display, AnyKey, AnyModifier,
201                    RootWindow(display, screen));
202     }
203 }
204 
keycodeToModmask(unsigned int keycode)205 unsigned int KeyUtil::keycodeToModmask(unsigned int keycode) {
206     XModifierKeymap *modmap = instance().m_modmap;
207 
208     if (!modmap)
209         return 0;
210 
211     // search through modmap for this keycode
212     for (int mod=0; mod < 8; mod++) {
213         for (int key=0; key < modmap->max_keypermod; ++key) {
214             // modifiermap is an array with 8 sets of keycodes
215             // each max_keypermod long, but in a linear array.
216             if (modmap->modifiermap[modmap->max_keypermod*mod + key] == keycode) {
217                 return modlist[mod].mask;
218             }
219         }
220     }
221     // no luck
222     return 0;
223 }
224 
225 
226 
227 } // end namespace FbTk
228