跳转到内容

Aros/开发者/文档/库/商品

来自 Wikibooks,开放世界中的开放书籍
Aros wiki 书籍的导航栏
Aros 用户
Aros 用户文档
Aros 用户常见问题解答
Aros 用户应用程序
Aros 用户 DOS Shell
Aros/用户/AmigaLegacy
Aros 开发文档
Aros 开发者文档
从 AmigaOS/SDL 移植软件
适用于 Zune 初学者
Zune .MUI 类
适用于 SDL 初学者
Aros 开发者构建系统
特定平台
Aros x86 完整系统 HCL
Aros x86 音频/视频支持
Aros x86 网络支持
Aros 英特尔 AMD x86 安装
Aros 存储支持 IDE SATA 等
Aros Poseidon USB 支持
x86-64 支持
摩托罗拉 68k Amiga 支持
Linux 和 FreeBSD 支持
Windows Mingw 和 MacOSX 支持
Android 支持
Arm 树莓派支持
PPC Power Architecture
杂项
Aros 公共许可证

随着 AmigaOS (TM) 2.0 的发布,商品被引入以扩展 Amiga Workbench(桌面)的功能。

商品库在直觉的处理程序之前设置了一个处理程序。当商品处理程序接收到 CxMessage 时

CxObjects 对 CxMessage 进行操作,以便它可以过滤某些 CxMessage、翻译 CxMessage、在 CxObject 接收到 CxMessage 时向任务发出信号、在 CxObject 接收到 CxMessage 时发送消息,或者在 CxObject 接收到 CxMessage 时调用自定义函数。

控制器程序称为 Exchange,非常适合需要监控所有用户输入的程序,例如热键、弹出窗口、屏幕保护程序和鼠标保护程序。

商品交换永远不应作为应用程序接收用户输入的替代方法。

看看 这里

默认情况下,每个 Zune 应用程序也是一个商品。MUI 也会为您完成此操作。查看 muimaster/classes/application.c 中启用的 MUIA_Application_UseCommodities 部分(第 625-660 行):它似乎只设置(或在为 FALSE 时避免)Zune 对您的工具作为商品的初始化,并且键盘快捷键有效。

过滤器

[编辑 | 编辑源代码]

在创建过滤器时,您应该创建代理、将过滤器附加到代理,然后是发送方。过滤器只接收您感兴趣的事件,而发送方通知代理。

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

[编辑 | 编辑源代码]

FKey 商品使用过滤器

工具类型 «RAWMOUSE LBUTTON RBUTTON MOUSE_RIGHTPRESS» RUN App QUIET DONOTBUT CURRENT TOBACK

"RAWMOUSE MBUTTON MOUSE_MIDDLEPRESS"

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

[编辑 | 编辑源代码]

ASCIITable

[编辑 | 编辑源代码]
/*
    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);

获得新屏幕保护程序的最简单方法可能是复制随 AROS 附带的屏幕保护程序,然后执行自己的图形渲染

/*
    Copyright � 1995-2006, The AROS Development Team. All rights reserved.
    $Id$
*/

#include <aros/symbolsets.h>
#include <workbench/startup.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfx.h>
#include <graphics/gfxbase.h>
#include <libraries/commodities.h>
#include <libraries/locale.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/commodities.h>
#include <proto/alib.h>
#include <proto/locale.h>
#include <proto/icon.h>

#ifdef __AROS__
#    include <aros/debug.h>
#else
#    undef kprintf
#    define kprintf(...) (void)0
# ifndef __MORPHOS__
     typedef ULONG IPTR;
# endif
#endif

#include <stdio.h>
#include <stdlib.h>

#define CATCOMP_ARRAY
#include "strings.h"

#define CATALOG_NAME     "System/Tools/Commodities.catalog"
#define CATALOG_VERSION  3

/************************************************************************************/

UBYTE version[] = "$VER: Blanker 0.11 (15.04.2006)";

#define ARG_TEMPLATE "CX_PRIORITY=PRI/N/K,SECONDS=SEC/N/K,STARS=ST/N/K"

#define ARG_PRI     	0
#define ARG_SEC     	1
#define ARG_STARS   	2
#define NUM_ARGS    	3

#define MAX_STARS   	1000

#define CMD_STARTBLANK	1
#define CMD_STOPBLANK   2

#ifdef __MORPHOS__
static void BlankerAction(void);

