Aros/Developer/Docs/Libraries/Commodities

Navbar for the Aros wikibook
Aros User Docs
Aros User Docs
Aros User FAQs
Aros User Applications
Aros User DOS Shell
Aros/User/AmigaLegacy
Aros Dev Docs
Aros Developer Docs
Porting Software from AmigaOS/SDL
For Zune Beginners
Zune .MUI Classes
For SDL Beginners
Aros Developer BuildSystem
Specific platforms
68k Support
PPC Power Architecture Support
Arm Raspberry Pi Support
Android support
Linux and FreeBSD Support
Windows Mingw and MacOSX Support
Aros x86 Installing
Aros x86 Audio/Video Support
Aros x86 Network Support
Aros x86 Complete System HCL
Aros Storage Support IDE SATA etc
Aros Poseidon USB Support
x86-64 Support
misc
Aros Public License


IntroductionEdit

With AmigaOS (TM) 2.0, Commodities were introduced to extend the feature of the Amiga Workbench (Desktop).


The commodities library sets up an handler before intuition's one. When the commodities handler receives a CxMessage


CxObjects operates on a CxMessage so that it can filter certain CxMessages, translate CxMessages, signal a task when a CxObject receives a CxMessage, send a message when a CxObject receives a CxMessage, or call a custom function when a CxObject receives a CxMessage.


The controller program is called the Exchange which is great for programs like hot keys, pop ups, screen blankers, and mouse blankers that need to monitor all user input.


Commodities Exchange should never be used as an alternate method of receiving user input for an application.

Take a look here


Every Zune application is per default also a Commodity. MUI also does this for you. Look at MUIA_Application_UseCommodities enabled part (lines 625-660) in muimaster/classes/application.c: it really only seems to set (or avoid if FALSE) the initialization by Zune of your tool as a commodity and the keyboard shortcuts work.



FiltersEdit

In creating filters, you should create a broker, attach a filter to it, then a sender. The filter takes in only the events that interest you, and the sender notifies the broker.


cx_lib/CxCustom() cx_lib/CxFilter() cx_lib/CxTranslate()Edit

FKey commodity does use a filter

tooltype «RAWMOUSE LBUTTON RBUTTON MOUSE_RIGHTPRESS» RUN App QUIET DONOTBUT CURRENT TOBACK

"RAWMOUSE MBUTTON MOUSE_MIDDLEPRESS"



cx_lib/CxSender() cx_lib/CxSignal() cx_lib/CxDebug()Edit

ExamplesEdit

/*
    Copyright © 2012, The AROS Development Team. All rights reserved.
    $Id$
 
    ASCIITable -- Insert characters to clipboard from GUI.
 */
 
/******************************************************************************
 
    NAME
 
        ASCIITable
 
    SYNOPSIS
 
        CX_PRIORITY/N/K,CX_POPKEY/K,CX_POPUP/S
 
    LOCATION
 
        SYS:Tools/Commodities
 
    FUNCTION
 
        Insert characters to clipboard from GUI
 
    INPUTS
 
        CX_PRIORITY  --  Priority of the ASCIITable broker
        CX_POPKEY    --  Hotkey combination for ASCIITable
        CX_POPUP     --  Appear at startup
 
    RESULT
 
    NOTES
 
    EXAMPLE
 
    BUGS
 
    SEE ALSO
 
    INTERNALS
 
******************************************************************************/
 
#define MUIMASTER_YES_INLINE_STDARG
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
//#define DEBUG 1
#include <aros/debug.h>
#include <aros/asmcall.h>
#include <aros/symbolsets.h>
#include <libraries/iffparse.h>
#include <libraries/mui.h>
#include <zune/customclasses.h>
#include <devices/clipboard.h>
#include <workbench/startup.h>
 
#include <proto/muimaster.h>
#include <proto/locale.h>
#include <proto/intuition.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/alib.h>
#include <proto/commodities.h>
#include <proto/utility.h>
#include <proto/icon.h>
 
#define CATCOMP_ARRAY
#include "strings.h"
 
#define CATALOG_NAME     "System/Tools/Commodities.catalog"
#define CATALOG_VERSION  3
 
TEXT version[] = "$VER: ASCIITable 1.2 (14.01.2012)";
 
#define ARG_TEMPLATE "CX_PRIORITY/N/K,CX_POPKEY/K,CX_POPUP/S"
#define DEF_POPKEY "ctrl alt a"
 
enum {
    ARG_CXPRI,
    ARG_CXPOPKEY,
    ARG_CXPOPUP,
    NUM_ARGS
};
 
static Object *app, *wnd;
static struct Catalog *catalog;
static UBYTE s[257];
 
static struct Hook broker_hook;
static struct Hook show_hook;
 
static LONG cx_pri;
static char *cx_popkey;
static BOOL cx_popup = FALSE;
static CxObj *broker;
static struct MsgPort *brokermp;
static struct Task *maintask;
 
static void Cleanup(CONST_STRPTR txt);
static void GetArguments(int argc, char **argv);
static void HandleAll(void);
static void InitMenus(void);
static VOID Locale_Deinitialize(VOID);
static int Locale_Initialize(VOID);
static void MakeGUI(void);
static void showSimpleMessage(CONST_STRPTR msgString);
static CONST_STRPTR _(ULONG id);
 
static struct IOClipReq *CBOpen(ULONG unit);
static void CBClose(struct IOClipReq *ior);
static BOOL CBWriteFTXT(struct IOClipReq *ior, CONST_STRPTR string);
static BOOL CBWriteLong(struct IOClipReq *ior, LONG *ldata);
static struct DiskObject *disko;
 
/*** ASCIITable class *******************************************************/
 
#define MAXLEN (60)
 
#define ASCIITableObject BOOPSIOBJMACRO_START(ASCIITable_CLASS->mcc_Class)
 
#define MUIM_ASCIITable_Copy   (TAG_USER | 1)
#define MUIM_ASCIITable_Clear  (TAG_USER | 2)
#define MUIM_ASCIITable_Insert (TAG_USER | 3)
struct  MUIP_ASCIITable_Insert  {STACKED ULONG MethodID; STACKED LONG code;};
 
struct ASCIITable_DATA
{
    Object *copy_button;
    Object *clear_button;
    Object *ascii_string;
    TEXT buffer[MAXLEN + 1];
    struct IOClipReq *clip_req;
    TEXT shorthelp[192][20];
};
 
/*** CBOpen *****************************************************************/
static struct IOClipReq *CBOpen(ULONG unit)
{
    struct MsgPort *mp;
    struct IORequest *ior;
 
    if ((mp = CreatePort(0, 0)))
    {
        if ((ior = (struct IORequest *)CreateExtIO(mp, sizeof(struct IOClipReq))))
        {
            if (!(OpenDevice("clipboard.device", unit, ior, 0)))
            {
                return (struct IOClipReq *)ior;
            }
            DeleteExtIO(ior);
        }
        DeletePort(mp);
    }
    return NULL;
}
 
/*** CBCLose ****************************************************************/
static void CBClose(struct IOClipReq *ior)
{
    if (ior)
    {
        struct MsgPort *mp = ior->io_Message.mn_ReplyPort;
 
        CloseDevice((struct IORequest *)ior);
        DeleteExtIO((struct IORequest *)ior);
        DeletePort(mp);
    }
}
 
/*** CBWriteFTXT ************************************************************/
static BOOL CBWriteFTXT(struct IOClipReq *ior, CONST_STRPTR string)
{
    LONG length, slen, temp;
    BOOL odd;
 
    if (!ior || !string)
        return FALSE;
 
    slen = strlen(string);
    odd = (slen & 1);
 
    length = (odd) ? slen+1 : slen;
 
    ior->io_Offset = 0;
    ior->io_Error  = 0;
    ior->io_ClipID = 0;
 
    CBWriteLong(ior, (LONG *) "FORM");
    length += 12;
 
    temp = AROS_LONG2BE(length);
    CBWriteLong(ior, &temp);
    CBWriteLong(ior, (LONG *) "FTXT");
    CBWriteLong(ior, (LONG *) "CHRS");
    temp = AROS_LONG2BE(slen);
    CBWriteLong(ior, &temp);
 
    ior->io_Data    = (STRPTR)string;
    ior->io_Length  = slen;
    ior->io_Command = CMD_WRITE;
    DoIO((struct IORequest *)ior);
 
    if (odd)
    {
        ior->io_Data   = (APTR)"";
        ior->io_Length = 1;
        DoIO((struct IORequest *)ior);
    }
 
    ior->io_Command=CMD_UPDATE;
    DoIO ((struct IORequest *)ior);
 
    return ior->io_Error ? FALSE : TRUE;
}
 
/*** WriteLong **************************************************************/
static BOOL CBWriteLong(struct IOClipReq *ior, LONG *ldata)
{
    ior->io_Data    = (APTR)ldata;
    ior->io_Length  = 4;
    ior->io_Command = CMD_WRITE;
    DoIO( (struct IORequest *) ior);
 
    if (ior->io_Actual == 4)
    {
        return ior->io_Error ? FALSE : TRUE;
    }
 
    return FALSE;
}
 
/*** MakeButton *************************************************************/
static Object *MakeButton(LONG code)
{
    char buffer[2] = {0};
    buffer[0] = code;
 
    Object *btn = (Object *)TextObject,
        ButtonFrame,
        MUIA_Font, MUIV_Font_Button,
        MUIA_Text_Contents, (IPTR)buffer,
        MUIA_Text_PreParse, (IPTR)"\33c",
        MUIA_InputMode    , MUIV_InputMode_RelVerify,
        MUIA_Background   , MUII_ButtonBack,
        MUIA_CycleChain   , TRUE,
    End;
    return btn;
}
 
/*** OM_NEW *****************************************************************/
IPTR ASCIITable__OM_NEW(Class *CLASS, Object *self, struct opSet *message)
{
    struct ASCIITable_DATA *data = NULL;
    Object *copy_button, *clear_button, *ascii_string, *key_group;
    struct TagItem key_group_tags[200];
    LONG i, code;
 
    for (code = 32 , i = 0 ; code < 128 ; code++ , i++)
    {
        key_group_tags[i].ti_Tag = Child;
        key_group_tags[i].ti_Data = (IPTR)MakeButton(code);
    }
    for (code = 160 ; code < 256 ; code++, i++)
    {
        key_group_tags[i].ti_Tag = Child;
        key_group_tags[i].ti_Data = (IPTR)MakeButton(code);
    }
    key_group_tags[i].ti_Tag = MUIA_Group_Columns;
    key_group_tags[i].ti_Data = 16;
    key_group_tags[++i].ti_Tag = TAG_DONE;
    key_group = MUI_NewObjectA(MUIC_Group, key_group_tags);
 
    self = (Object *) DoSuperNewTags
    (
        CLASS, self, NULL,
        Child, key_group,
        Child, (IPTR) (RectangleObject, 
            MUIA_Rectangle_HBar, TRUE,
            MUIA_FixHeight,      2,
        End),
        Child, (IPTR)(ascii_string = (Object *)StringObject,
            StringFrame,
            MUIA_String_MaxLen, MAXLEN,
        End),
        Child, (IPTR) (HGroup,
            MUIA_Weight,         0,
            MUIA_Group_SameSize, TRUE,
 
            Child, (IPTR) (copy_button    = SimpleButton(_(MSG_ASCIITABLE_GAD_COPY))),
            Child, (IPTR) (clear_button   = SimpleButton(_(MSG_ASCIITABLE_GAD_CLEAR))),
        End),
        TAG_MORE, message->ops_AttrList
    );
 
    if (self != NULL)
    {
        /*-- Store important variables -------------------------------------*/
        data = INST_DATA(CLASS, self);
        data->copy_button = copy_button;
        data->clear_button = clear_button;
        data->ascii_string = ascii_string;
 
        /*-- Setup notifications -------------------------------------------*/
        DoMethod
        (
            copy_button, MUIM_Notify, MUIA_Pressed, FALSE,
            (IPTR) self, 1, MUIM_ASCIITable_Copy
        );
        DoMethod
        (
            clear_button, MUIM_Notify, MUIA_Pressed, FALSE,
            (IPTR) self, 1, MUIM_ASCIITable_Clear
        );
 
        for (i = 0 ; i < 192 ; i++)
        {
            code = (i < 96) ? i + 32 : i + 64;
            sprintf(data->shorthelp[i], "%c\n%d\n0x%x", (int)code, (int)code, (unsigned int)code);
            set((Object *)key_group_tags[i].ti_Data, MUIA_ShortHelp, data->shorthelp[i]);
            DoMethod
            (
                (Object *)key_group_tags[i].ti_Data, MUIM_Notify, MUIA_Pressed, FALSE,
                (IPTR) self, 2, MUIM_ASCIITable_Insert, code
            );
        }
        data->clip_req = CBOpen(0);
        if (!data->clip_req)
        {
            showSimpleMessage(_(MSG_CANT_OPEN_CLIPDEVICE));
        }
    }
 
    return (IPTR) self;
}
 
/*** OM_DISPOSE *************************************************************/
IPTR ASCIITable__OM_DISPOSE(Class *CLASS, Object *self, Msg message)
{
    struct ASCIITable_DATA *data = INST_DATA(CLASS, self);
 
    CBClose(data->clip_req);
 
    return DoSuperMethodA(CLASS, self, message);
}
 
/*** MUIM_ASCIITable_Copy ***************************************************/
IPTR ASCIITable__MUIM_ASCIITable_Copy(Class *CLASS, Object *self, Msg msg)
{
    struct ASCIITable_DATA *data = INST_DATA(CLASS, self);
    CBWriteFTXT(data->clip_req, (CONST_STRPTR)XGET(data->ascii_string, MUIA_String_Contents));
    return TRUE;
}
 
/*** MUIM_ASCIITable_Clear **************************************************/
IPTR ASCIITable__MUIM_ASCIITable_Clear(Class *CLASS, Object *self, Msg msg)
{
    struct ASCIITable_DATA *data = INST_DATA(CLASS, self);
    data->buffer[0] = '\0';
    set(data->ascii_string, MUIA_String_Contents, "");
    return TRUE;
}
 
/*** MUIM_ASCIITable_Insert *************************************************/
IPTR ASCIITable__MUIM_ASCIITable_Insert(Class *CLASS, Object *self, struct MUIP_ASCIITable_Insert *msg)
{
    struct ASCIITable_DATA *data = INST_DATA(CLASS, self);
    LONG len;
    D(bug("insert code %d\n", msg->code));
    strcpy(data->buffer, (CONST_STRPTR)XGET(data->ascii_string, MUIA_String_Contents));
    len = strlen(data->buffer);
    if (len < MAXLEN)
    {
        data->buffer[len] = msg->code;
        data->buffer[len+1] = '\0';
        set(data->ascii_string, MUIA_String_Contents, data->buffer);
    }
    return TRUE;
}
 
/*** Setup ******************************************************************/
ZUNE_CUSTOMCLASS_5
(
    ASCIITable, NULL, MUIC_Group, NULL,
    OM_NEW,                   struct opSet *,
    OM_DISPOSE,               Msg,
    MUIM_ASCIITable_Copy,     Msg,
    MUIM_ASCIITable_Clear,    Msg,
    MUIM_ASCIITable_Insert,   struct MUIP_ASCIITable_Insert *
);
 
 
 
/*** Begin application ******************************************************/
 
 
static CONST_STRPTR _(ULONG id)
{
    if (LocaleBase != NULL && catalog != NULL)
    {
        return GetCatalogStr(catalog, id, CatCompArray[id].cca_Str);
    } 
    else 
    {
        return CatCompArray[id].cca_Str;
    }
}
 
#define __(id) ((IPTR) _(id))   /* Get a message, as an IPTR */
 
/*** Locale_Initialize ******************************************************/
static int Locale_Initialize(VOID)
{
    if (LocaleBase != NULL)
    {
        catalog = OpenCatalog
            ( 
             NULL, CATALOG_NAME, OC_Version, CATALOG_VERSION, TAG_DONE 
            );
    }
    else
    {
        catalog = NULL;
    }
    return TRUE;
}
 
/*** Locale_Deinitialize ****************************************************/
static VOID Locale_Deinitialize(VOID)
{
    if (LocaleBase != NULL && catalog != NULL) CloseCatalog(catalog);
}
 
/*** GetArguments ***********************************************************/
static void GetArguments(int argc, char **argv)
{
    static struct RDArgs *myargs;
    static IPTR args[NUM_ARGS];
    static UBYTE **wbargs;
    static STRPTR cxname;
    static struct WBStartup *argmsg;
    static struct WBArg *wb_arg;
 
    if (argc)
    {
        if (!(myargs = ReadArgs(ARG_TEMPLATE, args, NULL)))
        {
            Fault(IoErr(), 0, s, 256);
            Cleanup(s);
        }
        if (args[ARG_CXPRI]) cx_pri = *(LONG*)args[ARG_CXPRI];
        if (args[ARG_CXPOPKEY])
        {
            cx_popkey = StrDup((char *)args[ARG_CXPOPKEY]);
        }
        else
        {
            cx_popkey = StrDup(DEF_POPKEY);
        }
        if (args[ARG_CXPOPUP]) cx_popup = TRUE;
        FreeArgs(myargs);
        cxname = argv[0];
    }
    else
    {
        argmsg = (struct WBStartup *)argv;
        wb_arg = argmsg->sm_ArgList;
        cxname = wb_arg->wa_Name;
        wbargs = ArgArrayInit(argc, (UBYTE**)argv);
        cx_pri = ArgInt(wbargs, "CX_PRIORITY", 0);
        cx_popkey = StrDup(ArgString(wbargs, "CX_POPKEY", DEF_POPKEY));
        if (strnicmp(ArgString(wbargs, "CX_POPUP", "NO"), "Y", 1) == 0)
        {
            cx_popup = TRUE;
        }
        ArgArrayDone();
    }
    D(bug("ASCIITable Arguments pri %d popkey %s popup %d\n", cx_pri, cx_popkey, cx_popup));
    disko = GetDiskObject(cxname);
}
 
