Input method functions Sample Overview

Mobile native

The IMF sample application demonstrates how to implement the default keyboard layout change using the Ecore_IMF API from the EFL framework. This sample covers only a subset of the available keyboard layouts. Additionally, the text autosave feature is demonstrated.

The following figure illustrates the application views.

Figure: IMF screens

Main view Month view Normal view

Numeric view Phone number view

The application interface consists of a toolbar with action buttons and an elm_entry component for text input.

You can click:

  • Prev kbd to change the keyboard layout to the previous layout.
  • Next kbd to change the keyboard layout to the next layout.
  • Autosave to trigger the autosave feature. If enabled, the text provided in the elm_entry component is automatically saved to an external text file.
  • Bind file to upload the related autosave text file content (if not empty) to the elm_entry component.

The keyboard with the appropriate layout is displayed as the elm_entry component gets the input focus. The following keyboard layouts are demonstrated:

  • ELM_INPUT_PANEL_LAYOUT_NORMAL: common layout for text and number input with a switchable set of characters
  • ELM_INPUT_PANEL_LAYOUT_NUMBERONLY: layout consisting of digits only
  • ELM_INPUT_PANEL_LAYOUT_PHONENUMBER: common layout for phone number input and text messaging
  • ELM_INPUT_PANEL_LAYOUT_MONTH: layout consisting of month numbers

Figure: UI component layout structure

UI component layout structure

Implementation

