ฉันจะจำลองเหตุการณ์กุญแจ Arbitary จาก Elisp ได้อย่างไร


26

เป็นไปได้หรือไม่ที่จะจำลองเหตุการณ์กุญแจโดยพลการจาก elisp? ฉันตระหนักถึงวิธีที่ฉันสามารถค้นหาการเชื่อมโยงสำหรับคีย์ที่กำหนดและจากนั้นเรียกคำสั่งนั้นแบบโต้ตอบ แต่จะเกิดอะไรขึ้นถ้าเหตุการณ์คีย์นั้นไม่ได้ผูกไว้กับคำสั่ง

ในฐานะที่เป็นหนึ่งในตัวอย่างสิ่งที่ถ้าผมอยากจะผูกC-`จะประพฤติเช่นเดียวกับESCที่สำคัญในบริบททั้งหมด ?


ดูเหมือนว่าkey-bindingsจะเป็นแท็กที่ไม่ถูกต้องหากคุณไม่ได้พยายามใช้นามแฝงการโยงคีย์ นอกจากนี้คุณอาจเปลี่ยนตัวอย่างเป็นอย่างอื่นเพื่อไม่ให้สับสน
b4hand

@ b4hand ฉันเปิดรับข้อเสนอแนะสำหรับแท็กที่ดีกว่า ไม่มีkey-eventsแท็ก ฉันควรทำหรือไม่
nispio

ฟังดูสมเหตุสมผลสำหรับฉัน แต่เหตุการณ์อาจจะดีกว่าเนื่องจากอาจใช้กับเหตุการณ์เมาส์ได้
b4hand

2
ฉันยังคงสับสนเป็นไปได้ว่าคุณต้องการที่จะจำลองเหตุการณ์สำคัญใน Elisp หรือคุณโดยเฉพาะต้องการความสามารถในการที่จะทำให้การกระทำที่สำคัญราวกับว่ามันเป็นกุญแจสำคัญอื่นได้หรือไม่ ความชอบของสิ่งkey-translation-mapอำนวยความสะดวกด้านหลังดังนั้นถ้านั่นคือทั้งหมดที่คุณต้องการฉันขอแนะนำให้ใช้มันแทนที่จะทำอะไรเพิ่มเติมด้วยตนเอง
phils

... และหากการแปลที่สำคัญคือสิ่งที่คุณต้องการที่นี่ฉันคิดว่านั่นเป็นคำถามที่แตกต่างกันและคุณควรถามแยกต่างหาก จากนั้นให้ยกตัวอย่างของคุณอีกครั้งเพื่อให้คำถามนี้เหมาะสมกับปัญหาทั่วไปของ "ฉันจะจำลองเหตุการณ์สำคัญใน elisp ได้อย่างไร"
phils

คำตอบ:


24

คุณสามารถให้อาหารเหตุการณ์โดยพลการ (การกดแป้นพิมพ์คลิกเมาส์ ฯลฯ ) unread-command-eventsห่วงคำสั่งโดยการวางไว้บน ตัวอย่างเช่นต่อไปนี้จะทำให้คำสั่งวนซ้ำเพื่อดำเนินการพักในครั้งต่อไปที่มันถูกเรียกใช้:

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

โปรดทราบว่านี่เป็นเพียงฟีดเหตุการณ์ไปยังลูปคำสั่งดังนั้นมันจะไม่ทำอะไรที่น่าสนใจถ้าคุณลูปในรหัสของคุณเอง

วิธีที่แตกต่างซึ่งคุณดูเหมือนจะต้องระวังคือการหาฟังก์ชั่นที่คีย์ที่ให้มาถูกผูกไว้และรันด้วยตัวคุณเอง:

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

สิ่งนี้จะดำเนินการคำสั่งทันที อย่างไรก็ตามระวังว่าคำสั่งบางคำสั่งจะมีพฤติกรรมที่แตกต่างกันออกไปขึ้นอยู่กับว่าเรียกว่าแบบโต้ตอบหรือไม่เช่นอาร์กิวเมนต์เริ่มต้น คุณจะต้องชดเชยสิ่งนั้นโดยใช้call-interactively:

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

ฉันอ่านเกี่ยวกับunread-command-eventsแต่ฉันไม่สามารถหาวิธีใช้งานได้ การตั้งค่ามันไม่มีผลสำหรับฉัน มีตัวอย่างที่ดีเกี่ยวกับวิธีการใช้งานหรือไม่?
nispio

ผมเคยเห็นมันมาใช้เมื่อถามผู้ใช้สามารถกดพื้นที่ที่จะดำเนินการต่อไป - unread-command-eventsถ้าอะไรที่ผู้ใช้กดอื่นมันจะไปสู่
jch

@nispio: unread-command-eventsเป็นเพียงชื่อของมัน คุณสามารถตรวจสอบเหตุการณ์และจากนั้นขึ้นอยู่กับว่ามันคืออะไรผลักดันมันกลับมาอย่างมีเงื่อนไขu-c-eเพื่อที่จะดำเนินการตามปกติ มีตัวอย่างมากมายของการใช้งานในซอร์สโค้ด Emacs - grepเป็นเพื่อนของคุณ
ดึง

1
ฉันสามารถunread-command-eventsไปทำงาน ชิ้นส่วนที่ฉันขาดไปก่อนหน้านี้คือlistify-key-sequenceฟังก์ชั่น ฉันเพิ่งใช้เวกเตอร์คีย์ raw
nispio

1
ขอบคุณสำหรับคำตอบนี้ ฉันต้องการใช้การทดสอบที่ไม่โต้ตอบของระบบเสร็จสมบูรณ์ของฉันดังนั้นฉันจึงใช้ความคิดนี้เพื่อใช้with-simulated-inputแมโครที่ประเมินนิพจน์ใด ๆ ที่มีunread-command-eventsการโยงกับลำดับคีย์ที่ระบุ: github.com/DarwinAwardWinner/ido-ubiquitous/blob/ ......
Ryan C. Thompson

8

วิธีที่ง่ายที่สุดที่ฉันรู้ก็คือใช้execute-kbd-macro:

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

การประเมินดังกล่าวข้างต้นแล้วกดให้ฉันข้อผิดพลาดC-` apply: Wrong number of arguments: #[(ad--addoit-function ...
nispio

