[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Need to insert keydown events
- To: CORNELL@UNIX1.CS.UMASS.EDU
- Subject: Need to insert keydown events
- From: STEVE.M@AppleLink.Apple.COM (Carbon-based, S Mitchell,APD)
- Date: 20 Apr 92 07:35 GMT
- Cc: INFO-MCL@CAMBRIDGE.APPLE.COM
To: Matthew Cornell cornell@unix1.cs.umass.edu
cc: info-mcl
From: Steve Mitchell
Date: 4/19/92
Sub: Need to insert keydown events into MCL
> In trying to make incremental searches playback correctly in my
> fred-macros.lisp contribution I seem to need a new mechanism other
> than my current one, which uses RUN-FRED-COMMAND.
run-fred-command is intentionally not documented so getting away
from it asap is a good idea.
> Specifically, I want a function INSERT-KEY-EVENT that is passed
> a character and a list of modifiers, and makes the Mac or MCL
> think the user just hit those keys. For example:
> (defun TEST-PLAYBACK ()
> (dolist (event-item '((#\r :control) (#\m) (#\a) (#\c) (#\g :control)))
> (insert-key-event (first event-item) (rest event-item))))
> I looked at #_PostEvent but IM II-68 warns the modifiers will be the
> current ones, so I can't pass the saved ones.
MCL provides full access to event processing; it's really a question
of where and at what level you want to break in.
You don't seem to have an interest in saving context information, such
as which window and which key-handler is active, so I assume the aim is
simply to record sequences of keystrokes for playback in any window.
Therefore, your recording mechanism should just save off a copy of (the
relevant components of) each keystoke event. Playback would involve
injecting each keystoke event back into the event mechanism in place of
an idle event.
> The Journaling Mechanism described starting on IM I-261 requires
> writing a journaling device driver, setting global vars, etc. Seems
> too much work.
Apple deprecates the Journaling Mechanism anyway. (That didn't stop
them using it a couple of times)
> An MCL-specific hack would be just fine, something that might involve
> setting-up properly variables like *current-event*,
> *current-keystroke*, etc. then calling do-event or whatever.
> So I'd appreciate any ideas anyone might have. I'm using MCL 2.0f3.
*current-keystroke*, event-keystroke, etc, pre-suppose the existence
of a keystroke event, so using them begs the question of playback.
ccl::do-event is not documented, and will clobber *current-keystroke*.
*eventhook* and *current-event* are provided by MCL for the purpose of
custom event handling, and are documented in the Reference. An example:
(defparameter *key-events-list*
'((134930 . 4224) (142957 . 128) (131169 . 128) (133219 . 128) (132359 .
4224))
"Event msg & modifier flds for ((:control #\r) (#\m) (#\a) (#\c) (:control
#\g))")
;;Visual check:
(dolist (cons *key-events-list*)
(format t "~S " (keystroke-name (event-keystroke (car cons) (cdr cons)))))
(defun set-pseudo-event (cons)
"Sets *current-event* to a pseudo keystroke event"
(rlet ((pseudoEvent eventRecord))
(rset pseudoEvent eventRecord.what 3) ;$keyDown
(rset pseudoEvent eventRecord.message (car cons)) ;keyCode and/or charCode
(rset pseudoEvent eventRecord.when 0) ;irrelevant
(rset pseudoEvent eventRecord.where 0) ;irrelevant
(rset pseudoEvent eventRecord.modifiers (cdr cons))
(setf *current-event* pseudoEvent)))
(defun playback-eventhook ()
"Install a temporary eventhook to process keystrokes from
*key-events-list* during idle time, at the current cursor position
until either done or the user presses the mouse button or a key."
(let ((event-type (rref *current-event* eventRecord.what)))
(cond ((null *key-events-list*)
(setq *eventhook* nil)
T)
((equalp event-type 0) ;$nullEvent
(set-pseudo-event (pop *key-events-list*))
nil)
((equalp event-type 1) ;$mouseDown
(setq *eventhook* nil)
T)
((equalp event-type 3) ;$keyDown
(setq *eventhook* nil)
T))))
;;Play the sequence (this is your "insert-key-event"):
(setq *eventhook* '(playback-eventhook))
;;*key-events-list* will now be nil
;;; For recording, a pair of functions similar to the above
;;; could push a copy of *current-event* keystroke events
;;; onto *key-events-list*.
If you decide that side-effecting *current-event* is not ok, you
could instead try advise'ing get-next-event to return the next
pseudo keystroke-event if any, whenever it gets an idle from WNE.
Then you wouldn't need an eventhook either. For recording macros,
the advise'ing function would push a copy of keystroke events onto
*key-events-list*.
- - - - - - - - - -
EDITABLE KEYSTROKE MACROS
If you're recording keystroke events for playback, they don't have to
be in keystroke-code form, eg '(:control #\r) unless the user can edit
macros; not necessarily a desirable feature anyway.
The dolist form above translates *key-events-list* into keystroke-code
form and displays it. event-keystroke does the translation by (among
other things) applying #_KeyTrans to the installed KCHR resource.
There is no inverse trap, and MCL does not provide the inverse
translation, so converting from '(:control #\r) -> (134930 . 4224)
will have to be ad hoc.
If you have to be able to edit macros, and hence translate from
keystroke-code form to events, simplest and safest is to embed a
table of key Codes (a=0, b=11, c=8, ...) as MCL (ie event-keystroke)
will accept either key Code (* 256), or char Code, or both in the
message field, and does not need the ADB code. The modifiers field
can be readily reconstructed from a keystroke-code.
- - - - - - - - - -
_Steve