kb.c

Go to the documentation of this file.
00001 
00002 /*  $Id: kb.c 1208 2006-04-05 23:51:45Z karstenw $    */
00003 
00004 /******************************************************************************
00005 
00006     UserLand Frontier(tm) -- High performance Web content management,
00007     object database, system-level and Internet scripting environment,
00008     including source code editing and debugging.
00009 
00010     Copyright (C) 1992-2004 UserLand Software, Inc.
00011 
00012     This program is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with this program; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 
00026 ******************************************************************************/
00027 
00028 #include "frontier.h"
00029 #include "standard.h"
00030 
00031 #include "memory.h"
00032 #include "kb.h"
00033 #include "shell.h"
00034 
00035 
00036 #ifdef MACVERSION
00037 #define keycodeclear 71 /*keycodes for numeric keybad*/
00038 #define keycodeminus 78
00039 #define keycodeplus 69
00040 #define keycodetimes 67
00041 #define keycodeseven 89
00042 #define keycodeeight 91
00043 #define keycodenine 92
00044 #define keycodedivide 77
00045 #define keycodefour 86
00046 #define keycodefive 87
00047 #define keycodesix 88
00048 #define keycodecomma 72
00049 #define keycodeone 83
00050 #define keycodetwo 84
00051 #define keycodethree 85
00052 #define keycodeenter 76
00053 #define keycodezero 82
00054 #define keycodeperiod 65
00055 
00056 #define keycodeoption 61
00057 #define keycodecommand 48
00058 #define keycodeshift    63
00059 #define keycodecontrol 60
00060 #endif
00061 
00062 #ifdef WIN95VERSION
00063  /*keycodes for numeric keybad*/
00064 #define keycodeclear -1
00065 #define keycodeminus 0x4a
00066 #define keycodeplus 0x4e
00067 #define keycodedivide 0x135
00068 #define keycodetimes 0x37
00069 #define keycodeseven 0x47
00070 #define keycodeeight 0x48
00071 #define keycodenine 0x49
00072 #define keycodefour 0x4b
00073 #define keycodefive 0x4c
00074 #define keycodesix 0x4d
00075 #define keycodecomma -1
00076 #define keycodeone 0x4f
00077 #define keycodetwo 0x50
00078 #define keycodethree 0x51
00079 #define keycodeenter 0x11c
00080 #define keycodezero 0x52
00081 #define keycodeperiod 0x53
00082 
00083 //#define keycodeoption 61
00084 //#define keycodecommand VK_MENU
00085 //#define keycodeshift  VK_SHIFT
00086 //#define keycodecontrol VK_CONTROL
00087 #define keycodeoption VK_MENU
00088 #define keycodecommand VK_CONTROL
00089 #define keycodeshift    VK_SHIFT
00090 #define keycodecontrol 60
00091 #endif
00092 
00093 
00094 
00095 static boolean keydown (short keycode, boolean flasync) {
00096     
00097     /*
00098     5.0b6 dmb: added flasunc parameter
00099     */
00100 
00101     #ifdef MACVERSION
00102 #       pragma unused (flasync)
00103         KeyMap keys;
00104         
00105         GetKeys (keys);
00106         
00107         return (BitTst (&keys, keycode) != 0);
00108     #endif
00109     #ifdef WIN95VERSION
00110         if (flasync)
00111             return ((GetAsyncKeyState (keycode) & 0x8000) == 0x8000);
00112         else
00113             return ((GetKeyState (keycode) & 0x8000) == 0x8000);
00114     #endif
00115     } /*keydown*/
00116     
00117 
00118 
00120 
00121 
00122 tykeystrokerecord keyboardstatus; 
00123 
00124 static boolean flescapepending = false;
00125 
00126 
00127 
00128 boolean iscmdperiodevent (long eventmessage, long eventwhat, long eventmodifiers) {
00129 #ifdef MACVERSION
00130     /*
00131     Date: Tue, 17 Sep 1996 14:34:15 +0200
00132     To: FRONTIER-TALK@DMC.COM
00133     From: jegues@iol.it (Fabrizio Oddone)
00134     Reply-To: frontier-talk@DMC.COM
00135     Subject: Re: International canceling with Cmd-period
00136     
00137     You wrote:
00138     > I wasn't comfortable with the code you sent me. Was that yours, or is it
00139     > from Apple?
00140     
00141     It's almost from Apple.
00142     That is, it's from "Macintosh Programming Secrets" by Scott Knaster & Keith
00143     Rollin - the latter guy worked for years in Apple's Mac DTS.
00144     Page 484-486, FYI.
00145     
00146     I slightly improved the original code; it works at least on my Italian
00147     keyboard, US keyboards, and since one of my betatesters lives in Japan,
00148     even on a Japanese system.
00149     I've included this routine in every software I wrote, and I never got a
00150     complaint from anywhere.
00151     
00152     > I think there used to be a technote about the right way to
00153     > implement this. Do you know which it is?
00154     
00155     Yes, I have just checked it out.
00156     It's TN TE 23: International Canceling.
00157     Thanks for pointing this out: the note suggests the very same code, but in
00158     the end it mentions an extra trick not mentioned in the book (and the book
00159     was written two years after the technote... <g>).
00160     I have implemented the extra trick (it saves the GetResource() under System
00161     7.0 or later) as suggested and lo! the updated C code is below (I hope the
00162     tabs pass through fine). Note: it still works on my Italian kbd! 8-)
00163     */
00164     
00165     #define kModifiersMask  (0xFF00 & ~cmdKey)
00166     
00167     Handle  hKCHR = nil;
00168     Ptr     KCHRPtr;
00169     UInt32  state;
00170     long    keyInfo;
00171     UInt16  keyCode;
00172     Boolean result = false;
00173     
00174     if ((unsigned short)eventwhat == keyDown || (unsigned short)eventwhat == autoKey) {
00175     
00176         if ((unsigned short)eventmodifiers & cmdKey) {
00177         
00178             keyCode = ((unsigned short)eventmodifiers & kModifiersMask) | ((unsigned short)eventmessage >> 8);
00179             state = 0;
00180             KCHRPtr = (Ptr) GetScriptManagerVariable (smKCHRCache);
00181             
00182             if (KCHRPtr == nil) {
00183                 
00184                 hKCHR = GetResource('KCHR', GetScriptVariable (GetScriptManagerVariable (smKeyScript), smScriptKeys));
00185                 
00186                 KCHRPtr = *hKCHR;
00187                 }
00188             
00189             keyInfo = KCHRPtr ? KeyTranslate(KCHRPtr, keyCode, &state) : eventmessage;
00190             
00191             if (hKCHR)
00192                 ReleaseResource (hKCHR);
00193             
00194             if (((char)keyInfo == '.') || ((char)(keyInfo >> 16) == '.'))
00195                 result = true;
00196             }
00197         }
00198     
00199     return (result);
00200 #endif
00201 
00202 #ifdef WIN95VERSION
00203     /* For the Windows version, let us look for ALT-. and CTRL-C */
00204     if ((eventwhat == 'C') || (eventwhat == 'c')) {
00205         if (GetAsyncKeyState(VK_CONTROL) & 0x8000) {
00206             return (true);
00207             }
00208         }
00209 
00210     if ((eventwhat == '.') || (eventwhat == VK_DECIMAL)) {
00211         if (GetAsyncKeyState(VK_MENU) & 0x8000) {
00212             return (true);
00213             }
00214         }
00215 
00216     return (false);
00217 
00218 #endif
00219     } /*iscmdperiodevent*/
00220 
00221 
00222 boolean arrowkey (char chkb) {
00223     
00224     /*
00225     return true if the indicated key character is an arrow key.
00226     */
00227     
00228     register char ch = chkb;
00229     
00230     return (
00231         (ch == chuparrow) || (ch == chdownarrow) || 
00232         
00233         (ch == chleftarrow) || (ch == chrightarrow));
00234     } /*arrowkey*/
00235 
00236 
00237 tydirection keystroketodirection (char ch) {
00238     
00239     switch (ch) {
00240         
00241         case chleftarrow:
00242             return (left);
00243             
00244         case chrightarrow:
00245             return (right);
00246             
00247         case chuparrow:
00248             return (up);
00249             
00250         case chdownarrow:
00251             return (down);
00252         } /*switch*/
00253         
00254     return (nodirection);
00255     } /*keystroketodirection*/
00256     
00257 
00258 static void kbsetstatus (long eventmessage, long eventwhat, long eventmodifiers, tykeystrokerecord *kbs) {
00259     
00260     /*
00261     12/11/90 dmb: don't count the caps lock as a modifier in ctmodifiers.
00262     
00263     2/21/91 dmb: handle calls for mousedown events.  we just want to 
00264     record modifier keys
00265     
00266     4.1b12 dmb: use new international-aware iscmdperiodevent from Fabrizio Oddone
00267     */
00268     
00269     register short ct;
00270     short keycode;
00271     tykeystrokerecord kbcurrent;
00272     
00273 #ifdef MACVERSION
00274     kbcurrent.flshiftkey = (eventmodifiers & shiftKey) != 0;
00275     
00276     kbcurrent.flcmdkey = (eventmodifiers & cmdKey) != 0;
00277     
00278     kbcurrent.floptionkey = (eventmodifiers & optionKey) != 0;
00279     
00280     kbcurrent.flalphalock = (eventmodifiers & alphaLock) != 0;
00281     
00282     kbcurrent.flcontrolkey = (eventmodifiers & controlKey) != 0;
00283 #endif
00284     
00285 
00286 #ifdef WIN95VERSION
00287     kbcurrent.flshiftkey = keydown(keycodeshift, false);
00288     
00289     kbcurrent.flcmdkey = keydown(keycodecommand, false);
00290     
00291     kbcurrent.floptionkey = keydown(keycodeoption, false);
00292     
00293     kbcurrent.flalphalock = (GetKeyState (VK_CAPITAL) & 0x0001);  /*Use toggle state*/
00294     
00295     kbcurrent.flcontrolkey = keydown(keycodecontrol, false);
00296 #endif
00297     
00298 
00299     ct = 0;
00300     
00301     if (kbcurrent.flshiftkey) ct++;
00302     
00303     if (kbcurrent.flcmdkey) ct++;
00304     
00305     if (kbcurrent.floptionkey) ct++;
00306     
00307     /*
00308     if (kbcurrent.flalphalock) ct++;
00309     */
00310     
00311     if (kbcurrent.flcontrolkey) ct++;
00312     
00313     kbcurrent.ctmodifiers = ct; 
00314     
00315 #ifdef MACVERSION
00316     if (eventwhat == mouseDown) {
00317         
00318         kbcurrent.chkb = chnul;
00319         
00320         kbcurrent.keycode = 0;
00321         
00322         kbcurrent.flautokey = false;
00323         
00324         kbcurrent.keydirection = nodirection;
00325         }
00326     else {
00327         
00328         kbcurrent.chkb = eventmessage & charCodeMask; /*get the keystroke*/
00329         
00330         kbcurrent.flautokey = (eventwhat == autoKey);
00331         
00332         kbcurrent.keycode = keycode = (eventmessage & keyCodeMask) >> 8;
00333         
00334         kbcurrent.keydirection = keystroketodirection (kbcurrent.chkb);
00335         
00336         if ((kbcurrent.flcmdkey) && iscmdperiodevent (eventmessage, eventwhat, eventmodifiers)) { /*dmb 4.1b12*/
00337         
00338             kbcurrent.chkb = '.';
00339             
00340             kbcurrent.flshiftkey = false; /*dmb 4.1.1b1: prevent shellfilterfunctionkey menu mapping*/
00341             
00342             kbcurrent.ctmodifiers--;
00343             }
00344 
00345         if (kbcurrent.flcmdkey  &&  kbcurrent.floptionkey) {
00346     
00347             /*
00348             we don't want to option character, so find the normal character from 
00349             the keymap.  see IM V-195
00350             */
00351             
00352             Handle hkchr;
00353             unsigned long state = 0;
00354             
00355             if ((hkchr = GetResource ('KCHR', 0)) != nil)
00356                 kbcurrent.chkb = KeyTranslate (*hkchr, kbcurrent.keycode, &state) & 0x000000ff;
00357             };
00358 #endif
00359 
00360 #ifdef WIN95VERSION
00361     if ((eventmessage == WM_LBUTTONDOWN) || (eventmessage == WM_RBUTTONDOWN)) {
00362         
00363         kbcurrent.chkb = chnul;
00364         
00365         kbcurrent.keycode = 0;
00366         
00367         kbcurrent.flautokey = false;
00368         
00369         kbcurrent.keydirection = nodirection;
00370         }
00371     else {
00372         
00373         kbcurrent.chkb = eventmessage;
00374         
00375         kbcurrent.flautokey = ((eventmodifiers & 0x40000000) == 0x40000000);
00376         
00377         kbcurrent.keycode = keycode = (eventmodifiers & 0x01FF0000) >> 16;
00378         
00379         kbcurrent.keydirection = keystroketodirection (kbcurrent.chkb);
00380 
00381         if (keycode == keycodeenter)
00382             kbcurrent.chkb = chenter;
00383         
00384 //      if ((kbcurrent.flcmdkey) && iscmdperiodevent (eventmessage, eventwhat, eventmodifiers)) { /*dmb 4.1b12*/
00385 //      
00386 //          kbcurrent.chkb = '.';
00387 //          
00388 //          kbcurrent.flshiftkey = false; /*dmb 4.1.1b1: prevent shellfilterfunctionkey menu mapping*/
00389 //          
00390 //          kbcurrent.ctmodifiers--;
00391 //          }
00392 
00393 #endif
00394         
00395         kbcurrent.flkeypad = /*true if it is a keystroke from the numeric keypad*/
00396             
00397             (keycode == keycodeclear)       || (keycode == keycodeminus)    || 
00398             
00399             (keycode == keycodeplus)        || (keycode == keycodetimes)    ||
00400             
00401             (keycode == keycodeseven)       || (keycode == keycodeeight)    ||
00402             
00403             (keycode == keycodenine)        || (keycode == keycodedivide)   ||
00404             
00405             (keycode == keycodefour)        || (keycode == keycodefive)     ||
00406             
00407             (keycode == keycodesix)         || (keycode == keycodecomma)    ||
00408             
00409             (keycode == keycodeone)         || (keycode == keycodetwo)      ||
00410             
00411             (keycode == keycodethree)       || (keycode == keycodeenter)    ||
00412             
00413             (keycode == keycodezero)        || (keycode == keycodeperiod);
00414         }
00415     
00416     *kbs = kbcurrent; /*set for caller*/
00417     } /*kbsetstatus*/
00418     
00419 
00420 void setkeyboardstatus (long eventmessage, long eventwhat, long eventmodifiers) {
00421     
00422     /*
00423     sets a global that may be referenced by anyone.
00424     
00425     should be called every time a new event is received.
00426     */
00427     
00428     kbsetstatus (eventmessage, eventwhat, eventmodifiers, &keyboardstatus); /*use global*/
00429     } /*setkeyboardstatus*/
00430 
00431 
00432 void keyboardclearescape (void) {
00433     
00434     flescapepending = false;
00435     } /*keyboardclearescape*/
00436 
00437 
00438 void keyboardsetescape (void) {
00439     
00440     /*ouch (); %*audible feedback asap, multimedia!*/
00441     
00442     /*
00443     shellfrontrootwindowmessage ("\pCancelled.");
00444     */
00445     
00446     flescapepending = true;
00447     } /*keyboardsetescape*/
00448 
00449 
00450 boolean keyboardescape (void) {
00451     
00452     /*
00453     check to see if the user has pressed cmd-period.  if not, no effect on
00454     the event queue and we return false.
00455     
00456     otherwise, we remove the keystroke and return true.  the caller is expected
00457     to return quickly!
00458     
00459     10/29/91 dmb: treat Escape key the same as cmd-period.
00460     */
00461     
00462     register unsigned long tc;
00463 #ifdef MACVERSION
00464     tykeystrokerecord kbcurrent;
00465     EventRecord ev;
00466 #endif
00467 #ifdef WIN95VERSION
00468     MSG msg;
00469 #endif
00470 
00471     static unsigned long lastcheck = 0;
00472     
00473     if (flescapepending)
00474         return (true);
00475     
00476     tc = gettickcount ();
00477     
00478     if ((tc - 60) < lastcheck) /*check 1 time per second*/
00479         return (false);
00480     
00481     lastcheck = tc; /*remember for next time*/
00482 
00483 #ifdef MACVERSION
00484     if (EventAvail (keyDownMask, &ev)) {
00485         
00486         kbsetstatus (ev.message, ev.what, ev.modifiers, &kbcurrent);
00487         
00488         if ((kbcurrent.chkb == chescape) || (kbcurrent.flcmdkey && (kbcurrent.chkb == '.'))) {
00489             
00490             GetNextEvent (keyDownMask, &ev); /*get rid of the cmd-period*/
00491             
00492             keyboardsetescape (); /*multimedia!*/
00493             
00494             return (true);
00495             }
00496         }
00497 #endif
00498 #ifdef WIN95VERSION
00499     if (PeekMessage(&msg, NULL, WM_KEYDOWN, WM_KEYDOWN, PM_NOREMOVE)) {
00500         if ((msg.wParam == VK_ESCAPE) || iscmdperiodevent (msg.message, msg.wParam, 0)) {
00501             PeekMessage(&msg, NULL, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE); /*get rid of command*/
00502             
00503             keyboardsetescape (); /*multimedia!*/
00504             
00505             return (true);
00506             }
00507         }
00508 #endif
00509     
00510     /*motorsound ();*/
00511     
00512     return (false);
00513     } /*keyboardescape*/
00514     
00516 
00517 /*
00518 boolean enterkeydown (void) {   
00519     
00520     return (keydown (75));
00521     } %*enterkeydown*/
00522     
00523     
00524 boolean optionkeydown (void) {
00525     
00526     return (keydown (keycodeoption, true));
00527     } /*optionkeydown*/
00528     
00529     
00530 boolean cmdkeydown (void) {
00531         
00532     return (keydown (keycodecommand, true));
00533     } /*cmdkeydown*/
00534     
00535     
00536 boolean shiftkeydown (void) {
00537         
00538     return (keydown (keycodeshift, true));
00539     } /*shiftkeydown*/
00540 
00541 boolean controlkeydown (void) {
00542         
00543     return (keydown (keycodecontrol, true));
00544     } /*shiftkeydown*/
00545 
00546 
00547 
00548 void keyboardpeek (tykeystrokerecord *kbrecord) {
00549     
00550     /*
00551     10/29/91 dmb: set ctmodifiers too
00552     */
00553     
00554     register ptrkeystrokerecord p = kbrecord;
00555     register short ct = 0;
00556     
00557     clearbytes (p, longsizeof (tykeystrokerecord));
00558         
00559     if (shiftkeydown()) {
00560         
00561         (*p).flshiftkey = true;
00562         
00563         ct = 1;
00564         }
00565     
00566     if (cmdkeydown()) {
00567         
00568         (*p).flcmdkey = true;
00569         
00570         ++ct;
00571         }
00572     
00573     if (optionkeydown()) {
00574         
00575         (*p).floptionkey = true;
00576         
00577         ++ct;
00578         }
00579     
00580     if (controlkeydown()) {
00581         
00582         (*p).flcontrolkey = true;
00583         
00584         ++ct;
00585         }
00586     
00587     (*p).ctmodifiers = ct;
00588     } /*keyboardpeek*/
00589 
00590 
00591 short getkeyboardstartrepeattime (void) {
00592 
00593     #ifdef MACVERSION
00594     
00595         return (LMGetKeyThresh ());
00596     
00597     #endif
00598     
00599     #ifdef WIN95VERSION
00600     
00601         return (20);    // dmb to rab: what should this be?
00602     
00603     #endif
00604     } /*getkeyboardstartrepeattime*/
00605 
00606 
00607 
00608 

Generated on Wed May 31 18:19:50 2006 for frontierkernel 10.1.10a by  doxygen 1.4.6