/* Copyright 1986 - 1996 by Abacus Research and * Development, Inc. All rights reserved. */ #if !defined (OMIT_RCSID_STRINGS) char ROMlib_rcsid_osevent[] = "$Id: osevent.c 63 2004-12-24 18:19:43Z ctm $"; #endif /* Forward declarations in OSEvent.h (DO NOT DELETE THIS LINE) */ /* * really should be divided into two sections, just like main.c (that * is to say just like main.c should be, it isn't yet) */ #include "rsys/common.h" #include "QuickDraw.h" #include "MemoryMgr.h" #include "CQuickDraw.h" #include "ToolboxEvent.h" #include "OSEvent.h" #include "EventMgr.h" #include "OSUtil.h" #include "ResourceMgr.h" #include "ProcessMgr.h" #include "AppleEvents.h" #include "rsys/cquick.h" #include "rsys/mman.h" #include "rsys/arrowkeys.h" #include "rsys/notmac.h" #include "rsys/blockinterrupts.h" #include "rsys/time.h" #include "rsys/prefs.h" #include "rsys/vdriver.h" #include "rsys/host.h" #include "rsys/next.h" #include "rsys/segment.h" #include "rsys/toolevent.h" #include "rsys/osevent.h" #include "rsys/dirtyrect.h" #include "rsys/stdfile.h" #include "rsys/system_error.h" #include "rsys/string.h" #include "rsys/keyboard.h" #if defined (NEXTSTEP) #include "contextswitch.h" #endif #include "DialogMgr.h" #include "SegmentLdr.h" #if defined (MSDOS) #include "dosevents.h" #endif #define NEVENT 20 PRIVATE int nevent = 0; PRIVATE EvQEl evs[NEVENT], *freeelem = evs+NEVENT-1; #define ROMlib_curs MouseLocation PUBLIC INTEGER ROMlib_mods = btnState; PRIVATE LONGINT autoticks; PRIVATE LONGINT lastdown = -1; #if !defined(NEXTSTEP) PUBLIC short ROMlib_pinned = FALSE; #else PUBLIC short ROMlib_pinned = TRUE; #endif PRIVATE Ptr kchr_ptr; PUBLIC void invalidate_kchr_ptr (void) { kchr_ptr = 0; } PRIVATE INTEGER kchr_id = 0; PUBLIC Ptr ROMlib_kchr_ptr (void) { if (!kchr_ptr) { ZONE_SAVE_EXCURSION (SysZone, { Handle kchr_hand; kchr_hand = GetResource (TICK ("KCHR"), kchr_id); gui_assert (kchr_hand); LoadResource (kchr_hand); HLock (kchr_hand); kchr_ptr = STARH (kchr_hand); }); } return kchr_ptr; } PUBLIC boolean_t ROMlib_set_keyboard (const char *keyboardname) { Handle new_h; ZONE_SAVE_EXCURSION (SysZone, { Str255 pkeyboardname; str255_from_c_string (pkeyboardname, keyboardname); new_h = GetNamedResource (TICK ("KCHR"), pkeyboardname); if (new_h) { GetResInfo (new_h, &kchr_id, 0, 0); kchr_id = CW (kchr_id); LoadResource (new_h); if (kchr_ptr) { Handle kchr_hand; kchr_hand = RecoverHandle (kchr_ptr); HUnlock (kchr_hand); } HLock (new_h); kchr_ptr = STARH (new_h); } }); return !!new_h; } PRIVATE boolean_t map_right_to_left = TRUE; PUBLIC uint16 ROMlib_right_to_left_key_map (uint16 what) { uint16 retval; retval = what; if (map_right_to_left) switch (what) { default: break; case MKV_RIGHTSHIFT: retval = MKV_LEFTSHIFT; break; case MKV_RIGHTOPTION: retval = MKV_LEFTOPTION; break; case MKV_RIGHTCNTL: retval = MKV_LEFTCNTL; break; } return retval; } /* * NOTE: we figure out the value for a down keystroke, then we just remember * what we figured out and return that value on the up. This probably isn't * how the Mac does it, but it's probably close enough. Largely this * routine is just a wrapper for KeyTrans now. See IMV for an explanation * of what's going on here. */ PUBLIC LONGINT ROMlib_xlate (INTEGER virt, INTEGER modifiers, boolean_t down_p) { static uint16 down_value[VIRT_MASK + 1]; LONGINT retval; if (!down_p) retval = down_value[virt & VIRT_MASK]; else { static LONGINT state; retval = KeyTrans (ROMlib_kchr_ptr (), modifiers | (virt & VIRT_MASK), &state); down_value[virt & VIRT_MASK] = (retval >> 16 ? retval >> 16 : retval & 0xFFFF); } return retval; } A1(PUBLIC, void, ROMlib_eventinit, boolean_t, graphics_valid_p) /* INTERNAL */ { static int beenhere = 0; EvQEl *p, *ep; if (!beenhere) { MouseLocation.h = 0; MouseLocation.v = 0; MouseLocation2.h = 0; MouseLocation2.v = 0; ScrDmpEnb = TRUE; evs[0].qLink = 0; /* end of the line */ beenhere = 1; for (p = evs+1, ep = evs+NEVENT; p != ep; p++) p->qLink = RM((QElemPtr) (p-1)); SysEvtMask = CWC(~(1L<< keyUp)); /* EVERYTHING except keyUp */ #if defined (NEXT) ROMlib_started = 3; #endif if (graphics_valid_p) { Rect *main_gd_bounds; main_gd_bounds = &GD_BOUNDS (MR (MainDevice)); #if defined (MSDOS) init_dos_events (CW (main_gd_bounds->right), CW (main_gd_bounds->bottom)); #elif defined (EVENT_SVGALIB) if (!event_init (CW (main_gd_bounds->right), CW (main_gd_bounds->bottom))) { fprintf (stderr, "Unable to initialize svgalib events.\n" "Make sure that executor-svga is installed setuid root,\n" "that libvga.config has your mouse properly identified\n" "and that /dev/mouse is a symlink to the right place\n"); exit (-1); } #endif } } } A1(PRIVATE, void, dropevent, EvQEl *, qp) { Dequeue((QElemPtr) qp, &EventQueue); qp->qLink = RM((QElemPtr) freeelem); freeelem = qp; nevent--; } EvQEl * geteventelem (void) { EvQEl *retval = freeelem; if (nevent == NEVENT) { dropevent((EvQEl *) MR(EventQueue.qHead)); retval = freeelem; } freeelem = (EvQEl *) MR(freeelem->qLink); nevent++; return retval; } PUBLIC boolean_t ROMlib_get_index_and_bit (LONGINT loc, int *indexp, uint8 *bitp) { boolean_t retval; if (loc < 0 || loc / 8 >= sizeof_KeyMap) retval = FALSE; else { retval = TRUE; *indexp = loc / 8; *bitp = (1 << (loc % 8)); } return retval; } A2(PUBLIC, void, ROMlib_zapmap, LONGINT, loc, LONGINT, val) { int i; uint8 bit; if (ROMlib_get_index_and_bit (loc, &i, &bit)) { if (val) KeyMap[i] |= bit; else KeyMap[i] &= ~(bit); } } PRIVATE boolean_t key_down (uint8 loc) { boolean_t retval; int i; uint8 bit; if (!ROMlib_get_index_and_bit (loc, &i, &bit)) retval = FALSE; else retval = !!(KeyMap[i] & bit); return retval; } A3(PUBLIC trap, OSErrRET, PPostEvent, INTEGER, evcode, /* IMIV-85 */ LONGINT, evmsg, HIDDEN_EvQElPtr *, qelp) { EvQEl *qp; LONGINT tmpticks; /* * Here is where the portable autokey stuff should go * If it is a keyUp event, clear autoticks, if it is * a keyDown then set the appropriate bugger ... * * Now that the portable code is here, SCO stuff is out of date */ /* * NOTE: The code below isn't strictly correct, since IMI-260 says * you can have at most 2 non modifier keys down at one time. */ tmpticks = TickCount(); if (evcode == keyUp) { ROMlib_zapmap((evmsg >> 8) & 0xFF, 0); if (!(evmsg & 0xff)) { if (qelp) qelp->p = 0; return noErr; } lastdown = -1; } else if (evcode == keyDown) { ROMlib_zapmap((evmsg >> 8) & 0xFF, 1); if (!(evmsg & 0xff)) { if (qelp) qelp->p = 0; return noErr; } lastdown = evmsg; autoticks = tmpticks + Cx(KeyThresh); if ((evmsg & 0xff) == '2' && /* cmd-shift-2 */ key_down (MKV_CLOVER) && (key_down (MKV_LEFTSHIFT) || key_down (MKV_RIGHTSHIFT))) dofloppymount(); } if (!((1 << evcode)&Cx(SysEvtMask))) /*-->*/ return evtNotEnb; qp = geteventelem(); qp->evtQWhat = CW(evcode); qp->evtQMessage = CL(evmsg); qp->evtQWhen = CL(tmpticks); qp->evtQWhere = ROMlib_curs; qp->evtQModifiers = CW(ROMlib_mods); Enqueue((QElemPtr) qp, &EventQueue); if (qelp) (*qelp).p = qp; return noErr; } A3(PRIVATE, OSErrRET, _PPostEvent, INTEGER, evcode, LONGINT, evmsg, HIDDEN_EvQElPtr *, qelpp) { OSErrRET ret; ProcPtr proc; HIDDEN_EvQElPtr retquelp; proc = (ProcPtr) ostraptable[0x2F]; #if 0 /* FIXME */ if (proc == osstuff[0x2F].orig) #endif ret = PPostEvent(evcode, evmsg, &retquelp); #if 0 else { EM_A0 = evcode; EM_D0 = evmsg; CALL_EMULATOR((syn68k_addr_t) proc); retquelp = EM_A0; ret = EM_D0; } #endif if (qelpp) *qelpp = retquelp; return ret; } A6(PUBLIC, OSErrRET, ROMlib_PPostEvent, INTEGER, evcode, LONGINT, evmsg, HIDDEN_EvQElPtr *, qelp, LONGINT, when, Point, where, INTEGER, butmods) { MouseLocation2.h = ROMlib_curs.h = CW(where.h); MouseLocation2.v = ROMlib_curs.v = CW(where.v); ROMlib_mods = butmods; return _PPostEvent(evcode, evmsg, qelp); } A2(PUBLIC trap, OSErrRET, PostEvent, INTEGER, evcode, LONGINT, evmsg) { return _PPostEvent(evcode, evmsg, (HIDDEN_EvQElPtr *) 0); } A2(PUBLIC trap, void, FlushEvents, INTEGER, evmask, INTEGER, stopmask) /* II-69 */ { EvQEl *qp, *next; int x; virtual_int_state_t block; block = block_virtual_ints (); for (qp = (EvQEl *) MR(EventQueue.qHead); qp && !((x=1<evtQWhat))&stopmask); qp = next) { next = (EvQEl *) MR(qp->qLink); /* save before dropping event */ if (x & evmask) dropevent(qp); } restore_virtual_ints (block); /* NOTE: According to IMII-69 we should be leaving stuff in d0 */ } PUBLIC BOOLEAN ROMlib_bewaremovement; PUBLIC int ROMlib_refresh = 0; A3(PRIVATE, BOOLEAN, OSEventCommon, INTEGER, evmask, EventRecord *, eventp, BOOLEAN, dropit) { EvQEl *qp; virtual_int_state_t block; BOOLEAN retval; static Point oldpoint = { -1, -1 }; LONGINT ticks; /* We tend to call this routine from various ROMlib modal loops, so this * is a good place to check for timer interrupts, etc. */ check_virtual_interrupt (); if (send_application_open_aevt_p && application_accepts_open_app_aevt_p) { ProcessSerialNumber psn; OSErr err; GetCurrentProcess (&psn); { AppleEvent *aevt = alloca (sizeof *aevt); AEAddressDesc *target = alloca (sizeof *target); AEDescList *list = alloca (sizeof *list); int16 count, dummy; err = AECreateDesc (typeProcessSerialNumber, (Ptr) &psn, sizeof psn, target); CountAppFiles (&dummy, &count); count = CW (count); if (count) { int i; err = AECreateAppleEvent (kCoreEventClass, kAEOpenDocuments, target, /* dummy */ -1, /* dummy */ -1, aevt); err = AECreateList (NULL, 0, FALSE, list); for (i = 1; i <= count; i ++) { FSSpec spec; AppFile file; GetAppFiles (i, &file); #if 0 fprintf (stderr, "%d:`%s'\n", i, TEMP_C_STRING_FROM_STR255 (file.fName)); #endif FSMakeFSSpec (CW (file.vRefNum), 0, file.fName, &spec); AEPutPtr (list, i, typeFSS, (Ptr) &spec, sizeof spec); } AEPutKeyDesc (aevt, keyDirectObject, list); AESend (aevt, /* dummy */ NULL, kAENoReply, /* dummy */ -1, /* dummy */ -1, NULL, NULL); } else { err = AECreateAppleEvent (kCoreEventClass, kAEOpenApplication, target, /* dummy */ -1, /* dummy */ -1, aevt); AESend (aevt, /* dummy */ NULL, kAENoReply, /* dummy */ -1, /* dummy */ -1, NULL, NULL); } send_application_open_aevt_p = FALSE; } } eventp->message = CLC(0); #if defined (NEXTSTEP) contextswitch(&romlib_sp, &nextstep_sp); #endif /* NEXTSTEP */ ROMlib_memnomove_p = FALSE; /* this is an icky hack needed for Excel */ ticks = TickCount(); #if defined (X) /* if we are running on a version of linux that doesn't support SIGIO this will handle events (although not asynchronously) */ if (x_event_pending_p ()) post_pending_x_events (/* dummy */ -1, /* dummy */ NULL); #endif /* X */ #if defined (SDL) /* if we are running SDL with the event thread disabled... */ handle_sdl_events (/* dummy */ -1, /* dummy */ NULL); #endif /* SDL */ #if defined(CYGWIN32) && !defined(SDL) /* Run the Win32 event loop, since currently we don't do this in a separate thread. */ process_win32_events(); #endif /* CYGWIN32 */ block = block_virtual_ints (); for (qp = (EvQEl *) MR(EventQueue.qHead); qp && !((1<evtQWhat))&evmask) ; qp = (EvQEl *) MR(qp->qLink)) ; if (qp) { *eventp = *(EventRecord *)(&qp->evtQWhat); if (dropit) { dropevent(qp); } retval = TRUE; } else { eventp->when = CL(TickCount()); { #if defined(X) || defined(NEXTSTEP) if (!ROMlib_pinned) { LONGINT x, y; LONGINT newmods; querypointerX(&x, &y, &newmods); eventp->where.h = MouseLocation2.h = ROMlib_curs.h = CW(x); eventp->where.v = MouseLocation2.v = ROMlib_curs.v = CW(y); } else #endif MouseLocation2 = eventp->where = ROMlib_curs; } #if defined (MSDOS) || defined (EVENT_SVGALIB) { LONGINT x, y; querypointerX (&x, &y, NULL); eventp->where.h = MouseLocation2.h = ROMlib_curs.h = CW (x); eventp->where.v = MouseLocation2.v = ROMlib_curs.v = CW (y); } #endif eventp->modifiers = CW(ROMlib_mods); if ((evmask & autoKeyMask) && lastdown != -1 && ticks > autoticks) { autoticks = ticks + Cx(KeyRepThresh); eventp->what = CWC(autoKey); eventp->message = CL(lastdown); retval = TRUE; } else { eventp->what = CWC(nullEvent); retval = FALSE; } } restore_virtual_ints (block); if (eventp->where.h != oldpoint.h || eventp->where.v != oldpoint.v) { oldpoint = eventp->where; if (ROMlib_bewaremovement) { ROMlib_showhidecursor(); ROMlib_bewaremovement = FALSE; } } #if defined(NEXTSTEP) if (ROMlib_printtimeout < 0) { /* see MacViewClass.m */ dirty_rect_update_screen (); ROMlib_printtimeout = 1; } else #endif if (ROMlib_when == WriteInOSEvent) { dirty_rect_update_screen (); } else if (ROMlib_when == WriteAtEndOfTrap) { dirty_rect_update_screen (); } return retval; } A2(PUBLIC trap, BOOLEANRET, GetOSEvent, INTEGER, evmask, EventRecord *, eventp) { return OSEventCommon(evmask, eventp, TRUE); } A2(PUBLIC trap, BOOLEANRET, OSEventAvail, INTEGER, evmask, EventRecord *, eventp) { return OSEventCommon(evmask, eventp, FALSE); } A1(PUBLIC trap, void, SetEventMask, INTEGER, evmask) { SysEvtMask = CW(evmask); } A0(PUBLIC, QHdrPtr, GetEvQHdr) { return &EventQueue; } PUBLIC void post_keytrans_key_events (INTEGER evcode, LONGINT keywhat, int32 when, Point where, uint16 button_state, unsigned char virt) { INTEGER first_key, second_key; first_key = keywhat >> 16; second_key = keywhat; if (first_key) { ROMlib_PPostEvent (evcode, (virt << 8) | first_key, 0, when, where, button_state); if (second_key) ROMlib_PPostEvent (keyUp, (virt << 8) | first_key, 0, when, where, button_state); } if (second_key || !first_key) ROMlib_PPostEvent (evcode, (virt << 8) | second_key, 0, when, where, button_state); } PRIVATE int compare (const void *p1, const void *p2) { int retval; retval = ROMlib_strcmp (p1, p2); return retval; } PUBLIC void display_keyboard_choices (void) { INTEGER nres, i, nfound; unsigned char (*names)[256]; vdriver_shutdown (); printf ("Available keyboard maps:\n"); SetResLoad (FALSE); nres = CountResources (TICK ("KCHR")); names = alloca (nres * sizeof (*names)); nfound = 0; for (i = 1; i <= nres; ++i) { Handle h; h = GetIndResource (TICK ("KCHR"), i); if (h) { GetResInfo (h, 0, 0, (StringPtr) names[nfound]); ++nfound; } } qsort (names, nfound, sizeof (names[0]), compare); for (i = 0; i < nfound; ++i) printf ("%.*s\n", names[i][0], (char *) &names[i][1]); exit (0); } PUBLIC void maybe_wait_for_keyup (void) { #if defined (SDL) && defined (CYGWIN32) /* Run SDL's event processor so that any pending events get sent to us instead of the Win32 print stuff. Specifically we don't want to lose the key-up if someone hit to choose the default button in a dialog. Losing the key-up can cause all sorts of trouble. */ while (lastdown != -1) handle_sdl_events (0, NULL); #endif }