static struct EmulLibEntry BlankerActionEntry =
{
   TRAP_LIB,
   0,
   (void (*)(void))BlankerAction
};
#endif

static struct NewBroker nb =
{
   NB_VERSION,
   NULL,
   NULL,
   NULL,
   NBU_NOTIFY | NBU_UNIQUE, 
   0,
   0,
   NULL,
   0 
};

static struct MsgPort 	*cxport;
static struct Window 	*win;
static struct RastPort  *rp;
static struct ColorMap  *cm;
static struct Task  	*maintask;

static struct Catalog 	*catalog;
static struct RDArgs 	*myargs;
static CxObj 	    	*cxbroker, *cxcust;
static ULONG 	    	cxmask, actionmask;
static WORD 	    	scrwidth, scrheight, actioncmd, visible_sky;
static LONG 	    	blackpen, star1pen, star2pen, star3pen;
static WORD 	    	num_stars = 200, blankwait = 30;
static UBYTE 	    	actionsig;
static BOOL 	    	blanked, quitme, disabled, pens_allocated;

static IPTR 	    	args[NUM_ARGS];
static char 	    	s[256];
static WORD 	    	star_x[MAX_STARS], star_y[MAX_STARS],
	    	    	star_speed[MAX_STARS], star_col[MAX_STARS];

/************************************************************************************/

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_BLANKER_CXNAME);
    easyStruct.es_TextFormat	= msgString;
    easyStruct.es_GadgetFormat	= _(MSG_OK);		

    if (IntuitionBase != NULL && !Cli() )
    {
	EasyRequestArgs(NULL, &easyStruct, NULL, NULL);
    }
    else
    {
	PutStr(msgString);
    }
}

/************************************************************************************/

static void FreePens(void)
{
    if (pens_allocated)
    {
	ReleasePen(cm, blackpen);
	ReleasePen(cm, star1pen);
	ReleasePen(cm, star2pen);
	ReleasePen(cm, star3pen);

	pens_allocated = FALSE;
    }
}

/************************************************************************************/

static void Cleanup(CONST_STRPTR msg)
{
    struct Message  *cxmsg;

    if(msg)
    {
	puts(msg);
    }

    if(IntuitionBase)
    {
	if(win)
	{
	    FreePens();
	    CloseWindow(win);
	}
    }

    if(CxBase)
    {

	if(cxbroker)
	    DeleteCxObjAll(cxbroker);

	if(cxport)
	{
	    while((cxmsg = GetMsg(cxport)))
	    {
		ReplyMsg(cxmsg);
	    }

	    DeleteMsgPort(cxport);
	}
    }

    if(myargs)
	FreeArgs(myargs);

    if(actionsig)
	FreeSignal(actionsig);

    exit(0);
}

/************************************************************************************/

static void DosError(void)
{
    Fault(IoErr(), 0, s, sizeof (s));
    Cleanup(s);
}

/************************************************************************************/

static void Init(void)
{
    maintask = FindTask(0);
    actionsig = AllocSignal(-1);
    actionmask = 1L << actionsig;
}

/************************************************************************************/

static void GetArguments(int argc, char **argv)
{
    if (argc == 0)
    {
	UBYTE **array = ArgArrayInit(argc, (UBYTE **)argv);
	nb.nb_Pri = ArgInt(array, "CX_PRIORITY", 0);
	blankwait = ArgInt(array, "SECONDS"    , blankwait);
	num_stars = ArgInt(array, "STARS"      , num_stars);
	ArgArrayDone();
    }
    else
    {
	if (!(myargs = ReadArgs(ARG_TEMPLATE, args, 0)))
	{
	    DosError();
	}

	if (args[ARG_PRI]) nb.nb_Pri = *(LONG *)args[ARG_PRI];

	if (args[ARG_SEC]) blankwait = *(LONG *)args[ARG_SEC];

	if (args[ARG_STARS]) num_stars = *(LONG *)args[ARG_STARS];
    }	

    if (num_stars < 0)
    {
	num_stars = 0;
    }
    else if (num_stars > MAX_STARS)
    {
	num_stars = MAX_STARS;
    }
}

/************************************************************************************/

