xrdp/sesman/chansrv/input_ibus.c
2024-05-05 10:44:19 +08:00

258 lines
7.0 KiB
C

/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2009-2013
* Copyright (C) Laxmikant Rashinkar 2009-2012
*
* 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.
*/
#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif
#include <glib.h>
#include <glib-object.h>
#include <glib/gstdio.h>
#include <ibus.h>
#include "input.h"
#include "thread_calls.h"
static IBusBus *bus;
static IBusEngine *g_engine;
// This is the engine name enabled before unicode engine enabled
static const gchar *ori_name;
static int id = 0;
int
xrdp_input_enable()
{
IBusEngineDesc *desc;
const gchar *name;
if (ori_name)
{
// already enabled
return 0;
}
if (!bus)
{
LOG(LOG_LEVEL_ERROR, "xrdp_ibus_init: input method switched failed, ibus not connected");
return 1;
}
desc = ibus_bus_get_global_engine(bus);
name = ibus_engine_desc_get_name (desc);
if (!g_ascii_strcasecmp(name, "XrdpIme"))
{
return 0;
}
// remember user's input method, will switch back when disconnect
ori_name = name;
if (!ibus_bus_set_global_engine(bus, "XrdpIme"))
{
LOG(LOG_LEVEL_ERROR, "xrdp_input_enable: input method enable failed");
return 1;
}
LOG(LOG_LEVEL_INFO, "xrdp_ibus_init: input method switched sucessfully, old input name: %s", ori_name);
return 0;
}
int
xrdp_input_send_unicode(uint32_t unicode)
{
LOG(LOG_LEVEL_DEBUG, "xrdp_input_send_unicode: received unicode input %i", unicode);
if (xrdp_input_enable())
{
return 1;
}
gunichar chr = unicode;
ibus_engine_commit_text(g_engine, ibus_text_new_from_unichar(chr));
return 0;
}
void
xrdp_input_ibus_engine_enable(IBusEngine *engine)
{
LOG(LOG_LEVEL_INFO, "xrdp_ibus_engine_enable: IM enabled");
g_engine = engine;
}
void
xrdp_input_ibus_engine_disable(IBusEngine *engine)
{
LOG(LOG_LEVEL_INFO, "xrdp_ibus_engine_disable: IM disabled");
}
void
xrdp_input_ibus_disconnect(IBusEngine *engine)
{
LOG(LOG_LEVEL_INFO, "xrdp_ibus_engine_disable: IM disabled");
g_object_unref(g_engine);
g_object_unref(bus);
}
gboolean engine_process_key_event_cb(IBusEngine *engine,
guint keyval,
guint keycode,
guint state)
{
// Pass the keyboard event to system
return FALSE;
}
IBusEngine *
xrdp_input_ibus_create_engine(IBusFactory *factory,
gchar *engine_name,
gpointer user_data)
{
IBusEngine *engine;
gchar *path = g_strdup_printf("/org/freedesktop/IBus/Engine/%i", 1);
engine = ibus_engine_new(engine_name,
path,
ibus_bus_get_connection(bus));
LOG(LOG_LEVEL_DEBUG, "xrdp_input_ibus_create_engine: Creating IM Engine with name:%s and id:%d\n", engine_name, ++id);
g_signal_connect(engine, "process-key-event", G_CALLBACK(engine_process_key_event_cb), NULL);
g_signal_connect(engine, "enable", G_CALLBACK(xrdp_input_ibus_engine_enable), NULL);
g_signal_connect(engine, "disable", G_CALLBACK(xrdp_input_ibus_engine_disable), NULL);
return engine;
}
/*****************************************************************************/
THREAD_RV THREAD_CC
xrdp_input_main_loop()
{
IBusFactory *factory;
IBusComponent *component;
IBusEngineDesc *desc;
THREAD_RV rv = 0;
LOG(LOG_LEVEL_DEBUG, "xrdp_input_main_loop: Entering ibus loop");
g_signal_connect(bus, "disconnected", G_CALLBACK(xrdp_input_ibus_disconnect), NULL);
factory = ibus_factory_new(ibus_bus_get_connection(bus));
g_object_ref_sink(factory);
g_signal_connect(factory, "create-engine", G_CALLBACK(xrdp_input_ibus_create_engine), NULL);
g_signal_connect(factory, "enable", G_CALLBACK(xrdp_input_ibus_engine_enable), NULL);
g_signal_connect(factory, "disable", G_CALLBACK(xrdp_input_ibus_engine_disable), NULL);
ibus_factory_add_engine(factory, "XrdpIme", IBUS_TYPE_ENGINE);
component = ibus_component_new("org.freedesktop.IBus.XrdpIme", // name
"Xrdp input method", // description
"1.1", // version
"MIT", // license
"seflerZ", // author
"fake_page", // homepage
"/exec/fake_path", // cmd
"xrdpime"); // text domain
desc = ibus_engine_desc_new("XrdpIme",
"unicode input method for xrdp",
"unicode input method for xrdp",
"unicode",
"MIT",
"seflerZ",
"fake_icon.png",
"default"); // layout
ibus_component_add_engine(component, desc);
ibus_bus_register_component(bus, component);
ibus_main();
g_object_unref(desc);
g_object_unref(component);
g_object_unref(factory);
return rv;
}
int
xrdp_input_unicode_destory()
{
LOG(LOG_LEVEL_DEBUG, "xrdp_input_unicode_destory: ibus input is under destory");
if (ori_name)
{
LOG(LOG_LEVEL_INFO, "xrdp_input_unicode_destory: ibus engine rolling back to origin: %s", ori_name);
ibus_bus_set_global_engine(bus, ori_name);
}
g_object_unref(g_engine);
g_object_unref(bus);
ori_name = NULL;
bus = NULL;
g_engine = NULL;
return 0;
}
int
xrdp_input_unicode_init()
{
int retry = 10;
if (bus)
{
// Already initialized, just re-enable it
xrdp_input_enable();
return 0;
}
LOG(LOG_LEVEL_DEBUG, "xrdp_ibus_init: Initializing the iBus engine");
ibus_init();
bus = ibus_bus_new();
g_object_ref_sink(bus);
if (!ibus_bus_is_connected(bus))
{
LOG(LOG_LEVEL_ERROR, "xrdp_ibus_init: Connect to iBus failed");
return 1;
}
LOG(LOG_LEVEL_INFO, "xrdp_ibus_init: iBus connected");
tc_thread_create(xrdp_input_main_loop, NULL);
// session may not be ready, repeat until input method enabled
while (retry--)
{
if (ibus_bus_get_global_engine(bus))
{
break;
}
sleep(1);
}
if (retry == 0)
{
LOG(LOG_LEVEL_ERROR, "xrdp_ibus_init: failed to connect to ibus");
return 1;
}
return 1;
}