science@nems.dt.navy.mil (Mark Zimmermann) (12/27/89)
Help?! What is the 'officially approved' way to sense a command-period (cmd-.) so that a user can interrupt a long operation from the keyboard? I would like something that doesn't slow down my inner loop too much, and that would work on all Macs. A code fragment in any language would be appreciated -- I'll be working in Think C 4.0 on code segments (for HyperCard XFCNs), specifically. Many thanks, and Happy New Year! ^z
oster@dewey.soe.berkeley.edu (David Phillip Oster) (12/29/89)
In article <694@nems.dt.navy.mil> science@nems.dt.navy.mil (Mark Zimmermann) writes: >What is the 'officially approved' way to sense a command-period >(cmd-.) so that a user can interrupt a long operation from the keyboard? The best way is to run your event handler, so that other applications can run, and your other windows will update while you are calculating. Assuming you don't wish to do _that_, many people do a GetKeys(), and look for the command and period in the resulting binary key map. This technique may have internationalization problems, so make sure to put the bits you are checking into a resource and let your tech support people know how to customize it. --- David Phillip Oster -- No, I come from Boston. I just work Arpa: oster@dewey.soe.berkeley.edu -- in cyberspace. Uucp: {uwvax,decvax}!ucbvax!oster%dewey.soe.berkeley.edu
tim@hoptoad.uucp (Tim Maroney) (12/29/89)
In article <694@nems.dt.navy.mil> science@nems.dt.navy.mil (Mark Zimmermann) writes: >>What is the 'officially approved' way to sense a command-period >>(cmd-.) so that a user can interrupt a long operation from the keyboard? In article <33392@ucbvax.BERKELEY.EDU> oster@dewey.soe.berkeley.edu.UUCP (David Phillip Oster) writes: >The best way is to run your event handler, so that other applications can >run, and your other windows will update while you are calculating. Granted, but you're likely to make a long operation even longer. Also, the standard event handler is probably not appropriate; you want to mask out most mouse and keyboard operations. But since you're checking the keyboard, you have to throw away keyboard events (except Cmd-Period). This zaps typeahead, which is probably not what people will expect. >Assuming you don't wish to do _that_, many people do a GetKeys(), and look >for the command and period in the resulting binary key map. This technique >may have internationalization problems, so make sure to put the bits you >are checking into a resource and let your tech support people know how to >customize it. It's worse than that. You have to call the GetKeys when the user is depressing the key. This means you'd better be calling it very very very frequently. Again, your long operation is likely to get longer. I'm not really sure that there is any good way, short of patching the keyboard driver -- and even that would be an application-specific patch, so if you *are* giving other applications time, it could fail to be invoked when the actual keypress happens. I suppose you could insert a front-end to the driver into the unit table, but that seems like a big mess for such a small operation. -- Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com FROM THE FOOL FILE: "The men promise to provide unconditionally for their wives. The women in turn serve unconditionally to provide the other household services necessary for the men to fulfill their obligations to the women. The women are satisfied because they have the men working for THEM." -- Colin Jenkins, soc.women
siegel@endor.harvard.edu (Rich Siegel) (12/29/89)
In article <9421@hoptoad.uucp> tim@hoptoad.UUCP (Tim Maroney) writes: >>The best way is to run your event handler, so that other applications can >>run, and your other windows will update while you are calculating. > >Granted, but you're likely to make a long operation even longer. Also, >the standard event handler is probably not appropriate; you want to mask >out most mouse and keyboard operations. But since you're checking the >keyboard, you have to throw away keyboard events (except Cmd-Period). >This zaps typeahead, which is probably not what people will expect. > >>Assuming you don't wish to do _that_, many people do a GetKeys(), and look >>for the command and period in the resulting binary key map. This technique >>may have internationalization problems, so make sure to put the bits you >>are checking into a resource and let your tech support people know how to >>customize it. > >It's worse than that. You have to call the GetKeys when the user is >depressing the key. This means you'd better be calling it very very >very frequently. Again, your long operation is likely to get longer. > >I'm not really sure that there is any good way, short of patching the >keyboard driver -- and even that would be an application-specific >patch, so if you *are* giving other applications time, it could fail to >be invoked when the actual keypress happens. I suppose you could insert >a front-end to the driver into the unit table, but that seems like a >big mess for such a small operation. You're getting warmer... If you wanted to get *really* skanky, you could bottleneck _PostEvent, and set a global flag subject to whether the event was for a fan-period. This involves saving the application's A5 in a safe place, since _PostEvent can get called at interrupt time, and you will probably need to test KeyMap to look for the Command key... Then in whatever operation you'd want to check, just test your global flag each time through the loop, or at selective points during the computation. It's pretty cheap to do all of this, and can be used in places where you don't want to slow down by calling _GetNextEvent or _GetOSEvent... R. ~~~~~~~~~~~~~~~ Rich Siegel Staff Software Developer Symantec Corporation, Language Products Group Internet: siegel@endor.harvard.edu UUCP: ..harvard!endor!siegel "When someone who makes four hundred and fifty dollars an hour wants to tell you something for free, it's a good idea to listen." ~~~~~~~~~~~~~~~
freek@fwi.uva.nl (Freek Wiedijk) (12/29/89)
In article <9421@hoptoad.uucp> tim@hoptoad.UUCP (Tim Maroney) writes: >I'm not really sure that there is any good way, short of patching the >keyboard driver -- and even that would be an application-specific >patch, so if you *are* giving other applications time, it could fail to >be invoked when the actual keypress happens. I suppose you could insert >a front-end to the driver into the unit table, but that seems like a >big mess for such a small operation. Isn't it possible to patch PostEvent, to make it set a flag somewhere, and have your "calculation" test this flag often? Someone told me that this is what Mathematica does. -- Freek "the Pistol Major" Wiedijk Path: uunet!fwi.uva.nl!freek #P:+/ = #+/P?*+/ = i<<*+/P?*+/ = +/i<<**P?*+/ = +/(i<<*P?)*+/ = +/+/(i<<*P?)**
beard@ux1.lbl.gov (Patrick C Beard) (12/29/89)
In article <9421@hoptoad.uucp> tim@hoptoad.UUCP (Tim Maroney) writes: >In article <694@nems.dt.navy.mil> science@nems.dt.navy.mil (Mark Zimmermann) >writes: >>>What is the 'officially approved' way to sense a command-period >>>(cmd-.) so that a user can interrupt a long operation from the keyboard? ... [discussion of various ways that degrade performance] ... > >I'm not really sure that there is any good way, short of patching the >keyboard driver -- and even that would be an application-specific >patch, so if you *are* giving other applications time, it could fail to >be invoked when the actual keypress happens. I suppose you could insert >a front-end to the driver into the unit table, but that seems like a >big mess for such a small operation. How about a patch to PostEvent? That way, when the keypress occurs the patch can set an application global to take note of it, and all that is required in the inner loop of the application is polling that global variable. This provides both the friendliness and the performance. Another point, events such as keypresses and mouse clicks are only delivered to the application in the front layer in MultiFinder. Therefore, the application applied patch to PostEvent would only see cmd-. if that application is in front. MultiFinder, as well, unpatches application applied patches when context switching so you wouldn't interrupt the application if you happened to be in another layer. ------------------------------------------------------------------------------- - Patrick Beard, Macintosh Programmer (beard@lbl.gov) - - Berkeley Systems, Inc. ".......<dead air>.......Good day!" - Paul Harvey - -------------------------------------------------------------------------------
tim@hoptoad.uucp (Tim Maroney) (12/30/89)
In article <3506@husc6.harvard.edu> siegel@endor.UUCP (Rich Siegel) writes: > If you wanted to get *really* skanky, you could bottleneck _PostEvent, >and set a global flag subject to whether the event was for a fan-period. >This involves saving the application's A5 in a safe place, since _PostEvent >can get called at interrupt time, and you will probably need to test KeyMap >to look for the Command key... I pointed out the problem with this in the article you quoted. If you are giving time to other applications, then the PostEvent call at interrupt time may get called in another application's context, bypassing your application-specific patch. Due to the way the Event Manager works, you will still get the keyboard event, but PostEvent may not be called in your application context. So you can drop Command-Dots with this method too. If all applications get equal time, then the probability of correctly intercepting a Cmd-Dot is the reciprocal of the number of applications running. > Then in whatever operation you'd want to check, just test your global >flag each time through the loop, or at selective points during the computation. >It's pretty cheap to do all of this, and can be used in places where you >don't want to slow down by calling _GetNextEvent or _GetOSEvent... As long as you're not giving time to other applications, meaning you're not calling SystemTask, GetNextEvent, or WaitNextEvent, it should work. Otherwise not. -- Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com If you vote for clowns, you have no right to complain that only clowns make it to the ballot.
tim@hoptoad.uucp (Tim Maroney) (12/30/89)
In article <4539@helios.ee.lbl.gov> beard@ux1.lbl.gov (Patrick C Beard) writes: >How about a patch to PostEvent? That way, when the keypress occurs the >patch can set an application global to take note of it, and all that is >required in the inner loop of the application is polling that global variable. >This provides both the friendliness and the performance. See message to Rich. I already dealt with this issue in the message you quoted, and in addition, I've dealt with it in some of the trap patching messages last month. Guess you both missed those messages. >Another point, events such as keypresses and mouse clicks are only delivered >to the application in the front layer in MultiFinder. Therefore, the >application applied patch to PostEvent would only see cmd-. if that >application is in front. MultiFinder, as well, unpatches application >applied patches when context switching so you wouldn't interrupt the >application if you happened to be in another layer. Again, PostEvent is not the *delivery* routine. It simply puts the events in the global queue. The frontmost-only delivery is done by the Toolbox Event Manager (GetNextEvent, EventAvail, WaitNextEvent), not by the OS Event Manager (PostEvent, OSEventAvail, GetOSEvent). PostEvent is called when there is a device interrupt whatever the context may happen to be at the time. -- Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com "Prisons are built with stones of Law, Brothels with bricks of Religion." - Blake, "The Marriage of Heaven and Hell"
oster@dewey.soe.berkeley.edu (David Phillip Oster) (12/30/89)
It is beginning to sound like what we need is an INIT that launches a command-period driver. The command-period driver would patch the PostEvent trap before multi-finder is installed. Applications interested in command-periods would register a callback address with the driver using a control call, inform the driver of suspend and resume events, using a second control call, and de-register the callback before they quit. If a command period occurs, then the keyboard handler will call PostEvent, the command-period driver will detect it. If the last suspend/resume message was a "resume" the driver will assume that one of the registered applications was frontmost, remove the command-period from the queue, and call the callback address. Otherwise, it will assume an unknown application is frontmost and do nothing. Since the callback address is being called at interrupt time, there is a problem accessing the application's globals. We'll have the command-period driver cache the application's currentA5 when the application registers the callback, and the driver will setup A5 before calling the callback, and restore it afterward. Since the callback address is being called at interrupt time, the callback is limited in what it can do: it can't move memory or make most system calls. It could set a flag, or do a C longjump. If you do a longJump, your ongJump catcher should set a flag that your event loop should check, so that when your event loop next runs, it can execute a cleanup routine to cleanup any structures that were not properly deallocated by the longjump. --- David Phillip Oster -- No, I come from Boston. I just work Arpa: oster@dewey.soe.berkeley.edu -- in cyberspace. Uucp: {uwvax,decvax}!ucbvax!oster%dewey.soe.berkeley.edu