<commit_before>/*
 * Copyright © 2013 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <Eina.h>
#include <Ecore.h>
#include <Ecore_Wayland.h>
#include <Ecore_Evas.h>
#include <Edje.h>

#include <linux/input.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "input-method-client-protocol.h"
#include "text-client-protocol.h"

struct weekeyboard
{
   Ecore_Evas *ee;
   Ecore_Wl_Window *win;
   Evas_Object *edje_obj;
   const char *ee_engine;
   char **ignore_keys;

   struct wl_surface *surface;
   struct wl_input_panel *ip;
   struct wl_input_method *im;
   struct wl_output *output;
   struct wl_input_method_context *im_ctx;

   char *surrounding_text;
   char *preedit_str;
   char *language;

   uint32_t text_direction;
   uint32_t preedit_style;
   uint32_t content_hint;
   uint32_t content_purpose;
   uint32_t serial;
   uint32_t surrounding_cursor;

   Eina_Bool context_changed;
};

static void
_cb_wkb_delete_request(Ecore_Evas *ee EINA_UNUSED)
{
   ecore_main_loop_quit();
}

static char *
_wkb_insert_text(const char *text, uint32_t offset, const char *insert)
{
   char *new_text = malloc(strlen(text) + strlen(insert) + 1);

   strncat(new_text, text, offset);
   new_text[offset] = '\0';
   strcat(new_text, insert);
   strcat(new_text, text + offset);

   return new_text;
}

static void
_wkb_commit_preedit_str(struct weekeyboard *wkb)
{
   char *surrounding_text;

   if (!wkb->preedit_str || !strlen(wkb->preedit_str) == 0)
      return;

   wl_input_method_context_cursor_position(wkb->im_ctx, 0, 0);
   wl_input_method_context_commit_string(wkb->im_ctx, wkb->serial, wkb->preedit_str);

   if (wkb->surrounding_text)
     {
        surrounding_text = _wkb_insert_text(wkb->surrounding_text, wkb->surrounding_cursor, wkb->preedit_str);
        free(wkb->surrounding_text);
        wkb->surrounding_text = surrounding_text;
        wkb->surrounding_cursor += strlen(wkb->preedit_str);
     }
   else
     {
        wkb->surrounding_text = strdup(wkb->preedit_str);
        wkb->surrounding_cursor = strlen(wkb->preedit_str);
     }

   free(wkb->preedit_str);
   wkb->preedit_str = strdup("");
}

static void
_wkb_send_preedit_str(struct weekeyboard *wkb, int cursor)
{
   unsigned int index = strlen(wkb->preedit_str);

   if (wkb->preedit_style)
      wl_input_method_context_preedit_styling(wkb->im_ctx, 0, strlen(wkb->preedit_str), wkb->preedit_style);

   if (cursor > 0)
      index = cursor;

   wl_input_method_context_preedit_cursor(wkb->im_ctx, index);
   wl_input_method_context_preedit_string(wkb->im_ctx, wkb->serial, wkb->preedit_str, wkb->preedit_str);
}

static void
_wkb_update_preedit_str(struct weekeyboard *wkb, const char *key)
{
   char *tmp;

   if (!wkb->preedit_str)
      wkb->preedit_str = strdup("");

   tmp = calloc(1, strlen(wkb->preedit_str) + strlen(key) + 1);
   sprintf(tmp, "%s%s", wkb->preedit_str, key);
   free(wkb->preedit_str);
   wkb->preedit_str = tmp;

   if (strcmp(key, " ") == 0)
      _wkb_commit_preedit_str(wkb);
   else
      _wkb_send_preedit_str(wkb, -1);
}

static Eina_Bool
_wkb_ignore_key(struct weekeyboard *wkb, const char *key)
{
   int i;

   if (!wkb->ignore_keys)
       return EINA_FALSE;

   for (i = 0; wkb->ignore_keys[i] != NULL; i++)
      if (!strcmp(key, wkb->ignore_keys[i]))
         return EINA_TRUE;

   return EINA_FALSE;
}

static void
_cb_wkb_on_key_down(void *data, Evas_Object *obj, const char *emission EINA_UNUSED, const char *source)
{
   struct weekeyboard *wkb = data;
   char *src;
   const char *key;

   src = strdup(source);
   key = strtok(src, ":"); /* ignore group */
   key = strtok(NULL, ":");
   if (key == NULL)
       key = ":";

   if (_wkb_ignore_key(wkb, key))
     {
        printf("Ignoring key '%s'\n", key);
        goto end;
     }
   else if (strcmp(key, "backspace") == 0)
     {
        if (strlen(wkb->preedit_str) == 0)
             wl_input_method_context_delete_surrounding_text(wkb->im_ctx, -1, 1);
        else
          {
             wkb->preedit_str[strlen(wkb->preedit_str) - 1] = '\0';
             _wkb_send_preedit_str(wkb, -1);
          }

        goto end;
     }
   else if (strcmp(key, "enter") == 0)
     {
        _wkb_commit_preedit_str(wkb);
        wl_input_method_context_keysym(wkb->im_ctx, wkb->serial, time,
			XKB_KEY_Return, WL_KEYBOARD_KEY_STATE_PRESSED,
			0);
        goto end;
     }
   else if (strcmp(key, "space") == 0)
     {
        key = " ";
     }

   printf("KEY = '%s'\n", key);

   _wkb_update_preedit_str(wkb, key);
