[caribou] Add Ctrl/Alt functionality



commit 148a3d8a064a211a8ef0e332cbf21e8612106787
Author: Eitan Isaacson <eitan monotonous org>
Date:   Wed Jul 6 14:44:39 2011 -0500

    Add Ctrl/Alt functionality
    
    Based on a patch by Nohemi Fernandez <nf68 cornell edu>.

 libcaribou/column-model.vala     |    4 +-
 libcaribou/external-libs.vapi    |    9 +++-
 libcaribou/group-model.vala      |    6 ++-
 libcaribou/ikeyboard-object.vala |    6 ++-
 libcaribou/key-model.vala        |   90 +++++++++++++++++++++++++++++++------
 libcaribou/keyboard-model.vala   |   31 +++++++++++--
 libcaribou/level-model.vala      |    8 ++-
 libcaribou/row-model.vala        |    5 ++-
 libcaribou/xadapter.vala         |   10 ++++
 9 files changed, 139 insertions(+), 30 deletions(-)
---
diff --git a/libcaribou/column-model.vala b/libcaribou/column-model.vala
index b1db3cb..f127a10 100644
--- a/libcaribou/column-model.vala
+++ b/libcaribou/column-model.vala
@@ -10,7 +10,9 @@ namespace Caribou {
         }
 
         internal void add_key (KeyModel key) {
-            key.key_activated.connect ((k) => { key_activated (k); });
+            key.key_clicked.connect ((k) => { key_clicked (k); });
+            key.key_pressed.connect ((k) => { key_pressed (k); });
+            key.key_released.connect ((k) => { key_released (k); });
             keys.add (key);
         }
 
