📄 tkbind.c
字号:
* we save it in a dynamic string. * 2. The binding's action can potentially delete the binding, * so bindPtr may not point to anything valid once the action * completes. Thus we have to save bindPtr->interp in a * local variable in order to restore the result. */ interp = bindPtr->interp; Tcl_DStringInit(&savedResult); /* * Save information about the current screen, then invoke a script * if the screen has changed. */ Tcl_DStringGetResult(interp, &savedResult); screenPtr = &bindInfoPtr->screenInfo; oldDispPtr = screenPtr->curDispPtr; oldScreen = screenPtr->curScreenIndex; if ((dispPtr != screenPtr->curDispPtr) || (Tk_ScreenNumber(tkwin) != screenPtr->curScreenIndex)) { screenPtr->curDispPtr = dispPtr; screenPtr->curScreenIndex = Tk_ScreenNumber(tkwin); ChangeScreen(interp, dispPtr->name, screenPtr->curScreenIndex); } if (matchCount > 0) { pendingPtr->nextPtr = bindInfoPtr->pendingList; pendingPtr->tkwin = tkwin; pendingPtr->deleted = 0; bindInfoPtr->pendingList = pendingPtr; } /* * Save the current value of the TK_DEFER_MODAL flag so we can * restore it at the end of the loop. Clear the flag so we can * detect any recursive requests for a modal loop. */ flags = winPtr->flags; winPtr->flags &= ~TK_DEFER_MODAL; p = Tcl_DStringValue(&scripts); end = p + Tcl_DStringLength(&scripts); i = 0; while (p < end) { int code; screenPtr->bindingDepth++; Tcl_AllowExceptions(interp); if (*p == '\0') { PatSeq *psPtr; psPtr = pendingPtr->matchArray[i]; i++; code = TCL_OK; if ((pendingPtr->deleted == 0) && ((psPtr->flags & MARKED_DELETED) == 0)) { code = (*psPtr->eventProc)(psPtr->clientData, interp, eventPtr, tkwin, detail.keySym); } psPtr->refCount--; if ((psPtr->refCount == 0) && (psPtr->flags & MARKED_DELETED)) { if (psPtr->freeProc != NULL) { (*psPtr->freeProc)(psPtr->clientData); } ckfree((char *) psPtr); } } else { code = Tcl_GlobalEval(interp, p); p += strlen(p); } p++; screenPtr->bindingDepth--; if (code != TCL_OK) { if (code == TCL_CONTINUE) { /* * Do nothing: just go on to the next command. */ } else if (code == TCL_BREAK) { break; } else { Tcl_AddErrorInfo(interp, "\n (command bound to event)"); Tcl_BackgroundError(interp); break; } } } if (matchCount > 0 && !pendingPtr->deleted) { /* * Restore the original modal flag value and invoke the modal loop * if needed. */ deferModal = winPtr->flags & TK_DEFER_MODAL; winPtr->flags = (winPtr->flags & (unsigned int) ~TK_DEFER_MODAL) | (flags & TK_DEFER_MODAL); if (deferModal) { (*winPtr->classProcsPtr->modalProc)(tkwin, eventPtr); } } if ((screenPtr->bindingDepth != 0) && ((oldDispPtr != screenPtr->curDispPtr) || (oldScreen != screenPtr->curScreenIndex))) { /* * Some other binding script is currently executing, but its * screen is no longer current. Change the current display * back again. */ screenPtr->curDispPtr = oldDispPtr; screenPtr->curScreenIndex = oldScreen; ChangeScreen(interp, oldDispPtr->name, oldScreen); } Tcl_DStringResult(interp, &savedResult); Tcl_DStringFree(&scripts); if (matchCount > 0) { PendingBinding **curPtrPtr; for (curPtrPtr = &bindInfoPtr->pendingList; ; ) { if (*curPtrPtr == pendingPtr) { *curPtrPtr = pendingPtr->nextPtr; break; } curPtrPtr = &(*curPtrPtr)->nextPtr; } if (pendingPtr != &staticPending) { ckfree((char *) pendingPtr); } }}/* *--------------------------------------------------------------------------- * * TkBindDeadWindow -- * * This procedure is invoked when it is determined that a window is * dead. It cleans up bind-related information about the window * * Results: * None. * * Side effects: * Any pending C bindings for this window are cancelled. * *--------------------------------------------------------------------------- */ voidTkBindDeadWindow(winPtr) TkWindow *winPtr; /* The window that is being deleted. */{ BindInfo *bindInfoPtr; PendingBinding *curPtr; bindInfoPtr = (BindInfo *) winPtr->mainPtr->bindInfo; curPtr = bindInfoPtr->pendingList; while (curPtr != NULL) { if (curPtr->tkwin == (Tk_Window) winPtr) { curPtr->deleted = 1; } curPtr = curPtr->nextPtr; }}/* *---------------------------------------------------------------------- * * MatchPatterns -- * * Given a list of pattern sequences and a list of recent events, * return the pattern sequence that best matches the event list, * if there is one. * * This procedure is used in two different ways. In the simplest * use, "object" is NULL and psPtr is a list of pattern sequences, * each of which corresponds to a binding. In this case, the * procedure finds the pattern sequences that match the event list * and returns the most specific of those, if there is more than one. * * In the second case, psPtr is a list of pattern sequences, each * of which corresponds to a definition for a virtual binding. * In order for one of these sequences to "match", it must match * the events (as above) but in addition there must be a binding * for its associated virtual event on the current object. The * "object" argument indicates which object the binding must be for. * * Results: * The return value is NULL if bestPtr is NULL and no pattern matches * the recent events from bindPtr. Otherwise the return value is * the most specific pattern sequence among bestPtr and all those * at psPtr that match the event list and object. If a pattern * sequence other than bestPtr is returned, then *bestCommandPtr * is filled in with a pointer to the command from the best sequence. * * Side effects: * None. * *---------------------------------------------------------------------- */static PatSeq *MatchPatterns(dispPtr, bindPtr, psPtr, bestPtr, objectPtr, sourcePtrPtr) TkDisplay *dispPtr; /* Display from which the event came. */ BindingTable *bindPtr; /* Information about binding table, such as * ring of recent events. */ PatSeq *psPtr; /* List of pattern sequences. */ PatSeq *bestPtr; /* The best match seen so far, from a * previous call to this procedure. NULL * means no prior best match. */ ClientData *objectPtr; /* If NULL, the sequences at psPtr * correspond to "normal" bindings. If * non-NULL, the sequences at psPtr correspond * to virtual bindings; in order to match each * sequence must correspond to a virtual * binding for which a binding exists for * object in bindPtr. */ PatSeq **sourcePtrPtr; /* Filled with the pattern sequence that * contains the eventProc and clientData * associated with the best match. If this * differs from the return value, it is the * virtual event that most closely matched the * return value (a physical event). Not * modified unless a result other than bestPtr * is returned. */{ PatSeq *matchPtr, *bestSourcePtr, *sourcePtr; bestSourcePtr = *sourcePtrPtr; /* * Iterate over all the pattern sequences. */ for ( ; psPtr != NULL; psPtr = psPtr->nextSeqPtr) { XEvent *eventPtr; Pattern *patPtr; Window window; Detail *detailPtr; int patCount, ringCount, flags, state; int modMask; /* * Iterate over all the patterns in a sequence to be * sure that they all match. */ eventPtr = &bindPtr->eventRing[bindPtr->curEvent]; detailPtr = &bindPtr->detailRing[bindPtr->curEvent]; window = eventPtr->xany.window; patPtr = psPtr->pats; patCount = psPtr->numPats; ringCount = EVENT_BUFFER_SIZE; while (patCount > 0) { if (ringCount <= 0) { goto nextSequence; } if (eventPtr->xany.type != patPtr->eventType) { /* * Most of the event types are considered superfluous * in that they are ignored if they occur in the middle * of a pattern sequence and have mismatching types. The * only ones that cannot be ignored are ButtonPress and * ButtonRelease events (if the next event in the pattern * is a KeyPress or KeyRelease) and KeyPress and KeyRelease * events (if the next pattern event is a ButtonPress or * ButtonRelease). Here are some tricky cases to consider: * 1. Double-Button or Double-Key events. * 2. Double-ButtonRelease or Double-KeyRelease events. * 3. The arrival of various events like Enter and Leave * and FocusIn and GraphicsExpose between two button * presses or key presses. * 4. Modifier keys like Shift and Control shouldn't * generate conflicts with button events. */ if ((patPtr->eventType == KeyPress) || (patPtr->eventType == KeyRelease)) { if ((eventPtr->xany.type == ButtonPress) || (eventPtr->xany.type == ButtonRelease)) { goto nextSequence; } } else if ((patPtr->eventType == ButtonPress) || (patPtr->eventType == ButtonRelease)) { if ((eventPtr->xany.type == KeyPress) || (eventPtr->xany.type == KeyRelease)) { int i; /* * Ignore key events if they are modifier keys. */ for (i = 0; i < dispPtr->numModKeyCodes; i++) { if (dispPtr->modKeyCodes[i] == eventPtr->xkey.keycode) { /* * This key is a modifier key, so ignore it. */ goto nextEvent; } } goto nextSequence; } } goto nextEvent; } if (eventPtr->xany.window != window) { goto nextSequence; } /* * Note: it's important for the keysym check to go before * the modifier check, so we can ignore unwanted modifier * keys before choking on the modifier check. */ if ((patPtr->detail.clientData != 0) && (patPtr->detail.clientData != detailPtr->clientData)) { /* * The detail appears not to match. However, if the event * is a KeyPress for a modifier key then just ignore the * event. Otherwise event sequences like "aD" never match * because the shift key goes down between the "a" and the * "D". */ if (eventPtr->xany.type == KeyPress) { int i; for (i = 0; i < dispPtr->numModKeyCodes; i++) { if (dispPtr->modKeyCodes[i] == eventPtr->xkey.keycode) { goto nextEvent; } } } goto nextSequence; } flags = flagArray[eventPtr->type]; if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) { state = eventPtr->xkey.state; } else if (flags & CROSSING) { state = eventPtr->xcrossing.state; } else { state = 0; } if (patPtr->needMods != 0) { modMask = patPtr->needMods; if ((modMask & META_MASK) && (dispPtr->metaModMask != 0)) { modMask = (modMask & ~META_MASK) | dispPtr->metaModMask; } if ((modMask & ALT_MASK) && (dispPtr->altModMask != 0)) { modMask = (modMask & ~ALT_MASK) | dispPtr->altModMask; } if ((state & modMask) != modMask) { goto nextSequence; } } if (psPtr->flags & PAT_NEARBY) { XEvent *firstPtr; int timeDiff; firstPtr = &bindPtr->eventRing[bindPtr->curEvent]; timeDiff = (Time) firstPtr->xkey.time - eventPtr->xkey.time; if ((firstPtr->xkey.x_root < (eventPtr->xkey.x_root - NEARBY_PIXELS)) || (firstPtr->xkey.x_root > (eventPtr->xkey.x_root + NEARBY_PIXELS)) || (firstPtr->xkey.y_root < (eventPtr->xkey.y_root - NEARBY_PIXELS)) || (firstPtr->xkey.y_root > (eventPtr->xkey.y_root + NEARBY_PIXELS)) || (timeDiff > NEARBY_MS)) { goto nextSequence; } } patPtr++; patCount--; nextEvent: if (eventPtr == bindPtr->eventRing) { eventPtr = &bindPtr->eventRing[EVENT_BUFFER_SIZE-1]; detailPtr = &bindPtr->detailRing[EVENT_BUFFER_SIZE-1]; } else { eventPtr--; detailPtr--; } ringCount--; } matchPtr = psPtr; sourcePtr = psPtr; if (objectPtr != NULL) { int iVirt; VirtualOwners *voPtr; PatternTableKey key; /* * The sequence matches the physical constraints. * Is this object interested in any of the virtual events * that correspond to this sequence? */ voPtr = psPtr->voPtr; memset(&key, 0, sizeof(key)); key.object = *objectPtr; key.type = VirtualEvent;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -