Làm cách nào tôi có thể mô phỏng một sự kiện quan trọng của Elisp?


26

Có thể mô phỏng một sự kiện quan trọng tùy ý từ elisp? Tôi nhận thức được các cách mà tôi có thể tìm thấy ràng buộc cho một khóa đã cho, và sau đó gọi lệnh đó một cách tương tác, nhưng nếu sự kiện khóa đó không bị ràng buộc với một lệnh thì sao?

Lấy một ví dụ , điều gì sẽ xảy ra nếu tôi muốn liên kết C-`để hành xử giống như ESCchìa khóa trong tất cả các bối cảnh ?


Có vẻ như đó key-bindingslà thẻ sai nếu bạn không cố gắng đặt bí danh cho một ràng buộc chính. Ngoài ra, có lẽ bạn nên thay đổi ví dụ của mình sang một thứ khác để nó không bị nhầm lẫn.
b4hand

@ b4hand Tôi đang mở để đề xuất cho các thẻ tốt hơn. Không có key-eventsthẻ. Tôi có nên làm một?
nispio

Nghe có vẻ hợp lý với tôi, nhưng các sự kiện có thể tốt hơn vì điều này cũng có thể áp dụng cho các sự kiện chuột.
b4hand

2
Tôi vẫn bối rối không biết liệu bạn có muốn mô phỏng một sự kiện quan trọng trong elisp hay bạn đặc biệt muốn khả năng thực hiện một hành động chính như thể đó là một khóa khác? Thích key-translation-maptạo điều kiện cho cái sau, vì vậy nếu đó là tất cả những gì bạn muốn, tôi sẽ đề nghị sử dụng nó thay vì làm bất cứ điều gì thủ công hơn.
phils

... Và nếu bản dịch chính thực sự là những gì bạn muốn ở đây, tôi nghĩ đó là một câu hỏi khác và bạn nên hỏi riêng nó; và sau đó viết lại ví dụ của bạn cho câu hỏi này để phù hợp hơn với vấn đề chung hơn về "làm thế nào để tôi mô phỏng một sự kiện quan trọng trong elisp?"
phils

Câu trả lời:


24

Bạn có thể đưa các sự kiện tùy ý (tổ hợp phím, nhấp chuột, v.v.) vào vòng lặp lệnh bằng cách đặt chúng vào unread-command-events. Ví dụ, điều sau đây sẽ khiến vòng lặp lệnh thực thi lệnh ngắt trong lần chạy tiếp theo:

(setq unread-command-events (listify-key-sequence "\C-g"))

Lưu ý rằng điều này chỉ cung cấp các sự kiện cho vòng lặp lệnh, vì vậy nó sẽ không có gì thú vị nếu bạn lặp trong mã của riêng bạn.

Một cách tiếp cận khác, mà bạn dường như nhận thức được, là tìm chức năng mà một khóa đã cho bị ràng buộc và tự thực hiện nó:

(funcall (global-key-binding "\C-g"))

Điều này sẽ thực hiện lệnh ngay lập tức. Tuy nhiên, hãy coi chừng rằng một số lệnh có hành vi khác nhau tùy thuộc vào việc chúng có được gọi tương tác hay không, chẳng hạn như các đối số mặc định. Bạn sẽ muốn bù đắp cho điều đó bằng cách sử dụng call-interactively:

(call-interactively (global-key-binding "\C-g"))

Tôi đọc về unread-command-eventsnhưng tôi không thể tìm ra cách sử dụng nó. Thiết lập nó không có tác dụng đối với tôi. Có bất kỳ ví dụ tốt về cách nó được sử dụng?
nispio

Tôi đã thấy nó được sử dụng khi yêu cầu người dùng nhấn phím cách để tiếp tục - nếu người dùng nhấn bất cứ thứ gì khác, nó sẽ tiếp tục unread-command-events.
JCH

@nispio: unread-command-eventsđúng như tên gọi của nó. Bạn có thể kiểm tra một sự kiện và sau đó, tùy thuộc vào sự kiện đó, điều kiện đẩy nó trở lại u-c-eđể sau đó sẽ được xử lý bình thường. Có rất nhiều ví dụ về việc sử dụng nó trong mã nguồn Emacs - greplà bạn của bạn.
vẽ

1
Tôi đã có thể unread-command-eventsđi làm. Phần tôi bị thiếu trước đây là listify-key-sequencechức năng. Tôi vừa mới sử dụng véc tơ thô.
nispio

1
Cảm ơn câu trả lời này. Tôi muốn thực hiện các thử nghiệm không tương tác trong hệ thống hoàn thành của mình, vì vậy tôi đã sử dụng ý tưởng này để triển khai một with-simulated-inputmacro đánh giá bất kỳ biểu thức nào với unread-command-eventsgiới hạn cho một chuỗi khóa được chỉ định: github.com/DarwinAwardWinner/ido-ubiquitous/blob/
Ryan C. Thompson

8

Cách đơn giản nhất mà tôi biết chỉ là sử dụng execute-kbd-macro:

(defun foo () (interactive) (execute-kbd-macro (kbd "<escape>")))
(global-set-key (kbd "C-`") 'foo)