#ifdef __MORPHOS__
static void BlankerAction(void)
#else
static void BlankerAction(CxMsg *msg,CxObj *obj)
#endif
{
#ifdef __MORPHOS__
    CxMsg *msg = (CxMsg *)REG_A0;
    CxObj *obj = (CxObj *)REG_A1;
#endif
    struct InputEvent *ie = (struct InputEvent *)CxMsgData(msg);
    static ULONG       timecounter = 0;

    if (ie->ie_Class == IECLASS_TIMER)
    {
	if (disabled)
	{
	    timecounter = 0;
	}
	else if (!blanked)
	{
	    timecounter++;

	    if(timecounter >= blankwait * 10)
	    {
		actioncmd = CMD_STARTBLANK;
		Signal(maintask, actionmask);

		blanked = TRUE;
	    }
	}
    }
    else if ((ie->ie_Class == IECLASS_RAWMOUSE) || (ie->ie_Class == IECLASS_RAWKEY))
    {
	if (ie->ie_Class != IECLASS_TIMER)
	{
	    timecounter = 0;

	    if (blanked)
	    {
		actioncmd = CMD_STOPBLANK;
		Signal(maintask, actionmask);

		blanked = FALSE;
	    }
	}
    }
}

/************************************************************************************/

static void InitCX(void)
{
    if (!(cxport = CreateMsgPort()))
    {
	Cleanup(_(MSG_CANT_CREATE_MSGPORT));
    }

    nb.nb_Port = cxport;

    cxmask = 1L << cxport->mp_SigBit;

    if (!(cxbroker = CxBroker(&nb, 0)))
    {
	Cleanup(_(MSG_CANT_CREATE_BROKER));
    }

#ifdef __MORPHOS__
    if (!(cxcust = CxCustom(&BlankerActionEntry, 0)))
#else
	if (!(cxcust = CxCustom(BlankerAction, 0)))
#endif
	{
	    Cleanup(_(MSG_CANT_CREATE_CUSTOM));
	}

    AttachCxObj(cxbroker, cxcust);
    ActivateCxObj(cxbroker, 1);

}

/************************************************************************************/

#define MY_RAND_MAX 32767

static LONG myrand(void)
{
    static LONG a = 1;

    return (a = a * 1103515245 + 12345) & MY_RAND_MAX;
}

/************************************************************************************/

static void HandleWin(void);

/************************************************************************************/

static void MakeWin(void)
{
    struct Screen  *screenPtr;
    WORD    	    y, y2, stripheight = 20;
    LONG    	    i;

    if(!(screenPtr = LockPubScreen(NULL)))
	kprintf("Warning: LockPubScreen() failed!\n");

    win = OpenWindowTags(0, WA_Left, 0,
	    WA_Top, 0,
	    WA_Width, screenPtr->Width,
	    WA_Height, screenPtr->Height,
	    WA_AutoAdjust, TRUE,
	    WA_BackFill, (IPTR)LAYERS_NOBACKFILL,
	    WA_SimpleRefresh, TRUE,
	    WA_Borderless, TRUE,
	    TAG_DONE);

    if(screenPtr)
	UnlockPubScreen(NULL, screenPtr);

    if(win)
    {
	rp = win->RPort;

	scrwidth  = win->Width;
	scrheight = win->Height;

	cm = win->WScreen->ViewPort.ColorMap;

	blackpen = ObtainBestPenA(cm, 0x00000000, 0x00000000, 0x00000000, NULL);
	star1pen = ObtainBestPenA(cm, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, NULL);
	star2pen = ObtainBestPenA(cm, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, NULL);
	star3pen = ObtainBestPenA(cm, 0x88888888, 0x88888888, 0x88888888, NULL);

	pens_allocated = TRUE;

	for(i = 0;i < num_stars;i++)
	{
	    star_x[i] = myrand() * scrwidth / MY_RAND_MAX;
	    star_y[i] = 1 + (myrand() * (scrheight - 2)) / MY_RAND_MAX;
	    star_speed[i] = 1 + myrand() * 3 / MY_RAND_MAX;
	    if (star_speed[i] < 2)
	    {
		star_col[i] = star3pen;
	    }
	    else if (star_speed[i] < 3)
	    {
		star_col[i] = star2pen;
	    }
	    else
	    {
		star_col[i] = star1pen;
	    }
	}

	SetAPen(rp, blackpen);
	for(y = 0;y < scrheight - 1;y++, stripheight++)
	{
	    if (CheckSignal(actionmask))
	    {
		if (actioncmd == CMD_STOPBLANK)
		{
		    FreePens();
		    CloseWindow(win);
		    win = 0;
		    break;
		}
	    }

	    for(y2 = y;y2 < scrheight - 1;y2 += stripheight)
	    {
		ClipBlit(rp, 0, y2, rp, 0, y2 + 1, scrwidth, scrheight - y2 - 1, 192);
		SetAPen(rp, blackpen);
		RectFill(rp, 0, y2, scrwidth - 1, y2);

#if 0
		if (y2 == y)
		{
		    for(i = 0; i < num_stars; i++)
		    {
			if (star_y[i] == y2)
			{
			    SetAPen(rp, star_col[i]);
			    WritePixel(rp, star_x[i], y2);
			}
		    }

		} /* if (y2 == y) */
#endif

	    } /* for(y2 = y;y2 < scrheight - 1;y2 += stripheight) */

	    visible_sky = y;

	    HandleWin();

	    WaitTOF();

	} /* for(y = 0;y < scrheight - 1;y++, stripheight++) */

    } /* if (win) */
    else
    {
	showSimpleMessage(_(MSG_CANT_CREATE_WIN));
    }
}