To implement the IMF application:

  • The controller_application_view_create() function in the controller module is responsible for calling the view creation-specific routines, callback attachment, and the "bind file" creation. If file does not exist, the _bind_file_create() function creates it and fills it with a default "Hello world !" string. Otherwise, it does nothing and the previous content is preserved. You can load the content to the entry component by clicking Bind file.

    bool
    controller_application_view_create(void)
    {
       _bind_file_create();
    
       if (!main_view_create())
       {
          dlog_print(DLOG_ERROR, LOG_TAG,"View creation failed: on window handle");
          main_view_destroy();
    
          return false;
       }
    
       _attach_callbacks();
    
       dlog_print(DLOG_DEBUG, LOG_TAG,"View creation successful");
    
       return true;
    }
    
    static void
    _bind_file_create(void)
    {
       FILE *fp = NULL;
       char bind_file_full_path[FILE_PATH_MAX_LEN] = {0,};
    
       data_path_compile(BIND_FILE, bind_file_full_path);
    
       // Check whether the file does not exist
       if (access(bind_file_full_path, F_OK))
       {
          fp = fopen(bind_file_full_path, "w+");
    
          dlog_print(DLOG_DEBUG, LOG_TAG, "File %s does not exist - creating", bind_file_full_path);
    
          if (!fp)
          {
             dlog_print(DLOG_DEBUG, LOG_TAG, "Could not create file");
    
             return;
          }
          fwrite(bind_file_content, sizeof(char), sizeof(bind_file_content), fp);
          fclose(fp);
       }
    }
    
  • Another important module of in this sample is the top panel. It consists of 5 elementary UI components:

    • 3 elm_button components to switch between the keyboard layouts and to bind the file to the entry component.
    • elm_check component to trigger the autosave mode.
    • elm_layout component, which contains all the above. The layout component uses the main_window.edc layout file to display the UI components in specified positions and with a defined appearance. Note that there are 2 groups in the mentioned file. The top panel uses the TOP_PANEL_GROUP group.

    The top_panel_create() function creates 3 buttons and 1 checkbox and puts them in the layout container:

    Evas_Object *
    top_panel_create(Evas_Object *parent)
    {
       char layout_file_full_path[FILE_PATH_MAX_LEN] = {0,};
    
       if (s_view_data.top_panel_container)
       {
          return s_view_data.top_panel_container;
       }
    
       resource_path_compile(WIN_LAYOUT_CONTAINER_EDJ, layout_file_full_path);
    
       // Create the container
       s_view_data.top_panel_container = elm_layout_add(parent);
    
       if (!s_view_data.top_panel_container)
       {
          dlog_print(DLOG_ERROR, LOG_TAG,"Failure allocating resource: top panel container");
          evas_object_del(s_view_data.top_panel_container);
    		
          return s_view_data.top_panel_container = NULL;
       }
    
       if (!elm_layout_file_set(s_view_data.top_panel_container, layout_file_full_path, TOP_PANEL_GROUP))
       {
          dlog_print(DLOG_ERROR, LOG_TAG,"Could not set layout file on top panel container");
          evas_object_del(s_view_data.top_panel_container);
    		
          return s_view_data.top_panel_container = NULL;
       }
    
       // Create buttons inside the container
       _button_create(&s_view_data.btn_layout_prev, s_view_data.top_panel_container, PREV_LAYOUT_BUTTON_PART);
       if (!s_view_data.btn_layout_prev)
       {
          dlog_print(DLOG_ERROR, LOG_TAG,"Failure allocating resource: previous layout button");
          evas_object_del(s_view_data.top_panel_container);
    		
          return s_view_data.top_panel_container = NULL;
       }
    
       _button_create(&s_view_data.btn_layout_next, s_view_data.top_panel_container, NEXT_LAYOUT_BUTTON_PART);
       if (!s_view_data.btn_layout_next)
       {
          dlog_print(DLOG_ERROR, LOG_TAG,"Failure allocating resource: next layout button");
          evas_object_del(s_view_data.top_panel_container);
    		
          return s_view_data.top_panel_container = NULL;
       }
    
       _checkbox_create(&s_view_data.check_autosave_toggle, s_view_data.top_panel_container, AUTOSAVE_ON_OFF_BUTTON_PART);
       if (!s_view_data.check_autosave_toggle)
       {
          dlog_print(DLOG_ERROR, LOG_TAG,"Failure allocating resource: save file button");
          evas_object_del(s_view_data.top_panel_container);
    		
          return s_view_data.top_panel_container = NULL;
       }
    
       _button_create(&s_view_data.btn_bind_file, s_view_data.top_panel_container, BIND_FILE_BUTTON_PART);
       if (!s_view_data.btn_bind_file)
       {
          dlog_print(DLOG_ERROR, LOG_TAG,"Failure allocating resource: load file button");
          evas_object_del(s_view_data.top_panel_container);
    		
          return s_view_data.top_panel_container = NULL;
       }
    
       return s_view_data.top_panel_container;
    }
    
  • The main view module contains the main_view_create() function. It is responsible for the main window, entry component, and top panel creation. Also, it attaches UI-related callbacks to the top panel (button clicks and checkbox check events).

    bool
    main_view_create(void)
    {
       int screen_width = 0, screen_height = 0;
       s_view_data.win = elm_win_util_standard_add(PACKAGE, PACKAGE);
    
       if (!s_view_data.win)
       {
          dlog_print(DLOG_ERROR, LOG_TAG,"Failure allocating resource: main window");
    		
          return false;
       }
    
       elm_win_conformant_set(s_view_data.win, EINA_FALSE);
       elm_win_autodel_set(s_view_data.win, EINA_TRUE);
       elm_win_screen_size_get(s_view_data.win, NULL, NULL, &screen_width, &screen_height);
       evas_object_resize(s_view_data.win, screen_width, screen_height);
    
       evas_object_smart_callback_add(s_view_data.win, "delete,request", main_window_delete_cb, NULL);
    
       if (!_entry_container_create() || !_entry_create() ||
          !(s_view_data.win_layout_top_panel = top_panel_create(s_view_data.win)))
       {
          return false;
       }
    
       // Position top panel, and show it
       evas_object_resize(s_view_data.win_layout_top_panel, screen_width, screen_height);
       evas_object_move(s_view_data.win_layout_top_panel, 0, 0);
       evas_object_show(s_view_data.win_layout_top_panel);
    
       _callbacks_attach();
    
       // Show the window after the base GUI is set up
       evas_object_show(s_view_data.win);
    
       return true;
    }
    
  • The main view module also defines the IMF keypad layouts which are used by this application. Each time the user clicks Prev kbd or Next kbd, the _keypad_layout_change_cb() callback is called to set one of the defined keypad layouts:

    static Elm_Input_Panel_Layout 
    available_layouts[] = 
    {
       ELM_INPUT_PANEL_LAYOUT_NORMAL,
       ELM_INPUT_PANEL_LAYOUT_NUMBERONLY,
       ELM_INPUT_PANEL_LAYOUT_PHONENUMBER,
       ELM_INPUT_PANEL_LAYOUT_MONTH
    };
    
    static void
    _keypad_layout_change_cb(void *data, Evas_Object *obj, void *event_info)
    {
       data == LAYOUT_PREV ? --s_view_data.kbd_current_layout : ++s_view_data.kbd_current_layout;
    
       if (s_view_data.kbd_current_layout < 0)
       {
          s_view_data.kbd_current_layout = sizeof(available_layouts)/sizeof(Elm_Input_Panel_Layout) - 1;
       }
    
       if (s_view_data.kbd_current_layout >= sizeof(available_layouts)/sizeof(Elm_Input_Panel_Layout))
       {
          s_view_data.kbd_current_layout = 0;
       }
    
       elm_entry_input_panel_hide(s_view_data.entry);
       elm_entry_input_panel_layout_set(s_view_data.entry, available_layouts[s_view_data.kbd_current_layout]);
       elm_entry_input_panel_show(s_view_data.entry);
       elm_object_focus_allow_set(s_view_data.entry, EINA_TRUE);
       elm_object_focus_set(s_view_data.entry, EINA_TRUE);
    }
    
  • The main view module implements public functions to be used by the controller to bind the file and activate and deactivate the autosave feature:

    void
    main_view_bind_file_to_entry(const char *file_str)
    {
       if (!elm_entry_file_set(s_view_data.entry, file_str, ELM_TEXT_FORMAT_PLAIN_UTF8))
       {
          dlog_print(DLOG_ERROR, LOG_TAG,"Failed to bind file %s . Bad file name ?", file_str);
       }
       elm_entry_autosave_set(s_view_data.entry, EINA_TRUE);
    }
    

    The autosave feature works only when the file is bound to the entry component:

    void
    main_view_entry_autosave_set(Eina_Bool on)
    {
       elm_entry_autosave_set(s_view_data.entry, on);
       dlog_print(DLOG_ERROR, LOG_TAG, "AUTOSAVE: %d", elm_entry_autosave_get(s_view_data.entry));
    }