<commit_msg>Fix handling of backspace key press<commit_after>/*
 * Copyright © 2013 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <Eina.h>
#include <Ecore.h>
#include <Ecore_Wayland.h>
#include <Ecore_Evas.h>
#include <Edje.h>

#include <linux/input.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "input-method-client-protocol.h"
#include "text-client-protocol.h"

struct weekeyboard
{
   Ecore_Evas *ee;
   Ecore_Wl_Window *win;
   Evas_Object *edje_obj;
   const char *ee_engine;
   char **ignore_keys;

   struct wl_surface *surface;
   struct wl_input_panel *ip;
   struct wl_input_method *im;
   struct wl_output *output;
   struct wl_input_method_context *im_ctx;

   char *surrounding_text;
   char *preedit_str;
   char *language;

   uint32_t text_direction;
   uint32_t preedit_style;
   uint32_t content_hint;
   uint32_t content_purpose;
   uint32_t serial;
   uint32_t surrounding_cursor;

   Eina_Bool context_changed;
};

static void
_cb_wkb_delete_request(Ecore_Evas *ee EINA_UNUSED)
{
   ecore_main_loop_quit();
}

static char *
_wkb_insert_text(const char *text, uint32_t offset, const char *insert)
{
   char *new_text = malloc(strlen(text) + strlen(insert) + 1);

   strncat(new_text, text, offset);
   new_text[offset] = '\0';
   strcat(new_text, insert);
   strcat(new_text, text + offset);

   return new_text;
}

static void
_wkb_commit_preedit_str(struct weekeyboard *wkb)
{
   char *surrounding_text;

   if (!wkb->preedit_str || !strlen(wkb->preedit_str) == 0)
      return;

   wl_input_method_context_cursor_position(wkb->im_ctx, 0, 0);
   wl_input_method_context_commit_string(wkb->im_ctx, wkb->serial, wkb->preedit_str);

   if (wkb->surrounding_text)
     {
        surrounding_text = _wkb_insert_text(wkb->surrounding_text, wkb->surrounding_cursor, wkb->preedit_str);
        free(wkb->surrounding_text);
        wkb->surrounding_text = surrounding_text;
        wkb->surrounding_cursor += strlen(wkb->preedit_str);
     }
   else
     {
        wkb->surrounding_text = strdup(wkb->preedit_str);
        wkb->surrounding_cursor = strlen(wkb->preedit_str);
     }

   free(wkb->preedit_str);
   wkb->preedit_str = strdup("");
}

static void
_wkb_send_preedit_str(struct weekeyboard *wkb, int cursor)
{
   unsigned int index = strlen(wkb->preedit_str);

   if (wkb->preedit_style)
      wl_input_method_context_preedit_styling(wkb->im_ctx, 0, strlen(wkb->preedit_str), wkb->preedit_style);

   if (cursor > 0)
      index = cursor;

   wl_input_method_context_preedit_cursor(wkb->im_ctx, index);
   wl_input_method_context_preedit_string(wkb->im_ctx, wkb->serial, wkb->preedit_str, wkb->preedit_str);
}

static void
_wkb_update_preedit_str(struct weekeyboard *wkb, const char *key)
{
   char *tmp;

   if (!wkb->preedit_str)
      wkb->preedit_str = strdup("");

   tmp = calloc(1, strlen(wkb->preedit_str) + strlen(key) + 1);
   sprintf(tmp, "%s%s", wkb->preedit_str, key);
   free(wkb->preedit_str);
   wkb->preedit_str = tmp;

   if (strcmp(key, " ") == 0)
      _wkb_commit_preedit_str(wkb);
   else
      _wkb_send_preedit_str(wkb, -1);
}

static Eina_Bool
_wkb_ignore_key(struct weekeyboard *wkb, const char *key)
{
   int i;

   if (!wkb->ignore_keys)
       return EINA_FALSE;

   for (i = 0; wkb->ignore_keys[i] != NULL; i++)
      if (!strcmp(key, wkb->ignore_keys[i]))
         return EINA_TRUE;

   return EINA_FALSE;
}

static void
_cb_wkb_on_key_down(void *data, Evas_Object *obj, const char *emission EINA_UNUSED, const char *source)
{
   struct weekeyboard *wkb = data;
   char *src;
   const char *key;

   src = strdup(source);
   key = strtok(src, ":"); /* ignore group */
   key = strtok(NULL, ":");
   if (key == NULL)
       key = ":";

   if (_wkb_ignore_key(wkb, key))
     {
        printf("Ignoring key '%s'\n", key);
        goto end;
     }
   else if (strcmp(key, "backspace") == 0)
     {
        if (strlen(wkb->preedit_str) == 0)
          {
             wl_input_method_context_delete_surrounding_text(wkb->im_ctx, -1, 1);
             wl_input_method_context_commit_string(wkb->im_ctx, wkb->serial, "");
          }
        else
          {
             wkb->preedit_str[strlen(wkb->preedit_str) - 1] = '\0';
             _wkb_send_preedit_str(wkb, -1);
          }

        goto end;
     }
   else if (strcmp(key, "enter") == 0)
     {
        _wkb_commit_preedit_str(wkb);
        wl_input_method_context_keysym(wkb->im_ctx, wkb->serial, 0,
			XKB_KEY_Return, WL_KEYBOARD_KEY_STATE_PRESSED,
			0);
        goto end;
     }
   else if (strcmp(key, "space") == 0)
     {
        key = " ";
     }

   printf("KEY = '%s'\n", key);

   _wkb_update_preedit_str(wkb, key);

{'fraction_non_alphanumeric': 0.12407067683692188, 'fraction_numerical': 0.008593221975475523, 'mean_word_length': 3.4493127147766325, 'pattern_counts': {'":': 6, '<': 21, '<?xml version=': 0, '>': 115, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1014990', 'n_tokens_mistral': 3986, 'n_tokens_neox': 3864, 'n_words': 815}