Integrating IME into your Game

This section describes how to use IME in your game application. The section begins by introducing the IME Manager class responsible for IME implementation and explaining IME event data flow between the manager, movie views and the user code. Given the understanding of IME dataflow, Win32 IME Code Integration describes the code changes necessary to integrate IME support into your code. The remaining subsections discuss the details of focus handling, which becomes particularly important with IME, and provide additional information about IME implementation.

IME Interaction Dataflow

The GFx::ASIMEManager is the IME implementation class used to manage the display of IME user interface and to abstract away system-specific details of IME implementation. The diagram below illustrates the interaction between the user code, IME manager, movie views and the IME UI windows.

In the diagram solid arrow describe the creation/ownership relationship, while the dashed arrows illustrate the flow of events and message data. We will now describe the interactions labeled by the numbered arrows in more detail.

  1. During initialization, user code creates the IME manager and sets it on the loader. Here the user also specifies the path for the SWF/GFX file containing the IME UI implementation.
  2. User creates one or more movie views and calls HandleEvent(SetFocus) on the currently focused view, associating it with the IME manager.
  3. User notifies the movie view about input events including IME events and focus changes by calling HandleEvent. Although most events are passed in system independent format, IME events are system-specific and are passed only to the currently focused movie view.
  4. Internally, IME manager communicates with the movie view, informing the focused text field about the state of the composition string, current clause, highlighting information and other IME details. The movie view delegates system-specific IME Events handling to the IME manager, allowing those events to be processed correctly.
  5. When the IME implementation needs to display the reading window or candidate list popups, it loads the IME UI file into the focused movie view. From that point on, it uses Invokes and the internal imecommand interface to communicate with the popup windows about events such as content changes or the user clicking on a row of the candidate list.
  6. The IME UI windows live within the active movie view until they are closed by IME Manager or the focus changes. Living within a particular movie view enables popups to be rendered as a part of the scene and be customized to the appearance of its user interface.

Although it is helpful to understand the flow of events between the IME components, most of the details described in steps four through six are handled automatically by the IME implementation. The different aspects of composition string handling, including obtaining candidate string data from the system, string highlighting, display of popups, management of the cursor position, and candidate finalization are performed by the C++ logic separated between both libgfx_ime.lib and Scaleform library core. Developers should have no need to modify source code of these libraries.

Win32 IME Code Integration

As can be seen from the dataflow diagram, the only thing users need to do support IME is initialize the IME manager and the pass relevant IME system events to the movie view. Under Windows, this means creating the GFxIMEManagerWin32 object and passing the various WM_IME messages from the programs message loop into GFx::Movie::HandleEvent. For a working example of how this is done, you can search for the use of the SF_ENABLE_IME macro in the FxPlayerAppBase.cpp source file.

In the earlier version of GFxIME shipped with Scaleform 2.1, user were required to create a Unicode application window for IME to work correctly. This can be done by using the Unicode version of the CreateWindow and RegisterWindow functions. This requirement has now been considerably simplified. With Scaleform 2.2 and above, users only need to use Unicode version of the PeekMessage (PeekMessageW) function. No other Unicode Win API functions are needed.

