Enable creating FormsApplication based IMEs
authorJi-hoon Lee <dalton.lee@samsung.com>
Mon, 26 Jun 2017 12:25:34 +0000 (21:25 +0900)
committerJi-hoon Lee <dalton.lee@samsung.com>
Mon, 10 Jul 2017 05:36:28 +0000 (05:36 +0000)
Since the FormsApplication class automatically creates
normal application window when created, we will override
PreCreate() method to acquire IME window from InputMethod
capi and assign it to the MainWindow member variable.
This patch needs to be submitted after the patch is applied
that changes the access modifier of FormsApplication's
MainWindow variable to "protected".

Change-Id: I5940757d3cb4608c3e8d6e69c509c05866698ee6

src/Tizen.Uix.InputMethod/Interop/Interop.InputMethod.cs
src/Tizen.Uix.InputMethod/Tizen.Uix.InputMethod/IMEApplication.cs [new file with mode: 0644]
src/Tizen.Uix.InputMethod/Tizen.Uix.InputMethod/InputMethodEditor.cs

index d27f2b0..ba421a0 100755 (executable)
@@ -194,6 +194,15 @@ internal static partial class Interop
         [DllImport(Libraries.InputMethod, EntryPoint = "ime_get_main_window")]
         internal static extern IntPtr ImeGetMainWindow();
 
+        [DllImport(Libraries.InputMethod, EntryPoint = "ime_prepare")]
+        internal static extern ErrorCode ImePrepare();
+
+        [DllImport(Libraries.InputMethod, EntryPoint = "ime_initialize")]
+        internal static extern ErrorCode ImeInitialize();
+
+        [DllImport(Libraries.InputMethod, EntryPoint = "ime_finalize")]
+        internal static extern ErrorCode ImeFinalize();
+
         [DllImport(Libraries.InputMethod, EntryPoint = "ime_set_size")]
         internal static extern ErrorCode ImeSetSize(int portraitWidth, int portraitHeight, int landscapeWidth, int landscapeHeight);
 
