- vừa được xem lúc

Nhật ký phát triển GõKey - Tuần 1

0 0 16

Người đăng: Huy Tran

Theo The Full Snack

<- Quay về trang chủ

Nhật ký phát triển GõKey - Tuần 1

Gõ tiếng Việt trên máy tính là một chủ đề khá thú vị và xây dựng một bộ gõ tiếng Việt là ước mơ của mình từ khi mới chập chững học lập trình.

Giai đoạn 2006 thì mình có tham gia một diễn đàn công nghệ, và được may mắn theo dõi một số cuộc thảo luận về vấn đề bộ gõ, nhờ đó mà cũng lờ mờ nắm được ý tưởng về các kĩ thuật xử lý như Backspace giả, Clipboard... nhưng ở thời điểm đó, mình chỉ biết rồi thôi.

Thực ra xây dựng bộ gõ không phải là một vấn đề quá khó, cái khó nhất có lẽ là sẽ có rất nhiều behavior cần phải xử lý. Thêm nữa, vì chưa thấy có nhiều tài liệu nói về vấn đề xây dựng bộ gõ, nên ban đầu mình nảy ra ý tưởng làm một bộ gõ đơn giản rồi viết bài hướng dẫn, mô tả kĩ thuật, hy vọng sẽ lôi kéo được thêm nhiều người quan tâm đến chủ đề này

Lúc bắt tay vào làm rồi thì tự nhiên thấy đây là một dự án khá thú vị, nên có lẽ mình sẽ làm tiếp một thời gian nữa .

Dưới đây là vài ghi chú mình viết lại mỗi ngày khi thực hiện dự án này, đôi chỗ có thể sẽ khó hiểu, tuy nhiên nếu đọc chơi thì mình nghĩ chắc cũng không thành vấn đề, vì thế nên mình post lại lên blog.

Trước khi bắt đầu, mình rêcômmnd các bạn đọc qua vài bài viết về vấn đề bộ gõ / xử lý tiếng Việt:

Mã nguồn của dự án GõKey các bạn có thể tham khảo tại đây: https://github.com/huytd/goxkey/

Ngày 10/01/2023

Commit: 82aa2

Sau khi có ý tưởng thực hiện một bộ gõ thì việc đầu tiên mình làm là... đọc source của một vài bộ gõ đã có trước đó, chủ yếu là ibus-bogoOpenKey.

Mục tiêu chính sẽ là làm bộ gõ cho macOS, đơn giản vì mình đang xài macOS. Ngôn ngữ sử dụng sẽ là Rust, lý do thì rất hiển nhiên, mình là fanboi của Rút. JK. Đặc thù của dự án này đòi hỏi phải tương tác với những API bên dưới của hệ điều hành, việc gõ phím đòi hỏi tốc độ xử lý nhanh và ứng dụng phải chạy thật ổn định. Rust hội tụ đủ tất cả mọi yếu tố cần thiết đó: dễ dàng sử dụng các low level API từ hệ điều hành giống như C/C++, hiệu suất hoạt động miễn bàn, có rất nhiều feature/thư viện cho phép mình làm implement những gì mình muốn một cách nhanh chóng mà lại còn đảm bảo tính an toàn, xài Rust làm cho mình yên tâm đến mức có thể nghĩ là: Code compile được là chương trình sẽ hoạt động một cách ổn định và hiệu quả (đừng quá tin vào câu này =))). Mình không phải là một lập trình viên giỏi, và Rust có thể hướng cho mình viết code an toàn hơn, không giống như khi xài C/C++, mình có thể tạm yên tâm với performance, nhưng chưa bao giờ yên tâm về độ an toàn, mọi nước đi mình luôn sợ sẽ gây ra SEGFAULT Trong khi xài JS hay Python thì mình có thể yên tâm về productivity nhưng chưa bao giờ yên tâm về performance.

Tất nhiên những cái benefits trên khi xài Rust, mình vẫn có thể có nếu xài Go. Vấn đề duy nhất là mình không có rành Go

Trước khi bắt đầu thì mình cũng lờ mờ biết là, với kĩ thuật Backspace giả, bằng cách nào đó, phải bắt được thông tin các phím được nhấn, rồi "dịch" các phím đó ra thành một từ tiếng Việt có nghĩa, rồi gửi phím Backspace để xoá từ đã được gõ, rồi gửi tiếp nội dung từ tiếng Việt đó để thay thế.

Tuy nhiên bắt thông tin phím như thế nào thì chưa biết. Rất may là mã nguồn của OpenKey được trình bày tương đối rõ ràng nên mình cũng không tốn nhiều thời gian để tìm ra thứ cần tìm:

eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0, eventMask, OpenKeyCallback, NULL);

Như vậy, từ khoá ở đây là CGEventTapCreate, một API đến từ framework CoreGraphics của macOS.

Để dùng được API của macOS trong Rust thì cần phải viết binding cho các API đó, hoặc là dùng các binding có sẵn, tuy nhiên đang máu nên mình chọn cách tự viết binding, tiện để hiểu thêm những gì xảy ra bên dưới.