diff --git a/libcaribou/external-libs.vapi b/libcaribou/external-libs.vapi
index bab3978..078126e 100644
--- a/libcaribou/external-libs.vapi
+++ b/libcaribou/external-libs.vapi
@@ -38,6 +38,11 @@ namespace Xkb {
     public void latch_modifiers (X.Display dpy, uint device_spec, uint affect,
                                  uint values);
 
+    [CCode (cname = "XkbLockModifiers")]
+    public void lock_modifiers (X.Display dpy, uint device_spec, uint affect,
+                                uint values);
+
+
     [Compact]
     [CCode (cname = "XkbAnyEvent", free_function = "")]
     public struct AnyEvent {
@@ -86,7 +91,7 @@ namespace Xkb {
         public ushort flags;
         public ushort device_spec;
         public char min_key_code;
-        public char max_key_code;   
+        public char max_key_code;
         public Controls          ctrls;
         public ServerMap         server;
         public ClientMap         map;
@@ -231,4 +236,4 @@ namespace Xkb {
 
   [CCode (cname = "XkbAllMapComponentsMask")]
     public int AllMapComponentsMask;
-}
\ No newline at end of file
+}
diff --git a/libcaribou/group-model.vala b/libcaribou/group-model.vala
index 6b578d4..479ed52 100644
--- a/libcaribou/group-model.vala
+++ b/libcaribou/group-model.vala
@@ -26,7 +26,9 @@ namespace Caribou {
         internal void add_level (string lname, LevelModel level) {
             levels.set (lname, level);
             level.level_toggled.connect (on_level_toggled);
-            level.key_activated.connect ((k) => { key_activated (k); });
+            level.key_clicked.connect ((k) => { key_clicked (k); });
+            level.key_pressed.connect ((k) => { key_pressed (k); });
+            level.key_released.connect ((k) => { key_released (k); });
             if (level.mode == "default") {
                 default_level = lname;
                 active_level = lname;
@@ -53,4 +55,4 @@ namespace Caribou {
         }
 
     }
-}
\ No newline at end of file
+}
diff --git a/libcaribou/ikeyboard-object.vala b/libcaribou/ikeyboard-object.vala
index f227492..ce865d0 100644
--- a/libcaribou/ikeyboard-object.vala
+++ b/libcaribou/ikeyboard-object.vala
@@ -2,7 +2,9 @@ namespace Caribou {
     public interface IKeyboardObject : Object {
         public abstract IKeyboardObject[] get_children ();
 
-        public signal void key_activated (KeyModel key);
+        public signal void key_clicked (KeyModel key);
+        public signal void key_pressed (KeyModel key);
+        public signal void key_released (KeyModel key);
 
         public virtual KeyModel[] get_keys () {
             Gee.ArrayList<KeyModel> keys = new Gee.ArrayList<KeyModel> ();
@@ -15,4 +17,4 @@ namespace Caribou {
             return (KeyModel[]) keys.to_array ();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/libcaribou/key-model.vala b/libcaribou/key-model.vala
index 7153bc6..9525ecb 100644
--- a/libcaribou/key-model.vala
+++ b/libcaribou/key-model.vala
@@ -6,6 +6,17 @@ namespace Caribou {
         public double width { get; set; default = 1.0; }
         public string toggle { get; set; default = ""; }
 
+        private Gdk.ModifierType mod_mask;
+        public bool is_modifier {
+            get {
+                return (mod_mask != 0);
+            }
+
+            set {}
+        }
+
+        public ModifierState modifier_state;
+
         public bool show_subkeys { get; private set; default = false; }
         public string name { get; private set; }
         public uint keyval { get; private set; }
@@ -28,43 +39,79 @@ namespace Caribou {
         private XAdapter xadapter;
         private Gee.ArrayList<KeyModel> extended_keys;
 
-        public signal void key_pressed ();
-        public signal void key_released ();
         public signal void key_hold_end ();
         public signal void key_hold ();
 
+        private const ModifierMapEntry mod_map[] = {
+            { "Control_L", Gdk.ModifierType.CONTROL_MASK },
+            { "Alt_L", Gdk.ModifierType.MOD1_MASK },
+            { null, 0 }
+        };
+
         public KeyModel (string name) {
             this.name = name;
+            mod_mask = (Gdk.ModifierType) 0;
+
+            int i = 0;
+            for (ModifierMapEntry entry=mod_map[i];
+                 entry.name != null;
+                 entry=mod_map[++i]) {
+                if (name == entry.name)
+                    mod_mask = entry.mask;
+            }
+
+            if (mod_mask == 0)
+                keyval = Gdk.keyval_from_name (name);
+
             xadapter = XAdapter.get_default();
-            keyval = Gdk.keyval_from_name (name);
             extended_keys = new Gee.ArrayList<KeyModel> ();
         }
 
         internal void add_subkey (KeyModel key) {
-            key.key_activated.connect(on_subkey_activated);
+            key.key_clicked.connect(on_subkey_clicked);
             extended_keys.add (key);
         }
 
-        private void on_subkey_activated (KeyModel key) {
-            key_activated (key);
+        private void on_subkey_clicked (KeyModel key) {
+            key_clicked (key);
             show_subkeys = false;
         }
 
         public void press () {
+            if (is_modifier) {
+                if (modifier_state == ModifierState.NONE) {
+                    modifier_state = ModifierState.LATCHED;
+                    xadapter.mod_lock(mod_mask);
+                } else {
+                    modifier_state = ModifierState.NONE;
+                }
+            }
             hold_tid = GLib.Timeout.add(1000, on_key_held);
-            key_pressed();
+            key_pressed(this);
         }
 
         public void release () {
-            key_released();
-            if (hold_tid != 0) {
+            if (hold_tid != 0)
                 GLib.Source.remove (hold_tid);
-                hold_tid = 0;
-                key_activated (this);
-                if (keyval != 0) {
-                    xadapter.keyval_press(keyval);
-                    xadapter.keyval_release(keyval);
+
+            if (is_modifier) {
+                if (modifier_state == ModifierState.NONE) {
+                    xadapter.mod_unlock(mod_mask);
+                } else {
+                    return;
                 }
+            }
+
+            if (keyval != 0) {
+                xadapter.keyval_press(keyval);
+                xadapter.keyval_release(keyval);
+            }
+
+            key_released(this);
+
+            if (hold_tid != 0) {
+                key_clicked (this);
+                hold_tid = 0;
             } else {
                 key_hold_end ();
             }
@@ -74,6 +121,8 @@ namespace Caribou {
             hold_tid = 0;
             if (extended_keys.size != 0)
                 show_subkeys = true;
+            if (is_modifier && modifier_state == ModifierState.LATCHED)
+                modifier_state = ModifierState.LOCKED;
             key_hold ();
             return false;
         }
@@ -98,4 +147,15 @@ namespace Caribou {
             GLib.Timeout.add(200, () => { release (); return false; });
         }
     }
-}
\ No newline at end of file
+
+    public enum ModifierState {
+        NONE,
+        LATCHED,
+        LOCKED
+    }
+
+    private struct ModifierMapEntry {
+        string name;
+        Gdk.ModifierType mask;
+    }
+}
diff --git a/libcaribou/keyboard-model.vala b/libcaribou/keyboard-model.vala
index 0b7bea0..ef31235 100644
--- a/libcaribou/keyboard-model.vala
+++ b/libcaribou/keyboard-model.vala
@@ -8,6 +8,7 @@ namespace Caribou {
         private XAdapter xadapter;
         private Gee.HashMap<string, GroupModel> groups;
         private KeyModel last_activated_key;
+        private Gee.HashSet<KeyModel> active_mod_keys;
 
         construct {
             uint grpid;
@@ -29,6 +30,8 @@ namespace Caribou {
 
             grpid = xadapter.get_current_group (out group, out variant);
             on_group_changed (grpid, group, variant);
+
+            active_mod_keys = new Gee.HashSet<KeyModel> ();
         }
 
         private void populate_group (string group, string variant) {
@@ -36,17 +39,37 @@ namespace Caribou {
                                                           group, variant);
             if (grp != null) {
                 groups.set (GroupModel.create_group_name (group, variant), grp);
-                grp.key_activated.connect (on_key_activated);
+                grp.key_clicked.connect (on_key_clicked);
+                grp.key_pressed.connect (on_key_pressed);
+                grp.key_released.connect (on_key_released);
             }
         }
 
-        private void on_key_activated (KeyModel key) {
+        private void on_key_clicked (KeyModel key) {
             if (key.name == "Caribou_Repeat")
                 last_activated_key.activate ();
             else
                 last_activated_key = key;
 
-            key_activated (key);
+            key_clicked (key);
+        }
+
+        private void on_key_pressed (KeyModel key) {
+            if (key.is_modifier && key.modifier_state == ModifierState.LATCHED) {
+                active_mod_keys.add(key);
+            }
+        }
+
+        private void on_key_released (KeyModel key) {
+            if (!key.is_modifier) {
+                KeyModel[] modifiers = (KeyModel[]) active_mod_keys.to_array ();
+                foreach (KeyModel modifier in modifiers) {
+                    if (modifier.modifier_state == ModifierState.LATCHED) {
+                        modifier.modifier_state = ModifierState.NONE;
+                        modifier.release ();
+                    }
+                }
+            }
         }
 
         public string[] get_groups () {
@@ -70,4 +93,4 @@ namespace Caribou {
             return (IKeyboardObject[]) groups.values.to_array ();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/libcaribou/level-model.vala b/libcaribou/level-model.vala
index 981a3c0..6c526b9 100644
--- a/libcaribou/level-model.vala
+++ b/libcaribou/level-model.vala
@@ -13,7 +13,9 @@ namespace Caribou {
         }
 
         internal void add_row (RowModel row) {
-            row.key_activated.connect (on_key_activated);
+            row.key_clicked.connect (on_key_clicked);
+            row.key_pressed.connect ((k) => { key_pressed (k); });
+            row.key_released.connect ((k) => { key_released (k); });
             rows.add(row);
         }
 
@@ -21,12 +23,12 @@ namespace Caribou {
             return (RowModel[]) rows.to_array ();
         }
 
-        private void on_key_activated (KeyModel key) {
+        private void on_key_clicked (KeyModel key) {
             if (key.toggle != "")
                 level_toggled (key.toggle);
             else if (mode == "latched")
                 level_toggled ("default");
-            key_activated (key);
+            key_clicked (key);
         }
 
         public override IScannableItem[] get_scan_children () {
diff --git a/libcaribou/row-model.vala b/libcaribou/row-model.vala
index fcc4713..e74d887 100644
--- a/libcaribou/row-model.vala
+++ b/libcaribou/row-model.vala
@@ -10,7 +10,10 @@ namespace Caribou {
         }
 
         internal void add_column (ColumnModel column) {
-            column.key_activated.connect ((k) => { key_activated (k); });
+            column.key_clicked.connect ((k) => { key_clicked (k); });
+            column.key_pressed.connect ((k) => { key_pressed (k); });
+            column.key_released.connect ((k) => { key_released (k); });
+
             columns.add(column);
         }
 
diff --git a/libcaribou/xadapter.vala b/libcaribou/xadapter.vala
index 8b6b196..7c725b0 100644
--- a/libcaribou/xadapter.vala
+++ b/libcaribou/xadapter.vala
@@ -226,6 +226,16 @@ namespace Caribou {
             this.xdisplay.flush ();
         }
 
+        public void mod_lock (uint mask) {
+            Xkb.lock_modifiers (this.xdisplay, Xkb.UseCoreKbd, mask, mask);
+            this.xdisplay.flush ();
+        }
+
+        public void mod_unlock (uint mask) {
+            Xkb.lock_modifiers (this.xdisplay, Xkb.UseCoreKbd, mask, 0);
+            this.xdisplay.flush();
+        }
+
         public void mod_latch (uint mask) {
             Xkb.latch_modifiers (this.xdisplay, Xkb.UseCoreKbd, mask, mask);
             this.xdisplay.flush ();



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]