Đánh giá ở trên và sau đó nhấn C-` cho tôi một lỗi apply: Wrong number of arguments: #[(ad--addoit-function ....
nispio

1
@nispio Không dành cho tôi. Lỗi đó trông giống như một lời khuyên.
Malabarba

@Malabarba Tôi nghĩ bạn đúng. Sau khi bắt đầu mới với emacs -Qlỗi đó là không có. Tôi vẫn nhận được lỗi này:After 0 kbd macro iterations: foo: Lisp nesting exceeds `max-lisp-eval-depth'
nispio

Đây thực sự là những gì tôi đang tìm kiếm. Vì một số lý do lạ (có thể là một số chi tiết tương tác với evil), việc gọi trực tiếp hàm mong muốn có tác dụng không mong muốn trong trường hợp của tôi ( evilmi-jump-items) và tôi phải sử dụng(execute-kbd-macro (kbd "%"))
xji

4

Lấy từ câu trả lời này , bạn có thể sử dụng khóa toàn cầu như thế này

(global-set-key (kbd "C-`") (kbd "<escape>"))

Mà sẽ coi C-`escape

Điều này dường như có một số vấn đề mặc dù nếu sự kết hợp thứ hai không thực hiện một chức năng. Vì vậy, nếu escapeđang được sử dụng như thế Meta, thì nó không hoạt động chính xác. Nhưng nó dường như làm việc cho các lệnh bị ràng buộc với các chức năng.


@nispio: Trên thực tế, nó hoạt động được, vì đối số thứ hai được chuyển đổi hoàn toàn thành macro bàn phím.
shosti

1
@shosti Đánh giá ở trên và sau đó nhấn C-` cho tôi một lỗi : After 0 kbd macro iterations: command-execute: Lisp nesting exceeds `max-lisp-eval-depth'.
nispio

@nispio: Có lẽ bạn đã C-bị ràng buộc ESCbởi một số phương thức khác, vì vậy nó sẽ đi vào một vòng lặp vô hạn.
shosti

@shosti Bạn đã đúng. Quá nhiều eval-sexpdiễn ra trong một phiên. :-) Nhưng thử lại với emacs -Qnguyên nhân C-` đơn giản là không làm gì cả.
nispio

Tùy thuộc vào hệ thống của bạn (kbd "<escape>")(kbd "ESC")có thể có nghĩa là những thứ khác nhau - bạn đã thử cả hai chưa?
shosti

2

Sau khi đọc gợi ý từ jch để sử dụng unread-command-events, tôi đã có thể hack cùng nhau một giải pháp sẽ thực hiện một số điều mà tôi đang tìm kiếm.

(defun my-simulate-key-event (event &optional N)
  "Simulate an arbitrary keypress event.

This function sets the `unread-command-events' variable in order to simulate a
series of key events given by EVENT. Can also For negative N, simulate the
specified key EVENT directly.  For positive N, removes the last N elements from
the list of key events in `this-command-keys' and then appends EVENT.  For N nil,
treat as N=1."
  (let ((prefix (listify-key-sequence (this-command-keys)))
         (key (listify-key-sequence event))
         (n (prefix-numeric-value N)))
     (if (< n 0)
         (setq prefix key)
       (nbutlast prefix n)
       (nconc prefix key))
       (setq unread-command-events prefix)))

Vẫn còn một số kink để làm việc. Cụ thể, tôi không nhận được kết quả chính xác nếu tôi gọi hàm này hai lần liên tiếp trong một lần defun.


Lưu ý bên:

Sau khi kiểm tra đề xuất của phils để sử dụng, key-translation-maptôi có thể tìm thấy local-function-key-mapnó cũng rất hữu ích trong việc đạt được một số mục tiêu rộng lớn hơn của tôi.

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.