📄 macros.c
字号:
if( r->nmacros == 0 ) return; /* Nothing to be done */ for( i = 0; i < r->nmacros; i++) { if( r->macros[i].action.type == MacroFnDummy || r->macros[i].keysym == None ) { /* * Dummy macro needs to be deleted. Make sure this macro comes first * in the macro list. * * 2006-03-06 gi1242: Would be more efficient if we made sure that * this macro was last in the list, however that would involve * knowing what the max keysym value is. Could be different on * different architectures. */ r->macros[i].keysym = 0; r->macros[i].modFlags = 0; free( r->macros[i].action.str ); r->macros[i].action.str = NULL; /* Probably unnecessary */ nDummyMacros++; } } /* for */ /* * The macro list now needs to be sorted on keysym. When we look for macros, * we assume the macro list is sorted, so we can use a binary search to * lookup macros quickly. */ qsort( r->macros, r->nmacros, sizeof( macros_t ), macro_cmp); /* Remove dummy macros from our list */ MEMMOVE( r->macros, r->macros + nDummyMacros, (r->nmacros - nDummyMacros) * sizeof( macros_t ) ); r->nmacros -= nDummyMacros; /* Shrink our macros list */ if( r->nmacros < r->maxMacros ) { r->macros = rxvt_realloc( r->macros, r->nmacros * sizeof( macros_t )); r->maxMacros = r->nmacros; } DBG_MSG( 3, ( stderr, "Read %d macros. (Have space for %d macros)\n", r->nmacros, r->maxMacros));#if 0 /* {{{ Debug info */ for( i=0; i < r->nmacros; i++) { DBG_TMSG( 3, ( stderr, "%2d. Key 0x%08lx, Mods 0x%02hhx, Type %2hu, Action: %s\n", i, r->macros[i].keysym, r->macros[i].modFlags, r->macros[i].action.type, r->macros[i].action.str ) ); }#endif /* }}} */}/* {{{1 rxvt_set_action( action, astring) * * Check what action is specified by astring, and assign respective values in * action. * * The string astring might be modified, but can be freed immediately after * calling this function (regardless of wether it succeeds or not). *//* EXTPROTO */Boolrxvt_set_action (action_t *action, char *astring){ unsigned short type, len; DBG_MSG( 2, ( stderr, "Setting action '%s'\n", astring)); /* * Match head of "astring" to a name in macroNames to figure out the macro * type. */ for( type = 0; type < NMACRO_FUNCS; type++) { if( (len = rxvt_str_match( astring, macroNames[type])) ) { /* Matched a macroName at the start of astring */ if( astring[len] && !isspace( astring[len] ) ) /* Not delimited by a space */ continue; /* Skip macroName and delimiting spaces */ astring += len; while( *astring && isspace( *astring ) ) astring++; /* Exit for loop early */ break; } } if( type == NMACRO_FUNCS ) { rxvt_print_error( "Action %s is not of known type", astring); return False; /* Failure: No matching macro name */ } /* * Setup values in action */ action->type = type; /* * Interpolate escape sequences into action. XXX: Should we only do this for * MacroFnStr and MacroFnEsc?. */ len = rxvt_str_escaped( astring ); /* All macros exept MacroFnStr and MacroFnEsc have null terminated string */ if( type != MacroFnStr && type != MacroFnEsc && len > 0 && astring[len-1] ) astring[ len++ ] = 0; /* Since astring was null terminated, astring[len] is certainly part of the memory in astring. */ action->len = len; /* Set action->str. If any data is previously there, realloc it. */ if( len > 0 ) { action->str = (unsigned char *) rxvt_realloc( action->str, len * sizeof(unsigned char)); MEMCPY( action->str, astring, len); } else { free( action->str ); action->str = NULL; } return True;}/* {{{1 rxvt_process_macros( keysym, ev) * * Check to see if a macro key was pressed. If yes, exec the action and return * 1. Else return 0. * * 2006-02-24 gi1242: Take both a keysym, and a XKeyEvent argument because, the * caller might have modified keysym based on XIM. *//* EXTPROTO */intrxvt_process_macros( rxvt_t *r, KeySym keysym, XKeyEvent *ev){ macros_t ck, /* Storing the keysym and mods of the current key that's pressed. */ *macro; /* Macro we find in our saved list corresponding to the current key press */ int status; if( r->nmacros == 0 ) return 0; /* No macro processed */ /* Copy the modifier mask and keysym into ck */ ck.modFlags = 0; if (ev->state & ShiftMask) ck.modFlags |= MACRO_SHIFT; if (ev->state & ControlMask) ck.modFlags |= MACRO_CTRL; if (ev->state & r->h->ModMetaMask) ck.modFlags |= MACRO_META; /* Use lowercase version so we can ignore caps lock */ ck.keysym = tolower( keysym ); /* Check if macro ck is in our list of macros. */ macro = bsearch( &ck, r->macros, r->nmacros, sizeof( macros_t ), macro_cmp); if ( /* * No macro found. */ macro == NULL || ( /* * Primary only macro in secondary screen. */ (macro->modFlags & MACRO_PRIMARY) && AVTS(r)->current_screen != PRIMARY ) || ( /* * When macros are disabled, only the toggle macros macro should * work. */ ( r->Options2 & Opt2_disableMacros ) && macro->action.type != MacroFnToggleMacros ) ) return 0; /* No macro processed */ do { DBG_MSG( 3, ( stderr, "Processing macro #%d mods %02hhx\n", macro - r->macros, macro->modFlags ) ); status = rxvt_dispatch_action( r, &(macro->action), (XEvent*) ev ); } while( status == 1 && (macro - r->macros) < r->nmacros && MACRO_GET_NUMBER( (++macro)->modFlags ) ); return status;}/* {{{1 rxvt_dispatch_action( action, ev) * * Exec the macro / menu action with type "type" and action "action". Returns 1 * on success, -1 on failure. *//* EXTPROTO */intrxvt_dispatch_action( rxvt_t *r, action_t *action, XEvent *ev){ switch( action->type ) { case MacroFnEsc: /* Send action to rxvt */ rxvt_cmd_write( r, ATAB(r), action->str, action->len); break; case MacroFnStr: /* Send action to child process */ rxvt_tt_write( r, ATAB(r), action->str, action->len); break; case MacroFnNewTab: if( action->str != NULL ) { /* * If the first word is quoted, use that as the title. Don't be * fancy and check for nested quotes. That's probably * unnecessary. * * Everything after the first quoted word is the command. If * command starts with "!", then the shell is exec'ed before * running command. */ const int MaxMacroTitle = 80; /* Longest title we will have */ char titlestring[MaxMacroTitle]; char *command = (char *) action->str; char *title = NULL; int profile = 0; /* See if a profile is specified */ if( *command == '-' ) { profile = (int) ( *(++command) - '0' ); if( profile < 0 || profile >= MAX_PROFILES ) profile = AVTS(r)->profileNum; /* Skip spaces */ if( *command ) command++; while( isspace( *command ) ) command++; } /* See if a title is specified */ if( *command == '"' ) { int i; /* Copy everything until first " into title */ for( i=0, command++; i < MaxMacroTitle - 2 && *command && *command != '"'; i++, command++ ) titlestring[i] = *command; titlestring[i] = '\0'; /* Null terminate title */ title = titlestring; /* Skip spaces after title */ if( *command ) command++; while( isspace( *command ) ) command++; } /* Add page */ rxvt_append_page( r, profile, title, *command ? command : NULL ); } else rxvt_append_page( r, 0, NULL, NULL); break; case MacroFnClose: if( action->len > 0 && *(action->str) ) { /* Close tab specified by str */ int tabno = atoi( (char*) action->str) - 1; if( tabno == -1 ) tabno = ATAB(r); if ( tabno >=0 && tabno <=LTAB(r) && ( !(r->Options2 & Opt2_protectSecondary) || PVTS(r, tabno)->current_screen == PRIMARY ) ) { rxvt_kill_page (r, tabno); } } else rxvt_exit_request( r ); break; case MacroFnGoto: { /* Goto tab in position action->str */ int tabno; if( action->str != NULL && *(action->str) ) { tabno = atoi( (char*) action->str ); if( *(action->str) == '+' || *(action->str) == '-' ) { /* * Relative movement of tabs */ tabno += ATAB(r); /* Wrap around */ tabno = tabno % (LTAB(r) + 1); if( tabno < 0 ) tabno += LTAB(r) + 1; } else if( tabno == 0 ) { /* * Previous active tab */ tabno = PTAB(r); } else if( --tabno > LTAB(r) ) { /* * Absolute tab number. If we're too far to the right, * activate the last tab. */ tabno = LTAB(r); } } else tabno = PTAB(r); rxvt_activate_page( r, tabno); break; } case MacroFnMove: /* Move active tab to position in action->str */ if( action->len > 0 && *(action->str) ) { short tabno = atoi( (char*) action->str ); if( *(action->str) == '+' || *(action->str) == '-' ) rxvt_tabbar_move_tab( r, tabno + ATAB(r)); else rxvt_tabbar_move_tab( r, tabno-1 ); } break; case MacroFnScroll: /* Scroll by an amount specified in action->str */ if( action->len > 1 ) { int amount = abs( atoi( (char*) action->str )); enum page_dirn direction = (*(action->str) == '-' ? UP : DN); if( tolower( action->str[ action->len - 2] ) == 'p' ) /* scroll pages */ amount *=#ifdef PAGING_CONTEXT_LINES r->TermWin.nrow - PAGING_CONTEXT_LINES#else r->TermWin.nrow * 4 / 5#endif ; rxvt_scr_page( r, ATAB(r), direction, amount); } break;#if 0 case MacroFnCopy:#endif case MacroFnPaste: if( ev != NULL ) rxvt_selection_request (r, ATAB(r), ev->xkey.time, 0, 0); break; case MacroFnToggleSubwin: rxvt_toggle_subwin( r, action->str); break; case MacroFnFont: { const int MaxFontLen = 8; /* Only need space for "#+xx" */ char fontname[MaxFontLen]; if( action->len >= MaxFontLen - 1 ) break; /* Remember that action->len includes the trailing null char */ fontname[0] = FONT_CMD; /* Internal prefix */ STRNCPY( fontname + 1, action->str, MaxFontLen - 1); fontname[MaxFontLen - 1] = '\0'; /* Null terminate */ rxvt_resize_on_font( r, fontname ); break; } case MacroFnToggleVeryBold: rxvt_toggle_verybold(r); break; case MacroFnToggleTransp:#ifdef TRANSPARENT rxvt_toggle_transparency(r);#endif break; case MacroFnToggleBcst: r->Options2 ^= Opt2_broadcast; break; case MacroFnToggleHold: if (r->Options2 & Opt2_holdExit) { int k; for (k = LTAB(r); k>= 0; k --) if (PVTS(r, k)->dead && PVTS(r, k)->hold > 1) rxvt_remove_page (r, k); r->Options2 &= ~Opt2_holdExit; } else r->Options2 |= Opt2_holdExit; break; case MacroFnToggleFullscren: ewmh_message( r->Xdisplay, XROOT, r->TermWin.parent, XInternAtom( r->Xdisplay, "_NET_WM_STATE", True), _NET_WM_STATE_TOGGLE, XInternAtom( r->Xdisplay, "_NET_WM_STATE_FULLSCREEN", True), 0, 0, 0 ); break; case MacroFnSetTitle: if( action->str != NULL ) rxvt_tabbar_set_title( r, ATAB(r), (unsigned char*) action->str); else if( r->selection.text != NULL ) rxvt_tabbar_set_title( r, ATAB(r), (const unsigned char TAINTED*) r->selection.text); break; case MacroFnPrintScreen: { /* * If first argument is "-scrollback", then dump the whole * scroll back buffer. The argument if any is the command to use for * the printer pipe. */ char *s = action->str; int pretty = 0, scrollback = 0; if( *s && *s == '-' ) { while( *(++s) && !isspace( *s ) ) { if( *s == 's' ) scrollback = 1; else if( *s == 'p' ) pretty = 1; } while( isspace(*s) ) s++; } rxvt_scr_printscreen( r, ATAB(r), scrollback, pretty, *s ? s : NULL ); break; } case MacroFnSaveConfig: { char cfile[PATH_MAX] = ""; if( action->str != NULL ) STRNCPY( cfile, action->str, PATH_MAX-1 ); else { char* home = getenv ("HOME"); if (NULL == home) return -1; /* Failure */ snprintf (cfile, PATH_MAX-1, "%s/%s", home, ".mrxvtrc.save"); } cfile[PATH_MAX-1] = (char) 0; /* Null terminate */ return rxvt_save_options (r, cfile) ? 1 : -1; /* Not reached */ } case MacroFnToggleMacros: r->Options2 ^= Opt2_disableMacros; break; default: assert( action->type < sizeof( macroNames ) / sizeof( char ** ) ); rxvt_print_error( "Macro type '%s' not implemented yet", macroNames[action->type]); return -1; } return 1;}/* }}} *//* vim: set fdm=marker: *//*----------------------- end-of-file (C source) -----------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -