From 148a3d8a064a211a8ef0e332cbf21e8612106787 Mon Sep 17 00:00:00 2001 From: Eitan Isaacson Date: Wed, 6 Jul 2011 14:44:39 -0500 Subject: Add Ctrl/Alt functionality Based on a patch by Nohemi Fernandez . --- 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(-) (limited to 'libcaribou') 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 keys = new Gee.ArrayList (); @@ -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 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 (); } 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 groups; private KeyModel last_activated_key; + private Gee.HashSet 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 (); } 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 (); -- cgit v1.2.1