<aside> 💡 Gõ tiếng Việt là một trong những nhu cầu rất cơ bản của người dùng Việt. Tuy nhiên, hiện tại vẫn chưa có một bộ gõ tiếng Việt nào đạt được sự ổn định và thoải mái như bộ gõ Unikey trên Windows.

</aside>

Đặc biệt có một vấn đề mà rất nhiều người dùng than phiền là khi gõ tiếng Việt xuất hiện một dấu gạch bên dưới dòng chữ đang gõ. Dấu gạch này được gọi là preedit line. Để hiểu về vấn đề này thì cần phải biết sơ qua cách hoạt động của một bộ gõ.

Backspace và Preedit

Một bộ gõ (không nhất thiết là tiếng Việt) thường là một phần mềm chuyển đổi một chuỗi phím nhấn thành một đoạn văn bản ở ngôn ngữ mong muốn. Để làm điều này thì bộ gõ cần phải liên tục thay đổi và hiển thị mẩu văn bản đang gõ dựa theo những phím mới nhấn. VD: khi người dùng gõ a thì sẽ có một chữ a hiện ra màn hình, nhưng nếu gõ thêm một chữ a nữa thì phải thay thế chữ a đầu tiên bằng chữ â theo kiểu gõ Telex.

Gần như tất cả các bộ gõ trên Windows (tôi không dám chắc nhưng không thể kiểm chứng được vì phần lớn là phần mềm nguồn đóng) giải quyết vấn đề này bằng cách sử dụng dấu backspace giả. Như vậy, khi ấn phím a thứ hai thì bộ gõ sẽ gửi một dấu backspace giả để xóa chữ a thứ nhất rồi mới gửi chữ â đến ứng dụng.

Pseudo code cho Unikey:

while True:
    next_key = get_next_key()
    if next_key == 'a' and last_key == 'a':
        send_back_space()
        send_text('â')
    else:
        send_text(next_key)

    last_key = next_key

Tuy nhiên, preedit mới là giải pháp “chính thống” cho vấn đề edit liên tục này. Preedit là một vùng buffer tạm bên trong ứng dụng, cho phép bộ gõ sửa đổi thoải mái. Chỉ khi nào bộ gõ commit đoạn preedit này thì text đang gõ mới trở thành một phần chính thức của văn bản còn không thì nó được coi là độc lập và có thể bị discard bất cứ lúc nào. Vì có sự phân biệt này nên trong tất cả các hướng dẫn thiết kế giao diện của Windows, Mac OS X hay Linux đều khuyến cáo preedit phải được đánh dấu một cách đặc biệt, thông thường là với một dấu gạch chân màu đen 1 pixel. Preedit được dùng rất thông dụng với các bộ gõ tiếng Nhật, Trung, Hàn (CJK).

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/354b5d47-38de-43fd-ac95-e8db528c31d9/japanese-preedit.png

Preedit với bộ gõ tiếng Nhật trên Windows

Code thay đổi khi dùng preedit:

...
if next_key == 'a' and last_key == 'a':
    update_preedit_text('â')
...

Người dùng Việt do quen với kiểu gõ trực tiếp như Unikey trên Windows cảm thấy khó thích nghi với preedit, đặc biệt là với dấu gạch chân, nhưng cũng vì nhiều lý do khác.

Thao tác hiển thị preedit bắt buộc phải được implement phía ứng dụng chứ không phải ở phía hệ thống hay phía bộ gõ vì lý do rất đơn giản là nếu muốn hiển thị preedit ở đúng vị trí con trỏ và với formatting của text đang gõ từ trước thì cần phải có thông tin chính xác về text buffer, mà thông tin này thì chỉ có ứng dụng có. Chính vì được implement ở phía ứng dụng nên điều tất yếu xảy ra là có nhiều implementation khác nhau với những behavior khác nhau. Ví dụ như khi gõ mật khẩu trong gksu thì không hiện preedit nhưng khi gõ với lệnh sudo trong terminal thì sẽ hiện (rất nguy hiểm). Hay trong phần lớn các ứng dụng thì preedit không tạo hiệu ứng autocomplete như phím nhấn bình thường, người dùng phải gõ hết từ muốn tìm kiếm và commit thì chương trình mới bắt đầu autocomplete. Preedit cũng không hoạt động với các ứng dụng Windows chạy qua Wine vì Wine chỉ là một lớp tương thích và không thể biết chính xác con trỏ trong ứng dụng đang ở ví trí nào. Một vấn đề nữa là nếu bộ gõ chỉ sử dụng preedit thì một khi đã commit thì không thể quay trở lại sửa những từ đã gõ ở trước. VD như với ibus-unikey thì nếu đã gõ cón cò thì không thể nhấn backspace quay lại sửa dấu cho ó được (ibus- unikey gặp dấu cách sẽ commit luôn).

Vì vậy, nhiều bộ gõ trên Linux đã cố gắng bắt chước kiểu gõ direct của Unikey trên Windows với nhiều kỹ thuật và mức hiệu quả khác nhau.

Fake X11 event

Trên môi trường Unix thì X11 là phần mềm quản lý giao diện đồ họa, mọi thao tác nhập xuất bàn phím, con trỏ, hiển thị ra màn hình đều phải qua X11. Vì vậy dễ thấy nhất là tạo phím backspace giả từ X11 thông qua hàm XSendEvent() tới ứng dụng đang nhận focus. xvnkb phiên bản 0.1 sử dụng phương pháp này. Về ý tưởng thì gần như giống hệt Unikey, trên Win Unikey sử dụng hàm PostMessageW() với message type là WM_IME_CHAR hoặc WM_CHAR để tạo phím nhấn giả.

Tuy nhiên, X11 là một hệ thống bất đồng bộ nên không có gì đảm bảo sự kiện backspace sẽ đến trước sự kiện commit. Vì vậy có thể dẫn tới trường hợp chữ â tới trước dấu backspace và về phía người dùng thì chữ a thứ hai không có tác dụng gì hết.

Hơn nữa, fake X11 event được coi là một nguy cơ bảo mật nên nhiều ứng dụng không chấp nhận xử lý những sự kiện kiểu này.

Forward key event