Allow to define modifiers for keys (Mods: line in config).

portnov [2008-08-27 09:12:44]
Allow to define modifiers for keys (Mods: line in config).
Filename
qwerty.py
diff --git a/qwerty.py b/qwerty.py
index 5590e8a..c4110cd 100755
--- a/qwerty.py
+++ b/qwerty.py
@@ -17,6 +17,10 @@ GLOBAL = 0
 SECTION = 1
 KEY = 2

+SHIFT =   1
+CONTROL = 2
+ALT     = 4
+
 PADDING = 4
 ICON_TOP_MARGIN = 35
 LABEL_LEFT, LABEL_TOP = 15,25
@@ -222,11 +226,12 @@ class SectionButton(SuperButton):
 class Section(object):
     def __init__(self,title):
         self.title = title
-        self.keys = {}
+        self.keys = []

 class Key(object):
     def __init__(self,key):
         self.key = key
+        self.mods = []

 def parse_config():
     global sections
@@ -242,6 +247,17 @@ def parse_config():
         if line.startswith(key):
             return line[len(key):].strip()

+    def parse_mods(s):
+        r = []
+        ms = s.upper().split()
+        if 'SHIFT' in ms:
+            r.append(SHIFT)
+        if ('CONTROL' in ms) or ('CTRL' in ms):
+            r.append(CONTROL)
+        if 'ALT' in ms:
+            r.append(ALT)
+        return r
+
     context = GLOBAL
     for line in open(config_file):
         line = line.strip()
@@ -269,7 +285,7 @@ def parse_config():
         if v:
             v = v.upper()
             K = Key(v)
-            S.keys[v] = K
+            S.keys.append(K)
             context = KEY
             continue

@@ -280,6 +296,13 @@ def parse_config():
             context = KEY
             continue

+        v = parse_line('Mods', line)
+        if v:
+            if context == KEY:
+                K.mods = parse_mods(v)
+            else:
+                raise SyntaxError, "Unexpected 'Mods' key in config"
+
         v = parse_line('Description',line)
         if v:
             if context == KEY:
@@ -330,6 +353,16 @@ def save_config():
     def writeln():
         cf.write('\n')

+    def mods_str(ms):
+        r = ''
+        if SHIFT in ms:
+            r += 'Shift '
+        if CONTROL in ms:
+            r += 'Control '
+        if ALT in ms:
+            r += 'Alt'
+        return r
+
     global sections
     global defsection
     global speckeys
@@ -342,8 +375,11 @@ def save_config():
         write('Icon', S.icon)
         write('Order', S.order)
         writeln()
-        for K in S.keys.values():
+
+        for K in S.keys:
             write('Key', K.key)
+            if K.mods:
+                write('Mods', mods_str(K.mods))
             write('Icon', K.icon)
             write('Title', K.title)
             if hasattr(K, 'desc'):
@@ -415,7 +451,7 @@ class GUI(object):
             btn.connect("button-press-event",self.on_section)

         for i,S in sections.iteritems():
-            btn = self.sbuttons[(i-1)%10]
+            btn = self.sbuttons[i]
             btn.set_label(S.title)
             btn.set_icon(S.icon)

@@ -428,7 +464,8 @@ class GUI(object):
         self.window.set_title('Qwerty-Launcher')
         self.window.add(self.main)
         self.window.connect('destroy', self.exit)
-        self.window.connect('key-release-event', self.on_key)
+        self.window.connect('key-press-event', self.on_key)
+        self.window.connect('key-release-event', self.key_released)

         self.window.fullscreen()
         self.window.show()
@@ -518,7 +555,41 @@ class GUI(object):
         km = gtk.gdk.keymap_get_default()
         kv = km.lookup_key(hw_code,0,0)
         return gtk.gdk.keyval_name(kv)