1
@nispio ไม่ใช่สำหรับฉัน ข้อผิดพลาดนั้นดูเหมือนคำแนะนำ
Malabarba

@ Malabarba ฉันคิดว่าคุณพูดถูก หลังจากเริ่มต้นใหม่โดยมีemacs -Qข้อผิดพลาดนั้นไม่ปรากฏ ฉันยังคงได้รับข้อผิดพลาดนี้:After 0 kbd macro iterations: foo: Lisp nesting exceeds `max-lisp-eval-depth'
nispio

นี่คือสิ่งที่ฉันกำลังมองหา ด้วยเหตุผลแปลก ๆ บางอย่าง (อาจมีรายละเอียดการโต้ตอบด้วยevil) การเรียกฟังก์ชั่นที่ต้องการโดยตรงมีผลที่ไม่คาดคิดในกรณีของฉัน ( evilmi-jump-items) และฉันต้องใช้(execute-kbd-macro (kbd "%"))
xji

4

จากคำตอบนี้คุณสามารถใช้รหัสสากลแบบนี้

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

ซึ่งจะถือว่าC-`เป็นescape

สิ่งนี้ดูเหมือนว่าจะมีปัญหาบางอย่างแม้ว่าชุดที่สองจะไม่ใช้งานฟังก์ชั่น ดังนั้นหากescapeมีการใช้งานเช่นMetaนั้นจะไม่ทำงานอย่างถูกต้อง แต่ดูเหมือนว่าจะทำงานสำหรับคำสั่งที่ผูกไว้กับฟังก์ชั่น


@nispio: อันที่จริงมันใช้งานได้เนื่องจากอาร์กิวเมนต์ที่สองถูกแปลงเป็นแมโครคีย์บอร์ดโดยปริยาย
shosti

1
@shosti การประเมินดังกล่าวข้างต้นแล้วกดให้ฉันข้อผิดพลาด:C-` After 0 kbd macro iterations: command-execute: Lisp nesting exceeds `max-lisp-eval-depth'
nispio

@nispio: คุณอาจได้C-`ผูกไว้กับESCวิธีอื่นดังนั้นมันจะเข้าสู่วงวนไม่สิ้นสุด
shosti

@shosti คุณพูดถูก มีจำนวนมากเกินไปที่eval-sexpเกิดขึ้นในเซสชันเดียว :-) แต่ลองอีกครั้งด้วยemacs -Qสาเหตุที่C-` จะไม่ทำอะไรเลย
nispio

ขึ้นอยู่กับระบบของคุณ(kbd "<escape>")และ(kbd "ESC")อาจหมายถึงสิ่งที่แตกต่างกัน - คุณลองทั้งคู่แล้วหรือ
shosti

2

หลังจากอ่านข้อเสนอแนะจากjchเพื่อใช้unread-command-eventsฉันก็สามารถแฮ็ควิธีแก้ปัญหาร่วมกันที่จะทำบางสิ่งที่ฉันกำลังมองหา

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

ยังคงมีข้อผิดพลาดมากมายที่ต้องจัดการ defunคือฉันไม่ได้รับผลที่ถูกต้องถ้าผมเรียกฟังก์ชั่นนี้เป็นครั้งที่สองในแถวภายในครั้งเดียว


หมายเหตุด้านข้าง:

หลังจากตรวจสอบข้อเสนอแนะของ philsเพื่อใช้key-translation-mapฉันก็สามารถค้นหาได้local-function-key-mapซึ่งก็เป็นประโยชน์อย่างมากในการบรรลุเป้าหมายที่กว้างขึ้นของฉัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.