summaryrefslogtreecommitdiff
path: root/libcaribou
diff options
context:
space:
mode:
authorEitan Isaacson <eitan@monotonous.org>2011-04-27 20:32:35 -0700
committerEitan Isaacson <eitan@monotonous.org>2011-05-02 10:18:49 -0700
commit6294dab42aec83a4e9edd314544903a67152b7fb (patch)
treee44d70f016e22510032935816be3d58014bb847c /libcaribou
parent1242c1ea37f30109609c041de3572f5b900a2a3b (diff)
downloadcaribou-6294dab42aec83a4e9edd314544903a67152b7fb.tar.gz
libcaribou: Implemented CaribouKeyboardModel.
Diffstat (limited to 'libcaribou')
-rw-r--r--libcaribou/Makefile.am13
-rw-r--r--libcaribou/group-model.vala50
-rw-r--r--libcaribou/json-deserializer.vala126
-rw-r--r--libcaribou/key-model.vala71
-rw-r--r--libcaribou/keyboard-model.vala49
-rw-r--r--libcaribou/keyboard-service.vala35
-rw-r--r--libcaribou/level-model.vala41
-rw-r--r--libcaribou/row-model.vala22
-rw-r--r--libcaribou/util.vala13
9 files changed, 418 insertions, 2 deletions
diff --git a/libcaribou/Makefile.am b/libcaribou/Makefile.am
index ca2b6b7..90cc34b 100644
--- a/libcaribou/Makefile.am
+++ b/libcaribou/Makefile.am
@@ -9,7 +9,8 @@ libcaribou_la_VALAFLAGS = \
-H caribou.h --vapi caribou-1.0.vapi \
-h caribou-internals.h \
--vapidir=. \
- --pkg x11 --pkg libxklavier --pkg external-libs --pkg gdk-3.0 --pkg gdk-x11-3.0 \
+ --pkg x11 --pkg json-glib-1.0 --pkg gdk-3.0 --pkg gio-2.0 \
+ --pkg libxklavier --pkg external-libs --pkg gdk-x11-3.0 \
--internal-vapi caribou-internals-1.0.vapi \
--library caribou-1.0 --gir Caribou-1.0.gir \
$(VALAFLAGS)
@@ -29,7 +30,15 @@ libcaribou_la_LIBADD = \
$(LIBCARIBOU_LIBS)
libcaribou_la_SOURCES = \
- xadapter.vala
+ xadapter.vala \
+ keyboard-model.vala \
+ keyboard-service.vala \
+ group-model.vala \
+ level-model.vala \
+ row-model.vala \
+ key-model.vala \
+ util.vala \
+ json-deserializer.vala
EXTRA_DIST = \
external-libs.vapi \
diff --git a/libcaribou/group-model.vala b/libcaribou/group-model.vala
new file mode 100644
index 0000000..564dbd8
--- /dev/null
+++ b/libcaribou/group-model.vala
@@ -0,0 +1,50 @@
+using GLib;
+
+namespace Caribou {
+ public class GroupModel : GLib.Object {
+ public string active_level { get; private set; }
+
+ public string group;
+ public string variant;
+ private string default_level;
+ private HashTable<string, LevelModel> levels;
+
+ public GroupModel (string group, string variant) {
+ this.group = group;
+ this.variant = variant;
+ levels = new HashTable<string, LevelModel> (str_hash, str_equal);
+ active_level = default_level;
+ }
+
+ public static string create_group_name (string group, string variant) {
+ if (variant != "")
+ return @"$(group)_$(variant)";
+ else
+ return group;
+ }
+
+ public void add_level (string lname, LevelModel level) {
+ levels.insert (lname, level);
+ level.level_toggled.connect(on_level_toggled);
+ if (level.mode == "default") {
+ default_level = lname;
+ active_level = lname;
+ }
+ }
+
+ public string[] get_levels () {
+ return Util.list_to_array (levels.get_keys ());
+ }
+
+ public LevelModel get_level (string level_name) {
+ return levels.lookup(level_name);
+ }
+
+ private void on_level_toggled (string new_level) {
+ if (new_level == "default")
+ active_level = default_level;
+ else
+ active_level = new_level;
+ }
+ }
+} \ No newline at end of file
diff --git a/libcaribou/json-deserializer.vala b/libcaribou/json-deserializer.vala
new file mode 100644
index 0000000..e136042
--- /dev/null
+++ b/libcaribou/json-deserializer.vala
@@ -0,0 +1,126 @@
+namespace Caribou {
+
+ private class JsonDeserializer : Object {
+
+ public static bool get_layout_file_inner (string data_dir,
+ string group,
+ string variant,
+ out File fp) {
+ string[] files = {@"$(group)_$(variant).json", @"$(group).json"};
+
+ foreach (string fn in files) {
+ string layout_fn = GLib.Path.build_filename (data_dir, fn);
+ fp = GLib.File.new_for_path (layout_fn);
+ if (fp.query_exists ())
+ return true;
+ }
+
+ return false;
+ }
+
+ public static GLib.File get_layout_file (string group,
+ string variant) throws IOError {
+ Settings caribou_settings = new Settings ("org.gnome.caribou");
+ string kb_type = caribou_settings.get_string("keyboard-type");
+
+ List<string> dirs = new List<string> ();
+ string custom_dir = Environment.get_variable("CARIBOU_LAYOUTS_DIR");
+
+ if (custom_dir != null)
+ dirs.append (Path.build_filename (custom_dir, "layouts", kb_type));
+
+ dirs.append (Path.build_filename (Environment.get_user_data_dir (),
+ "caribou", "layouts", kb_type));
+
+ foreach (string data_dir in Environment.get_system_data_dirs ()) {
+ dirs.append (Path.build_filename (
+ data_dir, "caribou", "layouts", kb_type));
+ }
+
+ foreach (string data_dir in dirs) {
+ File fp;
+ if (get_layout_file_inner (data_dir, group, variant, out fp))
+ return fp;
+ }
+
+ throw new IOError.NOT_FOUND (
+ "Could not find layout file for %s %s", group, variant); }
+
+ public static void load_group (GroupModel group) {
+ Json.Parser parser = new Json.Parser ();
+
+ try {
+ GLib.File f = get_layout_file (group.group, group.variant);
+ parser.load_from_stream (f.read (), (Cancellable) null);
+ create_levels_from_json (group, parser.get_root ());
+ } catch (GLib.Error e) {
+ stdout.printf ("Failed to load JSON: %s\n", e.message);
+ return;
+ }
+ }
+
+ public static void create_levels_from_json (GroupModel group,
+ Json.Node root) {
+ Json.Object obj = root.get_object ();
+
+ if (root.get_node_type () != Json.NodeType.OBJECT)
+ return;
+
+ foreach (string levelname in obj.get_members ()) {
+ unowned Json.Object json_level = obj.get_object_member (levelname);
+ string mode = "";
+
+ if (json_level.has_member ("mode"))
+ mode = json_level.get_string_member ("mode");
+
+ Json.Array json_rows = json_level.get_array_member ("rows");
+ LevelModel level = new LevelModel(mode, json_rows.get_length ());
+
+ group.add_level(levelname, level);
+
+ load_rows (level, json_rows);
+ }
+ }
+
+ public static void load_rows (LevelModel level, Json.Array json_rows) {
+ uint i,j;
+
+ for (i=0;i<level.n_rows;i++) {
+ Json.Array json_keys = json_rows.get_array_element (i);
+ uint nkeys = json_keys.get_length ();
+ for (j=0;j<nkeys;j++) {
+ Json.Object json_key = json_keys.get_object_element (j);
+ level.add_key (i, load_key (json_key));
+ }
+ }
+
+ }
+
+ public static KeyModel load_key (Json.Object json_key) {
+ KeyModel key = new KeyModel (json_key.get_string_member ("name"));
+
+ if (json_key.has_member ("toggle"))
+ key.toggle = json_key.get_string_member ("toggle");
+
+ if (json_key.has_member ("margin_left"))
+ key.margin_left = json_key.get_double_member ("margin_left");
+
+ if (json_key.has_member ("width"))
+ key.width = json_key.get_double_member ("width");
+
+ if (json_key.has_member ("extended_names")) {
+ Json.Array json_keys = json_key.get_array_member ("extended_names");
+ uint nkeys = json_keys.get_length ();
+ uint i;
+
+ key.add_subkey(key.name);
+
+ for (i=0;i<nkeys;i++)
+ key.add_subkey(json_keys.get_string_element (i));
+ }
+
+ return key;
+ }
+
+ }
+} \ No newline at end of file
diff --git a/libcaribou/key-model.vala b/libcaribou/key-model.vala
new file mode 100644
index 0000000..90f3625
--- /dev/null
+++ b/libcaribou/key-model.vala
@@ -0,0 +1,71 @@
+using GLib;
+
+namespace Caribou {
+ public class KeyModel : GLib.Object {
+ public double margin_left { get; set; default = 0.0; }
+ public double width { get; set; default = 1.0; }
+ public string toggle { get; set; default = ""; }
+
+ public bool show_subkeys { get; private set; default = false; }
+ public string name { get; private set; }
+ public uint keyval { get; private set; }
+
+ private uint hold_tid;
+ private XAdapter xadapter;
+ private List<KeyModel> _extended_keys;
+
+ public signal void key_pressed ();
+ public signal void key_released ();
+ public signal void key_clicked ();
+ public signal void key_hold_end ();
+ public signal void key_hold ();
+
+ public KeyModel (string name) {
+ this.name = name;
+ xadapter = XAdapter.get_default();
+ keyval = Gdk.keyval_from_name (name);
+ }
+
+ public void add_subkey (string name) {
+ KeyModel key = new KeyModel (name);
+ key.key_clicked.connect(on_subkey_clicked);
+ _extended_keys.append (key);
+ }
+
+ private void on_subkey_clicked () {
+ show_subkeys = false;
+ }
+
+ public void press () {
+ hold_tid = GLib.Timeout.add(1000, on_key_held);
+ key_pressed();
+ }
+
+ public void release () {
+ key_released();
+ if (hold_tid != 0) {
+ GLib.Source.remove (hold_tid);
+ hold_tid = 0;
+ key_clicked();
+ if (keyval != 0) {
+ xadapter.keyval_press(keyval);
+ xadapter.keyval_release(keyval);
+ }
+ } else {
+ key_hold_end ();
+ }
+ }
+
+ private bool on_key_held () {
+ hold_tid = 0;
+ if (_extended_keys.length () != 0)
+ show_subkeys = true;
+ key_hold ();
+ return false;
+ }
+
+ public unowned List<KeyModel> get_extended_keys () {
+ return _extended_keys;
+ }
+ }
+} \ No newline at end of file
diff --git a/libcaribou/keyboard-model.vala b/libcaribou/keyboard-model.vala
new file mode 100644
index 0000000..b9d96f4
--- /dev/null
+++ b/libcaribou/keyboard-model.vala
@@ -0,0 +1,49 @@
+using Bus;
+
+namespace Caribou {
+ public class KeyboardModel : Object {
+ public string active_group { get; private set; default = ""; }
+
+ XAdapter xadapter;
+ HashTable<string, GroupModel> groups;
+
+ construct {
+ uint grpid;
+ string group, variant;
+ string[] grps, variants;
+ int i;
+
+ groups = new HashTable<string, GroupModel> (str_hash, str_equal);
+
+ xadapter = XAdapter.get_default ();
+ xadapter.group_changed.connect (on_group_changed);
+
+ grpid = xadapter.get_current_group (out group, out variant);
+ on_group_changed (grpid, group, variant);
+
+ xadapter.get_groups (out grps, out variants);
+
+ for (i=0;i<grps.length;i++)
+ populate_group (grps[i], variants[i]);
+ }
+
+ private void populate_group (string group, string variant) {
+ GroupModel grp = new GroupModel (group, variant);
+ groups.insert (GroupModel.create_group_name (group, variant), grp);
+ JsonDeserializer.load_group (grp);
+ }
+
+ public string[] get_groups () {
+ return Util.list_to_array (groups.get_keys ());
+ }
+
+ public GroupModel get_group (string group_name) {
+ return groups.lookup(group_name);
+ }
+
+ private void on_group_changed (uint grpid, string group, string variant) {
+ active_group = group;
+ }
+
+ }
+} \ No newline at end of file
diff --git a/libcaribou/keyboard-service.vala b/libcaribou/keyboard-service.vala
new file mode 100644
index 0000000..ee0035f
--- /dev/null
+++ b/libcaribou/keyboard-service.vala
@@ -0,0 +1,35 @@
+namespace Caribou {
+ [DBus(name = "org.gnome.Caribou.Keyboard")]
+ public abstract class KeyboardService : Object {
+ public string name { get; private set; default = "CaribouKeyboard"; }
+
+ public abstract void set_cursor_location(int x, int y, int w, int h);
+ public abstract void set_entry_location(int x, int y, int w, int h);
+ public abstract void show();
+ public abstract void hide();
+
+ protected void register_keyboard (string name) {
+ this.name = name;
+ string dbus_name = @"org.gnome.Caribou.$name";
+ Bus.own_name (BusType.SESSION, dbus_name, BusNameOwnerFlags.NONE,
+ on_bus_aquired, on_name_aquired, on_name_lost);
+ }
+
+ private void on_name_aquired (DBusConnection conn, string name) {
+ }
+
+ private void on_name_lost (DBusConnection conn, string name) {
+ stderr.printf ("Could not aquire %s\n", name);
+ }
+
+ private void on_bus_aquired (DBusConnection conn) {
+ try {
+ string path = @"/org/gnome/Caribou/$name";
+ conn.register_object (path, this);
+ } catch (IOError e) {
+ stderr.printf ("Could not register service: %s\n", e.message);
+ }
+ }
+
+ }
+} \ No newline at end of file
diff --git a/libcaribou/level-model.vala b/libcaribou/level-model.vala
new file mode 100644
index 0000000..14e8ea8
--- /dev/null
+++ b/libcaribou/level-model.vala
@@ -0,0 +1,41 @@
+using GLib;
+
+namespace Caribou {
+ public class LevelModel : GLib.Object {
+ public signal void level_toggled (string new_level);
+
+ public string mode { get; private set; default = ""; }
+ public int n_rows {
+ get {
+ return _rows.length;
+ }
+ }
+
+ private RowModel[] _rows;
+
+ public LevelModel (string mode, uint nrows) {
+ uint i;
+ this.mode = mode;
+ _rows = new RowModel[nrows];
+ for (i=0;i<nrows;i++)
+ _rows[i] = new RowModel ();
+ }
+
+ public void add_key (uint rownum, KeyModel key) {
+ key.key_clicked.connect (on_key_clicked);
+ _rows[rownum].add_key (key);
+ }
+
+ public RowModel[] get_rows () {
+ return _rows;
+ }
+
+ private void on_key_clicked (KeyModel key) {
+ if (key.toggle != "")
+ level_toggled (key.toggle);
+ else
+ level_toggled ("default");
+ }
+
+ }
+} \ No newline at end of file
diff --git a/libcaribou/row-model.vala b/libcaribou/row-model.vala
new file mode 100644
index 0000000..de4456c
--- /dev/null
+++ b/libcaribou/row-model.vala
@@ -0,0 +1,22 @@
+namespace Caribou {
+ public class RowModel : GLib.Object {
+
+ List<KeyModel> keys;
+
+ public RowModel () {
+ keys = new List<KeyModel> ();
+ }
+
+ public void add_key (KeyModel key) {
+ keys.append (key);
+ }
+
+ public KeyModel get_key (uint index) {
+ return keys.nth (index).data;
+ }
+
+ public unowned List<weak KeyModel> get_keys () {
+ return keys;
+ }
+ }
+}
diff --git a/libcaribou/util.vala b/libcaribou/util.vala
new file mode 100644
index 0000000..c4625ae
--- /dev/null
+++ b/libcaribou/util.vala
@@ -0,0 +1,13 @@
+namespace Caribou {
+ class Util {
+ public static string[] list_to_array (List<string> list) {
+ string[] rv = new string[list.length()];
+ int i = 0;
+ foreach (string v in list) {
+ rv[i] = v;
+ i++;
+ }
+ return rv;
+ }
+ }
+} \ No newline at end of file