The following actions need to be performed in your game/application to make it IME aware.

  1. Create IME Manager, inform it about the IME UI file and set it on the loader. This is done by the following sample code:

    // Create IMEManager after the application window has been set up 
    // since IME manager needs valid window handle as parameter.
    GFxIMEManager* pimemanager = new GFxIMEManagerWin32(app->hWND);
    
    // For error logging. If error logging not desired, just pass null to // Init. User must call Init though!
    pimemanager->Init(Loader.GetLog());
    
    if (pimemanager)
    {
        pimemanager->SetIMEMoviePath("IME.swf");
        Loader.SetIMEManager(pimemanager);
        if (pMovie)
            pMovie->HandleEvent(GFx::Event::SetFocus);
    }
    

    Sending the SetFocus event to the movie informs the IME Manager about the new movie so subsequent IME events are sent to the newly loaded movie. Each movie can load its own candidate list, by calling SetIMEMoviePath as illustrated above and providing the path to the IME UI swf file. If a new movie doesn’t call SetIMEMoviePath, the IME Manager will either use an already loaded list if one exists (possibly loaded by another movie) or not display the candidate list.

    Note that developers who are targeting Korean language input without using libgfx_ime.lib do not need to create the GFx::ASIMEManager instance. They are still required, however, to pass the WM_IME messages to GFx::Movie::HandleEvent as described on the next page.

  2. Tap into system IME notifications and create GFx::IMEEvents based on message parameters, passing them to the currently active movie view. For IME processing to work, the users may need to modify both the application message loop and the message processing function. The application message loop needs to be modified only if we are using the GFx::ASIMEManager for Chinese and Japanese support. If Korean support is being used without the IME manager, changes need to be made to only the message processing function.

    The application message loop is modified to allow Scaleform to receive the required keyboard messages before message translation. An example of such modification is illustrated by the following code.

    // Grab message queue events and pass some of them to IME.
    // This is not required for Korean IME without libgfx_ime.lib.
    MSG msg;
    
    if (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
    {
    
        // Pass raw system messages to GFxIME for pre-processing.
        if ((msg.message == WM_KEYDOWN) || (msg.message == WM_KEYUP) ||
            ImmIsUIMessage(NULL, msg.message, msg.wParam, msg.lParam))
        {
            GFx::IMEWin32Event ev(
                GFx::IMEEvent::IME_PreProcessKeyboard,
                (UPInt)msg.hwnd, msg.message, msg.wParam, msg.lParam);
            pmovie->HandleEvent(ev);
        }
    
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    

    The application message processing function will need to be modified to notify Scaleform about all WM_IME events. This is required for both GFx::ASIMEManager and Korean support and can be done by incorporating the following logic. The WM_IME_SETCONTEXT message is always discarded to prevent the system IME windows from showing up.

    LRESULT UserWindowProc(HWND hwnd, UINT iMsg,
                           WPARAM wParam, LPARAM lParam)
    {
        switch(iMsg)
        {    
            // Pass windows IME messages to Scaleform.
             case WM_IME_SETCONTEXT:
            return DefWindowProc(hwnd, iMsg, wParam, 0);    
           case WM_IME_STARTCOMPOSITION:
             case WM_IME_KEYDOWN:
             case WM_IME_COMPOSITION:        
             case WM_IME_ENDCOMPOSITION:
             case WM_IME_NOTIFY:
             case WM_IME_CHAR:
             {
                GFx::IMEWin32Event ev(GFx::IMEWin32Event::IME_Default,
                                   (UPInt)hwnd, iMsg, wParam, lParam);
                // Do not pass IME events handled by Scaleform to DefWindowProc.
                if (pmovie->HandleEvent(ev) & 
                            GFx::Movie::HE_NoDefaultAction)
                    return 0;
           }
            break;        
        }
        return DefWindowProcW(hwnd, iMsg, wParam, lParam);
    }
    

    A more detailed explanation of the purpose of various IME messages is provided in Appendix D.

  3. Handle focus changes among movie views by passing the appropriate focus messages to HandleEvent. If you only have one movie view in your game that receives input, your focus processing logic can be simplified. The details of focus handling are discussed below in subsection 6.3.

Note that the GFx::ASIMEManager needs to be instantiated only once and works across different movies loaded and unloaded during the life time of the Scaleform player. The candidate list movie clip is, however, bound to a GFx::Movie and will be re-created every time a new movie is loaded. If only the name but no path is specified for SetIMEMoviePath, the IME manager will try to load it from the directory where the currently active swf file is located.

Handling Focus Changes

This section describes focus changes within a movie and across multiple movies running on the player window. Focus change can result from user actions such as mouse clicks, and tab key as well as programmatically.

Focus Changes within a Movie

From the standpoint of IME, there are two types of Flash objects: editable and non-editable. Textfield is an example of editable object while non editable objects include movie clips, buttons etc. IME is only active when the focus is on an editable object. Whenever IME is active and the focus changes to an editable or non-editable text field, IME is finalized. By finalize we mean that the characters in the composition string that exist at the time of the focus change are finalized and become part of the text, and the state of IME is reset. The only exception to this rule is if the candidate list is open and the user clicks on a row of the candidate list. In this case, the composition string is changed to reflect the contents of the candidate list row on which the click occurred and focus is transferred back to the original editable object. IME is not finalized in this case.

Focus Changes across Movies

Scaleform Player allows two or more movies to be playing simultaneously on the stage. Each movie can load its own IME widgets by calling GFx::ASIMEManager::SetIMEMoviePath ahead of time and providing a path for the IME UI file. When focus changes from one movie to the other, the user should call HandleEvent(SetFocus) on the new movie which will finalize IME state on the previous movie and also inform IME manager about the new movie with focus.