Làm cách nào để kiểm tra xem người dùng có nhấn nút trong khi chức năng đang chạy không?


8

Tôi có một chức năng tự động chạy sau khi người dùng thực hiện một số hành động. Tuy nhiên, chức năng mất nhiều thời gian để hoàn thành. Điều này có nghĩa là Emacs trở nên không phản hồi trong một thời gian ngắn sau mỗi lần nhập. Để khắc phục điều này, tôi muốn kiểm tra xem người dùng đã nhập dữ liệu đầu vào mới chưa và nếu có, hãy hủy thực thi chức năng này và tiến hành nhập liệu của người dùng.

Có một biến giữ đầu vào bàn phím xếp hàng? Nếu không, có cách nào khác để kiểm tra xem người dùng đã nhấn nút từ khi một chức năng bắt đầu chạy chưa?


2
Bạn có thể muốn nhìn vào while-no-inputmacro. Nó dường như làm những gì bạn muốn: tức là nó hủy bỏ việc thực thi cơ thể của nó khi đầu vào mới xuất hiện.
wvxvw 4/11/2016

@wvxvw Nhận xét của bạn giống như một câu trả lời hay. Bạn nên đăng nó như vậy!
Phil Hudson

Câu trả lời:


5

OK, tôi sẽ thử một câu trả lời mở rộng. Vấn đề là, Emacs Lisp là đơn luồng. Bạn có thể quay nhiều tiến trình hơn, nhưng không phải bên trong trình thông dịch Emacs Lisp. Tuy nhiên, đầu vào bàn phím mà bạn cần đọc từ người dùng để làm gián đoạn chức năng của bạn cần được xử lý bởi cùng một trình thông dịch Emacs Lisp. Điều này có nghĩa là nếu trình thông dịch của bạn bị kẹt khi diễn giải một số mã Lisp thì có thể không có cách nào để bạn làm gián đoạn nó từ bên trong. Đây là một vị trí trong hướng dẫn mô tả tình huống này:

Ở cấp độ mã C, việc bỏ thuốc lá không thể xảy ra ở bất cứ đâu; chỉ ở những nơi đặc biệt kiểm tra cờ bỏ. Lý do cho điều này là việc bỏ việc ở những nơi khác có thể để lại sự không nhất quán trong trạng thái nội bộ của Emacs. Bởi vì việc bỏ thuốc bị trì hoãn cho đến khi một nơi an toàn, việc bỏ thuốc lá không thể khiến Emacs gặp sự cố.

https://www.gnu.org/software/emacs/manual/html_node/elisp/Quits.html

Vì vậy, làm thế nào Emacs vẫn có C-gchức năng / hủy? - Có các bộ định thời và chức năng thực hiện I / O (chờ các sự kiện trong vòng lặp lệnh). Bộ hẹn giờ có thể sắp xếp các tính toán của bạn được thực hiện theo từng khối, do đó bạn sẽ có điểm trong các tính toán của mình, nơi bạn có thể nhìn xung quanh và, nếu cần, ngăn chặn tất cả các tính toán tiếp theo. Chức năng I / O có thể gửi quittín hiệu. Macro with-keyboard-quitchờ tín hiệu này và một khi nhận được sẽ thoát một cách duyên dáng. Tuy nhiên, chức năng của bạn cần biết để gửi tín hiệu này. Điều này có nghĩa là nếu chức năng của bạn ngăn người dùng gửi đầu vào bàn phím, thì bạn sẽ không thể hưởng lợi từ việc ngắt bàn phím.

Dòng dưới cùng: hãy thử bọc mã của hàm của bạn vào while-no-input. Nếu điều này không hoạt động, hãy thử viết lại chức năng của bạn theo cách nó sẽ cho phép Emacs xử lý các sự kiện bàn phím.


C-gluôn có thể làm gián đoạn mã lisp, while-no-inputchỉ cần mở rộng này sang đầu vào bàn phím khác.
npostavs

@npostavs không thực sự. Hãy thử làm gián đoạn một cái gì đó như (while t). (Nhưng trước khi bạn làm, hãy đảm bảo bạn đã lưu tất cả các thay đổi của mình).
wvxvw

Tôi gõ (while t)vào *scratch*và đánh C-x C-esau đó C-g; Tôi nhận được Quittin nhắn, Emacs không bị kẹt.
npostavs

@npostavs tốt, tôi chắc chắn sẽ tìm thấy một sự kết hợp không thể làm gián đoạn, nhưng không có thời gian để tìm kiếm nó ngay bây giờ. Tôi không chắc *scratch*có thể tin tưởng được bao nhiêu vì mọi đánh giá bạn đưa ra đều được gói trong chức năng của người trợ giúp.
wvxvw

Tôi đã xoay sở để bị mắc kẹt (while t (condition-case _ (while t) (quit nil))), tôi nghĩ trên lý thuyết là gián đoạn nếu bạn có thể đánh C-gđúng lúc, nhưng trong thực tế, bạn không thể.
npostavs

3

Tôi sẽ đi với input-pending-t. Từ các tài liệu:

(đầu vào đang chờ xử lý-p & KIỂM TRA tùy chọn)

Trả về t nếu đầu vào lệnh hiện có sẵn mà không phải chờ đợi. Trên thực tế, giá trị chỉ bằng không nếu chúng ta có thể chắc chắn rằng không có đầu vào nào khả dụng; nếu có nghi ngờ, giá trị là t.

Một ví dụ nhanh:

(progn
  ;; I put this into a progn call so you can call it direcly from Emacs
  ;; if you are using the sx package
  (message "Try pressing a key in the next 2 seconds!")
  (sleep-for 2)
  (message (if (input-pending-p)
               "There is input waiting!"
             "No input, let’s move on!"))
  (sleep-for 2))

Hoàn hảo! Cả hai câu trả lời đều tuyệt vời, xấu hổ tôi chỉ có thể chấp nhận một. Cảm ơn!
jcaw
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.