From ff5b98f3a24a353cff8761d0f09ee5f2c8101374 Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Sat, 30 May 2015 16:22:25 +0700 Subject: [PATCH] New text commiting strategy for Firefox --- main.vala | 151 ++++++++++++++++++++++++++++++++++++++++------------ module.vala | 7 ++- 2 files changed, 122 insertions(+), 36 deletions(-) diff --git a/main.vala b/main.vala index da203d7..c57a989 100644 --- a/main.vala +++ b/main.vala @@ -16,49 +16,108 @@ namespace Bogo { } } -public class BogoIMContext : Gtk.IMContext { - private Gdk.Window client_window; - private uint32 last_event_time; - private string prgname; - private uint pending_fake_backspaces; - private string delayed_commit_text = ""; - private Bogo.InputContext input_ctx; - private string composition = ""; - - public BogoIMContext(string program_name, Bogo.InputContext ctx) { - debug("prgname: %s", program_name); - prgname = program_name; - input_ctx = ctx; +// This class will both commit and delete previous text by forwarding key events. +public class ForwardKeyEventIMContext : BogoIMContext { + public ForwardKeyEventIMContext(string program_name, Bogo.InputContext ctx) { + base(program_name, ctx); input_ctx.composition_updated.connect(update_composition); } - ~BogoIMContext() { - debug("destroyed()"); - } + public override bool filter_keypress(Gdk.EventKey event) { + last_event_time = event.time; - public override void set_client_window(Gdk.Window window) { - client_window = window; + if (is_fake_event(event)) { + return false; + } + + if (event.type != Gdk.EventType.KEY_PRESS) { + return false; + } + + debug(@"KEY_PRESS: $(event.keyval)"); + bool swallowed = input_ctx.process_key(event.keyval, event.state); + return swallowed; } - public override void focus_in() { + private void update_composition(string text, uint chars_to_delete) { + debug(@"update_composition($text, $chars_to_delete)"); + delete_with_backspace(chars_to_delete); + commit_by_forwarding(text); } - public override void focus_out() { + private void commit_by_forwarding(string text) { + unichar c; + for (int i = 0; text.get_next_char(ref i, out c);) { + uint keysym = unichar_to_keysym(c); + + debug("Send fake key 0x%x".printf(keysym)); + + fake_key(keysym, 0); + } } - public override void reset() { + private uint unichar_to_keysym(unichar c) { + unichar[] chars = + {'Ạ', 'ạ', 'Ả', 'ả', 'Ấ', 'ấ', 'Ầ', 'ầ', 'Ẩ', 'ẩ', + 'Ẫ', 'ẫ', 'Ậ', 'ậ', 'Ắ', 'ắ', 'Ằ', 'ằ', 'Ẳ', 'ẳ', + 'Ẵ', 'ẵ', 'Ặ', 'ặ', 'Ẹ', 'ẹ', 'Ẻ', 'ẻ', 'Ẽ', 'ẽ', + 'Ế', 'ế', 'Ề', 'ề', 'Ể', 'ể', 'Ễ', 'ễ', 'Ệ', 'ệ', + 'Ỉ', 'ỉ', 'Ị', 'ị', 'Ọ', 'ọ', 'Ỏ', 'ỏ', 'Ố', 'ố', + 'Ồ', 'ồ', 'Ổ', 'ổ', 'Ỗ', 'ỗ', 'Ộ', 'ộ', 'Ớ', 'ớ', + 'Ờ', 'ờ', 'Ở', 'ở', 'Ỡ', 'ỡ', 'Ợ', 'ợ', 'Ụ', 'ụ', + 'Ủ', 'ủ', 'Ứ', 'ứ', 'Ừ', 'ừ', 'Ử', 'ử', 'Ữ', 'ữ', + 'Ự', 'ự', 'Ỵ', 'ỵ', 'Ỷ', 'ỷ', 'Ỹ', 'ỹ', 'Ơ', 'ơ', + 'Ư', 'ư', 'ă', 'Ă', 'Ỳ', 'ỳ', 'Đ', 'đ', 'Ĩ', 'ĩ', + 'Ũ', 'ũ'}; + + int[] keysyms = + {0x1001ea0, 0x1001ea1, 0x1001ea2, 0x1001ea3, + 0x1001ea4, 0x1001ea5, 0x1001ea6, 0x1001ea7, + 0x1001ea8, 0x1001ea9, 0x1001eaa, 0x1001eab, + 0x1001eac, 0x1001ead, 0x1001eae, 0x1001eaf, + 0x1001eb0, 0x1001eb1, 0x1001eb2, 0x1001eb3, + 0x1001eb4, 0x1001eb5, 0x1001eb6, 0x1001eb7, + 0x1001eb8, 0x1001eb9, 0x1001eba, 0x1001ebb, + 0x1001ebc, 0x1001ebd, 0x1001ebe, 0x1001ebf, + 0x1001ec0, 0x1001ec1, 0x1001ec2, 0x1001ec3, + 0x1001ec4, 0x1001ec5, 0x1001ec6, 0x1001ec7, + 0x1001ec8, 0x1001ec9, 0x1001eca, 0x1001ecb, + 0x1001ecc, 0x1001ecd, 0x1001ece, 0x1001ecf, + 0x1001ed0, 0x1001ed1, 0x1001ed2, 0x1001ed3, + 0x1001ed4, 0x1001ed5, 0x1001ed6, 0x1001ed7, + 0x1001ed8, 0x1001ed9, 0x1001eda, 0x1001edb, + 0x1001edc, 0x1001edd, 0x1001ede, 0x1001edf, + 0x1001ee0, 0x1001ee1, 0x1001ee2, 0x1001ee3, + 0x1001ee4, 0x1001ee5, 0x1001ee6, 0x1001ee7, + 0x1001ee8, 0x1001ee9, 0x1001eea, 0x1001eeb, + 0x1001eec, 0x1001eed, 0x1001eee, 0x1001eef, + 0x1001ef0, 0x1001ef1, 0x1001ef4, 0x1001ef5, + 0x1001ef6, 0x1001ef7, 0x1001ef8, 0x1001ef9, + 0x10001a0, 0x10001a1, 0x10001af, 0x10001b0, + 0x01e3, 0x01c3, 0x1001ef2, 0x1001ef3, + 0x01d0, 0x01f0, 0x03a5, 0x03b5, + 0x03dd, 0x03fd}; + + for (int i = 0; i < chars.length; i++) { + if (chars[i] == c) { + return keysyms[i]; + } + } - // Firefox will throws reset() when it sees our fake key so we - // will not actually reset if we're still waiting for the - // delayed commit. - // if (!has_delayed_commit()) { - // input_ctx.reset(); - // } + return c; } +} + +// This class deletes previous text by sending backspaces +// but uses Gtk.IMContext.commit() +public class BackspaceRealCommitIMContext : BogoIMContext { + private string composition = ""; + private string delayed_commit_text = ""; - public override void set_cursor_location(Gdk.Rectangle area) { - debug("set_cursor_location()"); + public BackspaceRealCommitIMContext(string program_name, Bogo.InputContext ctx) { + base(program_name, ctx); + input_ctx.composition_updated.connect(update_composition); } public override bool filter_keypress(Gdk.EventKey event) { @@ -176,7 +235,29 @@ public class BogoIMContext : Gtk.IMContext { } } - private void delete_with_backspace(uint count) { + private bool has_delayed_commit() { + return delayed_commit_text != ""; + } +} + +public class BogoIMContext : Gtk.IMContext { + protected Gdk.Window client_window; + protected uint32 last_event_time; + protected string prgname; + protected Bogo.InputContext input_ctx; + protected uint pending_fake_backspaces; + + public BogoIMContext(string program_name, Bogo.InputContext ctx) { + debug("prgname: %s", program_name); + prgname = program_name; + input_ctx = ctx; + } + + ~BogoIMContext() { + debug("destroyed()"); + } + + protected void delete_with_backspace(uint count) { for (int i = 0; i < count; i++) { send_backspace(); } @@ -190,7 +271,7 @@ public class BogoIMContext : Gtk.IMContext { fake_key(0xff08, 0); } - private void fake_key(uint keysym, Gdk.ModifierType modifiers) { + protected void fake_key(uint keysym, Gdk.ModifierType modifiers) { // Convert keysym to keycode var keymap = Gdk.Keymap.get_default(); Gdk.KeymapKey[] keys; @@ -232,11 +313,11 @@ public class BogoIMContext : Gtk.IMContext { } } - private bool has_delayed_commit() { - return delayed_commit_text != ""; + protected bool is_fake_event(Gdk.EventKey e) { + return (e.state & (1 << 25)) != 0; } - private bool is_fake_event(Gdk.EventKey e) { - return (e.state & (1 << 25)) != 0; + public override void set_client_window(Gdk.Window window) { + client_window = window; } } diff --git a/module.vala b/module.vala index b635909..ee850ea 100644 --- a/module.vala +++ b/module.vala @@ -42,7 +42,12 @@ public Gtk.IMContext? im_module_create (string context_id) { @"/input_context/$ctx_id"); string prgname = Environment.get_prgname(); - return new BogoIMContext(prgname, input_ctx); + + if (true) { + return new ForwardKeyEventIMContext(prgname, input_ctx); + } else { + return new BackspaceRealCommitIMContext(prgname, input_ctx); + } } catch (IOError e) { warning("Cannot connect to bogo server"); }