void scim_bridge_client_imcontext_forward_key_event (ScimBridgeClientIMContext *imcontext, const ScimBridgeKeyEvent *key_event)
{ 
    GdkEventKey gdk_event;
    scim_bridge_key_event_bridge_to_gdk (&gdk_event, imcontext->client_window, key_event);
    gdk_event.send_event |= SEND_EVENT_MASK;
    if (imcontext == focused_imcontext && focused_widget != NULL) {
        const char *signal_name = NULL;
        if (scim_bridge_key_event_is_pressed (key_event)) {
            signal_name = "key-press-event";
        } else {
            signal_name = "key-release-event";
        }
        
        gboolean consumed;
        g_signal_emit_by_name (focused_widget, signal_name, &gdk_event, &consumed);
    } else {
        gdk_event_put ((GdkEvent*) &gdk_event);
    }
}
void scim_bridge_client_imcontext_forward_key_event (ScimBridgeClientIMContext *imcontext, const ScimBridgeKeyEvent *key_event)
{ 
    if (imcontext && imcontext == focused_imcontext) {
        GdkEventKey gdk_event;
        scim_bridge_key_event_bridge_to_gdk (&gdk_event, imcontext->client_window, key_event);
        gdk_event.send_event |= SEND_EVENT_MASK;

        if (!gtk_im_context_filter_keypress (GTK_IM_CONTEXT (imcontext->slave), &gdk_event)) {
            // To avoid timing issue, we need emit the signal directly, rather than put the event into the queue.
            if (focused_widget) {
                gboolean result;
                g_signal_emit_by_name(focused_widget,
                    scim_bridge_key_event_is_pressed (key_event) ? "key-press-event" : "key-release-event",
                    &gdk_event,
                    &result
                );
            } else {
                gdk_event_put ((GdkEvent *) &gdk_event);
            }
        }
    }
}