+
+    def translate_mods(self,event):
+        mods = []
+        shift = event.state & gtk.gdk.SHIFT_MASK
+        ctrl  = event.state & gtk.gdk.CONTROL_MASK
+        alt   = event.state & gtk.gdk.MOD1_MASK
+        if shift:
+            mods.append(SHIFT)
+        if ctrl:
+            mods.append(CONTROL)
+        if alt:
+            mods.append(ALT)
+        return mods
+
+    def key_in(self,kv,names):
+        return kv in map(gtk.gdk.keyval_from_name, names)
+
+    def key_in_mods(self,kv):
+        names = ['Shift_L', 'Shift_R','Control_L', 'Control_R', 'Mod1']
+        return self.key_in(kv,names)

+    def key_released(self,widget,event):
+
+        if self.key_in_mods(event.keyval):
+            mods = self.translate_mods(event)
+
+            if self.key_in(event.keyval,['Shift_L','Shift_R']):
+                mods.remove(SHIFT)
+            if self.key_in(event.keyval, ['Control_L', 'Control_R']):
+                mods.remove(CONTROL)
+            if self.key_in(event.keyval, ['Mod1']):
+                mods.remove(ALT)
+
+            self.show_section((self.S.order+1)%10, mods)
+
     def on_key(self,widget,event):
         global speckeys

@@ -526,6 +597,19 @@ class GUI(object):
             self.exit()
             return

+        mods = self.translate_mods(event)
+
+        if self.key_in(event.keyval,['Shift_L','Shift_R']):
+            mods.append(SHIFT)
+        if self.key_in(event.keyval, ['Control_L', 'Control_R']):
+            mods.append(CONTROL)
+        if self.key_in(event.keyval, ['Mod1']):
+            mods.append(ALT)
+
+        if self.key_in_mods(event.keyval):
+            self.show_section((self.S.order+1)%10, mods)
+            return
+
         for k in speckeys:
             if event.keyval == gtk.gdk.keyval_from_name(k):
                 self.do_special_button(speckeys[k])
@@ -534,19 +618,20 @@ class GUI(object):

         k = self.get_key(event.hardware_keycode)
         if k in DIGITS:
-            self.show_section(k)
+            self.show_section(k, mods)
         elif k == ' ':
             self.switch_taskbar()
         elif k in ALPHABET.lower():
-            self.do_button(k)
+            self.do_button(k, mods)

-    def key_exec(self,key):
-        cmd = self.S.keys[key].command
+    def key_exec(self,key,mods):
+        ks = dict([((k.key,tuple(k.mods)), k) for k in self.S.keys])
+        cmd = ks[key,tuple(mods)].command
         os.system(cmd + " &")

-    def do_button(self,key):
+    def do_button(self,key, mods):
         try:
-            self.on_button(self.buttons[key.upper()])
+            self.on_button(self.buttons[key.upper()],mods=mods)
         except KeyError:
             return

@@ -575,18 +660,18 @@ class GUI(object):
         else:
             os.system(key.command + ' &')

-    def on_button(self,widget,event=None):
+    def on_button(self,widget,event=None,mods=[]):
         if widget.running:
 #             print "Activating", widget.label
             self.activate_window(widget.cls)
         else:
-            self.key_exec(widget.key)
+            self.key_exec(widget.key,mods)
         self.exit()

     def on_section(self,widget,event=None):
-        self.show_section(widget.key)
+        self.show_section(widget.key, self.translate_mods(event))

-    def show_section(self,k):
+    def show_section(self,k,mods):
         global sections
         global defsection

@@ -595,7 +680,7 @@ class GUI(object):
         id = (int(k)-1)%10
 #         id = int(k)
         try:
-            self.S = sections[int(k)]
+            self.S = sections[id]
         except KeyError:
             return
         defsection = id
@@ -612,8 +697,11 @@ class GUI(object):
             btn = self.buttons[b]
             btn.clear()

-        for k in self.S.keys:
-            K = self.S.keys[k]
+        for K in self.S.keys:
+#             K = self.S.keys[k]
+            if K.mods != mods:
+                continue
+            k = K.key
             btn = self.buttons[k]
             btn.set_label(K.title)
             if hasattr(K, 'desc'):
@@ -627,5 +715,5 @@ class GUI(object):
 parse_config()

 g = GUI()
-g.show_section(defsection+1)
+g.show_section(defsection+1,[])
 gtk.main()
ViewGit