Reparación del sistema de entrada CJK en Sublime Text 3 para Ubuntu

En entornos Ubuntu modernos, los usuarios que requieren sistemas de entrada complejos como CJK (Chino, Japonés, Coreano) al usar Sublime Text 3 frecuentemente encuentran problemas de incompatibilidad. El editor, construido sobre GTK2, a menudo no logra integrarse correctamente con los marcos de trabajo de entrada actuales como Fcitx o IBus. Esto se manifiesta en una activación fallida del IME, retrasos perceptibles, desalineación del cursor o colisiones de eventos. La solución implica entender la arquitectura subyacente y aplicar un parche específico para sanar esta brecha de compatibilidad.

1. Análisis de la arquitectura de entrada en Linux

El flujo de entrada en un sistema X11 sigue un modelo de eventos. Los pulsos del teclado son capturados por el kernel, convertidos en eventos de tecla y enviados al servidor X. Este servidor los reenvía a la ventana que tiene el foco. Para los sistemas de entrada complejos, el protocolo X Input Method (XIM) o las bibliotecas IMModule actúan como intermediarios, permitiendo la preedición y la composición de texto antes de que se confirme. Los marcos como Fcitx y IBus son demonios que implementan estos protocolos y gestionan la interacción entre las aplicaciones y los motoras de entrada.

1.1 Causas de la falla en Sublime Text

Sublime Text 3 enlaza estáticamente su propia copia de GTK2. Esto significa que ignora la configuración del sistema de módulos IM (como im-fcitx.so) y puede no registrar adecuadamente su contexto de entrada. Además, utiliza una superficie de dibujo personalizada (no estándar GtkTextView), lo que impide que el sistema operativo le asigne un identificador de ventana válido para la cmounicación XIM. Como resultado, el editor permanece "ciego" ante los eventos del IME.

2. Mecanismo y aplicación del parche

El parche sublime-text-imfix opera en tiempo de ejecución usando el mecanismo LD_PRELOAD. Este permite inyectar una biblioteca compartida (.so) antes de que se cargue la aplicación principal. Esta biblioteca puede interceptar y redirigir llamadas a funciones específicas de GTK, simulando la presencia de un contexto de entrada funcional.

2.1 Interceptación de funciones clave

El parche redefine funciones como gtk_im_context_new para devolver un contexto virtual gestionado por el parche mismo. Este contexto está conectado a los demonios de entrada a través de D-Bus o XIM.

// Fragmento conceptual: Interceptar creación del contexto IM
GtkIMContext* (*original_im_new)(void);
GtkIMContext* wrapped_im_context_new(void) {
    GtkIMContext *ctx = original_im_new();
    if (!ctx) {
        // Crear un contexto de respaldo y vincular señales
        ctx = g_object_new(GTK_TYPE_IM_CONTEXT_SIMPLE, NULL);
        g_signal_connect(ctx, "commit", G_CALLBACK(on_text_commit), NULL);
        g_signal_connect(ctx, "preedit-changed", G_CALLBACK(on_preedit_update), NULL);
    }
    return ctx;
}

Esta función envuelve la original. Si la creación nativa falla, proporciona un contexto alternativo y establece los manejadores de señales necesarios para recibir texto preeditado y confirmado.

2.2 Sincronización de geometría y foco

Un aspecto crítico es informar al IME sobre la posición del cursor para que la ventana de candidatos aparezca en el lugar correcto. Dado que Sublime no proporciona esta información por defecto, el parche debe calcularla activamente.

// Calcular y reportar la posición del cursor al contexto IM
void update_ime_cursor_location(GtkIMContext *im_ctx, GdkWindow *editor_window) {
    GdkRectangle caret_rect;
    // Obtener posición absoluta en pantalla (lógica simplificada)
    gdk_window_get_origin(editor_window, &caret_rect.x, &caret_rect.y);
    // Aplicar factor de escala para DPI alto
    double scale = get_current_monitor_scale();
    caret_rect.x = (int)(caret_rect.x * scale);
    caret_rect.y = (int)(caret_rect.y * scale);
    caret_rect.width = 1;
    caret_rect.height = (int)(get_font_height() * scale);
    
    gtk_im_context_set_cursor_location(im_ctx, &caret_rect);
}