Sau một hồi loay hoay thì mình cũng build được một chiếc prototype tạm coi được:

Ngày 13/01/2023

Commit: f68750

Ngày xưa thời còn đi học, cuối tuần là thời điểm mà mình có thể dành toàn bộ thời gian để làm điều mình thích (ôm máy tính, code). Còn bây giờ, cuối tuần là thời điểm mà mình khó tập trung cho việc code nhất vì phải deal với 2 bạn quỷ nhỏ. Cho nên hôm nay không có nhiều progress lắm.

Việc duy nhất làm được hôm nay là tổ chức lại cấu trúc code cho dễ nhìn hơn, tách biệt giữa phần logic xử lý nhập liệu và phần logic giao tiếp với từng hệ điều hành.

Ngày 14/01/2023

Commit: 95fbc7

Dành phần lớn thời gian ngày hôm nay loay hoay tìm cách cải thiện tốc độ gõ. Thế quái nào mà, mang tiếng xài Rust, ấy thế mà performance lại cùi bắp không tưởng được, không thể chấp nhận được...

Một giải pháp được nghĩ ra đó là, khi gửi phím (trong hàm send_backspacesend_string), thay vì phải liên tục tạo thêm event object mới, thì mình sẽ tìm cách sử dụng lại các event object đã được tạo ra trước đó.

// thay vì:
let event = CGEvent::new_keyboard_event(...); // thì dùng:
static ref BACKSPACE_DOWN: CGEvent = CGEvent::new_keyboard_event(...);

Nhưng có một vấn đề, đó là kiểu CGEvent từ trong binding của Servo không được define để có thể share giữa nhiều thread với nhau. Thế là mình phải xài dark magic, tạo ra một kiểu SharedBox<T>, để wrap kiểu CGEvent, implement các trait SyncSend:

struct SharedBox<T>(T);
unsafe impl<T> Send for SharedBox<T> {}
unsafe impl<T> Sync for SharedBox<T> {}
impl<T> SharedBox<T> { unsafe fn new(v: T) -> Self { Self(v) }
} static ref BACKSPACE_DOWN: SharedBox<CGEvent> = unsafe { SharedBox::new(CGEvent::new_keyboard_event( EVENT_SOURCE.0.clone(), KeyCode::DELETE, true ).unwrap())
};

Mục đích của SharedBox<T> là để vỗ ngực bảo đảm với Rust rằng:

  • Mình: "Anh bảo đảm với chú là kiểu T có thể share giữa các thread một cách an toàn, chú cứ yên tâm công tác!"
  • Rust: "D' tin!"

Anyway, mặc cho cái phát minh SharedBox xịn xò mà mình chắc là ai cũng phải thán phục, bug mất chữ vẫn không được fix. Lâu lâu khi gõ thì vẫn xảy ra lỗi khó chịu như gõ "tiếng" trên màn hình sẽ hiện ra "ttiến".

Trong suốt quá trình này, @zerox-dg vẫn rất nhiệt tình và chăm chỉ fix bug từ phía vi-rs, update version mới liên tục. Mỗi lần update là một lần đổi interface, mình phải update theo mệt nghỉ =))


Kết thúc tuần 1. Tình hình bộ gõ vẫn chưa có tiến triển gì mấy ngoài một bản prototype

Bình luận

Bài viết tương tự

- vừa được xem lúc

Chuyện cái comment

Chuyện cái comment. Chuyện rằng, có một ông bạn nọ có cái blog ở trên mạng, cũng có dăm.

0 0 31

- vừa được xem lúc

Đừng đánh nhau với borrow checker

Đừng đánh nhau với borrow checker. TL;DR: Đừng bao giờ đánh nhau với borrow checker, nó được sinh ra để bạn phải phục tùng nó .

0 0 28

- vừa được xem lúc

Chuyện biểu diễn ma trận trên máy tính

Chuyện biểu diễn ma trận trên máy tính. Cách đây mấy hôm mình có share cái screenshot trên Facebook, khoe linh tinh vụ mình đang viết lại cái CHIP-8 emulator bằng Rust.

0 0 43

- vừa được xem lúc

Rust và Lập trình Web

Rust và Lập trình Web. Bài viết được dịch lại từ bản gốc "Rust for the Web" đăng tại phiên bản blog tiếng Anh của mình.

0 0 36

- vừa được xem lúc

Viết ứng dụng đọc tin HackerNews bằng Rust

Viết ứng dụng đọc tin HackerNews bằng Rust. Dạo này mình toàn viết bài linh tinh, lâu rồi chưa thấy viết bài kĩ thuật nào mới nên hôm nay mình viết trở lại, mất công các bạn lại bảo mình không biết co

0 0 24

- vừa được xem lúc

Cài đặt Rust trên Arch Linux

Cài đặt Rust trên Arch Linux. Việc cài đặt Rust trên môi trường Arch Linux khá là đơn giản.

0 0 40