⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 macros.c

📁 Mrxvt是一个小巧
💻 C
📖 第 1 页 / 共 2 页
字号:
/*--------------------------------*-C-*----------------------------------------* * File:	macros.c (used to be hotkeys.c) *-----------------------------------------------------------------------------* * * All portions of code are copyright by their respective author/s. * *	Copyright (c) 2005-2006   Gautam Iyer <gi1242@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 675 Mass * Ave, Cambridge, MA 02139, USA. *----------------------------------------------------------------------------*/#include "../config.h"#include "rxvt.h"#ifdef DEBUG_VERBOSE#define DEBUG_LEVEL 1#else #define DEBUG_LEVEL 0#endif#if DEBUG_LEVEL#define DBG_MSG(d,x) if(d <= DEBUG_LEVEL) fprintf x#else#define DBG_MSG(d,x)#endif/* * Must sync these to values for macro_t.type in rxvtlib.h. */static const char *const macroNames[] ={	"Dummy",				/* Delete macro */	"Esc",					/* Escape sequence to send to mrxvt */	"Str",					/* String to send to child process */	"NewTab",				/* Open a new tab, and exec a program in it. */	"Close",				/* Close tab(s) */	"GotoTab",				/* Switch to tab */	"MoveTab",				/* Move tab */	"Scroll",				/* Scroll up/down */	"Copy",					/* Copy selection */	"Paste",				/* Paste selection */	"ToggleSubwin",			/* Toggle subwindows (scroll / menu / tabbar) */	"ResizeFont",			/* Resize terminal font */	"ToggleVeryBold",		/* Toggle use of bold font for colored text */	"ToggleTransparency",	/* Toggle pseudo transparency */	"ToggleBroadcast",		/* Toggle broadcasting of input */	"ToggleHold",			/* Toggle holding of completed tabs */	"ToggleFullscreen",		/* Toggle full screen mode */	"SetTitle",				/* Set title of active tab to selection */	"PrintScreen",			/* Dump screen to file / printer */	"SaveConfig",			/* Save config to file */	"ToggleMacros"			/* Toggle using keyboard macros */};/******************************************************************************\* 					   BEGIN INTERNAL ROUTINE PROTOTYPES					   *\******************************************************************************/int				macro_cmp			( const void*, const void*);int				rxvt_add_macro		( rxvt_t*, KeySym, unsigned char, char*, Bool, Bool);unsigned char	macro_set_number	( unsigned char, unsigned char);/******************************************************************************\*						END INTERNAL ROUTINE PROTOTYPES						   *\******************************************************************************//* * 2006-02-23 gi1242: New macro code. This should extend the hotkey aproach * without causing code bloat. The idea is that defining "macros" can also * enable the user to communicate with mrxvt using escape sequences! *//* {{{ Macro action functions (called from rxvt_dispatch_action) *//* EXTPROTO */voidrxvt_toggle_verybold( rxvt_t *r ){	if (r->Options2 & Opt2_veryBold) r->Options2 &= ~Opt2_veryBold;	else r->Options2 |= Opt2_veryBold;	rxvt_scr_touch (r, ATAB(r), True);}/* * str = [+-][s|t|m|b] * *		'+' means show. '-' means hide. Neither means toggle. * *		s, t, m, b are the scroll tab and menubars respectively. 'b' is tabbar *		buttons. * * 2006-02-23 gi1242 TODO: Permit hiding / showing more than one sub window at * one time. Currently calls to resize_on_subwin must be followed by * ConfigureNotify event (which we process) to correct the sizeHint (otherwise * we end up having the wrong size). *//* EXTPROTO */voidrxvt_toggle_subwin( rxvt_t *r, const unsigned char *str){	if(	str == NULL || *str == '\0' ||			STRCHR( str, 't') || STRCHR( str, 'T' ) )	{		/*		 * Backward compatibility -- If str is NULL or empty, then toggle the		 * tabbar visibility.		 */		if( rxvt_tabbar_visible (r) && ( str == NULL || *str != '+' ))		{			/*			 * If the tabbar is visible, and we are not forced to show it then			 * hide it.			 */			if( rxvt_tabbar_hide(r) ) rxvt_resize_on_subwin (r, HIDE_TABBAR);		}		else if( !rxvt_tabbar_visible( r ) && ( str == NULL || *str != '-' ))		{			/*			 * If the tabbar is hidden, and we are not forced to hide it, then			 * show the tabbar.			 */			if( rxvt_tabbar_show(r)) rxvt_resize_on_subwin (r, SHOW_TABBAR);		}		return;	}	/*	 * The remainder of this function assumes a non-empty string.	 */	if( STRCHR( str, 'b') || STRCHR( str, 'B') )	{		/* Toggle tabbar buttons */		switch( *str )		{			case '+':				/* Show buttons */				r->Options2 &= ~Opt2_hideButtons;				break;			case '-':				/* Hide buttons */				r->Options2 |= Opt2_hideButtons;				break;			default:				/* Toggle buttons */				r->Options2 ^= Opt2_hideButtons;		}		/* Refresh tabbar */		rxvt_tabbar_set_visible_tabs (r, False);		if( r->tabBar.win != None)			XClearArea( r->Xdisplay, r->tabBar.win, 0, 0, 0, 0, True);		return;	}#ifdef HAVE_SCROLLBARS	if( STRCHR( str, 's') || STRCHR( str, 'S' ) )	{		if( rxvt_scrollbar_visible (r) && *str != '+' )		{			if( rxvt_scrollbar_hide(r) )				rxvt_resize_on_subwin (r, HIDE_SCROLLBAR);		}		else if( !rxvt_scrollbar_visible( r ) && *str != '-' )		{			if( rxvt_scrollbar_show(r) )				rxvt_resize_on_subwin (r, SHOW_SCROLLBAR);		}		return;	}#endif#ifdef HAVE_MENUBAR	if( STRCHR( str, 'm') || STRCHR( str, 'M' ) )	{		if( rxvt_menubar_visible (r) && *str != '+' )		{			if( rxvt_menubar_hide(r) )				rxvt_resize_on_subwin (r, HIDE_MENUBAR);		}		else if( !rxvt_menubar_visible( r ) && *str != '-' )		{			if( rxvt_menubar_show(r) )				rxvt_resize_on_subwin (r, SHOW_MENUBAR);		}		return;	}#endif}/* }}} *//* * Functions to parse macros (add them to our list), and exec actions. *//* {{{1 macro_cmp() * * Used by bsearch and qsort for macro comparison. */intmacro_cmp( const void *p1, const void *p2){	const macros_t	*macro1 = p1,			 		*macro2 = p2;	/* First compare keysyms, then modflags. Ignore the "Primary" modifier */	return	(macro1->keysym == macro2->keysym)					?				(macro1->modFlags & ~MACRO_PRIMARY)						- (macro2->modFlags & ~MACRO_PRIMARY)	:				macro1->keysym - macro2->keysym;}/* {{{1 macro_set_number( flag, num ) *//* INTPROTO */unsigned charmacro_set_number( unsigned char flag, unsigned char num ){	flag &= MACRO_MODMASK;	flag |= (num << MACRO_N_MOD_BITS);	return flag;}/* {{{1 rxvt_parse_macros(str, arg): Parse macro from arguments * * str and arg can be as follows: * * 		1. str = keyname,					arg = argument. * 		2. str = macro.keyname: argument,	arg = NULL * * If a valid macro is found, it is added to our list (r->macros) of macros. * Returns 1 if the macro is added to r->macros, 0 if it is not a macro (i.e. * does not begin with "macro."), and -1 if invalid syntax / error adding / etc. *//* EXTPROTO */#define NEWARGLIM	500	/* `reasonable' size */intrxvt_parse_macros( rxvt_t *r, const char *str, const char *arg, Bool noReplace){	char			newarg[NEWARGLIM],					keyname[ NEWARGLIM],					*keyname_nomods;	unsigned char	modFlags = 0;	KeySym			keysym;	Bool			addmacro = False;	if( arg == NULL )	{		char *keyend;		int		n;		/*		 * Need to split str into keyname and argument.		 */		if( (n = rxvt_str_match(str, "macro.")) == 0 )			return 0;		str += n;		/* skip `macro.' */		if( (keyend = STRCHR( str, ':' )) == NULL )			return -1;		n = min( keyend - str, NEWARGLIM - 1 );		STRNCPY( keyname, str, n );		keyname[n] = 0;		STRNCPY( newarg, keyend + 1, NEWARGLIM - 1 );	}	else	{		/*		 * Keyname is already in str. Copy arg into newarg.		 */		STRNCPY( keyname, str, NEWARGLIM - 1 );		keyname[ NEWARGLIM - 1] = '\0';		STRNCPY( newarg, arg, NEWARGLIM - 1 );	}	/* Null terminate and strip leading / trailing spaces */	newarg[NEWARGLIM - 1] = '\0';	rxvt_str_trim( newarg );	DBG_MSG( 1, ( stderr, "Got macro '%s' -- '%s'\n", keyname, newarg ) );	/*	 * Breakup keyname into a keysym and modifier flags.	 */	if( (keyname_nomods = STRRCHR( keyname, '+' )) == NULL )	{		/* No modifiers specified */#ifdef UNSHIFTED_MACROS		keyname_nomods = keyname;#else		return -1;#endif	}	else	{		*(keyname_nomods++) = 0;		/*		 * keyname is now a null terminated string containing only the		 * modifiers, and keyname_nomods is a null terminated string		 * containing only the key name.		 */		if( STRCASESTR( keyname, "ctrl" ) )			modFlags |= MACRO_CTRL;		if( STRCASESTR( keyname, "meta" ) || STRCASESTR( keyname, "alt"))			modFlags |= MACRO_META;		if( STRCASESTR( keyname, "shift") )			modFlags |= MACRO_SHIFT;		if( STRCASESTR( keyname, "primary"))			modFlags |= MACRO_PRIMARY;		if( STRCASESTR( keyname, "add" ) )			addmacro = True;	}	/*	 * Always store the keysym as lower case. That way we can treat shift	 * correctly even when Caps Lock is pressed.	 */	keysym = tolower( XStringToKeysym( keyname_nomods ) );	if( keysym == None )	{		rxvt_print_error( "Invalid keysym %s. Skipping macro.",				keyname_nomods);		return -1;	}	return rxvt_add_macro( r, keysym, modFlags, newarg, addmacro, noReplace)				? 1 : -1;}/* {{{1 rxvt_add_macro( keysym, modFlags, astring, noreplace) * * Add a macro to our list of macros (r->macros) if astring describes a valid * macro. If keysym == None, then add the macro to the previous one. * * If noReplace is true, don't replace existing macros. Required when reading * the system config file so that we don't replace existing user macros. *//* INTPROTO */intrxvt_add_macro( rxvt_t *r, KeySym keysym, unsigned char modFlags, char *astring,		Bool addmacro, Bool noReplace){	DBG_MSG( 2, ( stderr, "rxvt_add_macro(%08lx, %2hhx, %s)\n",				keysym, modFlags, astring));	const unsigned nmacros_increment = 64;	/* # extra macros to alloc space for											   when we need to enlarge our list											   of macros. A large number here is											   not wasteful as we clean it up											   after initialization */	unsigned short	i,					replaceIndex = r->nmacros,					dummyIndex = r->nmacros;	unsigned char	macroNum = 0;	action_t		action;	/*	 * Check to see if macro already exists.	 */	for( i=0; i < r->nmacros; i++ )	{		if(			r->macros[i].keysym == keysym			&& (r->macros[i].modFlags & MACRO_MODMASK & ~MACRO_PRIMARY)					== (modFlags & MACRO_MODMASK & ~MACRO_PRIMARY)		  )		{			if( addmacro )			{				/*				 * Find the last macro in the macro chain (the macro with the				 * largest number).				 */				unsigned char num;				num		 = MACRO_GET_NUMBER( r->macros[i].modFlags );				if( num > macroNum )					macroNum = num;				if( macroNum == MACRO_MAX_CHAINLEN )				{					rxvt_print_error( "Macro chain too long" );					return 0;				}				replaceIndex = i;			}			/*			 * Macro for key already exists. If noReplace is set, don't			 * touch this macro.			 */			else if( noReplace )				return 1; /* Claim to have succeded so that caller will not							 complain about "Failing to add a ... macro". */						/*			 * 2006-03-06 gi1242: Don't delete "Dummy" macros here. If we do			 * that then the user will have no way to delete macros defined in			 * the system /etc/mrxvt/mrxvtrc file. "Dummy" macros will be			 * deleted after init.			 */			else			{				if( replaceIndex < r->nmacros )				{					/*					 * replaceIndex points to a macro with keysym == the keysym					 * of the macro to be added. Set keysym to 0 so that it will					 * be cleaned up by rxvt_cleanup_macros().					 */					r->macros[replaceIndex].keysym = 0;				}				replaceIndex = i;			}		}		else if( r->macros[i].keysym == 0 )			/*			 * Macros with keysym 0 are dummies, and can be safely replaced.			 */			dummyIndex = i;	} /* for */	if( addmacro )	{		if( replaceIndex == r->nmacros )		{			rxvt_print_error( "No previous macro to add to (key %s%s%s%s)",					(modFlags & MACRO_CTRL) ? "Ctrl+" : "",					(modFlags & MACRO_META) ? "Meta+" : "",					(modFlags & MACRO_SHIFT) ? "Shift+" : "",					XKeysymToString( keysym ) );			return 0;	/* Failure */		}		modFlags = macro_set_number( modFlags, macroNum+1 );		/* Don't replace this macro. */		replaceIndex = dummyIndex;	}	else	{		modFlags = macro_set_number( modFlags, 0 );		/* Set replaceIndex to the index of a macro we can replace */		if( dummyIndex < replaceIndex )			replaceIndex = dummyIndex;	}	/*	 * Add action to the list of macros (making it bigger if necessary).	 */	if( replaceIndex == r->nmacros )	{		if( r->nmacros == r->maxMacros )		{			/* Get space for more macros*/			r->maxMacros += nmacros_increment;			r->macros = (macros_t *) rxvt_realloc( r->macros,										r->maxMacros * sizeof(macros_t));		}		r->nmacros++;	}	else	{		/* Macro action string needs to be freed (as it will be replaced) */		free( r->macros[replaceIndex].action.str );	}	/*	 * Set the action string. This malloc's memory so any returns after this	 * should either save action in to a global variable, or free it.	 */	assert( astring );	action.str = NULL;	/* Make sure rxvt_set_action won't free non-existent						   memory */	if( !rxvt_set_action( &action, astring) )		return 0; /* Failure: Probably unrecognized action type */	/*	 * Save macro values in our global macro list.	 */	r->macros[replaceIndex].keysym		= keysym;	r->macros[replaceIndex].modFlags	= modFlags;	r->macros[replaceIndex].action		= action;	DBG_MSG( 2, ( stderr, "Added macro %hu of %hu. "					"Type %s, len %hu, args '%s'.\n",				replaceIndex, r->maxMacros,				macroNames[ action.type ], action.len,				(action.type == MacroFnStr || action.type == MacroFnEsc) ?					"(escaped string)" :					((action.str == NULL) ? "(nil)" : (char*) action.str)));	return 1;	/* Success */}/* {{{1 rxvt_cleanup_macros() * * Delete all "Dummy" macros from our list of macros, and free space alloced for * extra macros */voidrxvt_cleanup_macros( rxvt_t *r ){	unsigned i, nDummyMacros = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -