2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* macros.c --
|
|
|
|
|
*
|
|
|
|
|
* Defines and retrieves macros
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
|
|
|
|
* * Permission to use, copy, modify, and distribute this *
|
|
|
|
|
* * software and its documentation for any purpose and without *
|
|
|
|
|
* * fee is hereby granted, provided that the above copyright *
|
|
|
|
|
* * notice appear in all copies. The University of California *
|
|
|
|
|
* * makes no representations about the suitability of this *
|
|
|
|
|
* * software for any purpose. It is provided "as is" without *
|
|
|
|
|
* * express or implied warranty. Export of this software outside *
|
|
|
|
|
* * of the United States of America may require an export license. *
|
2017-04-25 14:41:48 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/utils/macros.c,v 1.2 2010/06/24 12:37:58 tim Exp $";
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
2024-10-04 19:59:39 +02:00
|
|
|
#include <strings.h>
|
2017-04-25 14:41:48 +02:00
|
|
|
#include <signal.h>
|
2022-01-07 20:56:43 +01:00
|
|
|
#include <ctype.h>
|
2017-04-25 14:41:48 +02:00
|
|
|
#ifdef XLIB
|
|
|
|
|
#include <X11/X.h>
|
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
|
#include <X11/keysym.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include "utils/magic.h"
|
|
|
|
|
#include "utils/main.h"
|
|
|
|
|
#include "utils/utils.h"
|
|
|
|
|
#include "utils/hash.h"
|
|
|
|
|
#include "utils/malloc.h"
|
|
|
|
|
#include "utils/macros.h"
|
|
|
|
|
#include "windows/windows.h"
|
2025-10-09 21:43:54 +02:00
|
|
|
#include "dbwind/dbwind.h"
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2022-10-10 11:50:15 +02:00
|
|
|
/* C99 compat */
|
|
|
|
|
#include "textio/textio.h"
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Define the macro client table */
|
|
|
|
|
|
|
|
|
|
HashTable MacroClients;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------
|
|
|
|
|
* MacroInit ---
|
|
|
|
|
*
|
|
|
|
|
* Initialize the macro hash table
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side Effects:
|
|
|
|
|
* Memory allocated for the hash table MacroClients.
|
|
|
|
|
*
|
2025-10-09 21:43:54 +02:00
|
|
|
* Note:
|
|
|
|
|
* Hash type changed from WORDKEYS to STRINGKEYS.
|
|
|
|
|
* This is slightly less efficient but allows the
|
|
|
|
|
* layout window client to be divided into separate
|
|
|
|
|
* macro clients for each tool type, accessed by
|
|
|
|
|
* name.
|
|
|
|
|
*
|
2017-04-25 14:41:48 +02:00
|
|
|
*---------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
MacroInit()
|
|
|
|
|
{
|
2025-10-09 21:43:54 +02:00
|
|
|
HashInit(&MacroClients, 4, HT_STRINGKEYS);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------
|
2025-10-09 21:43:54 +02:00
|
|
|
* MacroDefineByName ---
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
2025-10-09 21:43:54 +02:00
|
|
|
* This procedure defines a macro. The macro table is
|
|
|
|
|
* defined by name, not by client. MacroDefine() is a
|
|
|
|
|
* wrapper for this routine.
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side Effects:
|
|
|
|
|
* The string passed is copied and considered to be the
|
|
|
|
|
* macro definition for the character.
|
|
|
|
|
*---------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
2025-10-09 21:43:54 +02:00
|
|
|
MacroDefineByName(clientName, xc, str, help, imacro)
|
|
|
|
|
char *clientName; /* window client name */
|
2017-04-25 14:41:48 +02:00
|
|
|
int xc; /* full (X11) keycode of macro with modifiers */
|
|
|
|
|
char *str; /* ...and the string to be attached to it */
|
|
|
|
|
char *help; /* ...and/or the help text for the macro */
|
|
|
|
|
bool imacro; /* is this an interactive macro? */
|
|
|
|
|
{
|
|
|
|
|
HashEntry *h;
|
|
|
|
|
HashTable *clienttable, newTable;
|
|
|
|
|
macrodef *oldMacro, *newMacro;
|
|
|
|
|
|
|
|
|
|
/* If a macro exists, delete the old string and redefine it */
|
2025-10-09 21:43:54 +02:00
|
|
|
h = HashFind(&MacroClients, (char *)clientName);
|
2017-04-25 14:41:48 +02:00
|
|
|
clienttable = (HashTable *)HashGetValue(h);
|
|
|
|
|
if (clienttable == NULL)
|
|
|
|
|
{
|
|
|
|
|
clienttable = (HashTable *)mallocMagic(sizeof(HashTable));
|
|
|
|
|
HashInit(clienttable, 32, HT_WORDKEYS);
|
|
|
|
|
HashSetValue(h, clienttable);
|
|
|
|
|
}
|
2024-10-21 10:13:23 +02:00
|
|
|
h = HashFind(clienttable, (char *)INT2CD(xc));
|
2017-04-25 14:41:48 +02:00
|
|
|
oldMacro = (macrodef *)HashGetValue(h);
|
|
|
|
|
if (oldMacro != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (oldMacro->macrotext != NULL)
|
|
|
|
|
freeMagic(oldMacro->macrotext);
|
|
|
|
|
if (oldMacro->helptext != NULL) {
|
|
|
|
|
freeMagic(oldMacro->helptext);
|
|
|
|
|
oldMacro->helptext = NULL;
|
|
|
|
|
}
|
|
|
|
|
newMacro = oldMacro;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
newMacro = (macrodef *)mallocMagic(sizeof(macrodef));
|
|
|
|
|
|
|
|
|
|
HashSetValue(h, newMacro);
|
|
|
|
|
newMacro->interactive = imacro;
|
|
|
|
|
newMacro->macrotext = StrDup((char **)NULL, str);
|
|
|
|
|
if (help != NULL)
|
|
|
|
|
newMacro->helptext = StrDup((char **)NULL, help);
|
|
|
|
|
else
|
|
|
|
|
newMacro->helptext = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-09 21:43:54 +02:00
|
|
|
/*
|
|
|
|
|
*------------------------------------------------------------------
|
|
|
|
|
* MacroDefine ---
|
|
|
|
|
*
|
|
|
|
|
* This procedure is a simple wrapper for MacroDefineByName().
|
|
|
|
|
* The window client is given as a client ID. This limits
|
|
|
|
|
* macros to one set per client type. To allow a more
|
|
|
|
|
* flexible macro handling, if the client is a layout window
|
|
|
|
|
* (DBWclientID), then the name is instead taken from the
|
|
|
|
|
* name of the tool currently active. This allows macros
|
|
|
|
|
* to be uniquely defined for each tool.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side Effects:
|
|
|
|
|
* The string passed is copied and considered to be the
|
|
|
|
|
* macro definition for the character.
|
|
|
|
|
*------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
MacroDefine(client, xc, str, help, imacro)
|
|
|
|
|
WindClient client; /* window client type */
|
|
|
|
|
int xc; /* full (X11) keycode of macro with modifiers */
|
|
|
|
|
char *str; /* ...and the string to be attached to it */
|
|
|
|
|
char *help; /* ...and/or the help text for the macro */
|
|
|
|
|
bool imacro; /* is this an interactive macro? */
|
|
|
|
|
{
|
|
|
|
|
char *clientName = NULL;
|
|
|
|
|
|
|
|
|
|
if (client == DBWclientID)
|
|
|
|
|
clientName = DBWGetButtonHandler();
|
|
|
|
|
if (clientName == NULL)
|
|
|
|
|
clientName = WindGetClientName(client);
|
|
|
|
|
|
|
|
|
|
MacroDefineByName(clientName, xc, str, help, imacro);
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*---------------------------------------------------------
|
|
|
|
|
* MacroDefineHelp ---
|
|
|
|
|
*
|
|
|
|
|
* This procedure defines the help text for a macro.
|
|
|
|
|
* A macro must already exist for the specified key.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side Effects:
|
|
|
|
|
* The string passed is copied and considered to be the
|
|
|
|
|
* macro definition for the character.
|
|
|
|
|
*---------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
MacroDefineHelp(client, xc, help)
|
|
|
|
|
WindClient client; /* window client type */
|
|
|
|
|
int xc; /* full (X11) keycode of macro with modifiers */
|
|
|
|
|
char *help; /* ...and/or the help text for the macro */
|
|
|
|
|
{
|
|
|
|
|
HashEntry *h;
|
|
|
|
|
HashTable *clienttable;
|
|
|
|
|
macrodef *curMacro;
|
2025-10-09 21:43:54 +02:00
|
|
|
char *clientName = NULL;
|
|
|
|
|
|
|
|
|
|
if (client == DBWclientID)
|
|
|
|
|
clientName = DBWGetButtonHandler();
|
|
|
|
|
if (clientName == NULL)
|
|
|
|
|
clientName = WindGetClientName(client);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* If a macro exists, delete the old string and redefine it */
|
2025-10-09 21:43:54 +02:00
|
|
|
h = HashFind(&MacroClients, (char *)clientName);
|
2017-04-25 14:41:48 +02:00
|
|
|
clienttable = (HashTable *)HashGetValue(h);
|
|
|
|
|
if (clienttable == NULL) return;
|
|
|
|
|
|
2024-10-21 10:13:23 +02:00
|
|
|
h = HashFind(clienttable, (char *)INT2CD(xc));
|
2017-04-25 14:41:48 +02:00
|
|
|
curMacro = (macrodef *)HashGetValue(h);
|
|
|
|
|
if (curMacro == NULL) return;
|
|
|
|
|
|
|
|
|
|
if (curMacro->helptext != NULL)
|
|
|
|
|
freeMagic(curMacro->helptext);
|
|
|
|
|
|
|
|
|
|
if (help == NULL)
|
|
|
|
|
curMacro->helptext = NULL;
|
|
|
|
|
else
|
|
|
|
|
curMacro->helptext = StrDup((char **)NULL, help);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*---------------------------------------------------------
|
|
|
|
|
* MacroRetrieve:
|
|
|
|
|
* This procedure retrieves a macro.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* A pointer to a new Malloc'ed string is returned.
|
|
|
|
|
* This structure should be freed when the caller is
|
|
|
|
|
* done with it.
|
|
|
|
|
*
|
|
|
|
|
* Side Effects:
|
|
|
|
|
* None.
|
|
|
|
|
*---------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
MacroRetrieve(client, xc, iReturn)
|
|
|
|
|
WindClient client; /* window client type */
|
|
|
|
|
int xc; /* the extended name of the macro */
|
|
|
|
|
bool *iReturn; /* TRUE if macro is interactive */
|
|
|
|
|
{
|
|
|
|
|
HashEntry *h;
|
|
|
|
|
HashTable *clienttable;
|
|
|
|
|
macrodef *cMacro;
|
2025-10-09 21:43:54 +02:00
|
|
|
char *clientName = NULL;
|
|
|
|
|
|
|
|
|
|
if (client == DBWclientID)
|
|
|
|
|
clientName = DBWGetButtonHandler();
|
|
|
|
|
if (clientName == NULL)
|
|
|
|
|
clientName = WindGetClientName(client);
|
|
|
|
|
if (clientName == NULL)
|
|
|
|
|
return NULL;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* If a macro exists, delete the old string and redefine it */
|
2025-10-09 21:43:54 +02:00
|
|
|
h = HashLookOnly(&MacroClients, (char *)clientName);
|
2017-04-25 14:41:48 +02:00
|
|
|
if (h != NULL)
|
|
|
|
|
{
|
|
|
|
|
clienttable = (HashTable *)HashGetValue(h);
|
|
|
|
|
if (clienttable != NULL)
|
|
|
|
|
{
|
2024-10-21 10:13:23 +02:00
|
|
|
h = HashLookOnly(clienttable, (char *)INT2CD(xc));
|
2017-04-25 14:41:48 +02:00
|
|
|
if (h != NULL)
|
|
|
|
|
{
|
|
|
|
|
cMacro = (macrodef *)HashGetValue(h);
|
|
|
|
|
if (cMacro != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (iReturn != NULL)
|
|
|
|
|
*iReturn = cMacro->interactive;
|
|
|
|
|
return StrDup((char **)NULL, cMacro->macrotext);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (iReturn != NULL) *iReturn = FALSE;
|
|
|
|
|
return (char *)NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*---------------------------------------------------------
|
|
|
|
|
* MacroRetrieveHelp:
|
|
|
|
|
* This procedure retrieves the help text for a macro.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* A pointer to a new Malloc'ed string is returned.
|
|
|
|
|
* This structure should be freed when the caller is
|
|
|
|
|
* done with it.
|
|
|
|
|
*
|
|
|
|
|
* Side Effects:
|
|
|
|
|
* None.
|
|
|
|
|
*---------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
MacroRetrieveHelp(client, xc)
|
|
|
|
|
WindClient client; /* window client type */
|
|
|
|
|
int xc; /* the extended name of the macro */
|
|
|
|
|
{
|
|
|
|
|
HashEntry *h;
|
|
|
|
|
HashTable *clienttable;
|
|
|
|
|
macrodef *cMacro;
|
2025-10-09 21:43:54 +02:00
|
|
|
char *clientName = NULL;
|
|
|
|
|
|
|
|
|
|
if (client == DBWclientID)
|
|
|
|
|
clientName = DBWGetButtonHandler();
|
|
|
|
|
if (clientName == NULL)
|
|
|
|
|
clientName = WindGetClientName(client);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* If a macro exists, delete the old string and redefine it */
|
2025-10-09 21:43:54 +02:00
|
|
|
h = HashLookOnly(&MacroClients, (char *)clientName);
|
2017-04-25 14:41:48 +02:00
|
|
|
if (h != NULL)
|
|
|
|
|
{
|
|
|
|
|
clienttable = (HashTable *)HashGetValue(h);
|
|
|
|
|
if (clienttable != NULL)
|
|
|
|
|
{
|
2024-10-21 10:13:23 +02:00
|
|
|
h = HashLookOnly(clienttable, (char *)INT2CD(xc));
|
2017-04-25 14:41:48 +02:00
|
|
|
if (h != NULL)
|
|
|
|
|
{
|
|
|
|
|
cMacro = (macrodef *)HashGetValue(h);
|
|
|
|
|
if (cMacro != NULL)
|
|
|
|
|
if (cMacro->helptext != NULL)
|
|
|
|
|
return StrDup((char **)NULL, cMacro->helptext);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return (char *)NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*---------------------------------------------------------
|
|
|
|
|
* MacroSubsitute:
|
|
|
|
|
* Make a substitution of one string for another
|
|
|
|
|
* in a macro string. This is really just a string
|
|
|
|
|
* manipulation; it doesn't have anything specifically
|
|
|
|
|
* to do with macros.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* A new string pointer to the macro contents.
|
|
|
|
|
*
|
|
|
|
|
* Side Effects:
|
|
|
|
|
* None.
|
|
|
|
|
*---------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
MacroSubstitute(macrostr, searchstr, replacestr)
|
|
|
|
|
char *macrostr;
|
|
|
|
|
char *searchstr;
|
|
|
|
|
char *replacestr;
|
|
|
|
|
{
|
|
|
|
|
char *found, *last, *new;
|
|
|
|
|
int expand, length, oldlength, srchsize;
|
|
|
|
|
|
|
|
|
|
if (macrostr == (char *)NULL) return NULL;
|
|
|
|
|
|
|
|
|
|
oldlength = strlen(macrostr);
|
|
|
|
|
srchsize = strlen(searchstr);
|
|
|
|
|
expand = strlen(replacestr) - srchsize;
|
|
|
|
|
last = macrostr;
|
|
|
|
|
length = oldlength;
|
|
|
|
|
while ((found = strstr(last, searchstr)) != NULL)
|
|
|
|
|
{
|
|
|
|
|
length += expand;
|
|
|
|
|
last = found + srchsize;
|
|
|
|
|
}
|
|
|
|
|
if (length > oldlength)
|
|
|
|
|
{
|
|
|
|
|
new = (char *)mallocMagic(length + 1);
|
|
|
|
|
*new = '\0';
|
|
|
|
|
last = macrostr;
|
|
|
|
|
while ((found = strstr(last, searchstr)) != NULL)
|
|
|
|
|
{
|
|
|
|
|
*found = '\0';
|
|
|
|
|
strcat(new, last);
|
|
|
|
|
strcat(new, replacestr);
|
|
|
|
|
last = found + srchsize;
|
|
|
|
|
}
|
|
|
|
|
strcat(new, last);
|
|
|
|
|
freeMagic(macrostr);
|
|
|
|
|
return new;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return macrostr;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*---------------------------------------------------------
|
|
|
|
|
* MacroDelete:
|
|
|
|
|
* This procedure deletes a macro.
|
|
|
|
|
*
|
|
|
|
|
* Results: None.
|
|
|
|
|
*
|
|
|
|
|
* Side Effects:
|
|
|
|
|
* The string that defines a macro is deleted. This means
|
|
|
|
|
* that if anybody still has a pointer to that string
|
|
|
|
|
* they are in trouble.
|
|
|
|
|
*---------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
MacroDelete(client, xc)
|
|
|
|
|
WindClient client; /* window client type */
|
|
|
|
|
int xc; /* the extended name of the macro */
|
|
|
|
|
{
|
|
|
|
|
HashEntry *h;
|
|
|
|
|
HashTable *clienttable;
|
|
|
|
|
macrodef *cMacro;
|
2025-10-09 21:43:54 +02:00
|
|
|
char *clientName = NULL;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2025-10-09 21:43:54 +02:00
|
|
|
if (client == DBWclientID)
|
|
|
|
|
clientName = DBWGetButtonHandler();
|
|
|
|
|
if (clientName == NULL)
|
|
|
|
|
clientName = WindGetClientName(client);
|
|
|
|
|
|
|
|
|
|
h = HashLookOnly(&MacroClients, (char *)clientName);
|
2017-04-25 14:41:48 +02:00
|
|
|
if (h != NULL)
|
|
|
|
|
{
|
|
|
|
|
clienttable = (HashTable *)HashGetValue(h);
|
|
|
|
|
if (clienttable != NULL)
|
|
|
|
|
{
|
2024-10-21 10:13:23 +02:00
|
|
|
h = HashLookOnly(clienttable, (char *)INT2CD(xc));
|
2017-04-25 14:41:48 +02:00
|
|
|
if (h != NULL)
|
|
|
|
|
{
|
|
|
|
|
cMacro = (macrodef *)HashGetValue(h);
|
|
|
|
|
if (cMacro != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (cMacro->macrotext != NULL)
|
|
|
|
|
freeMagic(cMacro->macrotext);
|
|
|
|
|
if (cMacro->helptext != NULL)
|
|
|
|
|
freeMagic(cMacro->helptext);
|
|
|
|
|
HashSetValue(h, NULL);
|
|
|
|
|
freeMagic(cMacro);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-09 21:43:54 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* MacroCopy --
|
|
|
|
|
* Copy all macros from one table to another.
|
|
|
|
|
* This is used with the "tool" command to simplify the process
|
|
|
|
|
* of defining new macro sets for button and keypress actions
|
|
|
|
|
* for a new tool type. It copies all of the macros from the
|
|
|
|
|
* table for the client passed as (WindClient type) "client" to
|
|
|
|
|
* the table for the client named by (string) "clientkey".
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* New hash entries are created.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
MacroCopy(client, clientkey)
|
|
|
|
|
WindClient client; /* Current window client */
|
|
|
|
|
char *clientkey; /* Name of client to copy macros to */
|
|
|
|
|
{
|
|
|
|
|
HashTable *clienttable;
|
|
|
|
|
HashTable *copytable;
|
|
|
|
|
HashEntry *h, *he;
|
|
|
|
|
HashSearch hs;
|
|
|
|
|
char *clientName;
|
|
|
|
|
int cKey;
|
|
|
|
|
macrodef *cMacro;
|
|
|
|
|
|
|
|
|
|
if (clientkey == NULL) return;
|
|
|
|
|
if (client == (WindClient)NULL) return;
|
|
|
|
|
|
|
|
|
|
if (client == DBWclientID)
|
|
|
|
|
clientName = DBWGetButtonHandler();
|
|
|
|
|
if (clientName == NULL)
|
|
|
|
|
clientName = WindGetClientName(client);
|
|
|
|
|
|
|
|
|
|
h = HashLookOnly(&MacroClients, (char *)clientName);
|
|
|
|
|
if (h == NULL) return; /* No clients, nothing can be done */
|
|
|
|
|
|
|
|
|
|
clienttable = (HashTable *)HashGetValue(h);
|
|
|
|
|
if (clienttable == NULL) return; /* Also nothing can be done */
|
|
|
|
|
|
|
|
|
|
HashStartSearch(&hs);
|
|
|
|
|
while (TRUE)
|
|
|
|
|
{
|
|
|
|
|
he = HashNext(clienttable, &hs);
|
|
|
|
|
if (he == NULL) break;
|
|
|
|
|
cMacro = (macrodef *)HashGetValue(he);
|
|
|
|
|
cKey = (int)CD2INT(he->h_key.h_ptr);
|
|
|
|
|
MacroDefineByName(clientkey, cKey, cMacro->macrotext,
|
|
|
|
|
cMacro->helptext, cMacro->interactive);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* MacroName --
|
|
|
|
|
* Convert an extended keycode to a string.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* The string.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* The string is malloc'ed from memory, and must be free'd later.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
MacroName(xc)
|
|
|
|
|
int xc;
|
|
|
|
|
{
|
|
|
|
|
char *vis;
|
|
|
|
|
static char hex[17] = "0123456789ABCDEF";
|
|
|
|
|
|
|
|
|
|
#ifdef XLIB
|
|
|
|
|
char *str;
|
|
|
|
|
extern Display *grXdpy;
|
|
|
|
|
KeySym ks = xc & 0xffff;
|
|
|
|
|
int kmod = xc >> 16;
|
|
|
|
|
|
|
|
|
|
str = NULL;
|
|
|
|
|
if (grXdpy != NULL) {
|
|
|
|
|
ks = xc & 0xffff;
|
|
|
|
|
if (ks != NoSymbol) str = XKeysymToString(ks);
|
|
|
|
|
}
|
|
|
|
|
if (str != NULL)
|
|
|
|
|
{
|
|
|
|
|
vis = (char *) mallocMagic( sizeof(char) * (strlen(str) + 32) );
|
|
|
|
|
vis[0] = '\0';
|
|
|
|
|
if (kmod & Mod1Mask) strcat(vis, "Meta_");
|
|
|
|
|
if (kmod & ControlMask) strcat(vis, "Control_");
|
|
|
|
|
if (kmod & LockMask) strcat(vis, "Capslock_");
|
|
|
|
|
if (kmod & ShiftMask) strcat(vis, "Shift_");
|
|
|
|
|
strcat(vis, "XK_");
|
|
|
|
|
strcat(vis, str);
|
|
|
|
|
return (vis);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
vis = (char *) mallocMagic( sizeof(char) * 6 );
|
|
|
|
|
if (xc < (int)' ')
|
|
|
|
|
{
|
|
|
|
|
vis[0] = '^';
|
|
|
|
|
vis[1] = (char)xc + '@';
|
|
|
|
|
vis[2] = '\0';
|
|
|
|
|
}
|
|
|
|
|
else if (xc == 0x7F)
|
|
|
|
|
{
|
|
|
|
|
vis[0] = '<';
|
|
|
|
|
vis[1] = 'd';
|
|
|
|
|
vis[2] = 'e';
|
|
|
|
|
vis[3] = 'l';
|
|
|
|
|
vis[4] = '>';
|
|
|
|
|
vis[5] = '\0';
|
|
|
|
|
}
|
|
|
|
|
else if (xc < 0x80)
|
|
|
|
|
{
|
|
|
|
|
vis[0] = (char)xc;
|
|
|
|
|
vis[1] = '\0';
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
vis = (char *) mallocMagic( sizeof(char) * 8 );
|
|
|
|
|
vis[0] = '0';
|
|
|
|
|
vis[1] = 'x';
|
|
|
|
|
#ifdef XLIB
|
|
|
|
|
vis[2] = hex[ (kmod & 0xf)];
|
|
|
|
|
#else
|
|
|
|
|
vis[2] = '0';
|
|
|
|
|
#endif
|
|
|
|
|
vis[3] = hex[ (xc & 0x0f000) >> 12];
|
|
|
|
|
vis[4] = hex[ (xc & 0x00f00) >> 8];
|
|
|
|
|
vis[5] = hex[ (xc & 0x000f0) >> 4];
|
|
|
|
|
vis[6] = hex[ (xc & 0x0000f) ];
|
|
|
|
|
vis[7] = '\0';
|
|
|
|
|
}
|
|
|
|
|
return(vis);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* MacroKey:
|
|
|
|
|
* Convert a string to an extended keycode.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* An extended macro name.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* If the display being used is not X11, a warning is printed the
|
|
|
|
|
* first time this function is called.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
MacroKey(str, verbose)
|
|
|
|
|
char *str;
|
|
|
|
|
int *verbose;
|
|
|
|
|
{
|
|
|
|
|
static int warn = 1;
|
|
|
|
|
|
|
|
|
|
#ifdef XLIB
|
|
|
|
|
int kc;
|
|
|
|
|
char *vis;
|
|
|
|
|
extern Display *grXdpy;
|
|
|
|
|
KeySym ks;
|
|
|
|
|
int kmod = 0;
|
|
|
|
|
|
|
|
|
|
*verbose = 1;
|
|
|
|
|
if (grXdpy != NULL)
|
|
|
|
|
{
|
|
|
|
|
vis = str;
|
|
|
|
|
while( (*vis) != '\0' )
|
|
|
|
|
{
|
|
|
|
|
if (!strncmp(vis, "Meta_", 5))
|
|
|
|
|
{
|
|
|
|
|
kmod |= Mod1Mask;
|
|
|
|
|
vis += 5;
|
|
|
|
|
}
|
|
|
|
|
else if (!strncmp(vis, "Alt_", 4))
|
|
|
|
|
{
|
|
|
|
|
kmod |= Mod1Mask;
|
|
|
|
|
vis += 4;
|
|
|
|
|
}
|
|
|
|
|
else if (!strncmp(vis, "Control_", 8))
|
|
|
|
|
{
|
|
|
|
|
kmod |= ControlMask;
|
|
|
|
|
vis += 8;
|
|
|
|
|
}
|
|
|
|
|
else if (((*vis) == '^') && (*(vis + 1) != '\0'))
|
|
|
|
|
{
|
|
|
|
|
kmod |= ControlMask;
|
|
|
|
|
vis++;
|
|
|
|
|
}
|
|
|
|
|
else if (!strncmp(vis, "Capslock_", 9))
|
|
|
|
|
{
|
|
|
|
|
kmod |= LockMask;
|
|
|
|
|
vis += 9;
|
|
|
|
|
}
|
|
|
|
|
else if (!strncmp(vis, "Shift_", 6))
|
|
|
|
|
{
|
|
|
|
|
kmod |= ShiftMask;
|
|
|
|
|
vis += 6;
|
|
|
|
|
}
|
|
|
|
|
else if (*vis == '\'')
|
|
|
|
|
{
|
|
|
|
|
// If single quotes are used to protect the integrity
|
|
|
|
|
// of the macro character, strip them now.
|
|
|
|
|
|
|
|
|
|
char *aptr = strrchr(vis, '\'');
|
|
|
|
|
if (aptr != NULL && aptr != vis)
|
|
|
|
|
{
|
|
|
|
|
vis++;
|
|
|
|
|
*aptr = '\0';
|
|
|
|
|
}
|
|
|
|
|
else break; // Don't hang on an unmatched quote
|
|
|
|
|
}
|
|
|
|
|
else break;
|
|
|
|
|
}
|
|
|
|
|
if (!strncmp(vis, "XK_", 3)) vis += 3;
|
|
|
|
|
|
|
|
|
|
/* We're converting all ASCII back into X Keycodes */
|
|
|
|
|
/* The original macro (.magicrc) file format allows */
|
|
|
|
|
/* embedded control characters, so we have to handle */
|
|
|
|
|
/* those. For regular ASCII characters, the keysym = */
|
|
|
|
|
/* the ASCII value. */
|
|
|
|
|
|
|
|
|
|
if ((*(vis + 1)) == '\0')
|
|
|
|
|
{
|
|
|
|
|
/* single ASCII character handling */
|
|
|
|
|
|
|
|
|
|
char tc = *vis;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Revert Control and Shift characters to ASCII */
|
|
|
|
|
/* unless other modifiers are present. Always make */
|
|
|
|
|
/* characters with Control and Shift uppercase. */
|
|
|
|
|
|
|
|
|
|
if (kmod & (ControlMask | ShiftMask))
|
|
|
|
|
{
|
|
|
|
|
tc = toupper(tc);
|
|
|
|
|
if (kmod & ShiftMask)
|
|
|
|
|
kc = (int)tc;
|
|
|
|
|
else if (kmod & ControlMask)
|
|
|
|
|
kc = (int)(tc - 'A' + 1);
|
2024-10-04 20:48:41 +02:00
|
|
|
else
|
|
|
|
|
kc = (int)tc;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
if (!(kmod & (Mod1Mask | LockMask)))
|
|
|
|
|
if (!(kmod & ShiftMask) || !(kmod & ControlMask))
|
|
|
|
|
kmod = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
kc = (int)tc;
|
|
|
|
|
}
|
|
|
|
|
else if (!strncmp(vis, "<del>", 5))
|
|
|
|
|
/* Because, weirdly, there is no keysymdef for the "Delete" key */
|
|
|
|
|
kc = (int)0x7f;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* X11 keysym name handling */
|
|
|
|
|
|
|
|
|
|
/* If macro "Button" is used, then prepend */
|
|
|
|
|
/* "Pointer" to match the keysymdef. */
|
|
|
|
|
/* (Added by NP 10/20/04) */
|
|
|
|
|
|
|
|
|
|
char *pointerStr = NULL;
|
|
|
|
|
if (!strncmp(vis, "Button", 6))
|
|
|
|
|
{
|
|
|
|
|
pointerStr = (char *)mallocMagic(9 + strlen(str));
|
|
|
|
|
strcpy(pointerStr, "Pointer_");
|
|
|
|
|
strcat(pointerStr, vis);
|
|
|
|
|
vis = pointerStr;
|
|
|
|
|
}
|
|
|
|
|
ks = XStringToKeysym(vis);
|
|
|
|
|
kc = (ks != NoSymbol) ? ks & 0xffff : 0;
|
|
|
|
|
if (pointerStr != NULL) freeMagic(pointerStr);
|
|
|
|
|
}
|
|
|
|
|
return (kc | (kmod << 16));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
*verbose = 1;
|
|
|
|
|
if (strlen(str) == 1)
|
|
|
|
|
{
|
|
|
|
|
return (int)str[0];
|
|
|
|
|
}
|
|
|
|
|
else if (strlen(str) == 2 && *str == '^')
|
|
|
|
|
{
|
|
|
|
|
return (int)str[1] - 'A' + 1;
|
|
|
|
|
}
|
|
|
|
|
if (warn)
|
|
|
|
|
{
|
|
|
|
|
if (strcasecmp(MainDisplayType, "NULL") || (TxTkConsole == TRUE))
|
|
|
|
|
TxPrintf("Extended macros are unavailable"
|
|
|
|
|
" with graphics type \"%s\".\n", MainDisplayType);
|
|
|
|
|
}
|
|
|
|
|
warn = 0;
|
|
|
|
|
*verbose = 0;
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* CommandLineTranslate
|
|
|
|
|
* Convert X11 definitions to readline controls
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* A converted character (integer)
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
TranslateChar(key)
|
|
|
|
|
int key;
|
|
|
|
|
{
|
|
|
|
|
int rval = key;
|
|
|
|
|
|
|
|
|
|
#ifdef XLIB
|
|
|
|
|
switch (key)
|
|
|
|
|
{
|
|
|
|
|
case XK_Left:
|
|
|
|
|
rval = (int)'\002'; /* Ctrl-B */
|
|
|
|
|
break;
|
|
|
|
|
case XK_Right:
|
|
|
|
|
rval = (int)'\006'; /* Ctrl-F */
|
|
|
|
|
break;
|
|
|
|
|
case XK_Up:
|
|
|
|
|
rval = (int)'\020'; /* Ctrl-P */
|
|
|
|
|
break;
|
|
|
|
|
case XK_Down:
|
|
|
|
|
rval = (int)'\016'; /* Ctrl-N */
|
|
|
|
|
break;
|
|
|
|
|
case XK_BackSpace:
|
|
|
|
|
case XK_Delete:
|
|
|
|
|
rval = (int)'\010'; /* Ctrl-H */
|
|
|
|
|
break;
|
|
|
|
|
case XK_Home:
|
|
|
|
|
rval = (int)'\001'; /* Ctrl-A */
|
|
|
|
|
break;
|
|
|
|
|
case XK_End:
|
|
|
|
|
rval = (int)'\005'; /* Ctrl-E */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return rval;
|
|
|
|
|
}
|