/* vim:set et sts=4: */ /* * KMFL Input Method for IBUS (The Input Bus) * * Copyright (C) 2009-2018 SIL International * * kmflutil is dual licensed under the MIT or GPL licenses as described below. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * MIT license * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * OR * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * */ #include #include #include #include #include #include #include "kmflutil.h" #define N_(text) text static gchar * get_dirname(const gchar * path) { gchar * dirend = g_strrstr(path, "/"); if (dirend) { return g_strndup(path, dirend-path); } else { return g_strdup(""); } } GList * kmfl_get_keyboard_fromdir( GList *keyboard_list, const gchar * path) { // g_message("KMFL: getting from dir: %s", path); DIR *dir = opendir(path); if (dir != NULL) { struct dirent *file = readdir(dir); while (file != NULL) { struct stat filestat; gchar * absfn = g_strdup_printf("%s/%s", path, file->d_name); stat(absfn, &filestat); if (S_ISDIR(filestat.st_mode)) { if(strcmp(file->d_name, ".") != 0 && strcmp(file->d_name, "..") != 0) keyboard_list = kmfl_get_keyboard_fromdir(keyboard_list, absfn); g_free(absfn); } // Only .kmfl and .kmn extensions are valid keyboard files else if (S_ISREG(filestat.st_mode) && ((g_str_has_suffix(absfn, ".kmfl") && kmfl_check_keyboard(absfn) == 0) || g_str_has_suffix(absfn, ".kmn"))) { keyboard_list=g_list_append(keyboard_list, absfn); } else { g_free(absfn); } file = readdir(dir); } closedir(dir); } return keyboard_list; } GList * kmfl_get_keyboard_list( const gchar * path) { GList * keyboard_list=NULL; keyboard_list = kmfl_get_keyboard_fromdir(keyboard_list, path); return keyboard_list; } gchar * kmfl_get_icon_file(KInputMethod * im) { const char * icon_file = kmfl_icon_file(im->keyboard_number); gchar * full_path_to_icon_file=NULL; struct stat filestat; char * valid_extensions[]= {"", ".png", ".bmp", ".jpg", NULL}; int valid_extension_index; if (strlen(icon_file) > 0) { for (valid_extension_index=0; valid_extensions[valid_extension_index] != NULL; valid_extension_index++) { full_path_to_icon_file=g_strdup_printf("%s/%s%s", get_dirname(im->keyboard_filename), icon_file, valid_extensions[valid_extension_index]); stat(full_path_to_icon_file, &filestat); if (S_ISREG(filestat.st_mode)) { break; } else { g_free(full_path_to_icon_file); full_path_to_icon_file=NULL; } } } if (full_path_to_icon_file==NULL) full_path_to_icon_file=g_strdup("/usr/share/kmfl/icons/default.png"); return full_path_to_icon_file; } gchar * kmfl_get_ldml_file(KInputMethod * im) { gchar * full_path_to_ldml_file=NULL, *p, *filename; struct stat filestat; if(g_strcmp0(im->keyboard_visualkeyboard, "") == 0) { g_debug("WDG: no kvk(s) so no ldml file"); return g_strdup(""); } p=rindex(im->keyboard_visualkeyboard,'.'); if (p==NULL) { g_debug("WDG: couldn't find . in vk filename %s", im->keyboard_visualkeyboard); return g_strdup(""); } if (strncmp(p, ".kvk", 4) != 0) // sometimes kmn have kvks as the "visual keyboard" { g_debug("WDG: visual keyboard is not a kvk. Filename: %s", im->keyboard_visualkeyboard); return g_strdup(""); } filename = g_strndup(im->keyboard_visualkeyboard, p-(im->keyboard_visualkeyboard)); full_path_to_ldml_file=g_strdup_printf("%s/%s.ldml", get_dirname(im->keyboard_filename), filename); g_free(filename); // don't forget to stat for the file before returning stat(full_path_to_ldml_file, &filestat); if (!S_ISREG(filestat.st_mode)) { g_debug("WDG: couldn't find ldml file %s", full_path_to_ldml_file); g_free(full_path_to_ldml_file); full_path_to_ldml_file=g_strdup(""); } return full_path_to_ldml_file; } void kmfl_get_keyboard_info(KInputMethod * im) { char buf[1024]; KMSI * p_kmsi; im->keyboard_name = g_strdup(kmfl_keyboard_name(im->keyboard_number)); p_kmsi = kmfl_make_keyboard_instance(NULL); kmfl_attach_keyboard(p_kmsi, im->keyboard_number); *buf='\0'; kmfl_get_header(p_kmsi,SS_AUTHOR,buf,sizeof(buf) - 1); im->keyboard_author=g_strdup(buf); *buf='\0'; kmfl_get_header(p_kmsi,SS_COPYRIGHT,buf,sizeof(buf) - 1); im->keyboard_copyright=g_strdup(buf); *buf='\0'; kmfl_get_header(p_kmsi,SS_LANGUAGE,buf,sizeof(buf) - 1); im->keyboard_language=g_strdup(buf); *buf='\0'; kmfl_get_header(p_kmsi,SS_MESSAGE,buf,sizeof(buf) - 1); im->keyboard_description=g_strdup(buf); if (g_strrstr(buf, "license") || g_strrstr(buf, "License") || g_strrstr(buf, "LICENSE")) im->keyboard_license=g_strdup(buf); else im->keyboard_license=g_strdup(""); *buf='\0'; kmfl_get_header(p_kmsi,SS_VISUALKEYBOARD,buf,sizeof(buf) - 1); im->keyboard_visualkeyboard=g_strdup(buf); *buf='\0'; kmfl_get_header(p_kmsi,SS_KEYBOARDVERSION,buf,sizeof(buf) - 1); im->keyboard_keyboardversion=g_strdup(buf); *buf='\0'; kmfl_get_header(p_kmsi,SS_LAYOUT,buf,sizeof(buf) - 1); if (*buf != '\0') im->keyboard_layout=g_strdup(buf); else im->keyboard_layout=g_strdup("us"); kmfl_detach_keyboard(p_kmsi); kmfl_delete_keyboard_instance(p_kmsi); im->keyboard_icon_filename = kmfl_get_icon_file(im); im->keyboard_ldmlfile = kmfl_get_ldml_file(im); } void kmfl_free_keyboard_info(KInputMethod * im) { g_assert(im != NULL); g_free(im->keyboard_filename); g_free(im->keyboard_name); g_free(im->keyboard_author); g_free(im->keyboard_copyright); g_free(im->keyboard_language); g_free(im->keyboard_description); g_free(im->keyboard_icon_filename); g_free(im->keyboard_layout); g_free(im->keyboard_license); g_free(im->keyboard_visualkeyboard); g_free(im->keyboard_keyboardversion); g_free(im->keyboard_ldmlfile); } static IBusEngineDesc * ibus_kmfl_engine_new (gchar * file_name, gchar *lang, gchar *name, gchar *author, gchar *icon, gchar *copyright, gchar *description, gchar *layout, gchar *license) { IBusEngineDesc *engine; gchar * desc = g_strdup_printf("%s\n%s", description, copyright); engine = ibus_engine_desc_new (file_name, name, desc ? desc : "", lang, license ? license : "", author ? author : "", icon ? icon : "", layout); return engine; } GList * ibus_kmfl_add_engines(GList * engines, GList * keyboard_list) { GList *p; for (p=keyboard_list; p != NULL; p = p->next) { gchar * keyboard_filename = (gchar *) p->data; KInputMethod im; im.keyboard_number = kmfl_load_keyboard(keyboard_filename); if (im.keyboard_number >=0) { im.keyboard_filename = g_strdup(keyboard_filename); kmfl_get_keyboard_info(&im); engines = g_list_append (engines, ibus_kmfl_engine_new (keyboard_filename, im.keyboard_language, im.keyboard_name, im.keyboard_author, im.keyboard_icon_filename, im.keyboard_copyright, im.keyboard_description, im.keyboard_layout, im.keyboard_license)); g_free(p->data); kmfl_free_keyboard_info(&im); } } return engines; } GList * ibus_kmfl_list_engines (void) { GList *engines = NULL; GList *keyboard_list; gchar *local_keyboard_path; keyboard_list = kmfl_get_keyboard_list("/usr/share/kmfl"); engines = ibus_kmfl_add_engines(engines, keyboard_list); g_list_free(keyboard_list); keyboard_list = kmfl_get_keyboard_list("/usr/local/share/kmfl"); engines = ibus_kmfl_add_engines(engines, keyboard_list); g_list_free(keyboard_list); local_keyboard_path= g_strdup_printf("%s/.kmfl", getenv("HOME")); keyboard_list = kmfl_get_keyboard_list(local_keyboard_path); engines = ibus_kmfl_add_engines(engines, keyboard_list); g_free(local_keyboard_path); g_list_free(keyboard_list); return engines; } IBusComponent * ibus_kmfl_get_component (void) { GList *engines, *p; IBusComponent *component; component = ibus_component_new ("org.freedesktop.IBus.KMFL", N_("KMFL"), "0.1.0", "GPL", "Doug Rintoul next) { ibus_component_add_engine (component, (IBusEngineDesc *) p->data); } g_list_free (engines); return component; } KInputMethod * kinput_open_im(const gchar * keyboard_filename) { KInputMethod * im = g_new(KInputMethod, 1); if (im != NULL) { im->keyboard_number = kmfl_load_keyboard(keyboard_filename); if (im->keyboard_number < 0) { g_free(im); im = NULL; } else { im->keyboard_filename = g_strdup(keyboard_filename); kmfl_get_keyboard_info(im) ; } } return im; } void kinput_close_im(KInputMethod * im) { g_assert(im != NULL); kmfl_free_keyboard_info(im); kmfl_unload_keyboard(im->keyboard_number); g_free(im); } void output_string(void *contrack, char *ptr) { KInputContext * ic = (KInputContext *)contrack; g_debug("DAR: output_string - ic->cmds=%p", ic->cmds); if (ptr) { Cmd * cmd = g_new(Cmd, 1); cmd->opcode=OUTPUT_STRING; cmd->cmdarg=g_strdup(ptr); ic->cmds = g_list_append(ic->cmds, cmd); } } void erase_char(void *contrack) { KInputContext * ic = (KInputContext *)contrack; g_debug("DAR: erase_char - ic->cmds=%p", ic->cmds); Cmd * cmd = g_new(Cmd, 1); cmd->opcode = ERASE_CHAR; cmd->cmdarg=NULL; ic->cmds = g_list_append(ic->cmds, cmd); } void output_char(void *contrack, unsigned char byte) { if (byte == 8) { erase_char(contrack); } else { char s[2]; s[0] = byte; s[1] = '\0'; output_string(contrack, s); } } void forward_keyevent(void *contrack, unsigned int key, unsigned int state) { } void output_beep(void *contrack) { KInputContext * ic = (KInputContext *)contrack; Cmd * cmd = g_new(Cmd, 1); cmd->opcode = OUTPUT_BEEP; cmd->cmdarg=NULL; ic->cmds = g_list_append(ic->cmds, cmd); } /* * Create an input context */ KInputContext * kmfl_create_ic(KInputMethod *im) { KInputContext * ic; g_debug("DAR: kmfl_create_ic"); ic = g_new(KInputContext, 1); ic->cmds = NULL; ic->p_kmsi=kmfl_make_keyboard_instance(ic); kmfl_attach_keyboard(ic->p_kmsi, im->keyboard_number); return ic; } /* * Destroy an input context */ void kmfl_destroy_ic(KInputContext *ic) { GList * p; g_debug("DAR: kmfl_destroy_ic"); kmfl_detach_keyboard(ic->p_kmsi); kmfl_delete_keyboard_instance(ic->p_kmsi); if (ic->cmds) { for (p=ic->cmds; p != NULL; p = p->next) { Cmd * cmd = (Cmd *)p->data; if (cmd) { if (cmd->cmdarg) g_free(cmd->cmdarg); g_free(cmd); } } g_list_free(ic->cmds); ic->cmds=NULL; } } #ifdef DEBUG #include int main () { IBusComponent *component; GString *output; setlocale (LC_ALL, ""); ibus_init (); component = ibus_kmfl_get_component (); output = g_string_new (""); ibus_component_output (component, output, 1); g_debug ("\n%s", output->str); g_string_free (output, TRUE); g_object_unref (component); return 0; } #endif