/****************************************************************************/
static struct NewMenu nm[] =
{
    {NM_TITLE, (STRPTR)MSG_MEN_PROJECT         },
     {NM_ITEM, (STRPTR)MSG_MEN_PROJECT_HIDE    },
     {NM_ITEM, (STRPTR)MSG_MEN_PROJECT_ICONIFY },
     {NM_ITEM, NM_BARLABEL    	               },
     {NM_ITEM, (STRPTR)MSG_MEN_PROJECT_QUIT    },
    {NM_END                                    }
};
 
/*** InitMenus **************************************************************/
static void InitMenus(void)
{
    struct NewMenu *actnm = nm;
 
    for(actnm = nm; actnm->nm_Type != NM_END; actnm++)
    {
        if (actnm->nm_Label != NM_BARLABEL)
        {
            ULONG  id = (IPTR)actnm->nm_Label;
            CONST_STRPTR str = _(id);
 
            if (actnm->nm_Type == NM_TITLE)
            {
                actnm->nm_Label = str;
            } else {
                actnm->nm_Label = str + 2;
                if (str[0] != ' ') actnm->nm_CommKey = str;
            }
            actnm->nm_UserData = (APTR)(IPTR)id;
 
        } /* if (actnm->nm_Label != NM_BARLABEL) */
 
    } /* for(actnm = nm; nm->nm_Type != NM_END; nm++) */
}
 
/*** showSimpleMessage ******************************************************/
static void showSimpleMessage(CONST_STRPTR msgString)
{
    struct EasyStruct easyStruct;
 
    easyStruct.es_StructSize	= sizeof(easyStruct);
    easyStruct.es_Flags		= 0;
    easyStruct.es_Title		= _(MSG_ASCIITABLE_CXNAME);
    easyStruct.es_TextFormat	= msgString;
    easyStruct.es_GadgetFormat	= _(MSG_OK);		
 
    if (IntuitionBase != NULL && !Cli() )
    {
        EasyRequestArgs(NULL, &easyStruct, NULL, NULL);
    }
    else
    {
        PutStr(msgString);
    }
}
 
/*** broker_func ************************************************************/
AROS_UFH3(void, broker_func,
    AROS_UFHA(struct Hook *, h,      A0),
    AROS_UFHA(Object *     , object, A2),
    AROS_UFHA(CxMsg *      , msg,    A1))
{
    AROS_USERFUNC_INIT
 
    D(bug("ASCIITable: Broker hook called\n"));
    if (CxMsgType(msg) == CXM_COMMAND)
    {
        if (CxMsgID(msg) == CXCMD_APPEAR)
        {
            CallHookPkt(&show_hook, NULL, NULL);
        }
        else if (CxMsgID(msg) == CXCMD_DISAPPEAR)
        {
            set(wnd, MUIA_Window_Open, FALSE);
        }
    }
    AROS_USERFUNC_EXIT
}
 
/*** show_func ************************************************************/
AROS_UFH3(
    void, show_func,
    AROS_UFHA(struct Hook *,    hook,   A0),
    AROS_UFHA(APTR *,           obj,    A2),
    AROS_UFHA(APTR,             param,  A1)
)
{
    AROS_USERFUNC_INIT
 
    if (XGET(app, MUIA_Application_Iconified) == TRUE)
        set(app, MUIA_Application_Iconified, FALSE);
    else
        set(wnd, MUIA_Window_Open, TRUE);
 
    AROS_USERFUNC_EXIT
}
 
