Bagaimana saya bisa memeriksa apakah pengguna telah menekan tombol saat fungsi sedang berjalan?


8

Saya memiliki fungsi yang secara otomatis berjalan setelah pengguna melakukan beberapa tindakan. Namun, fungsi ini membutuhkan waktu lama untuk diselesaikan. Ini berarti Emacs menjadi tidak responsif untuk waktu yang singkat setelah setiap input. Untuk memperbaikinya, saya ingin memeriksa apakah pengguna telah memasukkan input baru dan jika demikian, batalkan eksekusi fungsi ini dan lanjutkan dengan input pengguna.

Apakah ada variabel yang menyimpan input keyboard yang antri? Jika tidak, apakah ada cara lain untuk memeriksa apakah pengguna telah menekan tombol sejak fungsi mulai berjalan?


2
Anda mungkin ingin melihat while-no-inputmakro. Tampaknya melakukan apa yang Anda inginkan: yaitu membatalkan eksekusi tubuhnya ketika input baru muncul.
wvxvw

@ wvxvw Komentar Anda bagi saya seperti jawaban yang bagus. Anda harus mempostingnya seperti itu!
Phil Hudson

Jawaban:


5

OK, saya akan mencoba jawaban yang diperluas. Masalahnya, Emacs Lisp adalah single-threaded. Anda dapat memutar lebih banyak proses, tetapi tidak di dalam interpreter Emacs Lisp. Namun, input keyboard yang perlu Anda baca dari pengguna untuk mengganggu fungsi Anda perlu diproses oleh penerjemah Emacs Lisp yang sama. Ini berarti bahwa jika juru bahasa Anda macet menafsirkan beberapa kode Lisp mungkin tidak ada cara bagi Anda untuk menyela dari dalam. Inilah tempat di manual yang menggambarkan situasi ini:

Pada level kode C, berhenti tidak bisa terjadi di mana saja; hanya di tempat-tempat khusus yang memeriksa tanda berhenti. Alasan untuk ini adalah bahwa berhenti di tempat lain mungkin meninggalkan ketidakkonsistenan dalam kondisi internal Emacs. Karena berhenti ditunda sampai tempat yang aman, berhenti tidak dapat membuat Emacs crash.

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

Jadi, bagaimana Emacs masih memiliki fungsi C-g/ pembatalan? - Ada penghitung waktu dan fungsi yang dilakukan I / O (tunggu acara di loop perintah). Pengatur waktu dapat mengatur agar perhitungan Anda dilakukan dalam potongan, sehingga Anda memiliki poin dalam perhitungan Anda di mana Anda dapat melihat-lihat dan, jika perlu, mencegah semua perhitungan lebih lanjut. Fungsi I / O dapat mengirim quitsinyal. Makro with-keyboard-quitmenunggu sinyal ini dan setelah diterima akan keluar dengan anggun. Namun, fungsi Anda perlu tahu untuk mengirim sinyal ini. Ini berarti bahwa jika fungsi Anda mencegah pengguna mengirim input keyboard, maka Anda tidak akan dapat memanfaatkan interupsi keyboard.

Intinya: coba masukkan kode fungsi Anda while-no-input. Jika ini tidak berhasil, cobalah menulis ulang fungsi Anda dengan cara yang memungkinkan Emacs memproses acara papan ketik.


C-gselalu dapat menginterupsi kode lisp, while-no-inputhanya perluas ini ke input keyboard lain.
npostavs

@npostavs tidak terlalu. Coba menyela sesuatu seperti (while t). (Tetapi sebelum Anda melakukannya, pastikan Anda telah menyimpan semua perubahan Anda).
wvxvw

Saya mengetik (while t)ke dalam *scratch*dan memukul C-x C-ekemudian C-g; Saya mendapat Quitpesan, Emacs tidak macet.
npostavs

@ npostavs dengan baik, saya pasti akan menemukan kombinasi yang tidak mungkin terputus, tetapi tidak punya waktu untuk mencarinya sekarang. Saya tidak yakin berapa banyak yang *scratch*bisa dipercaya karena setiap evaluasi yang Anda lakukan ada dalam fungsi pembantu.
wvxvw

Saya berhasil terjebak dengan (while t (condition-case _ (while t) (quit nil))), saya pikir dalam teori yang interruptible jika Anda bisa menekan C-gpada waktu yang tepat, tetapi dalam praktiknya Anda tidak bisa.
npostavs

3

Saya akan pergi dengan input-pending-t. Dari dokumen:

(input-tertunda-p & CHECK-TIMER opsional)

Kembali t jika input perintah saat ini tersedia tanpa menunggu. Sebenarnya, nilainya hanya nol jika kita dapat memastikan bahwa tidak ada input yang tersedia; jika ada keraguan, nilainya adalah t.

Contoh cepat:

(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))

Sempurna! Kedua jawaban itu bagus, sayang saya hanya bisa menerimanya. Terima kasih!
jcaw
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.