diff --git a/src/Tizen.Uix.InputMethod/Tizen.Uix.InputMethod/IMEApplication.cs b/src/Tizen.Uix.InputMethod/Tizen.Uix.InputMethod/IMEApplication.cs
new file mode 100644 (file)
index 0000000..7ba45aa
--- /dev/null
@@ -0,0 +1,119 @@
+using System;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Tizen;
+using Tizen;
+using ElmSharp;
+using static Interop.InputMethod;
+
+namespace Tizen.Uix.InputMethod
+{
+    public class IMEWindow : Xamarin.Forms.Platform.Tizen.Native.Window
+    {
+        /* There can be only one single IME Window, so we are declaring the size variables as static */
+        static Xamarin.Forms.Size _portrait_size = new Xamarin.Forms.Size(0.0 ,0.0);
+        static Xamarin.Forms.Size _landscape_size = new Xamarin.Forms.Size(0.0, 0.0);
+
+        public static Xamarin.Forms.Size PortraitSize
+        {
+            get { return _portrait_size; }
+            internal set
+            {
+                _portrait_size = value;
+                ImeSetSize((int)PortraitSize.Width, (int)PortraitSize.Height,
+                           (int)LandscapeSize.Width, (int)LandscapeSize.Height);
+            }
+        }
+
+        public static Xamarin.Forms.Size LandscapeSize
+        {
+            get { return _landscape_size; }
+            internal set
+            {
+                _landscape_size = value;
+                ImeSetSize((int)PortraitSize.Width, (int)PortraitSize.Height,
+                           (int)LandscapeSize.Width, (int)LandscapeSize.Height);
+            }
+        }
+
+        public IMEWindow() : base()
+        {
+            if (_portrait_size.Width == 0 || _portrait_size.Height == 0)
+            {
+                Log.Warn(LogTag, "The width and/or height of portrait IME size contains value 0");
+            }
+            if (_landscape_size.Width == 0 || _landscape_size.Height == 0)
+            {
+                Log.Warn(LogTag, "The width and/or height of landscape IME size contains value 0");
+            }
+
+            ImeSetSize((int)PortraitSize.Width, (int)PortraitSize.Height,
+                       (int)LandscapeSize.Width, (int)LandscapeSize.Height);
+        }
+
+        protected override IntPtr CreateHandle(EvasObject parent)
+        {
+            /* We are acquiring IME Window's pointer which is expected to be created
+             * when calling Create() function of the InputMethodEditor class */
+            IntPtr handle = ImeGetMainWindow();
+            Log.Info(LogTag, "ImeGetMainWindow returned : " + handle.ToString());
+
+            return handle;
+        }
+    }
+
+    public class IMEApplication : Xamarin.Forms.Platform.Tizen.FormsApplication
+    {
+        protected IMEApplication()
+        {
+        }
+
+        public Xamarin.Forms.Size PortraitSize
+        {
+            get { return IMEWindow.PortraitSize; }
+            set { IMEWindow.PortraitSize = value; }
+        }
+
+        public Xamarin.Forms.Size LandscapeSize
+        {
+            get { return IMEWindow.LandscapeSize; }
+            set { IMEWindow.LandscapeSize = value; }
+        }
+
+        protected override void OnPreCreate()
+        {
+            try
+            {
+                Application.ClearCurrent();
+
+                /* Since the IMEWindow class acquires window handle from InputMethod module
+                 * which is created internally when calling InputMethodEditor.Create() function,
+                 * this needs to be called BEFORE creating new IMEWindow instance. */
+                InputMethod.InputMethodEditor.Create();
+
+                MainWindow = new IMEWindow();
+                MainWindow.IndicatorMode = IndicatorMode.Hide;
+                MainWindow.Show();
+            }
+            catch (Exception e)
+            {
+                Log.Error("EXCEPTION", "Exception caught : " + e.ToString());
+            }
+        }
+
+        protected override void OnTerminate()
+        {
+            InputMethod.InputMethodEditor.Destroy();
+            base.OnTerminate();
+        }
+
+        protected override void OnPause()
+        {
+            base.OnPause();
+        }
+
+        protected override void OnResume()
+        {
+            base.OnResume();
+        }
+    }
+}
index 36e4d1e..1473c8c 100755 (executable)
@@ -1,4 +1,4 @@
-/*
+/*
 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
 *
 * Licensed under the Apache License, Version 2.0 (the License);
@@ -964,7 +964,7 @@ namespace Tizen.Uix.InputMethod
         private static ImeFocusedOutCb _imeFocusedOutDelegate;
         private static event EventHandler<SurroundingTextUpdatedEventArgs> _surroundingTextUpdated;
         private static ImeSurroundingTextUpdatedCb _imeSurroundingTextUpdatedDelegate;
-        private static event EventHandler<System.EventArgs> _inputContextReset;
+        private static event EventHandler<EventArgs> _inputContextReset;
         private static ImeInputContextResetCb _imeInputContextResetDelegate;
         private static event EventHandler<CursorPositionitionUpdatedEventArgs> _cursorPositionUpdated;
         private static ImeCursorPositionitionUpdatedCb _imeCursorPositionitionUpdatedDelegate;
@@ -1201,7 +1201,7 @@ namespace Tizen.Uix.InputMethod
         /// <summary>
         /// Called to reset the input context of an associated text input UI control.
         /// </summary>
-        public static event EventHandler<System.EventArgs> InputContextReset
+        public static event EventHandler<EventArgs> InputContextReset
         {
             add
             {
@@ -1209,7 +1209,7 @@ namespace Tizen.Uix.InputMethod
                 {
                     _imeInputContextResetDelegate = (IntPtr userData) =>
                     {
-                        _inputContextReset?.Invoke(null, System.EventArgs.Empty);
+                        _inputContextReset?.Invoke(null, EventArgs.Empty);
                     };
                     ErrorCode error = ImeEventSetInputContextResetCb(_imeInputContextResetDelegate, IntPtr.Zero);
                     if (error != ErrorCode.None)
@@ -1774,7 +1774,7 @@ namespace Tizen.Uix.InputMethod
         /// 1) The application does not have the privilege to call this function
         /// 2) IME main loop isn't started yet
         /// </exception>
-        public static void SendKeyEvent(KeyCode keyCode, KeyMask keyMask, bool forwardKey)
+        public static void SendKeyEvent(KeyCode keyCode, KeyMask keyMask, bool forwardKey = false)
         {
             ErrorCode error = ImeSendKeyEvent(keyCode, keyMask, forwardKey);
             if (error != ErrorCode.None)
@@ -2022,6 +2022,58 @@ namespace Tizen.Uix.InputMethod
         }
 
         /// <summary>
+        /// This API requests the InputMethodEditor to initialize
+        /// </summary>
+        /// <privilege>
+        /// http://tizen.org/privilege/ime
+        /// </privilege>
+        /// <exception cref="InvalidOperationException">
+        /// This can occur due to the following reasons:
+        /// 1) The application does not have the privilege to call this function
+        /// 2) Operation Failed
+        /// </exception>
+        public static void Create()
+        {
+            ErrorCode error = ImeInitialize();
+            Log.Info(LogTag, "ImeInitialize result : " + error);
+            if (error != ErrorCode.None)
+            {
+                Log.Error(LogTag, "ImeInitialize Failed with error " + error);
+                throw InputMethodExceptionFactory.CreateException(error);
+            }
+
+            error = ImePrepare();
+            Log.Info(LogTag, "ImePrepare result : " + error);
+            if (error != ErrorCode.None)
+            {
+                Log.Error(LogTag, "ImePrepare Failed with error " + error);
+                throw InputMethodExceptionFactory.CreateException(error);
+            }
+        }
+
+        /// <summary>
+        /// This API requests the InputMethodEditor to finalize
+        /// </summary>
+        /// <privilege>
+        /// http://tizen.org/privilege/ime
+        /// </privilege>
+        /// <exception cref="InvalidOperationException">
+        /// This can occur due to the following reasons:
+        /// 1) The application does not have the privilege to call this function
+        /// 2) Operation Failed
+        /// </exception>
+        public static void Destroy()
+        {
+            ErrorCode error = ImeFinalize();
+            Log.Info(LogTag, "ImeFinalize result : " + error);
+            if (error != ErrorCode.None)
+            {
+                Log.Error(LogTag, "ImeFinalize Failed with error " + error);
+                throw InputMethodExceptionFactory.CreateException(error);
+            }
+        }
+
+        /// <summary>
         /// Requests to create an option window from the input panel.
         /// The input panel can call this function to open the option window. This function calls OptionWindowCreated Event with OptionWindowType.Keyboard.
         /// </summary>