/*** MakeGUI ****************************************************************/
static void MakeGUI(void)
{
    Object *menu;
    static TEXT wintitle[100];
    CxObj *popfilter;
 
    menu = MUI_MakeObject(MUIO_MenustripNM, &nm, 0);
 
    broker_hook.h_Entry = (HOOKFUNC)broker_func;
    show_hook.h_Entry = (HOOKFUNC)show_func;
 
    snprintf(wintitle, sizeof(wintitle), _(MSG_ASCIITABLE_WINTITLE), cx_popkey);
 
    app = (Object *)ApplicationObject,
        MUIA_Application_Title, __(MSG_ASCIITABLE_CXNAME),
        MUIA_Application_Version, (IPTR)version,
        MUIA_Application_Copyright, (IPTR)"Copyright  © 2012, The AROS Development TEAM",
        MUIA_Application_Author, (IPTR)"The AROS Development Team",
        MUIA_Application_Description, __(MSG_ASCIITABLE_CXDESCR),
        MUIA_Application_BrokerPri, cx_pri,
        MUIA_Application_BrokerHook, (IPTR)&broker_hook,
        MUIA_Application_Base, (IPTR)"ASCIITABLE",
        MUIA_Application_SingleTask, TRUE,
        MUIA_Application_Menustrip, (IPTR)menu,
        MUIA_Application_DiskObject, (IPTR)disko,
        SubWindow, (IPTR)(wnd = (Object *)WindowObject,
            MUIA_Window_Title, (IPTR)wintitle,
            MUIA_Window_ID, MAKE_ID('A', 'I', 'T', 'B'),
            WindowContents, (IPTR)ASCIITableObject,
            End,
        End),
    End;
 
    if (! app)
        Cleanup(NULL); // Propably double start
 
    // enable hotkey
    maintask = FindTask(NULL);
    get(app, MUIA_Application_Broker, &broker);
    get(app, MUIA_Application_BrokerPort, &brokermp);
    if ( ! broker || ! brokermp)
        Cleanup(_(MSG_CANT_CREATE_BROKER));
 
    popfilter = CxFilter(cx_popkey);
    if (popfilter)
    {
        CxObj *popsig = CxSignal(maintask, SIGBREAKB_CTRL_F);
        if (popsig)
        {
            CxObj *trans;
            AttachCxObj(popfilter, popsig);
            trans = CxTranslate(NULL);
            if (trans) AttachCxObj(popfilter, trans);
        }
        AttachCxObj(broker, popfilter);
    }
 
    DoMethod(wnd, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
        (IPTR)wnd, 3, MUIM_Set, MUIA_Window_Open, FALSE);
 
    DoMethod(app, MUIM_Notify, MUIA_Application_DoubleStart, TRUE,
        (IPTR)wnd, 2, MUIM_CallHook, &show_hook);
 
    DoMethod(wnd, MUIM_Notify, MUIA_Window_MenuAction, MSG_MEN_PROJECT_QUIT,
        (IPTR)app, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
 
    DoMethod(wnd, MUIM_Notify, MUIA_Window_MenuAction, MSG_MEN_PROJECT_HIDE,
        (IPTR)wnd, 3, MUIM_Set, MUIA_Window_Open, FALSE);
 
    DoMethod(wnd, MUIM_Notify, MUIA_Window_MenuAction, MSG_MEN_PROJECT_ICONIFY,
        (IPTR)app, 3, MUIM_Set, MUIA_Application_Iconified, TRUE);
}
 
/*** HandleAll **************************************************************/
static void HandleAll(void)
{
    ULONG sigs = 0;
 
    set(wnd, MUIA_Window_Open, cx_popup);
 
    while((LONG) DoMethod(app, MUIM_Application_NewInput, (IPTR)&sigs)
            != MUIV_Application_ReturnID_Quit)
    {
        if (sigs)
        {
            sigs = Wait(sigs | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F);
            if (sigs & SIGBREAKF_CTRL_C)
            {
                break;
            }
            if (sigs & SIGBREAKF_CTRL_F)
            {
                CallHookPkt(&show_hook, NULL, NULL);
            }
        }
    }
}
 
/*** Cleanup ****************************************************************/
static void Cleanup(CONST_STRPTR txt)
{
    MUI_DisposeObject(app);
    FreeVec(cx_popkey);
    FreeDiskObject(disko);
    if (txt)
    {
        showSimpleMessage(txt);
        exit(RETURN_ERROR);
    }
    exit(RETURN_OK);
}
 
/*** main *******************************************************************/
int main(int argc, char **argv)
{
    D(bug("ASCIITable started\n"));
    GetArguments(argc, argv);
    InitMenus();    
    MakeGUI();
    HandleAll();
    Cleanup(NULL);
    return RETURN_OK;
}
 
/****************************************************************************/
ADD2INIT(Locale_Initialize,   90);
ADD2EXIT(Locale_Deinitialize, 90);


/*
    Copyright © 1995-2012, The AROS Development Team. All rights reserved.
    $Id$
*/
 
/*********************************************************************************************/
 
#include <intuition/classusr.h>
#include <graphics/layers.h>
#include <graphics/clip.h>
#include <libraries/asl.h>
#include <libraries/locale.h>
#include <libraries/gadtools.h>
#include <libraries/commodities.h>
#include <libraries/mui.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>
#include <devices/inputevent.h>
#include <aros/asmcall.h>
 
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/locale.h>
#include <proto/muimaster.h>
#include <proto/intuition.h>
#include <proto/layers.h>
#include <proto/commodities.h>
#include <proto/alib.h>
#include <proto/icon.h>
#include <proto/utility.h>
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
 
#define CATCOMP_ARRAY
#include "strings.h"
 
#define CATALOG_NAME     "System/Tools/Commodities.catalog"
#define CATALOG_VERSION  3
 
#include <aros/debug.h>
 
/*********************************************************************************************/
 
#define VERSION 	1
#define REVISION 	6
#define DATESTR 	"14.01.2012"
#define VERSIONSTR	"$VER: FKey 1.6 (" DATESTR ")"
 
/*********************************************************************************************/
 
#define ARG_TEMPLATE "CX_PRIORITY/N/K,CX_POPKEY/K,CX_POPUP/S,PORT/K,QUIET/S"
 
#define ARG_CXPRI   	0
#define ARG_CXPOPKEY 	1
#define ARG_CXPOPUP 	2
#define ARG_CXPORT  	3
#define ARG_QUIET   	4
 
#define NUM_ARGS    	5
 
/*********************************************************************************************/
 
#define ACTION_CYCLE_WIN     0
#define ACTION_CYCLE_SCR     1
#define ACTION_ENLARGE_WIN   2
#define ACTION_SHRINK_WIN    3
#define ACTION_TOGGLE_WIN    4
#define ACTION_RESCUE_WIN    5
#define ACTION_INSERT_TEXT   6
#define ACTION_RUN_PROG      7
#define ACTION_RUN_AREXX     8
 
#define RETURNID_NEWKEY      1
#define RETURNID_DELKEY      2
#define RETURNID_STRINGACK   3
#define RETURNID_LVACK	     4
#define RETURNID_CMDACK      5
#define RETURNID_SAVE	     6
#define RETURNID_DOUBLESTART 7
 
/*********************************************************************************************/
 
struct KeyInfo
{
    struct InputEvent *translist;
    CxObj   	      *filter, *trans, *custom;    
    WORD    	       action;
    char    	       descr[80];
    char    	       param[256];
};
 
/*********************************************************************************************/
 
struct LocaleBase    	*LocaleBase;
 
static char 	     	*cx_popkey = "ctrl alt f";
static LONG 	         cx_pri = 0;
static BOOL 	      	 cx_popup = FALSE;
 
static CxObj	     	*broker, *activated_custom_cobj;
static Object	     	*app, *wnd, *cmdcycle, *list, *liststr;
static Object	     	*insertstr, *runprogstr, *runarexxstr;
static Object	     	*cmdpage;
static struct Task   	*maintask;
static struct Hook   	 keylist_construct_hook, keylist_destruct_hook, keylist_disp_hook;
static struct Hook   	 broker_hook;
static struct Hook       show_hook;
static struct MsgPort 	*brokermp;
static struct Catalog 	*catalog;
static struct RDArgs 	*myargs;
static struct WBStartup *wbstartup;
static LONG 	     	 prog_exitcode;
static UBYTE	       **wbargs;
static IPTR 	      	 args[NUM_ARGS];
static UBYTE	      	 s[257];
 
/*********************************************************************************************/
 
static void broker_func(struct Hook *hook, Object *obj, CxMsg *msg);
static UBYTE *BuildToolType(struct KeyInfo *ki);
static UBYTE **BuildToolTypes(UBYTE **src_ttypes);
static void Cleanup(CONST_STRPTR msg);
static void CleanupLocale(void);
static void CmdToKey(void);
static void DelKey(void);
static struct DiskObject *LoadProgIcon(BPTR *icondir, STRPTR iconname);
static void FreeArguments(void);
static void FreeToolTypes(UBYTE **ttypes);
static void GetArguments(int argc, char **argv);
static void HandleAction(void);
static void HandleAll(void);
static void InitCX(void);
static void InitLocale(STRPTR catname, ULONG version);
static void InitMenus(void);
static APTR keylist_construct_func(struct Hook *hook, APTR pool, struct KeyInfo *ki);
static void keylist_destruct_func(struct Hook *hook, APTR pool, struct KeyInfo *ki);
static void keylist_disp_func(struct Hook *hook, char **array, struct KeyInfo *ki);
static void KillCX(void);
static void KillGUI(void);
static void ListToString(void);
static void LoadSettings(void);
static void MakeGUI(void);
static CONST_STRPTR MSG(ULONG id);
static void NewKey(void);
static void RethinkAction(void);
static void RethinkKey(struct KeyInfo *ki);
static void SaveSettings(void);
static WORD ShowMessage(CONST_STRPTR title, CONST_STRPTR text, CONST_STRPTR gadtext);
static void StringToKey(void);
static struct DiskObject *disko;
 
/*********************************************************************************************/
 
static WORD ShowMessage(CONST_STRPTR title, CONST_STRPTR text, CONST_STRPTR gadtext)
{
    struct EasyStruct es;
 
    es.es_StructSize   = sizeof(es);
    es.es_Flags        = 0;
    es.es_Title        = title;
    es.es_TextFormat   = text;
    es.es_GadgetFormat = gadtext;
 
    return EasyRequestArgs(NULL, &es, NULL, NULL);  
}
 
/*********************************************************************************************/
 
static void Cleanup(CONST_STRPTR msg)
{
    if (msg)
    {
	if (IntuitionBase && !((struct Process *)FindTask(NULL))->pr_CLI)
	{
	    ShowMessage("Fkey", msg, MSG(MSG_OK));     
	}
	else
	{
	    printf("FKey: %s\n", msg);
	}
    }
 
    KillGUI();
    FreeDiskObject(disko);
    FreeArguments();
    KillCX();
    CleanupLocale();
 
    exit(prog_exitcode);
}
 
 
/*********************************************************************************************/
 
static void InitCX(void)
{
    maintask = FindTask(NULL);
}
 
/*********************************************************************************************/
 
static void KillCX(void)
{
}
 
/*********************************************************************************************/
 
static void InitLocale(STRPTR catname, ULONG version)
{
    LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library", 39);
    if (LocaleBase)
    {
	catalog = OpenCatalog(NULL, catname, OC_Version, version,
					     TAG_DONE);
    }
}
 
/*********************************************************************************************/
 
static void CleanupLocale(void)
{
    if (catalog) CloseCatalog(catalog);
    if (LocaleBase) CloseLibrary((struct Library *)LocaleBase);
}
 
/*********************************************************************************************/
 
static CONST_STRPTR MSG(ULONG id)
{
    if (catalog != NULL)
    {
        return GetCatalogStr(catalog, id, CatCompArray[id].cca_Str);
    }
    else 
    {
        return CatCompArray[id].cca_Str;
    }
}
 
/*********************************************************************************************/
 
static struct NewMenu nm[] =
{
    {NM_TITLE, (STRPTR)MSG_MEN_PROJECT              },
     {NM_ITEM, (STRPTR)MSG_FKEY_MEN_PROJECT_SAVE    },
     {NM_ITEM, NM_BARLABEL  	    	    	    },
     {NM_ITEM, (STRPTR)MSG_MEN_PROJECT_HIDE         },
     {NM_ITEM, (STRPTR)MSG_MEN_PROJECT_ICONIFY      },
     {NM_ITEM, NM_BARLABEL  	    	    	    },
     {NM_ITEM, (STRPTR)MSG_MEN_PROJECT_QUIT         },
    {NM_END 	    	    	    	    	    }
};
 
/*********************************************************************************************/
 
static void InitMenus(void)
{
    struct NewMenu *actnm = nm;
 
    for(actnm = nm; actnm->nm_Type != NM_END; actnm++)
    {
	if (actnm->nm_Label != NM_BARLABEL)
	{
	    ULONG  id = (IPTR)actnm->nm_Label;
	    CONST_STRPTR str = MSG(id);
 
	    if (actnm->nm_Type == NM_TITLE)
	    {
		actnm->nm_Label = str;
	    } else {
		actnm->nm_Label = str + 2;
		if (str[0] != ' ') actnm->nm_CommKey = str;
	    }
	    actnm->nm_UserData = (APTR)(IPTR)id;
 
	} /* if (actnm->nm_Label != NM_BARLABEL) */
 
    } /* for(actnm = nm; nm->nm_Type != NM_END; nm++) */
 
}
 
/*********************************************************************************************/
 
static void FreeArguments(void)
{
    if (myargs) FreeArgs(myargs);
    ArgArrayDone();
}
 
/*********************************************************************************************/
 
static void KillGUI(void)
{
    DisposeObject(app);
}
 
/*********************************************************************************************/
 
static void GetArguments(int argc, char **argv)
{
    static struct WBArg *wb_arg;
    static STRPTR cxname;
    if (argc)
    {
    	if (!(myargs = ReadArgs(ARG_TEMPLATE, args, NULL)))
    	{
	    Fault(IoErr(), 0, s, 256);
	    Cleanup(s);
    	}
 
	if (args[ARG_CXPRI]) cx_pri = (LONG)*(IPTR *)args[ARG_CXPRI];
	if (args[ARG_CXPOPKEY]) cx_popkey = (STRPTR)args[ARG_CXPOPKEY];
	if (args[ARG_CXPOPUP]) cx_popup = TRUE;
    cxname=argv[0];
    }
    else
    {
    	wbstartup = (struct WBStartup *)argv;
        wb_arg    = wbstartup->sm_ArgList;
        cxname    = wb_arg->wa_Name;
    	wbargs = ArgArrayInit(argc, (UBYTE **)argv);
 
	cx_pri = ArgInt(wbargs, "CX_PRIORITY", 0);
	cx_popkey = ArgString(wbargs, "CX_POPKEY", cx_popkey);
 
	if (strnicmp(ArgString(wbargs, "CX_POPUP", "NO"), "Y", 1) == 0)
	{
	    cx_popup = TRUE;
	}
    }
    disko = GetDiskObject(cxname);
}
 
/*********************************************************************************************/
 
static APTR keylist_construct_func(struct Hook *hook, APTR pool, struct KeyInfo *ki)
{
    struct KeyInfo *new;
 
    new = AllocPooled(pool, sizeof(*ki));
    if (new) *new = *ki;
 
    return new;
}
 
/*********************************************************************************************/
 
static void keylist_destruct_func(struct Hook *hook, APTR pool, struct KeyInfo *ki)
{
    if (ki)
    {
    	if (ki->filter) DeleteCxObjAll(ki->filter);
    	if (ki->translist) FreeIEvents(ki->translist);
 
    	FreePooled(pool, ki, sizeof(*ki));
    }
}
 
/*********************************************************************************************/
 
static void keylist_disp_func(struct Hook *hook, char **array, struct KeyInfo *ki)
{
    *array = ki->descr;
}
 
/*********************************************************************************************/
 
static void broker_func(struct Hook *hook, Object *obj, CxMsg *msg)
{
    D(bug("FKey: broker_func called\n"));
    if (CxMsgType(msg) == CXM_COMMAND)
    {
        if (CxMsgID(msg) == CXCMD_APPEAR)
        {
            CallHookPkt(&show_hook, NULL, NULL);
        }
        else if (CxMsgID(msg) == CXCMD_DISAPPEAR)
        {
            set(wnd, MUIA_Window_Open, FALSE);
        }
    }
}
 
/*** show_func ************************************************************/
AROS_UFH3(
    void, show_func,
    AROS_UFHA(struct Hook *,    hook,   A0),
    AROS_UFHA(APTR *,           obj,    A2),
    AROS_UFHA(APTR,             param,  A1)
)
{
    AROS_USERFUNC_INIT
 
    if (XGET(app, MUIA_Application_Iconified) == TRUE)
        set(app, MUIA_Application_Iconified, FALSE);
    else
        set(wnd, MUIA_Window_Open, TRUE);
 
    AROS_USERFUNC_EXIT
}
 
/*********************************************************************************************/
 
AROS_UFH2S(void, custom_func,
    AROS_UFHA(CxMsg *, msg, A0),
    AROS_UFHA(CxObj *, co, A1))
{
    AROS_USERFUNC_INIT
 
    activated_custom_cobj = co;
    Signal(maintask, SIGBREAKF_CTRL_E);
 
    AROS_USERFUNC_EXIT
}
 
 
/*********************************************************************************************/
 
static void MakeGUI(void)
{
    static CONST_STRPTR cmdarray[] =
    {
    	(CONST_STRPTR)MSG_FKEY_CMD_CYCLE_WIN,
    	(CONST_STRPTR)MSG_FKEY_CMD_CYCLE_SCR,
    	(CONST_STRPTR)MSG_FKEY_CMD_ENLARGE_WIN,
    	(CONST_STRPTR)MSG_FKEY_CMD_SHRINK_WIN,
    	(CONST_STRPTR)MSG_FKEY_CMD_TOGGLE_WIN_SIZE,
	(CONST_STRPTR)MSG_FKEY_CMD_RESCUE_WIN,
    	(CONST_STRPTR)MSG_FKEY_CMD_INSERT_TEXT,
    	(CONST_STRPTR)MSG_FKEY_CMD_RUN_PROG,
    	(CONST_STRPTR)MSG_FKEY_CMD_RUN_AREXX,
	0,
    };
    static TEXT wintitle[100];
    WORD i;
    Object *menu, *newkey, *delkey, *savekey;
 
    for(i = 0; cmdarray[i]; i++)
    {
    	cmdarray[i] = MSG((IPTR) cmdarray[i]);
    }
 
    keylist_construct_hook.h_Entry = HookEntry;
    keylist_construct_hook.h_SubEntry = (HOOKFUNC)keylist_construct_func;
 
    keylist_destruct_hook.h_Entry = HookEntry;
    keylist_destruct_hook.h_SubEntry = (HOOKFUNC)keylist_destruct_func;
 
    keylist_disp_hook.h_Entry = HookEntry;
    keylist_disp_hook.h_SubEntry = (HOOKFUNC)keylist_disp_func;
 
    broker_hook.h_Entry = HookEntry;
    broker_hook.h_SubEntry = (HOOKFUNC)broker_func;
 
    show_hook.h_Entry = (HOOKFUNC)show_func;
 
    menu = MUI_MakeObject(MUIO_MenustripNM, &nm, 0);
 
    snprintf(wintitle, sizeof(wintitle), MSG(MSG_FKEY_WINTITLE), cx_popkey);
 
    app = ApplicationObject,
	MUIA_Application_Title, (IPTR)MSG(MSG_FKEY_CXNAME),
	MUIA_Application_Version, (IPTR)VERSIONSTR,
	MUIA_Application_Copyright, (IPTR)"Copyright © 1995-2012, The AROS Development Team",
	MUIA_Application_Author, (IPTR)"The AROS Development Team",
	MUIA_Application_Description, (IPTR)MSG(MSG_FKEY_CXDESCR),
	MUIA_Application_BrokerPri, cx_pri,
	MUIA_Application_BrokerHook, (IPTR)&broker_hook,
	MUIA_Application_Base, (IPTR)"FKey",
	MUIA_Application_SingleTask, TRUE,
	menu ? MUIA_Application_Menustrip : TAG_IGNORE, menu,
    MUIA_Application_DiskObject, (IPTR)disko,
  	SubWindow, wnd = WindowObject,
	    MUIA_Window_Title, (IPTR)wintitle,
	    MUIA_Window_ID, MAKE_ID('F','W','I','N'),
	    WindowContents, HGroup,
	    	Child, VGroup,
		    GroupFrameT(MSG(MSG_FKEY_DEFINED_KEYS)),
		    Child, VGroup,
		    	GroupSpacing(0),
			Child, ListviewObject,
		    	    MUIA_Listview_List, list = ListObject,
				InputListFrame,
				MUIA_List_ConstructHook, (IPTR)&keylist_construct_hook,
				MUIA_List_DestructHook, (IPTR)&keylist_destruct_hook,
				MUIA_List_DisplayHook, (IPTR)&keylist_disp_hook,
				End,
			    End,
			Child, liststr = StringObject,
			    MUIA_Disabled, TRUE,
		    	    StringFrame,
			    End,
			End,
		    Child, HGroup,
		    	Child, newkey = SimpleButton(MSG(MSG_FKEY_NEW_KEY)),
			Child, delkey = SimpleButton(MSG(MSG_FKEY_DELETE_KEY)),
			End,
		    Child, savekey = SimpleButton(MSG(MSG_FKEY_SAVE_KEY)),
		    End,
		Child, VGroup,
		    GroupFrameT(MSG(MSG_FKEY_COMMAND)),
		    Child, cmdcycle = MUI_MakeObject(MUIO_Cycle, NULL, cmdarray),
		    Child, cmdpage = PageGroup,
		    	Child, HVSpace, /* cycle win */
			Child, HVSpace, /* cycle scr */
			Child, HVSpace, /* enlarge win */
			Child, HVSpace, /* shrink win */
			Child, HVSpace, /* Toggle win */
			Child, HVSpace, /* rescue win */
                        Child, insertstr = StringObject, StringFrame, End, /* Insert text */
			Child, PopaslObject, /* Run prog */
				MUIA_Popstring_String, runprogstr = StringObject, StringFrame, End,
				MUIA_Popstring_Button, PopButton(MUII_PopFile),
				ASLFR_RejectIcons, TRUE,
			End,		
			Child, PopaslObject, /* Run AREXX */
				MUIA_Popstring_String, runarexxstr = StringObject, StringFrame, End,
				MUIA_Popstring_Button, PopButton(MUII_PopFile),
				ASLFR_RejectIcons, TRUE,
			End,	
		    End,
		    Child, HVSpace,
		    End,
		End,
	    End,
	End;
 
    if (!app)
    {
    #if 1
    	Cleanup(NULL); /* Make no noise. Is ugly if FKey is double-started. */
    #else
    	Cleanup(MSG(MSG_CANT_CREATE_GADGET));
    #endif
    }
 
    get(app, MUIA_Application_Broker, &broker);  
    get(app, MUIA_Application_BrokerPort, &brokermp);  
 
    if (!broker || !brokermp)
	Cleanup(MSG(MSG_CANT_CREATE_GADGET));
 
    {
    	CxObj *popfilter = CxFilter(cx_popkey);
 
	if (popfilter)
	{
	    CxObj *popsig = CxSignal(maintask, SIGBREAKB_CTRL_F);
 
	    if (popsig)
	    {
	    	CxObj *trans;
 
	    	AttachCxObj(popfilter, popsig);
 
		trans = CxTranslate(NULL);
    	    	if (trans) AttachCxObj(popfilter, trans);
	    }
 
	    AttachCxObj(broker, popfilter);
	}
 
    }
 
    set(liststr, MUIA_String_AttachedList, (IPTR)list);
 
    DoMethod(app, MUIM_Notify, MUIA_Application_DoubleStart, TRUE, (IPTR) app, 2, MUIM_Application_ReturnID, RETURNID_DOUBLESTART);
 
    DoMethod(wnd, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, (IPTR) wnd, 3, MUIM_Set, MUIA_Window_Open, FALSE);
 
    DoMethod(wnd, MUIM_Notify, MUIA_Window_MenuAction, MSG_MEN_PROJECT_QUIT, (IPTR) app, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
    DoMethod(wnd, MUIM_Notify, MUIA_Window_MenuAction, MSG_MEN_PROJECT_HIDE, (IPTR) wnd, 3, MUIM_Set, MUIA_Window_Open, FALSE);
    DoMethod(wnd, MUIM_Notify, MUIA_Window_MenuAction, MSG_MEN_PROJECT_ICONIFY, (IPTR) app, 3, MUIM_Set, MUIA_Application_Iconified, TRUE);
    DoMethod(wnd, MUIM_Notify, MUIA_Window_MenuAction, MSG_FKEY_MEN_PROJECT_SAVE, (IPTR) app, 2, MUIM_Application_ReturnID, RETURNID_SAVE);
 
    DoMethod(cmdcycle, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime, (IPTR)cmdpage, 3, MUIM_Set, MUIA_Group_ActivePage, MUIV_TriggerValue);
    DoMethod(cmdcycle, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime, (IPTR)app, 2, MUIM_Application_ReturnID, RETURNID_CMDACK);
    DoMethod(newkey, MUIM_Notify, MUIA_Pressed, FALSE, (IPTR)app, 2, MUIM_Application_ReturnID, RETURNID_NEWKEY);
    DoMethod(delkey, MUIM_Notify, MUIA_Pressed, FALSE, (IPTR)app, 2, MUIM_Application_ReturnID, RETURNID_DELKEY);
    DoMethod(savekey, MUIM_Notify, MUIA_Pressed, FALSE, (IPTR)app, 2, MUIM_Application_ReturnID, RETURNID_SAVE);
    DoMethod(list, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime, (IPTR)app, 2, MUIM_Application_ReturnID, RETURNID_LVACK);
    DoMethod(liststr, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, (IPTR)app, 2, MUIM_Application_ReturnID, RETURNID_STRINGACK);
    DoMethod(insertstr, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, (IPTR)app, 2, MUIM_Application_ReturnID, RETURNID_CMDACK);
    DoMethod(runprogstr, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, (IPTR)app, 2, MUIM_Application_ReturnID, RETURNID_CMDACK);
    DoMethod(runarexxstr, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, (IPTR)app, 2, MUIM_Application_ReturnID, RETURNID_CMDACK);
 
}
 
/*********************************************************************************************/
 
static void RethinkKey(struct KeyInfo *ki)
{
    if (ki->filter) DeleteCxObjAll(ki->filter);
    if (ki->translist)
    {
    	FreeIEvents(ki->translist);
	ki->translist = NULL;
    }
    ki->custom = ki->trans = ki->filter = NULL;
 
    if ((ki->filter = CxFilter(ki->descr)))
    {
    	switch(ki->action)
	{
	    case ACTION_INSERT_TEXT:
	    	strrev(ki->param);
	    	if ((ki->translist = InvertStringForwd(ki->param, NULL)))
		{		
	    	    if ((ki->trans = CxTranslate(ki->translist)))
		    {
		    	AttachCxObj(ki->filter, ki->trans);
		    }
		}
		strrev(ki->param);
	    	break;
 
	    default:
	    	/* This CxCustom thing is hacky/ugly. A CxSender
		   would be better, but if want to send a pointer
		   with it then this would require some fixes in
		   commodities.library and it's header in case we are
		   running on 64 bit machines :-\ */
 
    		if ((ki->custom = CxCustom(custom_func, 0)))
		{
		    AttachCxObj(ki->filter, ki->custom);
		    if ((ki->trans = CxTranslate(NULL)))
		    {
		    	AttachCxObj(ki->filter, ki->trans);
		    }
		}
		break;
 
	}
 
	AttachCxObj(broker, ki->filter);
 
    }
}
 
/*********************************************************************************************/
 
static void RethinkAction(void)
{
    struct KeyInfo *ki = NULL;
 
    DoMethod(list, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, (IPTR)&ki);
 
    if (ki)
    {
	Object *str = NULL;
    	IPTR val = 0;
 
	get(cmdcycle, MUIA_Cycle_Active, &val);
    	ki->action = val;
 
	switch(ki->action)
	{
	    case ACTION_INSERT_TEXT:
	    	str = insertstr;
		break;
 
	    case ACTION_RUN_PROG:
	    	str = runprogstr;
		break;
 
	    case ACTION_RUN_AREXX:
	    	str = runarexxstr;
		break;
 
	}
 
	if (str)
	{
	    STRPTR s = "";
 
	    get(str, MUIA_String_Contents, &s);
 
	    strncpy(ki->param, s, sizeof(ki->param));
	}
 
	RethinkKey(ki);
    }
}
 
/*********************************************************************************************/
 
static void NewKey(void)
{
    struct KeyInfo ki = {0};
 
    StringToKey();
 
    DoMethod(list, MUIM_List_InsertSingle, (IPTR)&ki, MUIV_List_Insert_Bottom);
    nnset(list, MUIA_List_Active, MUIV_List_Active_Bottom);
    nnset(liststr, MUIA_String_Contents, "");
    nnset(liststr, MUIA_Disabled, FALSE);
    set(wnd, MUIA_Window_ActiveObject, (IPTR)liststr);
 
    RethinkAction();
}
 
/*********************************************************************************************/
 
static void DelKey(void)
{
    struct KeyInfo *ki = NULL;
 
    DoMethod(list, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, (IPTR)&ki);
 
    if (ki)
    {
    	DoMethod(list, MUIM_List_Remove, MUIV_List_Remove_Active);
    	DoMethod(list, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, (IPTR)&ki);
    	if (!ki)
	{
	    nnset(liststr, MUIA_String_Contents, (IPTR)"");
	    nnset(liststr, MUIA_Disabled, TRUE);
 
	    ListToString();
	}
    }
}
 
/*********************************************************************************************/
 
static void StringToKey(void)
{
    struct KeyInfo *ki = NULL;
    STRPTR  	    text = "";
 
    DoMethod(list, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, (IPTR)&ki);
    if (!ki) return;
 
    get(liststr, MUIA_String_Contents, &text);    
    strncpy(ki->descr, text, sizeof(ki->descr));
 
    DoMethod(list, MUIM_List_Redraw, MUIV_List_Redraw_Active);
 
    RethinkKey(ki);
}
 
/*********************************************************************************************/
 
static void ListToString(void)
{
    struct KeyInfo *ki = NULL;
 
    DoMethod(list, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, (IPTR)&ki);
    if (!ki) return;
 
    nnset(liststr, MUIA_Disabled, FALSE);
    nnset(liststr, MUIA_String_Contents, ki->descr);
 
    switch(ki->action)
    {
    	case ACTION_INSERT_TEXT:
	    nnset(insertstr, MUIA_String_Contents, ki->param);
	    break;
 
	case ACTION_RUN_PROG:
	    nnset(runprogstr, MUIA_String_Contents, ki->param);
	    break;
 
	case ACTION_RUN_AREXX:
	    nnset(runarexxstr, MUIA_String_Contents, ki->param);
	    break;
    }
 
    nnset(cmdcycle, MUIA_Cycle_Active, ki->action);
    nnset(cmdpage, MUIA_Group_ActivePage, ki->action);
}
 
/*********************************************************************************************/
 
static void CmdToKey(void)
{
    RethinkAction();
}
 
/*********************************************************************************************/
 
static void HandleAction(void)
{
    struct KeyInfo  *ki;
    struct Window   *win;
    struct Screen   *scr;
    CxObj   	    *cobj;
    WORD    	     i;
 
    cobj = activated_custom_cobj;	
    activated_custom_cobj = NULL;
 
    for(i = 0; ; i++)
    {
	DoMethod(list, MUIM_List_GetEntry, i, (IPTR)&ki);
	if (!ki) break;
 
	if (ki->custom == cobj) break;
    }
 
    if (!ki) return;
 
    win = IntuitionBase->ActiveWindow;
    scr = IntuitionBase->FirstScreen;
 
    switch(ki->action)
    {
    	case ACTION_CYCLE_WIN:
	    if (win)
	    {
	    	struct Layer *lay;
 
	    	scr = win->WScreen;
		win = NULL;
 
		LockLayerInfo(&scr->LayerInfo);
		lay = scr->LayerInfo.top_layer;
		while(lay)
		{
		    if (lay->Window &&
		    	(lay != scr->BarLayer) &&
		    	!(lay->Flags & LAYERBACKDROP) &&
			!(((struct Window *)lay->Window)->Flags & WFLG_BORDERLESS))
		    {
		    	win = (struct Window *)lay->Window;
		    }
 
		    lay = lay->back;
		}		
		UnlockLayerInfo(&scr->LayerInfo);
 
		if (win)
		{
		    WindowToFront(win);
		    ActivateWindow(win);
		}
	    }
	    break;
 
	case ACTION_CYCLE_SCR:
	    if (scr) ScreenToBack(scr);
	    break;
 
	case ACTION_ENLARGE_WIN:
	    if (win && (win->Flags & WFLG_SIZEGADGET))
	    {
	    	WORD neww = win->MaxWidth;
		WORD newh = win->MaxHeight;
 
		if (neww > win->WScreen->Width) neww = win->WScreen->Width;
		if (newh > win->WScreen->Height) newh = win->WScreen->Height;
 
		ChangeWindowBox(win, win->LeftEdge, win->TopEdge, neww, newh);
	    }
	    break;
 
	case ACTION_SHRINK_WIN:
	    if (win && (win->Flags & WFLG_SIZEGADGET))
	    {
	    	WORD neww = win->MinWidth;
		WORD newh = win->MinHeight;
 
		ChangeWindowBox(win, win->LeftEdge, win->TopEdge, neww, newh);
	    }
	    break;
 
	case ACTION_RESCUE_WIN:
	    if (win)
	    {
		WORD dx = 0, dy = 0;
		if (win->LeftEdge < 0)
			dx = -win->LeftEdge;
		else if (win->LeftEdge + win->Width > win->WScreen->Width)
			dx = win->WScreen->Width - win->Width - win->LeftEdge;
 
		if (win->TopEdge + win->Height > win->WScreen->Height)
			dy = win->WScreen->Height - win->Height - win->TopEdge;
		else if (win->TopEdge < win->WScreen->BarHeight)
        {
			// try to keep the screen title bar visible
			if (win->WScreen->BarHeight + win->Height < win->WScreen->Height)
				dy = -win->TopEdge + win->WScreen->BarHeight;
			else
				dy = win->WScreen->Height - win->Height - win->TopEdge;
		}
		MoveWindow(win, dx, dy);
	    }
	    break;
 
	case ACTION_TOGGLE_WIN:
	    if (win) ZipWindow(win);
	    break;
 
	case ACTION_RUN_PROG:
	    if (ki->param)
	    {
	    	BPTR infh;
 
		infh = Open("CON:20/20/500/300/FKey/CLOSE/AUTO/WAIT", MODE_READWRITE);
		if (infh)
		{
		    struct TagItem systemtags[] =
		    {
		    	{SYS_Asynch , TRUE  	},
			{SYS_Input  , (IPTR)infh},
			{SYS_Output , 0	    	},
			{TAG_DONE   	    	}
		    };
 
		    if (SystemTagList(ki->param, systemtags) == -1)
		    {
		    	/* Error */
		    	Close(infh);
		    }
		}
	    }
	    break;
 
	case ACTION_RUN_AREXX:
	    break;
 
    } /* switch(ki->action) */
 
}
 
/*********************************************************************************************/
 
#define QUOTE_START 0xAB
#define QUOTE_END   0xBB
 
/*********************************************************************************************/
 
static UBYTE *BuildToolType(struct KeyInfo *ki)
{
    static UBYTE  ttstring[500];
    UBYTE   	 *param1 = "";
    UBYTE   	 *param2 = "";
 
    switch(ki->action)
    {
    	case ACTION_CYCLE_WIN:
	    param1 = "CYCLE";
	    break;
 
	case ACTION_CYCLE_SCR:
	    param1 = "CYCLESCREEN";
	    break;
 
	case ACTION_ENLARGE_WIN:
	    param1 = "MAKEBIG";
	    break;
 
	case ACTION_SHRINK_WIN:
	    param1 = "MAKESMALL";
	    break;
 
	case ACTION_TOGGLE_WIN:
	    param1 = "ZIPWINDOW";
	    break;
 
	case ACTION_RESCUE_WIN:
	    param1 = "RESCUEWIN";
	    break;
 
	case ACTION_INSERT_TEXT:
	    param1 = "INSERT ";
	    param2 = ki->param;
	    break;
 
	case ACTION_RUN_PROG:
	    param1 = "RUN ";
	    param2 = ki->param;
	    break;
 
	case ACTION_RUN_AREXX:
	    param1 = "AREXX ";
    	    param2 = ki->param;
	    break;
 
    }
 
    snprintf(ttstring, sizeof(ttstring), "%c%s%c %s%s",
    	     QUOTE_START,
	     ki->descr,
	     QUOTE_END,
	     param1,
	     param2);
 
    return ttstring;
}
 
/*********************************************************************************************/
 
static UBYTE **BuildToolTypes(UBYTE **src_ttypes)
{
    APTR     pool = CreatePool(MEMF_CLEAR, 200, 200);
    Object  *listobj = list;
    UBYTE   *tt;
    WORD     list_index = 0, num_ttypes = 0, alloc_ttypes = 10;
 
    UBYTE **dst_ttypes;
 
    if (!pool) return NULL;
 
    dst_ttypes = AllocPooled(pool, (alloc_ttypes + 2) * sizeof(UBYTE *));
    if (!dst_ttypes)
    {
    	DeletePool(pool);
	return NULL;
    }
 
    /* Put together final tooltypes list based on old tooltypes and
       new tooltypes all in one loop */
 
    for(;;)
    {
    	tt = NULL;
 
    	if (listobj)
	{
	    /* New tooltypes */
 
    	    struct KeyInfo *ki = NULL;
 
    	    DoMethod(listobj, MUIM_List_GetEntry, list_index, (IPTR)&ki);
    	    list_index++;
 
	    if (ki)
	    {
	    	tt = BuildToolType(ki);
	    }
	    else
	    {
	    	listobj = NULL;
	    }	    
	}
 
	if (!listobj)
	{
	    /* Old tooltypes */
 
	    if (src_ttypes) tt = *src_ttypes++;
	    if (!tt) break; /* Done. Skip out of "for(;;)" loop */
 
    	    if (tt[0] == QUOTE_START) continue; /* skip tooltype containing old settings */
	}
 
	if (!tt) break; /* Paranoia. Should not happen. */
 
	if (num_ttypes >= alloc_ttypes)
	{
	    UBYTE **new_dst_ttypes = AllocPooled(pool, (alloc_ttypes + 10 + 2) * sizeof(UBYTE *));
 
	    if (!new_dst_ttypes)
	    {
	    	DeletePool(pool);
		return NULL;
	    }
 
	    CopyMem(dst_ttypes + 1, new_dst_ttypes + 1, alloc_ttypes * sizeof(UBYTE *));
	    dst_ttypes = new_dst_ttypes;
	    alloc_ttypes += 10;
	}
 
	dst_ttypes[num_ttypes + 1] = AllocPooled(pool, strlen(tt) + 1);
	if (!dst_ttypes[num_ttypes + 1])
	{
    	    DeletePool(pool);
    	    return NULL;
	}
 
	CopyMem(tt, dst_ttypes[num_ttypes + 1], strlen(tt) + 1);
	num_ttypes++;
 
    }
 
    dst_ttypes[0] = (APTR)pool;
 
    return dst_ttypes + 1;
 
}
 
/*********************************************************************************************/
 
static void FreeToolTypes(UBYTE **ttypes)
{
    if (ttypes)
    {
    	DeletePool((APTR)ttypes[-1]);
    }
}
 
/*********************************************************************************************/
 
static struct DiskObject *LoadProgIcon(BPTR *icondir, STRPTR iconname)
{
    struct DiskObject *progicon = NULL;
 
    if (wbstartup)
    {
    	BPTR olddir;
 
	*icondir = wbstartup->sm_ArgList[0].wa_Lock;
 
	olddir = CurrentDir(*icondir);	
    	progicon = GetDiskObject(wbstartup->sm_ArgList[0].wa_Name);		
	CurrentDir(olddir);
 
	strncpy(iconname, wbstartup->sm_ArgList[0].wa_Name, 255);
    }
    else
    {	
	if (GetProgramName(iconname, 255))
	{
    	    BPTR olddir;
 
	    *icondir = GetProgramDir();
 
	    olddir = CurrentDir(*icondir);
    	    progicon = GetDiskObject(iconname);	    
	    CurrentDir(olddir);
	}	    
    }
 
    return progicon;
}
 
/*********************************************************************************************/
 
static void SaveSettings(void)
{
    struct DiskObject 	 *progicon;
    UBYTE   	    	**ttypes, **old_ttypes;
    UBYTE   	    	  iconname[256];
    BPTR    	    	  icondir = BNULL;
 
    progicon = LoadProgIcon(&icondir, iconname);
 
    if (!progicon) return;
 
    old_ttypes = (UBYTE **)progicon->do_ToolTypes;
    if ((ttypes = BuildToolTypes(old_ttypes)))
    {
    	BPTR olddir;
 
#if 0 /* DEBUG */
    	UBYTE *tt, **ttypes_copy = ttypes;
 
	while((tt = *ttypes_copy++))
	{
	    kprintf("TT: %s\n", tt);
	}
#endif
 
    	olddir = CurrentDir(icondir);
 
    	progicon->do_ToolTypes = ttypes;
	PutDiskObject(iconname, progicon);
	progicon->do_ToolTypes = old_ttypes;
 
	CurrentDir(olddir);
 
    	FreeToolTypes(ttypes);
    }
 
    FreeDiskObject(progicon);
 
}
 
/*********************************************************************************************/
 
static void LoadSettings(void)
{
    struct DiskObject *progicon;
    UBYTE   	       iconname[256];
    BPTR    	       icondir = BNULL;
    UBYTE   	      **ttypes, *tt;
 
    progicon = LoadProgIcon(&icondir, iconname);
    if (!progicon) return;
 
    if ((ttypes = (UBYTE **)progicon->do_ToolTypes))
    {
    	while((tt = *ttypes++))
	{
	    struct KeyInfo   ki = {0};
	    UBYTE   	    *quote_end;
 
	    ki.action = 0xFF;
 
	    if ((tt[0] == QUOTE_START) && ((quote_end = strchr(tt, (char)QUOTE_END))))
	    {
	    	WORD len = quote_end - tt - 1;
 
		if (len >= sizeof(ki.descr)) continue;
		if (quote_end[1] != ' ') continue;
 
	    	strncpy(ki.descr, tt + 1, len);
 
	    	if (strncmp(quote_end + 2, "CYCLE", 5 + 1) == 0)
		{
		    ki.action = ACTION_CYCLE_WIN;
		}
		else if (strncmp(quote_end + 2, "CYCLESCREEN", 11 + 1) == 0)
		{
		    ki.action = ACTION_CYCLE_SCR;
		}
		else if (strncmp(quote_end + 2, "MAKEBIG", 7 + 1) == 0)
		{
		    ki.action = ACTION_ENLARGE_WIN;
		}
		else if (strncmp(quote_end + 2, "MAKESMALL", 9 + 1) == 0)
		{
		    ki.action = ACTION_SHRINK_WIN;
		}
		else if (strncmp(quote_end + 2, "ZIPWINDOW", 9 + 1) == 0)
		{
		    ki.action = ACTION_TOGGLE_WIN;
		}
		else if (strncmp(quote_end + 2, "RESCUEWIN", 9 + 1) == 0)
		{
			ki.action = ACTION_RESCUE_WIN;
		}
		else if (strncmp(quote_end + 2, "INSERT ", 7) == 0)
		{
		    ki.action = ACTION_INSERT_TEXT;
		    strncpy(ki.param, quote_end + 2 + 7, sizeof(ki.param) - 1);
 
		}
		else if (strncmp(quote_end + 2, "RUN ", 4) == 0)
		{
		    ki.action = ACTION_RUN_PROG;
		    strncpy(ki.param, quote_end + 2 + 4, sizeof(ki.param) - 1);
		}
		else if (strncmp(quote_end + 2, "AREXX ", 6) == 0)
		{
		    ki.action = ACTION_RUN_AREXX;
		    strncpy(ki.param, quote_end + 2 + 6, sizeof(ki.param) - 1);
		}
 
		if (ki.action != 0xFF)
		{
    	    	    DoMethod(list, MUIM_List_InsertSingle, (IPTR)&ki, MUIV_List_Insert_Bottom);
		}
 
	    } /* if ((tt[0] == QUOTE_START) && ((quote_end = strchr(tt, QUOTE_END)))) */
 
	} /* while((tt = *ttypes++)) */
 
	{
	    LONG index;
 
	    for(index = 0; ; index++)
	    {
	    	struct KeyInfo *ki = NULL;
 
		DoMethod(list, MUIM_List_GetEntry, index, (IPTR)&ki);
		if (!ki) break;
 
		RethinkKey(ki);
	    }
	}
 
    } /* if ((ttypes = (UBYTE **)progicon->do_ToolTypes)) */
 
    FreeDiskObject(progicon);
}
 
/*********************************************************************************************/
 
static void HandleAll(void)
{
    ULONG sigs = 0;
    LONG  returnid;
    IPTR  num_list_entries = 0;
 
    get(list, MUIA_List_Entries, &num_list_entries);
    if ((num_list_entries == 0) || cx_popup)
    {
        set(wnd, MUIA_Window_Open, TRUE);
    }
    else
    {
        set(wnd, MUIA_Window_Open, FALSE);
    }
 
    for(;;)
    {
    	returnid = (LONG) DoMethod(app, MUIM_Application_NewInput, (IPTR) &sigs);
 
	if (returnid == MUIV_Application_ReturnID_Quit) break;
 
	switch(returnid)
	{
	    case RETURNID_NEWKEY:
	    	NewKey();
	    	break;
 
	    case RETURNID_DELKEY:
    	    	DelKey();
		break;
 
	    case RETURNID_LVACK:
	    	ListToString();
		break;
 
	    case RETURNID_STRINGACK:
	    	StringToKey();
		break;
 
	    case RETURNID_CMDACK:
	    	CmdToKey();
		break;
 
	    case RETURNID_SAVE:
    	    	SaveSettings();
		break;
 
	    case RETURNID_DOUBLESTART:
	        CallHookPkt(&show_hook, NULL, NULL);
		break;
	}
 
	if (sigs)
	{
	    sigs = Wait(sigs | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F);
	    if (sigs & SIGBREAKF_CTRL_C) break;
	    if (sigs & SIGBREAKF_CTRL_E) HandleAction();
	    if (sigs & SIGBREAKF_CTRL_F)
	    {
	        CallHookPkt(&show_hook, NULL, NULL);
	    }
	}
    }
 
}
 
/*********************************************************************************************/
 
int main(int argc, char **argv)
{
    GetArguments(argc, argv);
    InitLocale(CATALOG_NAME, CATALOG_VERSION);
    InitCX();
    InitMenus();
    MakeGUI();
    LoadSettings();
    HandleAll();       
    Cleanup(NULL);
 
    return 0;
}


/*
    Copyright © 1995-2008, The AROS Development Team. All rights reserved.
    $Id: ClickToFront.c 31657 2009-08-03 13:08:00Z mazze $
 
    ClickToFront commodity -- puts windows to front when clicked in.
*/
 
/******************************************************************************
 
    NAME
 
        ClickToFront
 
    SYNOPSIS
 
        CX_PRIORITY/N/K, QUALIFIER/K, NUMCLICKS/N/K
 
    LOCATION
 
        SYS:Tools/Commodities
 
    FUNCTION
 
        Automatically raises and activates a window when clicking in it.
 
    INPUTS
 
        CX_PRIORITY  --  The priority of the commodity
 
        QUALIFIER    --  Qualifier to match the clicks (LEFT_ALT, RIGHT_ALT,
                         CTRL or NONE).
 
        NUMCLICKS    --  Number of clicks to bring window to front. Value
                         must be greater than 0.
 
    RESULT
 
    NOTES
 
    EXAMPLE
 
    BUGS
 
    SEE ALSO
 
    INTERNALS
 
******************************************************************************/
 
#include <aros/symbolsets.h>
#include <workbench/startup.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <libraries/commodities.h>
#include <libraries/locale.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/layers.h>
#include <proto/commodities.h>
#include <proto/input.h>
#include <proto/alib.h>
#include <proto/locale.h>
#include <proto/icon.h>
 
#include <stdio.h>
 
#define  DEBUG 0
#include <aros/debug.h>
 
#define CATCOMP_ARRAY
#include "strings.h"
 
#define CATALOG_NAME     "System/Tools/Commodities.catalog"
#define CATALOG_VERSION  3
 
 
/***************************************************************************/
 
UBYTE version[] = "$VER: ClickToFront 0.4 (13.10.2008)";
 
#define ARG_TEMPLATE "CX_PRIORITY=PRI/N/K,QUALIFIER/K,NUMCLICKS=CLICKS/N/K"
 
#define  ARG_PRI        0
#define  ARG_QUALIFIER  1
#define  ARG_CLICKS     2
#define  NUM_ARGS       3
 
struct Device         *InputBase = NULL;
struct Catalog        *catalog;
struct IOStdReq       *inputIO;
 
 
/* The ClickToFront broker */
static struct NewBroker nb =
{
    NB_VERSION,
    NULL,
    NULL,
    NULL,
    NBU_NOTIFY | NBU_UNIQUE,
    0,
    0,
    NULL,                             
    0 
};
 
 
typedef struct _CFState
{
    CxObj          *cs_broker;
    struct MsgPort *cs_msgPort;
} CFState;
 
 
typedef struct CF
{
    struct Window *ci_thisWindow;
    struct Window *ci_lastWindow;
    UWORD          ci_qualifiers; /* Qualifiers that must match */
    BOOL           ci_mouseHasMoved;
    ULONG          ci_clicksToDo; /* Bring to front after how many clicks? */
    ULONG          ci_clicksDone; /* How many clicks are we already aware of? */
    ULONG          ci_lcSeconds;  /* Time stamp for the last click */
    ULONG          ci_lcMicros;
} CF;
 
 
static CF cfInfo = 
{
    NULL,
    NULL,
    0,
    FALSE,
    0,
    0,
    0,
    0
};
 
/************************************************************************************/
 
static void freeResources(CFState *cs);
static BOOL initiate(int argc, char **argv, CFState *cs);
static void getQualifier(STRPTR qualString);
static void clicktoFront(CxMsg *msg, CxObj *co);
static CONST_STRPTR _(ULONG id);
static BOOL Locale_Initialize(VOID);
static VOID Locale_Deinitialize(VOID);
static void showSimpleMessage(CONST_STRPTR msgString);
 
/************************************************************************************/
 
static CONST_STRPTR _(ULONG id)
{
    if (LocaleBase != NULL && catalog != NULL)
    {
        return GetCatalogStr(catalog, id, CatCompArray[id].cca_Str);
    } 
    else 
    {
        return CatCompArray[id].cca_Str;
    }
}
 
/************************************************************************************/
 
static BOOL Locale_Initialize(VOID)
{
    if (LocaleBase != NULL)
    {
    	catalog = OpenCatalog(NULL, CATALOG_NAME, OC_Version, CATALOG_VERSION, 
                    TAG_DONE);
    }
    else
    {
        catalog = NULL;
    }
 
    return TRUE;
}
 
/************************************************************************************/
 
static VOID Locale_Deinitialize(VOID)
{
    if(LocaleBase != NULL && catalog != NULL) CloseCatalog(catalog);
}
 
/************************************************************************************/
 
static void showSimpleMessage(CONST_STRPTR msgString)
{
    struct EasyStruct easyStruct;
 
    easyStruct.es_StructSize	= sizeof(easyStruct);
    easyStruct.es_Flags		= 0;
    easyStruct.es_Title		= _(MSG_CLICK2FNT_CXNAME);
    easyStruct.es_TextFormat	= msgString;
    easyStruct.es_GadgetFormat	= _(MSG_OK);		
 
    if (IntuitionBase != NULL && !Cli() )
    {
        EasyRequestArgs(NULL, &easyStruct, NULL, NULL);
    }
    else
    {
        PutStr(msgString);
    }
}
 
/************************************************************************************/
 
static BOOL initiate(int argc, char **argv, CFState *cs)
{
    CxObj *customObj;
 
    memset(cs, 0, sizeof(CFState));
 
    if (argc != 0)
    {
        struct RDArgs *rda;
        IPTR           args[] = { (IPTR) NULL, (IPTR) NULL, FALSE };
 
        rda = ReadArgs(ARG_TEMPLATE, args, NULL);
 
        if (rda != NULL)
        {
            if (args[ARG_PRI] != (IPTR) NULL)
            {
	            nb.nb_Pri = *(LONG *)args[ARG_PRI];
            }
 
            getQualifier((STRPTR)args[ARG_QUALIFIER]);
 
            if (args[ARG_CLICKS] != (IPTR) NULL)
            {
                cfInfo.ci_clicksToDo = *(LONG *)args[ARG_CLICKS];
            }
 
        }
 
        FreeArgs(rda);
    }
    else
    {
        D(bug("Cli() == NULL\n"));
        UBYTE  **array = ArgArrayInit(argc, (UBYTE **)argv);
 
        nb.nb_Pri = ArgInt(array, "CX_PRIORITY", 0);
 
        cfInfo.ci_clicksToDo = ArgInt(array, "NUMCLICKS", 0);
        D(bug("CLICKS in array from ArgArrayInit = %i\n",ArgInt(array,"NUMCLICKS", 0)));
 
        getQualifier(ArgString(array, "QUALIFIER", NULL));
 
        ArgArrayDone();
    }
 
    if (cfInfo.ci_clicksToDo == 0)
        cfInfo.ci_clicksToDo = 2; /* Default value is 2 */
 
   	D(bug("CLICKS to do = %i\n",cfInfo.ci_clicksToDo));
    nb.nb_Name = _(MSG_CLICK2FNT_CXNAME);
    nb.nb_Title = _(MSG_CLICK2FNT_CXTITLE);
    nb.nb_Descr = _(MSG_CLICK2FNT_CXDESCR);
 
    cs->cs_msgPort = CreateMsgPort();
 
    if (cs->cs_msgPort == NULL)
    {
        showSimpleMessage(_(MSG_CANT_CREATE_MSGPORT));
 
        return FALSE;
    }
 
    nb.nb_Port = cs->cs_msgPort;
 
    cs->cs_broker = CxBroker(&nb, 0);
 
    if (cs->cs_broker == NULL)
    {
        return FALSE;
    }
 
    customObj = CxCustom(clicktoFront, 0);
 
    if (customObj == NULL)
    {
        showSimpleMessage(_(MSG_CANT_CREATE_MSGPORT));
 
        return FALSE;
    }
 
    AttachCxObj(cs->cs_broker, customObj);
    ActivateCxObj(cs->cs_broker, TRUE);
 
    cfInfo.ci_thisWindow = IntuitionBase->ActiveWindow;
 
    inputIO = (struct IOStdReq *)CreateIORequest(cs->cs_msgPort, 
                                    sizeof(struct IOStdReq));
 
    if (inputIO == NULL)
    {
        showSimpleMessage(_(MSG_CANT_ALLOCATE_MEM));
 
        return FALSE;
    }
 
    if ((OpenDevice("input.device", 0, (struct IORequest *)inputIO, 0)) != 0)
    {
        showSimpleMessage(_(MSG_CANT_OPEN_INPUTDEVICE));
 
        return FALSE;
    }
 
    InputBase = (struct Device *)inputIO->io_Device;
 
    return TRUE;
}
 
/************************************************************************************/
 
static void getQualifier(STRPTR qualString)
{
    if (qualString == NULL)
    {
        return;
    }
 
    if (strcmp("CTRL", qualString) == 0)
    {
        cfInfo.ci_qualifiers = IEQUALIFIER_CONTROL;
    }
 
    if (strcmp("LEFT_ALT", qualString) == 0)
    {
        cfInfo.ci_qualifiers = IEQUALIFIER_LALT;
    }
 
    if (strcmp("RIGHT_ALT", qualString) == 0)
    {
        cfInfo.ci_qualifiers = IEQUALIFIER_RALT;
    }
 
    /* Default is NONE */
}
 
/************************************************************************************/
 
static void freeResources(CFState *cs)
{
    struct Message *cxm;
 
    if (cs->cs_broker != NULL)
    {
        DeleteCxObjAll(cs->cs_broker);
    }
 
    if (cs->cs_msgPort != NULL)
    {
        while ((cxm = GetMsg(cs->cs_msgPort)))
        {
    	    ReplyMsg(cxm);
        }
 
        DeleteMsgPort(cs->cs_msgPort);
    }
 
    if (inputIO != NULL)
    {
        CloseDevice((struct IORequest *)inputIO);
        DeleteIORequest((struct IORequest *)inputIO);
    }
}
 
/************************************************************************************/
 
static void clicktoFront(CxMsg *cxm, CxObj *co)
{
    /* NOTE! Should use arbitration for IntuitionBase... */
 
    struct InputEvent *ie = (struct InputEvent *)CxMsgData(cxm);
 
    if (ie->ie_Class == IECLASS_RAWMOUSE)
    {
        if (ie->ie_Code == SELECTDOWN)
        {
            struct Screen *screen;
            struct Layer  *layer;
 
            /* Mask relvant qualifiers (key qualifiers) */
            if ((PeekQualifier() & 0xff) != cfInfo.ci_qualifiers)
            {
		        D(bug("Qualifiers: %i, Wanted qualifiers: %i\n",
			            (int)PeekQualifier(),
			            (int)cfInfo.ci_qualifiers | IEQUALIFIER_LEFTBUTTON));
 
                return;
            }
 
            cfInfo.ci_lastWindow = cfInfo.ci_thisWindow;
 
            if (IntuitionBase->ActiveWindow != NULL)
            {
                screen = IntuitionBase->ActiveWindow->WScreen;
            }
            else
            {
                screen = IntuitionBase->ActiveScreen;
            }
 
            layer = WhichLayer(&screen->LayerInfo,
	                               screen->MouseX,
                                   screen->MouseY);
 
            if (layer == NULL)
            {
                return;
            }
 
            cfInfo.ci_thisWindow = (layer != NULL) ?
	        (struct Window *)layer->Window : NULL;
 
            /* 
               Error: IB->ActiveWindow is non-NULL even if there is no
               active window!
            */
            if (layer->front != NULL)
            {
                /* 
                   Counting clicks is only meaningfull if cfInfo.ci_clicksToDo
                   is no less than 2
                */
                if (cfInfo.ci_clicksToDo > 1)
		        {
                    cfInfo.ci_clicksDone++;
 
                    D(bug("clicksDone = %i\n",cfInfo.ci_clicksDone));
 
                    /* 
                       Return if the delay between two clicks is longer than 
                       Input-Preferences-set double-click delay
                    */
                    if (!DoubleClick(cfInfo.ci_lcSeconds,
                                      cfInfo.ci_lcMicros,
                                ie->ie_TimeStamp.tv_secs,
                               ie->ie_TimeStamp.tv_micro))
		            {
                        cfInfo.ci_lcSeconds = ie->ie_TimeStamp.tv_secs;
                        cfInfo.ci_lcMicros  = ie->ie_TimeStamp.tv_micro;
                        cfInfo.ci_clicksDone = 1L;
                        D(bug("DoubleClick is FALSE\nclicksDone = %i\n",
                                                  cfInfo.ci_clicksDone));
                        return;
		            }
 
                    D(bug("DoubleClick is TRUE\n"));
 
		            D(bug("Time %i %i, last time %i %i\n",
				        ie->ie_TimeStamp.tv_secs,
				        ie->ie_TimeStamp.tv_micro,
				        cfInfo.ci_lcSeconds,
				        cfInfo.ci_lcMicros));
 
                    cfInfo.ci_lcSeconds = ie->ie_TimeStamp.tv_secs;
                    cfInfo.ci_lcMicros  = ie->ie_TimeStamp.tv_micro;
 
                    /* Return if the user didn't make enough clicks */
                    if (cfInfo.ci_clicksDone < cfInfo.ci_clicksToDo)
                    {
                        return;
                    }
 
		            /* Return if the clicks weren't made in the same window */
		            if (cfInfo.ci_lastWindow != cfInfo.ci_thisWindow)
		            {
                        cfInfo.ci_clicksDone = 1L;
                        D(bug("Window changed. clicksDone = %i\n",
                                            cfInfo.ci_clicksDone));
                        return;
		            }
 
                    /* 
                       If we didn't return yet, that means that all conditions
                       are good to bring the window to front, and it will be
                       done now. We just reset cfInfo.ci_clicksDone to 0 in 
                       order to be ready for another bring-to-front loop...
                    */
                    cfInfo.ci_clicksDone = 0L;
 
                }/* if (cfInfo.ci_nbClicks) */
 
                WindowToFront(cfInfo.ci_thisWindow);
 
                if (cfInfo.ci_thisWindow != IntuitionBase->ActiveWindow)
                {
                    ActivateWindow(cfInfo.ci_thisWindow);
                }
 
		        D(bug("Window %s was put to front.\n",
			             cfInfo.ci_thisWindow->Title));
            }
            else
            {
		        D(bug("New: %p Old: %p\n", cfInfo.ci_thisWindow,
                                   IntuitionBase->ActiveWindow));
            }
        } /* if (ie->ie_Code == SELECTDOWN) */
    } /* if (ie->ie_Class == IECLASS_RAWMOUSE) */
}
 
/************************************************************************************/
 
static void handleCx(CFState *cs)
{
    CxMsg *msg;
    BOOL   quit = FALSE;
    LONG   signals;
 
    while (!quit)
    {
	signals = Wait((1 << nb.nb_Port->mp_SigBit)  | SIGBREAKF_CTRL_C);
 
	if (signals & (1 << nb.nb_Port->mp_SigBit))
	{
	    while ((msg = (CxMsg *)GetMsg(cs->cs_msgPort)))
	    {
		switch (CxMsgType(msg))
		{
		    case CXM_COMMAND:
			switch (CxMsgID(msg))
			{
			    case CXCMD_DISABLE:
				ActivateCxObj(cs->cs_broker, FALSE);
				break;
 
			    case CXCMD_ENABLE:
				ActivateCxObj(cs->cs_broker, TRUE);
				break;
 
			    case CXCMD_UNIQUE:
				/* Running the program twice is the same as shutting
				   down the existing program... */
				/* Fall through */
 
			    case CXCMD_KILL:
				quit = TRUE;
				break;
 
			} /* switch (CxMsgID(msg)) */
			break;
		} /* switch (CxMsgType(msg))*/
 
		ReplyMsg((struct Message *)msg);
 
	    } /* while ((msg = (CxMsg *)GetMsg(cs->cs_msgPort))) */
	}	    
 
	if (signals & SIGBREAKF_CTRL_C)
	{
	    quit = TRUE;
	}
 
    } /* while(!quit) */
}
 
/************************************************************************************/
 
int main(int argc, char **argv)
{
    CFState cState;
    int      error = RETURN_OK;
 
    D((argc == 0) ? bug("argc == 0\n") : bug("argc != 0\n") );
 
    if (initiate(argc, argv, &cState))
    {
        handleCx(&cState);
    }
    else
    {
        error = RETURN_FAIL;
    }
 
    freeResources(&cState);
 
    return error;
}
 
/************************************************************************************/
 
ADD2INIT(Locale_Initialize,   90);
ADD2EXIT(Locale_Deinitialize, 90);


/*
    Copyright © 1995-2012, The AROS Development Team. All rights reserved.
    $Id: FKey.c 43632 2012-01-14 20:15:31Z deadwood $
*/
 
/*********************************************************************************************/
 
#include <intuition/classusr.h>
#include <graphics/layers.h>
#include <graphics/clip.h>
#include <libraries/asl.h>
#include <libraries/locale.h>
#include <libraries/gadtools.h>
#include <libraries/commodities.h>
#include <libraries/mui.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>
#include <devices/inputevent.h>
#include <aros/asmcall.h>
 
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/locale.h>
#include <proto/muimaster.h>
#include <proto/intuition.h>
#include <proto/layers.h>
#include <proto/commodities.h>
#include <proto/alib.h>
#include <proto/icon.h>
#include <proto/utility.h>
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
 
#define CATCOMP_ARRAY
#include "strings.h"
 
#define CATALOG_NAME     "System/Tools/Commodities.catalog"
#define CATALOG_VERSION  3
 
#include <aros/debug.h>
 
/*********************************************************************************************/
 
#define VERSION 	1
#define REVISION 	6
#define DATESTR 	"14.01.2012"
#define VERSIONSTR	"$VER: FKey 1.6 (" DATESTR ")"
 
/*********************************************************************************************/
 
#define ARG_TEMPLATE "CX_PRIORITY/N/K,CX_POPKEY/K,CX_POPUP/S,PORT/K,QUIET/S"
 
#define ARG_CXPRI   	0
#define ARG_CXPOPKEY 	1
#define ARG_CXPOPUP 	2
#define ARG_CXPORT  	3
#define ARG_QUIET   	4
 
#define NUM_ARGS    	5
 
/*********************************************************************************************/
 
#define ACTION_CYCLE_WIN     0
#define ACTION_CYCLE_SCR     1
#define ACTION_ENLARGE_WIN   2
#define ACTION_SHRINK_WIN    3
#define ACTION_TOGGLE_WIN    4
#define ACTION_RESCUE_WIN    5
#define ACTION_INSERT_TEXT   6
#define ACTION_RUN_PROG      7
#define ACTION_RUN_AREXX     8
 
#define RETURNID_NEWKEY      1
#define RETURNID_DELKEY      2
#define RETURNID_STRINGACK   3
#define RETURNID_LVACK	     4
#define RETURNID_CMDACK      5
#define RETURNID_SAVE	     6
#define RETURNID_DOUBLESTART 7
 
/*********************************************************************************************/
 
struct KeyInfo
{
    struct InputEvent *translist;
    CxObj   	      *filter, *trans, *custom;    
    WORD    	       action;
    char    	       descr[80];
    char    	       param[256];
};
 
/*********************************************************************************************/
 
struct LocaleBase    	*LocaleBase;
 
static char 	     	*cx_popkey = "ctrl alt f";
static LONG 	         cx_pri = 0;
static BOOL 	      	 cx_popup = FALSE;
 
static CxObj	     	*broker, *activated_custom_cobj;
static Object	     	*app, *wnd, *cmdcycle, *list, *liststr;
static Object	     	*insertstr, *runprogstr, *runarexxstr;
static Object	     	*cmdpage;
static struct Task   	*maintask;
static struct Hook   	 keylist_construct_hook, keylist_destruct_hook, keylist_disp_hook;
static struct Hook   	 broker_hook;
static struct Hook       show_hook;
static struct MsgPort 	*brokermp;
static struct Catalog 	*catalog;
static struct RDArgs 	*myargs;
static struct WBStartup *wbstartup;
static LONG 	     	 prog_exitcode;
static UBYTE	       **wbargs;
static IPTR 	      	 args[NUM_ARGS];
static UBYTE	      	 s[257];
 
/*********************************************************************************************/
 
static void broker_func(struct Hook *hook, Object *obj, CxMsg *msg);
static UBYTE *BuildToolType(struct KeyInfo *ki);
static UBYTE **BuildToolTypes(UBYTE **src_ttypes);
static void Cleanup(CONST_STRPTR msg);
static void CleanupLocale(void);
static void CmdToKey(void);
static void DelKey(void);
static struct DiskObject *LoadProgIcon(BPTR *icondir, STRPTR iconname);
static void FreeArguments(void);
static void FreeToolTypes(UBYTE **ttypes);
static void GetArguments(int argc, char **argv);
static void HandleAction(void);
static void HandleAll(void);
static void InitCX(void);
static void InitLocale(STRPTR catname, ULONG version);
static void InitMenus(void);
static APTR keylist_construct_func(struct Hook *hook, APTR pool, struct KeyInfo *ki);
static void keylist_destruct_func(struct Hook *hook, APTR pool, struct KeyInfo *ki);
static void keylist_disp_func(struct Hook *hook, char **array, struct KeyInfo *ki);
static void KillCX(void);
static void KillGUI(void);
static void ListToString(void);
static void LoadSettings(void);
static void MakeGUI(void);
static CONST_STRPTR MSG(ULONG id);
static void NewKey(void);
static void RethinkAction(void);
static void RethinkKey(struct KeyInfo *ki);
static void SaveSettings(void);
static WORD ShowMessage(CONST_STRPTR title, CONST_STRPTR text, CONST_STRPTR gadtext);
static void StringToKey(void);
 
/*********************************************************************************************/
 
static WORD ShowMessage(CONST_STRPTR title, CONST_STRPTR text, CONST_STRPTR gadtext)
{
    struct EasyStruct es;
 
    es.es_StructSize   = sizeof(es);
    es.es_Flags        = 0;
    es.es_Title        = title;
    es.es_TextFormat   = text;
    es.es_GadgetFormat = gadtext;
 
    return EasyRequestArgs(NULL, &es, NULL, NULL);  
}
 
/*********************************************************************************************/
 
static void Cleanup(CONST_STRPTR msg)
{
    if (msg)
    {
	if (IntuitionBase && !((struct Process *)FindTask(NULL))->pr_CLI)
	{
	    ShowMessage("Fkey", msg, MSG(MSG_OK));     
	}
	else
	{
	    printf("FKey: %s\n", msg);
	}
    }
 
    KillGUI();
    FreeArguments();
    KillCX();
    CleanupLocale();
 
    exit(prog_exitcode);
}
 
 
/*********************************************************************************************/
 
static void InitCX(void)
{
    maintask = FindTask(NULL);
}
 
/*********************************************************************************************/
 
static void KillCX(void)
{
}
 
/*********************************************************************************************/
 
static void InitLocale(STRPTR catname, ULONG version)
{
    LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library", 39);
    if (LocaleBase)
    {
	catalog = OpenCatalog(NULL, catname, OC_Version, version,
					     TAG_DONE);
    }
}
 
/*********************************************************************************************/
 
static void CleanupLocale(void)
{
    if (catalog) CloseCatalog(catalog);
    if (LocaleBase) CloseLibrary((struct Library *)LocaleBase);
}
 
/*********************************************************************************************/
 
static CONST_STRPTR MSG(ULONG id)
{
    if (catalog != NULL)
    {
        return GetCatalogStr(catalog, id, CatCompArray[id].cca_Str);
    }
    else 
    {
        return CatCompArray[id].cca_Str;
    }
}
 
/*********************************************************************************************/
 
static struct NewMenu nm[] =
{
    {NM_TITLE, (STRPTR)MSG_MEN_PROJECT              },
     {NM_ITEM, (STRPTR)MSG_FKEY_MEN_PROJECT_SAVE    },
     {NM_ITEM, NM_BARLABEL  	    	    	    },
     {NM_ITEM, (STRPTR)MSG_MEN_PROJECT_HIDE         },
     {NM_ITEM, (STRPTR)MSG_MEN_PROJECT_ICONIFY      },
     {NM_ITEM, NM_BARLABEL  	    	    	    },
     {NM_ITEM, (STRPTR)MSG_MEN_PROJECT_QUIT         },
    {NM_END 	    	    	    	    	    }
};
 
/*********************************************************************************************/
 
static void InitMenus(void)
{
    struct NewMenu *actnm = nm;
 
    for(actnm = nm; actnm->nm_Type != NM_END; actnm++)
    {
	if (actnm->nm_Label != NM_BARLABEL)
	{
	    ULONG  id = (IPTR)actnm->nm_Label;
	    CONST_STRPTR str = MSG(id);
 
	    if (actnm->nm_Type == NM_TITLE)
	    {
		actnm->nm_Label = str;
	    } else {
		actnm->nm_Label = str + 2;
		if (str[0] != ' ') actnm->nm_CommKey = str;
	    }
	    actnm->nm_UserData = (APTR)(IPTR)id;
 
	} /* if (actnm->nm_Label != NM_BARLABEL) */
 
    } /* for(actnm = nm; nm->nm_Type != NM_END; nm++) */
 
}
 
/*********************************************************************************************/
 
static void FreeArguments(void)
{
    if (myargs) FreeArgs(myargs);
    ArgArrayDone();
}
 
/*********************************************************************************************/
 
static void KillGUI(void)
{
    DisposeObject(app);
}
 
/*********************************************************************************************/
 
static void GetArguments(int argc, char **argv)
{
    if (argc)
    {
    	if (!(myargs = ReadArgs(ARG_TEMPLATE, args, NULL)))
    	{
	    Fault(IoErr(), 0, s, 256);
	    Cleanup(s);
    	}
 
	if (args[ARG_CXPRI]) cx_pri = (LONG)*(IPTR *)args[ARG_CXPRI];
	if (args[ARG_CXPOPKEY]) cx_popkey = (STRPTR)args[ARG_CXPOPKEY];
	if (args[ARG_CXPOPUP]) cx_popup = TRUE;
    }
    else
    {
    	wbstartup = (struct WBStartup *)argv;
    	wbargs = ArgArrayInit(argc, (UBYTE **)argv);
 
	cx_pri = ArgInt(wbargs, "CX_PRIORITY", 0);
	cx_popkey = ArgString(wbargs, "CX_POPKEY", cx_popkey);
 
	if (strnicmp(ArgString(wbargs, "CX_POPUP", "NO"), "Y", 1) == 0)
	{
	    cx_popup = TRUE;
	}
    }    
}
 
/*********************************************************************************************/
 
static APTR keylist_construct_func(struct Hook *hook, APTR pool, struct KeyInfo *ki)
{
    struct KeyInfo *new;
 
    new = AllocPooled(pool, sizeof(*ki));
    if (new) *new = *ki;
 
    return new;
}
 
/*********************************************************************************************/
 
static void keylist_destruct_func(struct Hook *hook, APTR pool, struct KeyInfo *ki)
{
    if (ki)
    {
    	if (ki->filter) DeleteCxObjAll(ki->filter);
    	if (ki->translist) FreeIEvents(ki->translist);
 
    	FreePooled(pool, ki, sizeof(*ki));
    }
}
 
/*********************************************************************************************/
 
static void keylist_disp_func(struct Hook *hook, char **array, struct KeyInfo *ki)
{
    *array = ki->descr;
}
 
/*********************************************************************************************/
 
static void broker_func(struct Hook *hook, Object *obj, CxMsg *msg)
{
    D(bug("FKey: broker_func called\n"));
    if (CxMsgType(msg) == CXM_COMMAND)
    {
        if (CxMsgID(msg) == CXCMD_APPEAR)
        {
            CallHookPkt(&show_hook, NULL, NULL);
        }
        else if (CxMsgID(msg) == CXCMD_DISAPPEAR)
        {
            set(wnd, MUIA_Window_Open, FALSE);
        }
    }
}
 
/*** show_func ************************************************************/
AROS_UFH3(
    void, show_func,
    AROS_UFHA(struct Hook *,    hook,   A0),
    AROS_UFHA(APTR *,           obj,    A2),
    AROS_UFHA(APTR,             param,  A1)
)
{
    AROS_USERFUNC_INIT
 
    if (XGET(app, MUIA_Application_Iconified) == TRUE)
        set(app, MUIA_Application_Iconified, FALSE);
    else
        set(wnd, MUIA_Window_Open, TRUE);
 
    AROS_USERFUNC_EXIT
}
 
/*********************************************************************************************/
 
AROS_UFH2S(void, custom_func,
    AROS_UFHA(CxMsg *, msg, A0),
    AROS_UFHA(CxObj *, co, A1))
{
    AROS_USERFUNC_INIT
 
    activated_custom_cobj = co;
    Signal(maintask, SIGBREAKF_CTRL_E);
 
    AROS_USERFUNC_EXIT
}
 
 
/*********************************************************************************************/
 
static void MakeGUI(void)
{
    static CONST_STRPTR cmdarray[] =
    {
    	(CONST_STRPTR)MSG_FKEY_CMD_CYCLE_WIN,
    	(CONST_STRPTR)MSG_FKEY_CMD_CYCLE_SCR,
    	(CONST_STRPTR)MSG_FKEY_CMD_ENLARGE_WIN,
    	(CONST_STRPTR)MSG_FKEY_CMD_SHRINK_WIN,
    	(CONST_STRPTR)MSG_FKEY_CMD_TOGGLE_WIN_SIZE,
	(CONST_STRPTR)MSG_FKEY_CMD_RESCUE_WIN,
    	(CONST_STRPTR)MSG_FKEY_CMD_INSERT_TEXT,
    	(CONST_STRPTR)MSG_FKEY_CMD_RUN_PROG,
    	(CONST_STRPTR)MSG_FKEY_CMD_RUN_AREXX,
	0,
    };
    static TEXT wintitle[100];
    WORD i;
    Object *menu, *newkey, *delkey, *savekey;
 
    for(i = 0; cmdarray[i]; i++)
    {
    	cmdarray[i] = MSG((IPTR) cmdarray[i]);
    }
 
    keylist_construct_hook.h_Entry = HookEntry;
    keylist_construct_hook.h_SubEntry = (HOOKFUNC)keylist_construct_func;
 
    keylist_destruct_hook.h_Entry = HookEntry;
    keylist_destruct_hook.h_SubEntry = (HOOKFUNC)keylist_destruct_func;
 
    keylist_disp_hook.h_Entry = HookEntry;
    keylist_disp_hook.h_SubEntry = (HOOKFUNC)keylist_disp_func;
 
    broker_hook.h_Entry = HookEntry;
    broker_hook.h_SubEntry = (HOOKFUNC)broker_func;
 
    show_hook.h_Entry = (HOOKFUNC)show_func;
 
    menu = MUI_MakeObject(MUIO_MenustripNM, &nm, 0);
 
    snprintf(wintitle, sizeof(wintitle), MSG(MSG_FKEY_WINTITLE), cx_popkey);
 
    app = ApplicationObject,
	MUIA_Application_Title, (IPTR)MSG(MSG_FKEY_CXNAME),
	MUIA_Application_Version, (IPTR)VERSIONSTR,
	MUIA_Application_Copyright, (IPTR)"Copyright © 1995-2012, The AROS Development Team",
	MUIA_Application_Author, (IPTR)"The AROS Development Team",
	MUIA_Application_Description, (IPTR)MSG(MSG_FKEY_CXDESCR),
	MUIA_Application_BrokerPri, cx_pri,
	MUIA_Application_BrokerHook, (IPTR)&broker_hook,
	MUIA_Application_Base, (IPTR)"FKey",
	MUIA_Application_SingleTask, TRUE,
	menu ? MUIA_Application_Menustrip : TAG_IGNORE, menu,
  	SubWindow, wnd = WindowObject,
	    MUIA_Window_Title, (IPTR)wintitle,
	    MUIA_Window_ID, MAKE_ID('F','W','I','N'),
	    WindowContents, HGroup,
	    	Child, VGroup,
		    GroupFrameT(MSG(MSG_FKEY_DEFINED_KEYS)),
		    Child, VGroup,
		    	GroupSpacing(0),
			Child, ListviewObject,
		    	    MUIA_Listview_List, list = ListObject,
				InputListFrame,
				MUIA_List_ConstructHook, (IPTR)&keylist_construct_hook,
				MUIA_List_DestructHook, (IPTR)&keylist_destruct_hook,
				MUIA_List_DisplayHook, (IPTR)&keylist_disp_hook,
				End,
			    End,
			Child, liststr = StringObject,
			    MUIA_Disabled, TRUE,
		    	    StringFrame,
			    End,
			End,
		    Child, HGroup,
		    	Child, newkey = SimpleButton(MSG(MSG_FKEY_NEW_KEY)),
			Child, delkey = SimpleButton(MSG(MSG_FKEY_DELETE_KEY)),
			End,
		    Child, savekey = SimpleButton(MSG(MSG_FKEY_SAVE_KEY)),
		    End,
		Child, VGroup,
		    GroupFrameT(MSG(MSG_FKEY_COMMAND)),
		    Child, cmdcycle = MUI_MakeObject(MUIO_Cycle, NULL, cmdarray),
		    Child, cmdpage = PageGroup,
		    	Child, HVSpace, /* cycle win */
			Child, HVSpace, /* cycle scr */
			Child, HVSpace, /* enlarge win */
			Child, HVSpace, /* shrink win */
			Child, HVSpace, /* Toggle win */
			Child, HVSpace, /* rescue win */
                        Child, insertstr = StringObject, StringFrame, End, /* Insert text */
			Child, PopaslObject, /* Run prog */
				MUIA_Popstring_String, runprogstr = StringObject, StringFrame, End,
				MUIA_Popstring_Button, PopButton(MUII_PopFile),
				ASLFR_RejectIcons, TRUE,
			End,		
			Child, PopaslObject, /* Run AREXX */
				MUIA_Popstring_String, runarexxstr = StringObject, StringFrame, End,
				MUIA_Popstring_Button, PopButton(MUII_PopFile),
				ASLFR_RejectIcons, TRUE,
			End,	
		    End,
		    Child, HVSpace,
		    End,
		End,
	    End,
	End;
 
    if (!app)
    {
    #if 1
    	Cleanup(NULL); /* Make no noise. Is ugly if FKey is double-started. */
    #else
    	Cleanup(MSG(MSG_CANT_CREATE_GADGET));
    #endif
    }
 
    get(app, MUIA_Application_Broker, &broker);  
    get(app, MUIA_Application_BrokerPort, &brokermp);  
 
    if (!broker || !brokermp)
	Cleanup(MSG(MSG_CANT_CREATE_GADGET));
 
    {
    	CxObj *popfilter = CxFilter(cx_popkey);
 
	if (popfilter)
	{
	    CxObj *popsig = CxSignal(maintask, SIGBREAKB_CTRL_F);
 
	    if (popsig)
	    {
	    	CxObj *trans;
 
	    	AttachCxObj(popfilter, popsig);
 
		trans = CxTranslate(NULL);
    	    	if (trans) AttachCxObj(popfilter, trans);
	    }
 
	    AttachCxObj(broker, popfilter);
	}
 
    }
 
    set(liststr, MUIA_String_AttachedList, (IPTR)list);
 
    DoMethod(app, MUIM_Notify, MUIA_Application_DoubleStart, TRUE, (IPTR) app, 2, MUIM_Application_ReturnID, RETURNID_DOUBLESTART);
 
    DoMethod(wnd, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, (IPTR) wnd, 3, MUIM_Set, MUIA_Window_Open, FALSE);
 
    DoMethod(wnd, MUIM_Notify, MUIA_Window_MenuAction, MSG_MEN_PROJECT_QUIT, (IPTR) app, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
    DoMethod(wnd, MUIM_Notify, MUIA_Window_MenuAction, MSG_MEN_PROJECT_HIDE, (IPTR) wnd, 3, MUIM_Set, MUIA_Window_Open, FALSE);
    DoMethod(wnd, MUIM_Notify, MUIA_Window_MenuAction, MSG_MEN_PROJECT_ICONIFY, (IPTR) app, 3, MUIM_Set, MUIA_Application_Iconified, TRUE);
    DoMethod(wnd, MUIM_Notify, MUIA_Window_MenuAction, MSG_FKEY_MEN_PROJECT_SAVE, (IPTR) app, 2, MUIM_Application_ReturnID, RETURNID_SAVE);
 
    DoMethod(cmdcycle, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime, (IPTR)cmdpage, 3, MUIM_Set, MUIA_Group_ActivePage, MUIV_TriggerValue);
    DoMethod(cmdcycle, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime, (IPTR)app, 2, MUIM_Application_ReturnID, RETURNID_CMDACK);
    DoMethod(newkey, MUIM_Notify, MUIA_Pressed, FALSE, (IPTR)app, 2, MUIM_Application_ReturnID, RETURNID_NEWKEY);
    DoMethod(delkey, MUIM_Notify, MUIA_Pressed, FALSE, (IPTR)app, 2, MUIM_Application_ReturnID, RETURNID_DELKEY);
    DoMethod(savekey, MUIM_Notify, MUIA_Pressed, FALSE, (IPTR)app, 2, MUIM_Application_ReturnID, RETURNID_SAVE);
    DoMethod(list, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime, (IPTR)app, 2, MUIM_Application_ReturnID, RETURNID_LVACK);
    DoMethod(liststr, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, (IPTR)app, 2, MUIM_Application_ReturnID, RETURNID_STRINGACK);
    DoMethod(insertstr, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, (IPTR)app, 2, MUIM_Application_ReturnID, RETURNID_CMDACK);
    DoMethod(runprogstr, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, (IPTR)app, 2, MUIM_Application_ReturnID, RETURNID_CMDACK);
    DoMethod(runarexxstr, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, (IPTR)app, 2, MUIM_Application_ReturnID, RETURNID_CMDACK);
 
}
 
/*********************************************************************************************/
 
static void RethinkKey(struct KeyInfo *ki)
{
    if (ki->filter) DeleteCxObjAll(ki->filter);
    if (ki->translist)
    {
    	FreeIEvents(ki->translist);
	ki->translist = NULL;
    }
    ki->custom = ki->trans = ki->filter = NULL;
 
    if ((ki->filter = CxFilter(ki->descr)))
    {
    	switch(ki->action)
	{
	    case ACTION_INSERT_TEXT:
	    	strrev(ki->param);
	    	if ((ki->translist = InvertString(ki->param, NULL)))
		{		
	    	    if ((ki->trans = CxTranslate(ki->translist)))
		    {
		    	AttachCxObj(ki->filter, ki->trans);
		    }
		}
		strrev(ki->param);
	    	break;
 
	    default:
	    	/* This CxCustom thing is hacky/ugly. A CxSender
		   would be better, but if want to send a pointer
		   with it then this would require some fixes in
		   commodities.library and it's header in case we are
		   running on 64 bit machines :-\ */
 
    		if ((ki->custom = CxCustom(custom_func, 0)))
		{
		    AttachCxObj(ki->filter, ki->custom);
		    if ((ki->trans = CxTranslate(NULL)))
		    {
		    	AttachCxObj(ki->filter, ki->trans);
		    }
		}
		break;
 
	}
 
	AttachCxObj(broker, ki->filter);
 
    }
}
 
/*********************************************************************************************/
 
static void RethinkAction(void)
{
    struct KeyInfo *ki = NULL;
 
    DoMethod(list, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, (IPTR)&ki);
 
    if (ki)
    {
	Object *str = NULL;
    	IPTR val;
 
	get(cmdcycle, MUIA_Cycle_Active, &val);
    	ki->action = val;
 
	switch(ki->action)
	{
	    case ACTION_INSERT_TEXT:
	    	str = insertstr;
		break;
 
	    case ACTION_RUN_PROG:
	    	str = runprogstr;
		break;
 
	    case ACTION_RUN_AREXX:
	    	str = runarexxstr;
		break;
 
	}
 
	if (str)
	{
	    STRPTR s;
 
	    get(str, MUIA_String_Contents, &s);
 
	    strncpy(ki->param, s, sizeof(ki->param));
	}
 
	RethinkKey(ki);
    }
}
 
/*********************************************************************************************/
 
static void NewKey(void)
{
    struct KeyInfo ki = {0};
 
    StringToKey();
 
    DoMethod(list, MUIM_List_InsertSingle, (IPTR)&ki, MUIV_List_Insert_Bottom);
    nnset(list, MUIA_List_Active, MUIV_List_Active_Bottom);
    nnset(liststr, MUIA_String_Contents, "");
    nnset(liststr, MUIA_Disabled, FALSE);
    set(wnd, MUIA_Window_ActiveObject, (IPTR)liststr);
 
    RethinkAction();
}
 
/*********************************************************************************************/
 
static void DelKey(void)
{
    struct KeyInfo *ki = NULL;
 
    DoMethod(list, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, (IPTR)&ki);
 
    if (ki)
    {
    	DoMethod(list, MUIM_List_Remove, MUIV_List_Remove_Active);
    	DoMethod(list, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, (IPTR)&ki);
    	if (!ki)
	{
	    nnset(liststr, MUIA_String_Contents, (IPTR)"");
	    nnset(liststr, MUIA_Disabled, TRUE);
 
	    ListToString();
	}
    }
}
 
/*********************************************************************************************/
 
static void StringToKey(void)
{
    struct KeyInfo *ki = NULL;
    STRPTR  	    text;
 
    DoMethod(list, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, (IPTR)&ki);
    if (!ki) return;
 
    get(liststr, MUIA_String_Contents, &text);    
    strncpy(ki->descr, text, sizeof(ki->descr));
 
    DoMethod(list, MUIM_List_Redraw, MUIV_List_Redraw_Active);
 
    RethinkKey(ki);
}
 
/*********************************************************************************************/
 
static void ListToString(void)
{
    struct KeyInfo *ki = NULL;
 
    DoMethod(list, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, (IPTR)&ki);
    if (!ki) return;
 
    nnset(liststr, MUIA_Disabled, FALSE);
    nnset(liststr, MUIA_String_Contents, ki->descr);
 
    switch(ki->action)
    {
    	case ACTION_INSERT_TEXT:
	    nnset(insertstr, MUIA_String_Contents, ki->param);
	    break;
 
	case ACTION_RUN_PROG:
	    nnset(runprogstr, MUIA_String_Contents, ki->param);
	    break;
 
	case ACTION_RUN_AREXX:
	    nnset(runarexxstr, MUIA_String_Contents, ki->param);
	    break;
    }
 
    nnset(cmdcycle, MUIA_Cycle_Active, ki->action);
    nnset(cmdpage, MUIA_Group_ActivePage, ki->action);
}
 
/*********************************************************************************************/
 
static void CmdToKey(void)
{
    RethinkAction();
}
 
/*********************************************************************************************/
 
static void HandleAction(void)
{
    struct KeyInfo  *ki;
    struct Window   *win;
    struct Screen   *scr;
    CxObj   	    *cobj;
    WORD    	     i;
 
    cobj = activated_custom_cobj;	
    activated_custom_cobj = NULL;
 
    for(i = 0; ; i++)
    {
	DoMethod(list, MUIM_List_GetEntry, i, (IPTR)&ki);
	if (!ki) break;
 
	if (ki->custom == cobj) break;
    }
 
    if (!ki) return;
 
    win = IntuitionBase->ActiveWindow;
    scr = IntuitionBase->FirstScreen;
 
    switch(ki->action)
    {
    	case ACTION_CYCLE_WIN:
	    if (win)
	    {
	    	struct Layer *lay;
 
	    	scr = win->WScreen;
		win = NULL;
 
		LockLayerInfo(&scr->LayerInfo);
		lay = scr->LayerInfo.top_layer;
		while(lay)
		{
		    if (lay->Window &&
		    	(lay != scr->BarLayer) &&
		    	!(lay->Flags & LAYERBACKDROP) &&
			!(((struct Window *)lay->Window)->Flags & WFLG_BORDERLESS))
		    {
		    	win = (struct Window *)lay->Window;
		    }
 
		    lay = lay->back;
		}		
		UnlockLayerInfo(&scr->LayerInfo);
 
		if (win)
		{
		    WindowToFront(win);
		    ActivateWindow(win);
		}
	    }
	    break;
 
	case ACTION_CYCLE_SCR:
	    if (scr) ScreenToBack(scr);
	    break;
 
	case ACTION_ENLARGE_WIN:
	    if (win && (win->Flags & WFLG_SIZEGADGET))
	    {
	    	WORD neww = win->MaxWidth;
		WORD newh = win->MaxHeight;
 
		if (neww > win->WScreen->Width) neww = win->WScreen->Width;
		if (newh > win->WScreen->Height) newh = win->WScreen->Height;
 
		ChangeWindowBox(win, win->LeftEdge, win->TopEdge, neww, newh);
	    }
	    break;
 
	case ACTION_SHRINK_WIN:
	    if (win && (win->Flags & WFLG_SIZEGADGET))
	    {
	    	WORD neww = win->MinWidth;
		WORD newh = win->MinHeight;
 
		ChangeWindowBox(win, win->LeftEdge, win->TopEdge, neww, newh);
	    }
	    break;
 
	case ACTION_RESCUE_WIN:
	    if (win)
	    {
		WORD dx = 0, dy = 0;
		if (win->LeftEdge < 0)
			dx = -win->LeftEdge;
		else if (win->LeftEdge + win->Width > win->WScreen->Width)
			dx = win->WScreen->Width - win->Width - win->LeftEdge;
 
		if (win->TopEdge + win->Height > win->WScreen->Height)
			dy = win->WScreen->Height - win->Height - win->TopEdge;
		else if (win->TopEdge < win->WScreen->BarHeight)
        {
			// try to keep the screen title bar visible
			if (win->WScreen->BarHeight + win->Height < win->WScreen->Height)
				dy = -win->TopEdge + win->WScreen->BarHeight;
			else
				dy = win->WScreen->Height - win->Height - win->TopEdge;
		}
		MoveWindow(win, dx, dy);
	    }
	    break;
 
	case ACTION_TOGGLE_WIN:
	    if (win) ZipWindow(win);
	    break;
 
	case ACTION_RUN_PROG:
	    if (ki->param)
	    {
	    	BPTR infh;
 
		infh = Open("CON:20/20/500/300/FKey/CLOSE/AUTO/WAIT", MODE_READWRITE);
		if (infh)
		{
		    struct TagItem systemtags[] =
		    {
		    	{SYS_Asynch , TRUE  	},
			{SYS_Input  , (IPTR)infh},
			{SYS_Output , 0	    	},
			{TAG_DONE   	    	}
		    };
 
		    if (SystemTagList(ki->param, systemtags) == -1)
		    {
		    	/* Error */
		    	Close(infh);
		    }
		}
	    }
	    break;
 
	case ACTION_RUN_AREXX:
	    break;
 
    } /* switch(ki->action) */
 
}
 
/*********************************************************************************************/
 
#define QUOTE_START 0xAB
#define QUOTE_END   0xBB
 
/*********************************************************************************************/
 
static UBYTE *BuildToolType(struct KeyInfo *ki)
{
    static UBYTE  ttstring[500];
    UBYTE   	 *param1 = "";
    UBYTE   	 *param2 = "";
 
    switch(ki->action)
    {
    	case ACTION_CYCLE_WIN:
	    param1 = "CYCLE";
	    break;
 
	case ACTION_CYCLE_SCR:
	    param1 = "CYCLESCREEN";
	    break;
 
	case ACTION_ENLARGE_WIN:
	    param1 = "MAKEBIG";
	    break;
 
	case ACTION_SHRINK_WIN:
	    param1 = "MAKESMALL";
	    break;
 
	case ACTION_TOGGLE_WIN:
	    param1 = "ZIPWINDOW";
	    break;
 
	case ACTION_RESCUE_WIN:
	    param1 = "RESCUEWIN";
	    break;
 
	case ACTION_INSERT_TEXT:
	    param1 = "INSERT ";
	    param2 = ki->param;
	    break;
 
	case ACTION_RUN_PROG:
	    param1 = "RUN ";
	    param2 = ki->param;
	    break;
 
	case ACTION_RUN_AREXX:
	    param1 = "AREXX ";
    	    param2 = ki->param;
	    break;
 
    }
 
    snprintf(ttstring, sizeof(ttstring), "%c%s%c %s%s",
    	     QUOTE_START,
	     ki->descr,
	     QUOTE_END,
	     param1,
	     param2);
 
    return ttstring;
}
 
/*********************************************************************************************/
 
static UBYTE **BuildToolTypes(UBYTE **src_ttypes)
{
    APTR     pool = CreatePool(MEMF_CLEAR, 200, 200);
    Object  *listobj = list;
    UBYTE   *tt;
    WORD     list_index = 0, num_ttypes = 0, alloc_ttypes = 10;
 
    UBYTE **dst_ttypes;
 
    if (!pool) return NULL;
 
    dst_ttypes = AllocPooled(pool, (alloc_ttypes + 2) * sizeof(UBYTE *));
    if (!dst_ttypes)
    {
    	DeletePool(pool);
	return NULL;
    }
 
    /* Put together final tooltypes list based on old tooltypes and
       new tooltypes all in one loop */
 
    for(;;)
    {
    	tt = NULL;
 
    	if (listobj)
	{
	    /* New tooltypes */
 
    	    struct KeyInfo *ki = NULL;
 
    	    DoMethod(listobj, MUIM_List_GetEntry, list_index, (IPTR)&ki);
    	    list_index++;
 
	    if (ki)
	    {
	    	tt = BuildToolType(ki);
	    }
	    else
	    {
	    	listobj = NULL;
	    }	    
	}
 
	if (!listobj)
	{
	    /* Old tooltypes */
 
	    if (src_ttypes) tt = *src_ttypes++;
	    if (!tt) break; /* Done. Skip out of "for(;;)" loop */
 
    	    if (tt[0] == QUOTE_START) continue; /* skip tooltype containing old settings */
	}
 
	if (!tt) break; /* Paranoia. Should not happen. */
 
	if (num_ttypes >= alloc_ttypes)
	{
	    UBYTE **new_dst_ttypes = AllocPooled(pool, (alloc_ttypes + 10 + 2) * sizeof(UBYTE *));
 
	    if (!new_dst_ttypes)
	    {
	    	DeletePool(pool);
		return NULL;
	    }
 
	    CopyMem(dst_ttypes + 1, new_dst_ttypes + 1, alloc_ttypes * sizeof(UBYTE *));
	    dst_ttypes = new_dst_ttypes;
	    alloc_ttypes += 10;
	}
 
	dst_ttypes[num_ttypes + 1] = AllocPooled(pool, strlen(tt) + 1);
	if (!dst_ttypes[num_ttypes + 1])
	{
    	    DeletePool(pool);
    	    return NULL;
	}
 
	CopyMem(tt, dst_ttypes[num_ttypes + 1], strlen(tt) + 1);
	num_ttypes++;
 
    }
 
    dst_ttypes[0] = (APTR)pool;
 
    return dst_ttypes + 1;
 
}
 
/*********************************************************************************************/
 
static void FreeToolTypes(UBYTE **ttypes)
{
    if (ttypes)
    {
    	DeletePool((APTR)ttypes[-1]);
    }
}
 
/*********************************************************************************************/
 
static struct DiskObject *LoadProgIcon(BPTR *icondir, STRPTR iconname)
{
    struct DiskObject *progicon;
 
    if (wbstartup)
    {
    	BPTR olddir;
 
	*icondir = wbstartup->sm_ArgList[0].wa_Lock;
 
	olddir = CurrentDir(*icondir);	
    	progicon = GetDiskObject(wbstartup->sm_ArgList[0].wa_Name);		
	CurrentDir(olddir);
 
	strncpy(iconname, wbstartup->sm_ArgList[0].wa_Name, 255);
    }
    else
    {	
	if (GetProgramName(iconname, 255))
	{
    	    BPTR olddir;
 
	    *icondir = GetProgramDir();
 
	    olddir = CurrentDir(*icondir);
    	    progicon = GetDiskObject(iconname);	    
	    CurrentDir(olddir);
	}	    
    }
 
    return progicon;
}
 
/*********************************************************************************************/
 
static void SaveSettings(void)
{
    struct DiskObject 	 *progicon;
    UBYTE   	    	**ttypes, **old_ttypes;
    UBYTE   	    	  iconname[256];
    BPTR    	    	  icondir = NULL;
 
    progicon = LoadProgIcon(&icondir, iconname);
 
    if (!progicon) return;
 
    old_ttypes = (UBYTE **)progicon->do_ToolTypes;
    if ((ttypes = BuildToolTypes(old_ttypes)))
    {
    	BPTR olddir;
 
#if 0 /* DEBUG */
    	UBYTE *tt, **ttypes_copy = ttypes;
 
	while((tt = *ttypes_copy++))
	{
	    kprintf("TT: %s\n", tt);
	}
#endif
 
    	olddir = CurrentDir(icondir);
 
    	progicon->do_ToolTypes = ttypes;
	PutDiskObject(iconname, progicon);
	progicon->do_ToolTypes = old_ttypes;
 
	CurrentDir(olddir);
 
    	FreeToolTypes(ttypes);
    }
 
    FreeDiskObject(progicon);
 
}
 
/*********************************************************************************************/
 
static void LoadSettings(void)
{
    struct DiskObject *progicon;
    UBYTE   	       iconname[256];
    BPTR    	       icondir = NULL;
    UBYTE   	      **ttypes, *tt;
 
    progicon = LoadProgIcon(&icondir, iconname);
    if (!progicon) return;
 
    if ((ttypes = (UBYTE **)progicon->do_ToolTypes))
    {
    	while((tt = *ttypes++))
	{
	    struct KeyInfo   ki = {0};
	    UBYTE   	    *quote_end;
 
	    ki.action = 0xFF;
 
	    if ((tt[0] == QUOTE_START) && ((quote_end = strchr(tt, (char)QUOTE_END))))
	    {
	    	WORD len = quote_end - tt - 1;
 
		if (len >= sizeof(ki.descr)) continue;
		if (quote_end[1] != ' ') continue;
 
	    	strncpy(ki.descr, tt + 1, len);
 
	    	if (strncmp(quote_end + 2, "CYCLE", 5 + 1) == 0)
		{
		    ki.action = ACTION_CYCLE_WIN;
		}
		else if (strncmp(quote_end + 2, "CYCLESCREEN", 11 + 1) == 0)
		{
		    ki.action = ACTION_CYCLE_SCR;
		}
		else if (strncmp(quote_end + 2, "MAKEBIG", 7 + 1) == 0)
		{
		    ki.action = ACTION_ENLARGE_WIN;
		}
		else if (strncmp(quote_end + 2, "MAKESMALL", 9 + 1) == 0)
		{
		    ki.action = ACTION_SHRINK_WIN;
		}
		else if (strncmp(quote_end + 2, "ZIPWINDOW", 9 + 1) == 0)
		{
		    ki.action = ACTION_TOGGLE_WIN;
		}
		else if (strncmp(quote_end + 2, "RESCUEWIN", 9 + 1) == 0)
		{
			ki.action = ACTION_RESCUE_WIN;
		}
		else if (strncmp(quote_end + 2, "INSERT ", 7) == 0)
		{
		    ki.action = ACTION_INSERT_TEXT;
		    strncpy(ki.param, quote_end + 2 + 7, sizeof(ki.param) - 1);
 
		}
		else if (strncmp(quote_end + 2, "RUN ", 4) == 0)
		{
		    ki.action = ACTION_RUN_PROG;
		    strncpy(ki.param, quote_end + 2 + 4, sizeof(ki.param) - 1);
		}
		else if (strncmp(quote_end + 2, "AREXX ", 6) == 0)
		{
		    ki.action = ACTION_RUN_AREXX;
		    strncpy(ki.param, quote_end + 2 + 6, sizeof(ki.param) - 1);
		}
 
		if (ki.action != 0xFF)
		{
    	    	    DoMethod(list, MUIM_List_InsertSingle, (IPTR)&ki, MUIV_List_Insert_Bottom);
		}
 
	    } /* if ((tt[0] == QUOTE_START) && ((quote_end = strchr(tt, QUOTE_END)))) */
 
	} /* while((tt = *ttypes++)) */
 
	{
	    LONG index;
 
	    for(index = 0; ; index++)
	    {
	    	struct KeyInfo *ki = NULL;
 
		DoMethod(list, MUIM_List_GetEntry, index, (IPTR)&ki);
		if (!ki) break;
 
		RethinkKey(ki);
	    }
	}
 
    } /* if ((ttypes = (UBYTE **)progicon->do_ToolTypes)) */
 
    FreeDiskObject(progicon);
}
 
/*********************************************************************************************/
 
static void HandleAll(void)
{
    ULONG sigs = 0;
    LONG  returnid;
    IPTR  num_list_entries = 0;
 
    get(list, MUIA_List_Entries, &num_list_entries);
    if ((num_list_entries == 0) || cx_popup)
    {
        set(wnd, MUIA_Window_Open, TRUE);
    }
    else
    {
        set(wnd, MUIA_Window_Open, FALSE);
    }
 
    for(;;)
    {
    	returnid = (LONG) DoMethod(app, MUIM_Application_NewInput, (IPTR) &sigs);
 
	if (returnid == MUIV_Application_ReturnID_Quit) break;
 
	switch(returnid)
	{
	    case RETURNID_NEWKEY:
	    	NewKey();
	    	break;
 
	    case RETURNID_DELKEY:
    	    	DelKey();
		break;
 
	    case RETURNID_LVACK:
	    	ListToString();
		break;
 
	    case RETURNID_STRINGACK:
	    	StringToKey();
		break;
 
	    case RETURNID_CMDACK:
	    	CmdToKey();
		break;
 
	    case RETURNID_SAVE:
    	    	SaveSettings();
		break;
 
	    case RETURNID_DOUBLESTART:
	        CallHookPkt(&show_hook, NULL, NULL);
		break;
	}
 
	if (sigs)
	{
	    sigs = Wait(sigs | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F);
	    if (sigs & SIGBREAKF_CTRL_C) break;
	    if (sigs & SIGBREAKF_CTRL_E) HandleAction();
	    if (sigs & SIGBREAKF_CTRL_F)
	    {
	        CallHookPkt(&show_hook, NULL, NULL);
	    }
	}
    }
 
}
 
/*********************************************************************************************/
 
int main(int argc, char **argv)
{
    GetArguments(argc, argv);
    InitLocale(CATALOG_NAME, CATALOG_VERSION);
    InitCX();
    InitMenus();
    MakeGUI();
    LoadSettings();
    HandleAll();       
    Cleanup(NULL);
 
    return 0;
}


/* HotKey.c - Simple hot key commodity */
#include <exec/libraries.h>
#include <libraries/commodities.h>
#include <dos/dos.h>
 
#include <proto/exec.h>
#include <proto/commodities.h>
 
#define EVT_HOTKEY 1L
 
void main(int, char **);
void ProcessMsg(void);
 
struct Library *CxBase, *IconBase;
struct MsgPort *broker_mp;
CxObj *broker, *filter, *sender, *translate;
 
struct NewBroker newbroker = {
    NB_VERSION,
    "RKM HotKey",           /* string to identify this broker */
    "A Simple HotKey",
    "A simple hot key commodity",
    NBU_UNIQUE | NBU_NOTIFY,    /* Don't want any new commodities starting with this name. */
    0, 0, 0, 0                  /* If someone tries it, let me know */
};
 
ULONG cxsigflag;
 
void main(int argc, char **argv)
{
    UBYTE *hotkey, **ttypes;
    CxMsg *msg;
 
    if (CxBase = OpenLibrary("commodities.library", 37L))
    {
        /* open the icon.library for the support library */
        /* functions, ArgArrayInit() and ArgArrayDone()  */
        if (IconBase = OpenLibrary("icon.library", 36L))
        {
            if (broker_mp = CreateMsgPort())
            {
                newbroker.nb_Port = broker_mp;
                cxsigflag = 1L << broker_mp->mp_SigBit;
 
                /* ArgArrayInit() is a support library function (from the 2.0 version
                 * of amiga.lib) that makes it easy to read arguments from either a
                 * CLI or from Workbench's ToolTypes.  Because it uses icon.library,
                 * the library has to be open before calling this function.
                 * ArgArrayDone() cleans up after this function.
                 */
                ttypes = ArgArrayInit(argc, argv);
 
                /* ArgInt() (also from amiga.lib) searches through the array set up
                 * by ArgArrayInit() for a specific ToolType.  If it finds one, it
                 * returns the numeric value of the number that followed the
                 * ToolType (i.e., CX_PRIORITY=7). If it doesn't find the ToolType,
                 * it returns the default value (the third argument)
                 */
                newbroker.nb_Pri = (BYTE)ArgInt(ttypes, "CX_PRIORITY", 0);
 
                /* ArgString() works just like ArgInt(), except it returns a pointer to a string
                 * rather than an integer. In the example below, if there is no ToolType
                 * "HOTKEY", the function returns a pointer to "rawkey control esc".
                 */
                hotkey = ArgString(ttypes, "HOTKEY", "rawkey control esc");
 
                if (broker = CxBroker(&newbroker, NULL))
                {
                    /* CxFilter() is a macro that creates a filter CxObject.  This filter
                     * passes input events that match the string pointed to by hotkey.
                     */
                    if (filter = CxFilter(hotkey))
                    {
                        /* Add a CxObject to another's personal list */
                        AttachCxObj(broker, filter);
 
                        /* CxSender() creates a sender CxObject.  Every time a sender gets
                         * a CxMessage, it sends a new CxMessage to the port pointed to in
                         * the first argument. CxSender()'s second argument will be the ID
                         * of any CxMessages the sender sends to the port.  The data pointer
                         * associated with the CxMessage will point to a *COPY* of the
                         * InputEvent structure associated with the orginal CxMessage.
                         */
                        if (sender = CxSender(broker_mp, EVT_HOTKEY))
                        {
                            AttachCxObj(filter, sender);
 
                            /* CxTranslate() creates a translate CxObject. When a translate
                             * CxObject gets a CxMessage, it deletes the original CxMessage
                             * and adds a new input event to the input.device's input stream
                             * after the Commodities input handler. CxTranslate's argument
                             * points to an InputEvent structure from which to create the new
                             * input event.  In this example, the pointer is NULL, meaning no
                             * new event should be introduced, which causes any event that
                             * reaches this object to disappear from the input stream.
                             */
                            if (translate = (CxTranslate(NULL)))
                            {
                                AttachCxObj(filter, translate);
 
                                /* CxObjError() is a commodities.library function that returns
                                 * the internal accumulated error code of a CxObject.
                                 */
                                if (! CxObjError(filter))
                                {
                                    ActivateCxObj(broker, 1L);
                                    ProcessMsg();
                                }
                            }
                        }
                    }
                    /* DeleteCxObjAll() is a commodities.library function that not only
                     * deletes the CxObject pointed to in its argument, but it deletes
                     * all of the CxObjects that are attached to it.
                     */
                    DeleteCxObjAll(broker);
 
                    /* Empty the port of all CxMsgs */
                    while(msg = (CxMsg *)GetMsg(broker_mp))
                        ReplyMsg((struct Message *)msg);
                }
                DeletePort(broker_mp);
            }
            /* this amiga.lib function cleans up after ArgArrayInit() */
            ArgArrayDone();
            CloseLibrary(IconBase);
        }
        CloseLibrary(CxBase);
    }
}
void ProcessMsg(void)
{
    extern struct MsgPort *broker_mp;
    extern CxObj *broker;
    extern ULONG cxsigflag;
    CxMsg *msg;
    ULONG sigrcvd, msgid, msgtype;
    LONG returnvalue = 1L;
 
    while(returnvalue)
    {
        sigrcvd = Wait(SIGBREAKF_CTRL_C | cxsigflag);
 
        while(msg = (CxMsg *)GetMsg(broker_mp))
        {
            msgid = CxMsgID(msg);
            msgtype = CxMsgType(msg);
            ReplyMsg((struct Message *)msg);
 
            switch(msgtype)
            {
                case CXM_IEVENT:
                    printf("A CXM_EVENT, ");
                    switch(msgid)
                    {
                        case EVT_HOTKEY: /* We got the message from the sender CxObject */
                            printf("You hit the HotKey.\n");
                            break;
                        default:
                            printf("unknown.\n");
                            break;
                    }
                    break;
                case CXM_COMMAND:
                    printf("A command: ");
                    switch(msgid)
                    {
                        case CXCMD_DISABLE:
                            printf("CXCMD_DISABLE\n");
                            ActivateCxObj(broker, 0L);
                            break;
                        case CXCMD_ENABLE:
                            printf("CXCMD_ENABLE\n");
                            ActivateCxObj(broker, 1L);
                            break;
                        case CXCMD_KILL:
                            printf("CXCMD_KILL\n");
                            returnvalue = 0L;
                            break;
                        case CXCMD_UNIQUE:
                        /* Commodities Exchange can be told not only to refuse to launch a
                         * commodity with a name already in use but also can notify the
                         * already running commodity that it happened. It does this by
                         * sending a CXM_COMMAND with the ID set to CXMCMD_UNIQUE.  If the
                         * user tries to run a windowless commodity that is already running,
                         * the user wants the commodity to shut down. */
                            printf("CXCMD_UNIQUE\n");
                            returnvalue = 0L;
                            break;
                        default:
                            printf("Unknown msgid\n");
                            break;
                    }
                    break;
                default:
                    printf("Unknown msgtype\n");
                    break;
            }
        }
        if (sigrcvd & SIGBREAKF_CTRL_C)
        {
            returnvalue = 0L;
            printf("CTRL C signal break\n");
        }
    }
}



ReferenceEdit

CxObj *CreateCxObj(ULONG type, IPTR arg1, IPTR arg2) 
CxObj *CxBroker(struct NewBroker *nb, LONG *error) 
LONG ActivateCxObj(CxObj *co, LONG true) 
void DeleteCxObj(CxObj *co) 
void DeleteCxObjAll(CxObj *co) 
ULONG CxObjType(CxObj *co) 
LONG CxObjError(CxObj *co) 
void ClearCxObjError(CxObj *co) 
LONG SetCxObjPri(CxObj *co, LONG pri) 

void AttachCxObj(CxObj *headObj, CxObj *co) 
void EnqueueCxObj(CxObj *headObj, CxObj *co) 
void InsertCxObj(CxObj *headObj, CxObj *co, CxObj *pred) 
void RemoveCxObj(CxObj *co) 

void SetTranslate(CxObj *translator, struct InputEvent *events) 
void SetFilter(CxObj *filter, STRPTR text) 
void SetFilterIX(CxObj *filter, IX *ix) 
LONG ParseIX(CONST_STRPTR desc, IX *ix) 

ULONG CxMsgType(CxMsg *cxm) 
APTR CxMsgData(CxMsg *cxm) 
LONG CxMsgID(CxMsg *cxm) 

void DivertCxMsg(CxMsg *cxm, CxObj *headObj, CxObj *returnObj) 
void RouteCxMsg(CxMsg *cxm, CxObj *co) 
void DisposeCxMsg(CxMsg *cxm) 

BOOL InvertKeyMap(ULONG ansiCode, struct InputEvent *event, struct KeyMap *km) 
void AddIEvents(struct InputEvent *events) 

LONG CopyBrokerList(struct List *CopyofList) 
void FreeBrokerList(struct List *brokerList) 
ULONG BrokerCommand(STRPTR name, ULONG command) 

BOOL MatchIX(struct InputEvent *event, IX *ix) 


struct NewBroker {
    BYTE    nb_Version;
    BYTE    nb_Pad;
    APTR    nb_Name;
    APTR    nb_Title;
    APTR    nb_Descr;
    SHORT   nb_Unique;
    WORD    nb_Flags;
    BYTE    nb_Pri;
    BYTE    nb_Pad2;
    APTR    nb_Port;
    WORD    nb_ReservedChannel;
};


Flags

NBU_NOTIFY

COF_SHOW_HIDE

CX_INVALID
CX_FILTER
CX_TYPEFILTER
CX_SEND
CX_SIGNAL
CX_TRANSLATE
CX_BROKER
CX_DEBUG
CX_CUSTOM
CX_ZERO

CXM_UNIQUE
CXM_IEVENT
CXM_COMMAND

CXCMD_DISABLE
CXCMD_ENABLE
CXCMD_APPEAR
CXCMD_DISAPPEAR
CXCMD_KILL
CXCMD_UNIQUE
CXCMD_LIST_CHG

CMDE_OK CMDE_NOBROKER CMDE_NOPORT CMDE_NOMEM

COERR_ISNULL COERR_NULLATTACH COERR_BADFILTER COERR_BADTYPE


struct IX {
    UBYTE ix_Version;
    UBYTE ix_Class;
    UWORD ix_Code;
    UWORD ix_CodeMask;
    UWORD ix_Qualifier;
    UWORD ix_QualMask;
    UWORD ix_QualSame;
];

Flags for IX and QualMask

IXSYM_SHIFT
IXSYM_CAPS
IXSYM_ALT

IXSYM_SHIFTMASK
IXSYM_CAPSMASK
IXSYM_ALTMASK
IX_NORMALQUALS
Last modified on 28 September 2012, at 10:18