Esta rutina consulta la geometría de la ventana, aplica escalado DPI si es necesario y notifica al contexto IM mediante gtk_im_context_set_cursor_location.

3. Gestión de eventos y resolución de conflictos

Una vez establecida la comunicación básica, es vital manejar los flujos de eventos para evitar conflictos, especialmente durante operaciones de selección de texto.

3.1 Distinción entre preedición y confirmación

El flujo de entrada tiene estados claros: Start → Preedit → Commit. El parche debe distinguir estos estados. La preedición (por ejemplo, "zhong") solo debe mostrar la cadena provisional sin modificar el documento. Solo el evento de confirmación (por ejemplo, "中") debe desencadenar la inserción real del texto.

// Manejador simplificado para eventos de confirmación
static void handle_commit_event(GtkIMContext *context, gchar *committed_text, gpointer data) {
    if (committed_text && strlen(committed_text) > 0) {
        // Inyectar el texto confirmado en el editor de Sublime
        inject_text_into_editor(committed_text);
        // Limpiar cualquier estado de preedición restante
        clear_preedit_display();
    }
}

Este callback se activa únicamente cuando el usuario selecciona y confirma una palabra candidata.

3.2 Mitigación de conflictos durante la selección

Las acciones de selección (ratón, teclas de flecha con Shift) pueden interrumpir el estado del IME. Por ejemplo, cortar texto mientras hay preedición activa puede dejar el IME en un estado inconsistente. El parche puede monitorizar estas acciones y enviar una señal de reinicio (reset) al contexto IM antes de proceder.

4. Soporte extendido para IME específicos

Diferentes motores de entrada tienen peculiaridades. El parche debe ser lo suficientemente robusto para manejarlas.

  • RIME: Requiere un contexto IM estable y soporte para configuraciones avanzadas como la sincronización de frases. El parche asegura que el contexto virtual persista entre sesiones de enfoque.
  • Google Pinyin / Sogou: Pueden enviar metadatos extra o texto enriquecido. El parche puede incluir filtros para normalizar esta información antes de pasarla al editor.
  • Anthy (Japonés) / Nabi (Coreano): Usan composición por bloques. El parche garantiza que los eventos de composición no se confirmen prematuramente, evitando la inserción de caracteres intermedios no deseados.

5. Optimización del rendimiento

La sobrecarga de la capa de intercepción puede introducir latencia. Las optimizaciones incluyen:

  • Hilos separados: Procesar los eventos del IME en un hilo secundario para no bloquear el bucle principal de GUI.
  • Caché de objetos: Reutilizar instancias de GtkIMContext en lugar de crearlas y destruirlas constantemente.
  • Reducción de bloqueos: Utilizar mecanismos de sincronización finos (mutex por contexto) para minimizar la contención entre hilos.
// Ejemplo de cola de eventos con buffer circular
#define EVENT_QUEUE_SIZE 32
typedef struct { /* campos del evento */ } InputEvent;
static InputEvent event_queue[EVENT_QUEUE_SIZE];
static volatile int head = 0, tail = 0;

void enqueue_input_event(const InputEvent *event) {
    int next = (head + 1) % EVENT_QUEUE_SIZE;
    if (next != tail) { // Si no hay desbordamiento
        event_queue[head] = *event;
        __sync_synchronize(); // Barrera de memoria
        head = next;
    }
    // El hilo de procesamiento consume desde 'tail'
}

Esta cola sin bloqueo absorbe ráfagas de eventos de entrada, procesándolas de manera asíncrona para mantener la interfaz receptiva.

6. Verificación y despliegue

El parche se despliega típicamente mediante un script que establece LD_PRELOAD antes de ejecutar Sublime Text. Es crucial probarlo en diferentes versiones de Ubuntu (18.04, 20.04, 22.04) y combinaciones de toolkit (GNOME, KDE). Las pruebas deben cubrir casos de uso comunes: escritura continua, edición con selección, cambio entre pestañas y múltiples monitores con DPI escalado.

Este enfoque de parcheo en tiempo de ejecución proporciona una solución no intrusiva y reversible que restaura la funcionalidad del IME sin requerir modificaciones del binario original de Sublime Text.

Etiquetas: sublime-text-3 Ubuntu linux fcitx ibus

Publicado el 6-15 22:33