|
View:
New views
1 Messages
—
Rating Filter:
Alert me
|
|
|
on-the-spot Input method editing in mono WinFormsHi,
I need to implement in a custom control on-the-spot Input method editing. The Control is driven by WinForm events - although all the drawing is completely custom. I have had a first stab at adding support to mono's X11 classes to allow a custom control to get at this information. I've attached the (not finished) initial patch for comments and suggestions. I have also attached a small test program which I use for testing this. For which I run it with: XMODIFIERS="@im=SCIM" MONO_WINFORMS_XIM_STYLE=on-the-spot mono TestApp.exe I have been testing with Scim using 'Amharic' and 'Chinese (Simplified) - Wubi' (note: mono winforms seems to have problems rending Amharic - but it's good enough for testing). What I would like to know is what are the changes of accepting a patch which allows custom controls to hook into mono's XIM use? I have currently put externally access-able classes in a System.Windows.Forms.X11 namespace, it this the right thing to do? Another thing which I think may be necessary is the ability to have a control specific xim or a least to be able to switch xim in application code ( currently it seems to be one per applications) This would allow some controls to do on-the-spot and some to do an alternative method like off-the-spot. Thanks Tom [IM-on-the-spot.patch] Index: class/Managed.Windows.Forms/System.Windows.Forms/X11Keyboard.cs =================================================================== --- class/Managed.Windows.Forms/System.Windows.Forms/X11Keyboard.cs (revision 144586) +++ class/Managed.Windows.Forms/System.Windows.Forms/X11Keyboard.cs (working copy) @@ -32,11 +32,91 @@ // using System; using System.Collections; +using System.Diagnostics; using System.Drawing; using System.Text; using System.Globalization; using System.Runtime.InteropServices; +namespace System.Windows.Forms.X11 +{ + public class XIM + { + /// <summary> + /// Allows user to request preedit notifications. + /// </summary> + public interface IPreedit + { + int PreeditStart(IntPtr xic, IntPtr clientData, IntPtr callData); + int PreeditDone(IntPtr xic, IntPtr clientData, IntPtr callData); + int PreeditDraw (IntPtr xic, IntPtr clientData, IntPtr callData); + int PreeditCaret (IntPtr xic, IntPtr clientData, IntPtr callData); + } + + /// <summary> + /// Allow Applications to register interest in X Input methods preedit callbacks + /// TODO: Generalize this to allow specifiying window/control + /// </summary> + public static void RegisterPreeditNotification(IPreedit preedit) + { + System.Windows.Forms.XplatUIX11.Keyboard.RegisterPreeditNotification(preedit); + } + + /// <summary> + /// Converts IntPtr if XIMPreeditDrawCallbackStruct into an easier to use form + /// </summary> + public class PreeditDrawInfo + { + public PreeditDrawInfo(IntPtr ximPreeditDrawPtr) + { + if (ximPreeditDrawPtr != IntPtr.Zero) + { + XIMPreeditDrawCallbackStruct preeditStruct = (XIMPreeditDrawCallbackStruct) Marshal.PtrToStructure (ximPreeditDrawPtr, typeof (XIMPreeditDrawCallbackStruct)); + this.Caret = preeditStruct.Caret; + this.ChangeFirst = preeditStruct.ChangeFirst; + this.ChangeLength = preeditStruct.ChangeLength; + if (preeditStruct.Text != IntPtr.Zero) + { + XIMText text = (XIMText) Marshal.PtrToStructure(preeditStruct.Text, typeof(XIMText)); + { + this.Length = text.Length; + if (text.Feedback != IntPtr.Zero) + { + XIMFeedbackStruct Feedback = (XIMFeedbackStruct) Marshal.PtrToStructure(text.Feedback, typeof(XIMFeedbackStruct)); + this.Feedback = Feedback.FeedbackMask; + } + this.EncodingIsWChar = text.EncodingIsWChar; + if (text.String != IntPtr.Zero) + { + if (text.EncodingIsWChar) + this.String = Marshal.PtrToStringUni(text.String); + else + this.String = Marshal.PtrToStringAuto(text.String); + } + } + } + } + } + + public override string ToString() + { + return String.Format("PreeditDrawInfo: Carret = {0} ChangeFirst = {1} ChangeLength = {2} Length = {3} Feedback = {4} EncodingIsWChar = {5} String = {6}", + Caret, ChangeFirst, ChangeLength, Length, Feedback, EncodingIsWChar, String); + } + + public int Caret = 0; + public int ChangeFirst = 0; + public int ChangeLength = 0; + public ushort Length = 0; + public ulong Feedback = 0; + public bool EncodingIsWChar = false; + public String String = string.Empty; + } + + } + +} + namespace System.Windows.Forms { internal class X11Keyboard : IDisposable { @@ -63,6 +143,8 @@ private int NumLockMask; private int AltGrMask; + + private System.Windows.Forms.X11.XIM.IPreedit ximPreedit; public X11Keyboard (IntPtr display, IntPtr clientWindow) { @@ -1001,9 +1083,14 @@ } } + public void RegisterPreeditNotification(System.Windows.Forms.X11.XIM.IPreedit preedit) + { + ximPreedit = preedit; + } + private IntPtr CreateOnTheSpotXic (IntPtr window, IntPtr xim) { - callbackContext = new XIMCallbackContext (window); + callbackContext = new XIMCallbackContext (window, ximPreedit); return callbackContext.CreateXic (window, xim); } @@ -1012,8 +1099,10 @@ XIMCallback startCB, doneCB, drawCB, caretCB; IntPtr pStartCB = IntPtr.Zero, pDoneCB = IntPtr.Zero, pDrawCB = IntPtr.Zero, pCaretCB = IntPtr.Zero; IntPtr pStartCBN = IntPtr.Zero, pDoneCBN = IntPtr.Zero, pDrawCBN = IntPtr.Zero, pCaretCBN = IntPtr.Zero; + + System.Windows.Forms.X11.XIM.IPreedit preeditApplicationCallback; // allows user application to register for preedit methods. - public XIMCallbackContext (IntPtr clientWindow) + public XIMCallbackContext (IntPtr clientWindow, System.Windows.Forms.X11.XIM.IPreedit preedit) { startCB = new XIMCallback (IntPtr.Zero, DoPreeditStart); doneCB = new XIMCallback (IntPtr.Zero, DoPreeditDone); @@ -1027,6 +1116,8 @@ pDoneCBN = Marshal.StringToHGlobalAnsi (XNames.XNPreeditDoneCallback); pDrawCBN = Marshal.StringToHGlobalAnsi (XNames.XNPreeditDrawCallback); pCaretCBN = Marshal.StringToHGlobalAnsi (XNames.XNPreeditCaretCallback); + + preeditApplicationCallback = preedit; } ~XIMCallbackContext () @@ -1052,27 +1143,33 @@ int DoPreeditStart (IntPtr xic, IntPtr clientData, IntPtr callData) { - Console.WriteLine ("DoPreeditStart"); + Debug.WriteLine ("DoPreeditStart"); + if (preeditApplicationCallback != null) + return preeditApplicationCallback.PreeditStart(xic, clientData, callData); return 100; } int DoPreeditDone (IntPtr xic, IntPtr clientData, IntPtr callData) { - Console.WriteLine ("DoPreeditDone"); + Debug.WriteLine ("DoPreeditDone"); + if (preeditApplicationCallback != null) + return preeditApplicationCallback.PreeditDone(xic, clientData, callData); return 0; } int DoPreeditDraw (IntPtr xic, IntPtr clientData, IntPtr callData) { - Console.WriteLine ("DoPreeditDraw"); - //XIMPreeditDrawCallbackStruct cd = (XIMPreeditDrawCallbackStruct) Marshal.PtrToStructure (callData, typeof (XIMPreeditDrawCallbackStruct)); + Debug.WriteLine ("DoPreeditDraw"); + if (preeditApplicationCallback != null) + return preeditApplicationCallback.PreeditDraw(xic, clientData, callData); return 0; } int DoPreeditCaret (IntPtr xic, IntPtr clientData, IntPtr callData) { - Console.WriteLine ("DoPreeditCaret"); - //XIMPreeditCaretCallbackStruct cd = (XIMPreeditCaretCallbackStruct) Marshal.PtrToStructure (callData, typeof (XIMPreeditCaretCallbackStruct)); + Debug.WriteLine ("DoPreeditCaret"); + if (preeditApplicationCallback != null) + return preeditApplicationCallback.PreeditCaret(xic, clientData, callData); return 0; } Index: class/Managed.Windows.Forms/System.Windows.Forms/X11Structs.cs =================================================================== --- class/Managed.Windows.Forms/System.Windows.Forms/X11Structs.cs (revision 144586) +++ class/Managed.Windows.Forms/System.Windows.Forms/X11Structs.cs (working copy) @@ -1702,11 +1702,26 @@ gch.Free (); } } + + internal enum XIMFeedback + { + Reverse = 1, + Underline = 2, + Highlight = 4, + Primary = 8, + Secondary = 16, + Tertiary = 32, + } + internal struct XIMFeedbackStruct + { + public ulong FeedbackMask; // one or more of XIMFeedback enum + } + internal struct XIMText { public ushort Length; - public IntPtr Feedback; + public IntPtr Feedback; // to XIMFeedbackStruct public bool EncodingIsWChar; public IntPtr String; // it could be either char* or wchar_t* } Index: class/Managed.Windows.Forms/System.Windows.Forms/XplatUIX11.cs =================================================================== --- class/Managed.Windows.Forms/System.Windows.Forms/XplatUIX11.cs (revision 144586) +++ class/Managed.Windows.Forms/System.Windows.Forms/XplatUIX11.cs (working copy) @@ -112,7 +112,7 @@ private static bool wake_waiting; private static object wake_waiting_lock = new object (); #endif // - private static X11Keyboard Keyboard; // + internal static X11Keyboard Keyboard; // private static X11Dnd Dnd; private static Socket listen; // private static Socket wake; // [TestApp.cs] using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Windows.Forms.X11; using System.Collections; /// <summary> /// Proof on concept implementation of a user defined TextBox that does on-the-spot /// input method editing. /// This a number of know flaws - eg. doesn't end preedit when user moves cursor with mouse. /// Need to run with MONO_WINFORMS_XIM_STYLE=on-the-spot mono /// </summary> public class OnTheSpotTextBox : TextBox, XIM.IPreedit { string backup; // store text before preedit. #region IPreedit implementation public int PreeditStart(IntPtr xic, IntPtr clientData, IntPtr callData) { backup = Text; return 100; } public int PreeditDone(IntPtr xic, IntPtr clientData, IntPtr callData) { Clear(); AppendText(backup); return 0; } public int PreeditDraw (IntPtr xic, IntPtr clientData, IntPtr callData) { XIM.PreeditDrawInfo info = new XIM.PreeditDrawInfo(callData); if (info.ChangeLength > 0) { Clear(); AppendText(backup); } if (info.Caret > 0) { AppendText(info.String); } return 0; } public int PreeditCaret (IntPtr xic, IntPtr clientData, IntPtr callData) { return 0; } #endregion } #region Testing OnTheSpotTextBox public class Form1 : Form { private OnTheSpotTextBox textBox1; private ComboBox comboBox1; public Form1() { InitializeComponent(); } private IEnumerable Names(Graphics graphics) { var families = FontFamily.GetFamilies(graphics); foreach(FontFamily f in families) { string s = f.GetName(0); yield return s; } } private void ComboBox1_SelectedIndexChanged(object sender, System.EventArgs e) { textBox1.Font = new Font((string)comboBox1.SelectedItem, 10); } private void InitializeComponent() { this.textBox1 = new OnTheSpotTextBox(); System.Windows.Forms.X11.XIM.RegisterPreeditNotification(textBox1); this.comboBox1 = new System.Windows.Forms.ComboBox(); comboBox1.Sorted = true; this.SuspendLayout(); // // textBox1 // var graphics = textBox1.CreateGraphics(); foreach (string name in Names(graphics)) comboBox1.Items.Add(name); this.comboBox1.SelectedIndexChanged += new System.EventHandler(ComboBox1_SelectedIndexChanged); this.textBox1.Font = new Font("AR PL UMing CN", 10); this.textBox1.AcceptsReturn = true; this.textBox1.AcceptsTab = true; this.textBox1.Multiline = true; this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; this.textBox1.Top = 30; this.textBox1.Height = 300; this.textBox1.Width = 300; // // Form1 // this.ClientSize = new System.Drawing.Size(284, 264); this.Controls.Add(this.textBox1); this.Controls.Add(this.comboBox1); this.Text = "TextBox Example"; this.ResumeLayout(false); this.PerformLayout(); } [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } #endregion _______________________________________________ Mono-devel-list mailing list Mono-devel-list@... http://lists.ximian.com/mailman/listinfo/mono-devel-list |
| Free embeddable forum powered by Nabble | Forum Help |