研究的软键盘是基于 matchbox-keyboard 实现的。并结合scim-bridge
首先我们看下scim-bridge在各个图形库的插件目录
三种插件目录分别位于 /usr/lib/qt4/plugins/inputmethods/im-scim-bridge.so /usr/lib/clutter-imcontext/immodules/im-scim-bridge.so /usr/lib/gtk-2.0/immodules/im-scim-bridge.so
+------------+ +------------+ +----------------+ | Qt-plugin | | GTK plugin | | Clutter plugin | +------------+ +------------+ +----------------+ | | | +--------------------------------------------+ |socket +---------------+ | scimbridge | +---------------+ |socket +-------------------------+ | SCIM | | +---------------+ | | | mbkeyboard.so | | | +---------------+ | +-------------------------+ | send X event | +-------------------+ | matchbox-keyboard | +-------------------+
class ScimBridgeInputContextPlugin: public QInputContextPlugin { } Q_EXPORT_PLUGIN2 (ScimBridgeInputContextPlugin, ScimBridgeInputContextPlugin)
/* 当有输入窗口时,就会调用QInputContextPlugin::create函数 * 参考 http://qt-project.org/doc/qt-4.8/qinputcontextplugin.html#create */ QInputContext *ScimBridgeInputContextPlugin::create (const QString &key) { return ScimBridgeClientIMContext::alloc (); }创建好的私有成员,实现了X消息过滤,focus_in, focus_out等的操作
void ScimBridgeClientIMContextImpl::focus_in () { if (scim_bridge_client_is_messenger_opened ()) { if (scim_bridge_client_change_focus (this, TRUE)) { scim_bridge_perrorln ("An IOException occurred at focus_in ()"); } } retval_t scim_bridge_client_change_focus (const ScimBridgeClientIMContext *imcontext, boolean focus_in) { pending_response.header = SCIM_BRIDGE_MESSAGE_FOCUS_CHANGED; if (scim_bridge_messenger_send_message (messenger, NULL)) { } } retval_t scim_bridge_messenger_send_message (ScimBridgeMessenger *messenger, const struct timeval *timeout) { ssize_t written_bytes = send (fd, messenger->sending_buffer + buffer_offset, sizeof (char) * write_size, MSG_NOSIGNAL); }
retval_t ScimBridgeAgentImpl::run_event_loop () { const int retval = select (max_fd + 1, &read_set, &write_set, &error_set, NULL); const scim_bridge_agent_event_type_t triggers = client->get_trigger_events (); --- scim_bridge_agent_event_type_t ScimBridgeAgentClientListenerImpl::get_trigger_events () const { if (received_messages.size () > 0) triggers |= SCIM_BRIDGE_AGENT_EVENT_INTERRUPT; if (scim_bridge_messenger_get_sending_buffer_size (messenger) > 0) triggers |= SCIM_BRIDGE_AGENT_EVENT_WRITE; } --- if (interrupted && (triggers & SCIM_BRIDGE_AGENT_EVENT_INTERRUPT)) { events |= SCIM_BRIDGE_AGENT_EVENT_INTERRUPT; } if (!client->handle_event (events)) { } } bool ScimBridgeAgentClientListenerImpl::handle_event (scim_bridge_agent_event_type_t event_type) { if (event_type & SCIM_BRIDGE_AGENT_EVENT_INTERRUPT) { if (process_message (message) == RETVAL_FAILED) { } } } retval_t ScimBridgeAgentClientListenerImpl::process_message (const ScimBridgeMessage *message) { if() { } else if (strcmp (message_header, SCIM_BRIDGE_MESSAGE_CHANGE_FOCUS) == 0) { return change_focus (imcontext_id, focus_in); } } retval_t ScimBridgeAgentClientListenerImpl::change_focus (scim_bridge_imcontext_id_t imcontext_id, bool focus_in) { agent->change_focus (imcontext_id, focus_in); scim_bridge_messenger_push_message (messenger, message); } /* class ScimBridgeAgentClientListenerImpl: public ScimBridgeAgentClientListener { private: ScimBridgeAgentProtected *agent; * } */ void ScimBridgeAgentImpl::change_focus (scim_bridge_imcontext_id_t imcontext_id, bool focus_in) { imcontext->focus_in (); } void ScimBridgeAgentIMContextImpl::focus_in () { get_imengine ()->focus_in (); }