public delegate bool Callback (Context ic, MPlist args);
// Class members
- public static Callback PreeditStart, PreeditDone, PreeditDraw;
- public static Callback StatusStart, StatusDone, StatusDraw;
- public static Callback CandidateStart, CandidateDone, CandidateDraw;
- public static Callback SetSpot;
- public static Callback Toggle;
- public static Callback Reset;
+ public static event Callback PreeditChanged;
+ public static event Callback StatusChanged;
+ public static event Callback CandidateChanged;
public static Callback GetSurroundingText;
public static Callback DeleteSurroundingText;
private static MSymbol Mstate = "state";
internal static MSymbol Mcandidates = "candidates";
-
- private static MSymbol Mget_surrounding_text = "get-surrounding-text";
- private static MSymbol Mdel_surrounding_text = "del-surrounding-text";
-
private static Xex.Symbol Qmap = "map";
private static Xex.Symbol Qrule = "rule";
private static Xex.Symbol Qkeyseq = "keyseq";
internal static MInputMethod im_global = null;
[FlagsAttribute]
- private enum LoadStatus
+ protected enum LoadStatus
{
None = 0x00,
Header = 0x01,
{
None = 0x00,
StateTitle = 0x01,
- Preedit = 0x02,
+ PreeditText = 0x02,
CursorPos = 0x04,
CandidateList = 0x08,
CandidateIndex = 0x10,
CandidateShow = 0x20,
+ Preedit = PreeditText | CursorPos,
+ Candidate = CandidateList | CandidateIndex | CandidateShow,
}
private static ChangedStatus CandidateAll = (ChangedStatus.CandidateList
// Instance members
internal Xex.Domain domain = new Xex.Domain (im_domain, null);
- private LoadStatus load_status = LoadStatus.None;
- private MDatabase.Tag tag;
+ protected LoadStatus load_status = LoadStatus.None;
+ protected MDatabase.Tag tag;
private MDatabase mdb;
private MText description;
return (im_table.TryGetValue (tag, out im) ? im : null);
}
- public bool Open ()
+ private bool Open ()
{
return ((load_status == LoadStatus.Full) || load_body ());
}
private void add_default_state ()
{
Xex.Symbol Qinit = "init";
- State state = new State (Qinit, im.title);
+ State state = new State (Qinit, title);
foreach (KeyValuePair<MSymbol, Map>kv in maps)
state.keymap.AddMap (kv.Value, null);
states[Qinit] = initial_state = state;
{
State state = new State (this, plist.Plist);
states[state.name] = state;
+ if (initial_state == null)
+ initial_state = state;
}
}
{
State state = new State (this, node);
states[state.name] = state;
+ if (initial_state == null)
+ initial_state = state;
}
}
Context ic = (Context) domain.context;
Marker m = (Marker) args[0].Objval;
- return new Xex.Term (ic.char_at (m.Position (ic)));
+ return new Xex.Term (m.CharAt (ic));
}
private static Xex.Term Fdelete (Xex.Domain domain, Xex.Variable vari,
Marker m = (Marker) args[0].Objval;
pos = m.Position (ic);
}
- ic.delete (pos);
- return args[0];
+ return new Xex.Term (ic.delete (pos));
}
private static Xex.Term Fselect (Xex.Domain domain, Xex.Variable vari,
Xex.Variable vari,
Xex.Term[] args)
{
- return new Xex.Term (((Context) domain.context).SurroundingFlag);
+ return new Xex.Term (GetSurroundingText == null ? 0 : 1);
}
public override string ToString ()
{
+ this.Open ();
string str = (String.Format ("({0} (title \"{1}\")", tag, title));
if (commands != null)
{
{
internal MInputMethod im;
internal Xex.Domain domain;
- private Dictionary<MSymbol, Callback> callbacks
- = new Dictionary<MSymbol, Callback> ();
private bool active;
private MText status;
internal int cursor_pos;
internal Dictionary<Marker, int> marker_positions
= new Dictionary<Marker, int> ();
+
internal Candidates candidates;
private int candidate_from, candidate_to;
private bool candidate_show;
public bool CandidateShow { get { return candidate_show; } }
- private List<State> state_list = new List<State> ();
- private Keymap keymap;
+ private State state, prev_state;
+ private MText state_preedit = new MText ();
+ private int state_key_head;
+ private object state_var_values, state_initial_var_values;
+ private int state_pos;
+ private Keymap keymap;
// Sequence of input keys.
internal KeySeq keys = new KeySeq ();
-
// Index into KEYS specifying the next key to handle.
internal int key_head;
- private int state_key_head;
- private object state_var_values;
private int commit_key_head;
- private MText state_preedit;
- private int state_pos;
internal MText preceding_text = new MText ();
internal MText following_text = new MText ();
status = im.initial_state.title;
produced.Del ();
preedit.Del ();
+
cursor_pos = 0;
marker_positions.Clear ();
candidates = null;
candidate_show = false;
- keys.keyseq.Clear ();
+
+ state = im.initial_state;
+ prev_state = null;
state_preedit.Del ();
- key_head = commit_key_head = 0;
- state_list.Clear ();
- state_list.Add (im.initial_state);
- keymap = im.initial_state.keymap;
- key_head = state_key_head = 0;
+ state_key_head = 0;
+ state_var_values = state_initial_var_values;
state_pos = 0;
- }
- static MPlist callback_arg = new MPlist ();
+ keymap = im.initial_state.keymap;
+ keys.keyseq.Clear ();
+ key_head = commit_key_head = 0;
+
+ preceding_text.Del ();
+ following_text.Del ();
+
+ changed = ChangedStatus.None;
+ }
static Xex.Term[] catch_args = new Xex.Term[2];
- private bool take_action (Xex.Term[] actions)
+ private bool take_actions (Xex.Term[] actions)
{
catch_args[0] = Tcatch_tag;
catch_args[1]= new Xex.Term (domain, Qprogn, actions);
return (! term.IsSymbol || term.Symval != Tcatch_tag.Symval);
}
-
- private bool call_callback (MSymbol name, MPlist arg)
- {
- Callback callback;
- if (! callbacks.TryGetValue (name, out callback))
- return false;
- return callback (this, arg);
- }
+ static MPlist callback_arg = new MPlist ();
private bool get_surrounding_text (int len)
{
if (len < 0 ? -len <= preceding_text.Length
: len <= following_text.Length)
return true;
+ if (GetSurroundingText == null)
+ return false;
callback_arg.Set (MSymbol.integer, len);
- if (! call_callback (Mget_surrounding_text, callback_arg)
+ if (! GetSurroundingText (this, callback_arg)
|| ! callback_arg.IsMText)
return false;
if (len < 0)
return (len <= following_text.Length);
}
- internal int SurroundingFlag
- {
- get { return (callbacks.ContainsKey (Mget_surrounding_text) ? 1 : 0); }
- }
-
internal int GetSurroundingChar (int pos)
{
if (! get_surrounding_text (pos < 0 ? pos : pos + 1))
}
}
- internal int char_at (int pos)
+ internal int delete (int pos)
{
- int c;
+ int deleted = pos - cursor_pos;
- pos += cursor_pos;
- if (pos < 0)
+ if (pos < cursor_pos)
{
- if (preceding_text.Length < -pos)
+ if (pos < 0)
{
- MPlist plist = new MPlist ();
- plist.Push (MSymbol.integer, pos);
- if (GetSurroundingText != null
- && GetSurroundingText (this, plist)
- && plist.IsMText
- && preceding_text.Length < plist.Text.Length)
- preceding_text = plist.Text;
+ if (DeleteSurroundingText != null)
+ {
+ callback_arg.Set (MSymbol.integer, pos);
+ if (DeleteSurroundingText (this, callback_arg))
+ {
+ if (callback_arg.IsInteger)
+ deleted = callback_arg.Integer - cursor_pos;
+ preceding_text.Del ();
+ }
+ else
+ deleted = - cursor_pos;
+ }
+ pos = 0;
}
- c = (-pos < preceding_text.Length
- ? preceding_text[preceding_text.Length + pos] : -1);
+ if (pos < cursor_pos)
+ preedit_replace (pos, cursor_pos, null);
}
- else if (pos >= 0 && pos < preedit.Length)
- c = preedit[pos];
else
{
- pos -= preedit.Length;
- if (pos >= following_text.Length)
+ if (pos > preedit.Length)
{
- MPlist plist = new MPlist ();
- plist.Push (MSymbol.integer, pos + 1);
- if (GetSurroundingText != null
- && GetSurroundingText (this, plist)
- && plist.IsMText
- && following_text.Length < plist.Text.Length)
- following_text = plist.Text;
+ if (DeleteSurroundingText != null)
+ {
+ callback_arg.Set (MSymbol.integer, pos - preedit.Length);
+ if (DeleteSurroundingText (this, callback_arg))
+ {
+ if (callback_arg.IsInteger)
+ deleted = callback_arg.Integer - cursor_pos;
+ preceding_text.Del ();
+ }
+ else
+ deleted = preedit.Length - cursor_pos;
+ }
+ pos = preedit.Length;
}
- c = (pos < following_text.Length ? following_text[pos] : -1);
+ if (pos > cursor_pos)
+ preedit_replace (cursor_pos, pos, null);
}
- return c;
- }
-
- internal void delete (int pos)
- {
- if (pos < cursor_pos)
- preedit_replace (pos, cursor_pos, null);
- else
- preedit_replace (cursor_pos, pos, null);
- changed |= ChangedStatus.Preedit | ChangedStatus.CursorPos;
+ if (deleted != 0)
+ changed |= ChangedStatus.Preedit | ChangedStatus.CursorPos;
+ return deleted;
}
internal void show ()
internal void shift (State state)
{
- bool changed;
-
if (state == null)
{
- if (state_list.Count > 1)
- state_list.RemoveAt (state_list.Count - 1);
- state = state_list[state_list.Count - 1];
- changed = true;
+ if (prev_state == null)
+ return;
+ state = prev_state;
}
- else
- {
- changed = state != state_list[state_list.Count - 1];
- if (changed)
- state_list.Add (state);
- }
- if (state_list.Count == 1)
+
+ if (state == im.initial_state)
{
commit ();
- reset ();
- }
- else
- {
- state_key_head = key_head;
- state_pos = cursor_pos;
- state_preedit = preedit.Dup ();
- state_var_values = domain.SaveValues ();
- if (changed)
+ keys.keyseq.RemoveRange (0, key_head);
+ key_head = 0;
+ if (state != this.state)
{
- status = state.title;
- this.changed |= ChangedStatus.StateTitle;
+ domain.RestoreValues (state_initial_var_values);
if (state.enter_actions != null)
- take_action (state.enter_actions);
+ take_actions (state.enter_actions);
}
+ prev_state = null;
+ }
+ else
+ {
+ if (state != this.state && state.enter_actions != null)
+ take_actions (state.enter_actions);
+ prev_state = this.state;
}
+ save_state ();
+ if (this.state.title != state.title)
+ this.changed |= ChangedStatus.StateTitle;
+ this.state = state;
}
public Context (MInputMethod im)
{
+ if (im.load_status != LoadStatus.Full
+ && ! im.Open ())
+ throw new Exception ("Openging " + im.tag + " failed");
this.im = im;
domain = new Xex.Domain (im.domain, this);
+ state_initial_var_values = domain.SaveValues ();
reset ();
active = true;
+ if (PreeditChanged != null)
+ {
+ callback_arg.Set (MSymbol.mtext, preedit);
+ PreeditChanged (this, callback_arg);
+ }
+ if (StatusChanged != null)
+ {
+ callback_arg.Set (MSymbol.mtext, status);
+ StatusChanged (this, callback_arg);
+ }
}
public ChangedStatus Changed { get { return changed; } }
- public void AddCallback (MSymbol name, Callback callback)
- {
- callbacks[name] = callback;
- }
-
internal object GetCandidates (out int column)
{
column = 0;
return candidates.Current;
}
+ private void save_state ()
+ {
+ state_var_values = domain.SaveValues ();
+ state_preedit.Del ();
+ state_preedit.Ins (0, preedit);
+ state_key_head = key_head;
+ state_pos = cursor_pos;
+ }
+
private void restore_state ()
{
+ domain.RestoreValues (state_var_values);
+ preedit.Del ();
+ preedit.Ins (0, state_preedit);
+ key_head = state_key_head;
+ cursor_pos = state_pos;
}
private bool handle_key ()
{
- State state = state_list[state_list.Count - 1];
+ State current_state = state;
Keymap sub = keymap.Lookup (keys, ref key_head);
if (sub != keymap)
if (keymap.map_actions != null)
{
restore_state ();
- if (! take_action (keymap.map_actions))
+ if (! take_actions (keymap.map_actions))
return false;
}
else if (keymap.submaps != null)
{
if (keymap.branch_actions != null)
{
- if (! take_action (keymap.branch_actions))
+ if (! take_actions (keymap.branch_actions))
return false;
}
if (keymap != state.keymap)
{
if (keymap.branch_actions != null)
{
- if (! take_action (keymap.branch_actions))
+ if (! take_actions (keymap.branch_actions))
return false;
}
- if (state == state_list[state_list.Count - 1])
+ if (state == current_state)
{
if (state == im.initial_state
&& key_head < keys.keyseq.Count)
// Return value:
// true: All keys are handled and there's no text to commit.
- // false: Some key is unhandled or there's a text to commit.
- // The caller should use methods UnhandledKey and Produced.
+ // false: Some key is left unhandled or there's a text to
+ // commit. The caller should refer to UnhandledKey and
+ // Produced.
public bool Filter (Key key)
{
break;
}
keys.keyseq.RemoveRange (0, key_head);
+
+ if ((changed & ChangedStatus.Preedit) != ChangedStatus.None
+ && PreeditChanged != null)
+ {
+ callback_arg.Set (MSymbol.mtext, preedit);
+ PreeditChanged (this, callback_arg);
+ }
+ if ((changed & ChangedStatus.StateTitle) != ChangedStatus.None
+ && StatusChanged != null)
+ {
+ callback_arg.Set (MSymbol.mtext, status);
+ StatusChanged (this, callback_arg);
+ }
+ if ((changed & ChangedStatus.Candidate) != ChangedStatus.None
+ && CandidateChanged != null)
+ {
+ CandidateChanged (this, callback_arg);
+ }
+
return (! key_unhandled && produced.Length == 0);
}
}