/************************************************************************************/

static void HandleWin(void)
{
    LONG i;

    for(i = 0; i < num_stars;i++)
    {
	if (star_y[i] <= visible_sky)
	{
	    SetAPen(rp, blackpen);
	    WritePixel(rp, star_x[i], star_y[i]);

	    star_x[i] -= star_speed[i];
	    if (star_x[i] < 0) star_x[i] += scrwidth;

	    SetAPen(rp, star_col[i]);
	    WritePixel(rp, star_x[i], star_y[i]);
	}
    }
}

/************************************************************************************/

static void HandleAction(void)
{
    switch(actioncmd)
    {
	case CMD_STARTBLANK:
	    if (!win) MakeWin();
	    break;

	case CMD_STOPBLANK:
	    if (win)
	    {
		FreePens();
		CloseWindow(win);
		win = 0;
	    }
	    break;		
    }
}

/************************************************************************************/

static void HandleCx(void)
{
    CxMsg *msg;

    while((msg = (CxMsg *)GetMsg(cxport)))
    {
	switch(CxMsgType(msg))
	{
	    case CXM_COMMAND:
		switch(CxMsgID(msg))
		{
		    case CXCMD_DISABLE:
			ActivateCxObj(cxbroker,0L);
			disabled = TRUE;
			break;

		    case CXCMD_ENABLE:
			ActivateCxObj(cxbroker,1L);
			disabled = FALSE;
			break;

		    case CXCMD_UNIQUE:
		    case CXCMD_KILL:
			quitme = TRUE;
			break;

		} /* switch(CxMsgID(msg)) */
		break;

	} /* switch (CxMsgType(msg))*/

	ReplyMsg((struct Message *)msg);

    } /* while((msg = (CxMsg *)GetMsg(cxport))) */

}

/************************************************************************************/

static void HandleAll(void)
{
    ULONG sigs;

    while(!quitme)
    {
	if (win)
	{
	    HandleWin();
	    WaitTOF();
	    sigs = CheckSignal(cxmask | actionmask | SIGBREAKF_CTRL_C);
	}
	else
	{
	    sigs = Wait(cxmask | actionmask | SIGBREAKF_CTRL_C);
	}

	if (sigs & cxmask) HandleCx();
	if (sigs & actionmask) HandleAction();
	if (sigs & SIGBREAKF_CTRL_C) quitme = TRUE;

    } /* while(!quitme) */

}

/************************************************************************************/

int main(int argc, char **argv)
{
    Init();

    nb.nb_Name = _(MSG_BLANKER_CXNAME);
    nb.nb_Title = _(MSG_BLANKER_CXTITLE);
    nb.nb_Descr = _(MSG_BLANKER_CXDESCR);

    GetArguments(argc, argv);
    InitCX();
    HandleAll();
    Cleanup(0);
    return 0;
}

/************************************************************************************/

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;
}

ClickToFront

[编辑 | 编辑源代码]
/*
    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);
/* 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 original 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");
        }
    }
}

参考文献

[编辑 | 编辑源代码]
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;
};

标志

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;
];

IX 和 QualMask 的标志

IXSYM_SHIFT
IXSYM_CAPS
IXSYM_ALT

IXSYM_SHIFTMASK
IXSYM_CAPSMASK
IXSYM_ALTMASK
IX_NORMALQUALS
华夏公益教科书