欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

汉王手写输入的系统部分(Palm平台) (20千字)

汉王手写输入的系统部分(Palm平台) (20千字)

汉王手写输入的系统部分
工具: IDA Pro 4.x
平台: Palm OS 3.5, Motorola 68000 指令集
http://www.hwpen.net/download.htm
年初, 下了一个汉王试了一下, 觉得它的浮动菜单做的比较好, 因为它在任何App下都可以冒出来. 要知道Palm是单任务的, 在一个时候只能有一个APP在运行. 当时刚刚接触Palm, 如果要让我实现这些功能, 还真的不知道怎么下手. 于是想到了用IDA试试在非Windows平台的反汇编. 最后得到的这些代码完全说明了它是怎样实现这些功能的. 对于Palm程序员是有参考价值的.

另外, 有几点需要特别说明:
1. 对于它的识别引擎, 我没有做逆向, 因为我对它后面的高深理论不了解也没有兴趣.
2. 因为是为了学习, 而不是破解这套软件, 我没有去逆向它的注册码算法部分. 从支持国产软件方面考虑, 我也不会这样做.(言下之意:汉王你可别找我麻烦 :) )
3. 这里公布的只是任何Palm书籍上都有的编程的最基础部分, 应该不会对汉王在技术上构成什么危害.
4. 这些可以编译的代码只用于学习目的, 请勿做它用.
5. 用SetTrap的方法挂接HW_SysHandleEvent()而没有其它措施是不安全的,因为系统在特定的时候会移动代码资源, 这肯定会让系统垮掉, 应该使用DmDatabaseProtect()对这段代码资源加以保护. 希望汉王以后会这样做.
// #include <windows.h>
#include <PalmOS.h>
#include <DLServer.h>
#include <PalmUtils.h>
#define version350                0x3503000
#define HW_MainForm                1000
#define RomIncompatibleAlert     1001
#define HWDefinedCmd            0xddbb
#define HW_COMMONCCHAR            0x0001
#define HW_SUBCOMMONCCHAR        0x0002
#define HW_TRA2SIMPLIFIED        0x0008
#define HW_NUMERIC                0x0010
#define HW_ENGLISH                0x0060
#define HW_SYMBOL                0x0180
#define HW_UPPER2LOWER            0x2000
#define HW_LOWER2UPPER            0x4000
#define HW_HALF2FULL            0x8000
// 菜单模式
#define FOLDED    0    // 收成"V"
#define LOWER    1    // 在屏幕的下半部
#define UPPER    2    // 在屏幕的上半部
#define HIDDEN    3    // 隐藏
// 手写系统阶段
#define READY    0    // 就绪
#define ENTER    1    // 进入窗口或Form
#define LEAVE    2    // 离开窗口或Form
#define CHGFLD    3    // 切换到其它字段
typedef struct tagHW_PREF {
    Boolean bInstallHW;        // 是否安装汉王手写输入系统. 0
    Int8 al_b1;                // 未被使用 1
    UInt16 flags;            // 标志位 2
    UInt16 RecogRange;        // 识别范围 4
    Int8 RecogWaitTime;        // 识别等待时间 6
    Int8 PenThickness;        // 笔迹粗细 7
    Int8 PenColor;            // 笔的颜色 8
    Int8 al_b9;                // 未被使用 9
    Int16 ShotcutPenDownX;    // 快捷方式的起点屏幕坐标 X a
    Int16 ShotcutPenDownY;    // 快捷方式的起点屏幕坐标 Y c
    Int16 ShotcutPenUpX;    // 快捷方式的终点屏幕坐标 X e
    Int16 ShotcutPenUpY;    // 快捷方式的终点屏幕坐标 Y 10
    Boolean bSetting;        // 是否正在设置快捷方式 12
    Int8 bUsingShortcut;    // 是否正在使用快捷方式 13
    Boolean bSplitScreen;    // 全屏分割 14
    Boolean bHalfToFull;    // 半角字符转成全角字符 15
    Boolean bUpperToLower;    // 大写字母转成小写字母 16
    Boolean bLowerToUpper;    // 小写字母转成大写字母 17
    Boolean bMouse;            // 是否作为鼠标使用 18
    Boolean bReged;            // 是否是注册用户: 0xff 是, 0 否. 19
    Int8 MenuMode;            // 0: FOLDED, 1: LOWER, 2: UPPER, 3: HIDDEN 1a
    Boolean bMenuFolded;    // 菜单是否被收成"V" 1b
    Boolean bOpenHW;        // 是否启动汉王手写输入 1c
    Boolean bHalfScrnInput;    // 是否在半屏手写模式 1d
    Boolean bRedrawMenu;    // 菜单是否需要重画 1e
    Int8 Phase;                // 手写系统阶段 0: READY, 1: ENTER, 2: LEAVE, 3: CHGFLD 1f
} HW_PREF;
typedef struct tagHW_PENS {
    UInt16 Cands[20][10];    // 候选字Buffer 0
    UInt8 index;            // 候选字在候选字Buffer中的下标索引 0x190/400
    UInt8 b191;                // not used
    UInt16 InsPtPos;        // 插入点偏移, 192h, 402
    UInt16 CandiDispOfs;    // 候选字显示偏移 194h 404
    char* AssocBuffer;        // 联想字buf 196h 406
    UInt16 AssocNum;        // 联想字个数 19a 410
    UInt8 AssocOfs;            // 联想字偏移 19c 412
    UInt8 AssocDispOfs;        // 联想字显示偏移 19d 413
} HW_PENS;
typedef struct tagHW_TRACE {
    PointType points[2048]; // 笔迹采样点数组 0
    UInt16    PtCount;        // 笔迹采样存放位置 2000
    UInt32 dw2002; // 2002
    UInt8 b2006; // 2006
    UInt8 b2007; // 2007
    UInt8 b2008; // 2008
} HW_TRACE;

int HW_Install(void);
void HW_Uninstall(void);
UInt16 GetRecogRange(HW_PREF* pPref)
{
    UInt16 flags;
    if (pPref->RecogRange)
        flags = pPref->RecogRange;
    else
        flags = pPref->flags;
    if (pPref->bHalfToFull)
        flags |= 0x8000;
    if (pPref->bUpperToLower)
        flags |= 0x2000;
    if (pPref->bLowerToUpper)
        flags |= 0x4000;
    return flags;
}
Int8 GetMenuMode(void)
{
    Int16 x, y;
    InsPtGetLocation(&x, &y);
    if (y > 109)
        return UPPER;
    else
        return LOWER;
}
char V[] = "V";
void ClearMenu(Int8 MenuMode)
{
    RectangleType rc;
    if (MenuMode == HIDDEN) return;
    if (MenuMode == FOLDED) {
        WinEraseChars(V, 1, 141, 141);
        return;
    }
    if (MenuMode == LOWER)
        RctSetRectangle(&rc, 0, 118, 160, 30);
    else if (MenuMode == UPPER)
        RctSetRectangle(&rc, 0, 78, 160, 30);
    WinEraseRectangle(&rc, 0/*cornerDiam, 0 for square corners*/);
}
void RedrawCurForm(void)
{
    FormPtr frm = FrmGetActiveForm();
    WindowType* winHandle = FrmGetWindowHandle(frm);
    if (winGetActiveWindow() == winHandle && FrmValidatePtr(frm))
        FrmDrawForm(frm);
}
void DrawMenu(HW_PREF* pPrefs, HW_PENS* pHWPens) // a3 = pPrefs, a2 = pHWPens
{
    int ofs, x, d5;
    RectangleType rc;
    UInt16* ptr;
    if (pHWPens->index == 0)
        x = 0;
    else
        x = pHWPens->index - 1;
    if (pPrefs->MenuMode == UPPER) {
        RctSetRectangle(&rc, 2, 80, 155, 25);
        WinDrawRectangleFrame(dialogFrame, &rc);
        // This routine does not draw in the gray color; it draws with
        // alternating foreground and background pixels. That is, it uses
        // the grayPattern pattern type.
        WinDrawGrayLine(74, 93, 74, 104);
        WinDrawGragLine(2, 92, 156, 92);
        WinDrawChars("→", 2, 63, 94);
        WinDrawChars("英", 2, 76, 94);
        if (pPrefs->RecogRange == HW_ENGLISH) {
            RctSetRectangle(&rc, 75, 93, 12, 12);
            WinInvertRectangle(&rc, 0);
        }
        WinDrawChars("数", 2, 88, 94);
        if (pPrefs->RecogRange == HW_NUMERIC) {
            RctSetRectangle(&rc, 87, 93, 12, 12);
            WinInvertRectangle(&rc, 0);
        }
        WinDrawChars("符", 2, 100, 94);
        if (pPrefs->RecogRange == HW_SYMBOL) {
            RctSetRectangle(&rc, 99, 93, 12, 12);
            WinInvertRectangle(&rc, 0);
        }
        WinDrawChars("全", 2, 112, 94);
        if (pPrefs->bHalfToFull) {
            RctSetRectangle(&rc, 111, 93, 12, 12);
            WinInvertRectangle(&rc, 0);
        }
        WinDrawChars("窗", 2, 124, 94);
        WinDrawChars("鼠", 2, 136, 94);
        if (pPrefs->bMouse) {
            RctSetRectangle(&rc, 135, 93, 12, 12);
            WinInvertRectangle(&rc, 0);
        }
        WinDrawChars("^", 1, 148, 94);
        WinDrawChars("←", 2, 132, 81);
        WinDrawChars("→", 2, 145, 81);
        d5 = pHWPens->CandiDispOfs * 2;
        ptr = pHWPens->Cands[x];
        // 显示5个候选字
        if (ptr[d5] || ptr[d5 + 1]) {
            for (ofs = d5; ofs < d5 + 10; ofs += 2) {
                if (ptr[ofs]) {
                    WinDrawChars(&ptr[ofs], 2, x, 94);
                    x += 12;
                }
                else {
                    if (ptr[d5 + 1] <= ' ')
                        break;
                    WinDrawChars(&ptr[d5 + 1], 1, x, 94);
                    x += 12;
                }
            }
        }
        // 显示10个联想字
        if (pHWPens->AssocNum) {
            x = 3;
            for (ofs = pHWPens->AssocDispOfs; ofs < pHWPens->AssocOfs + 20; ofs += 2) {
                if (ofs - pHWPens->AssocOfs < pHWPens->AssocNum)
                    break;
                WinDrawChars(&pHWPens->AssocBuffer[ofs], 2, x, 81);
                x += 13;
            }
        }
    }
    else if (pPrefs->MenuMode == LOWER) {
        RctSetRectangle(&rc, 2, 120, 155, 25);
        WinDrawRectangleFrame(dialogFrame, &rc);
        // This routine does not draw in the gray color; it draws with
        // alternating foreground and background pixels. That is, it uses
        // the grayPattern pattern type.
        WinDrawGrayLine(74, 133, 74, 144);
        WinDrawGragLine(2, 132, 156, 312);
        WinDrawChars("→", 2, 63, 134);
        WinDrawChars("英", 2, 76, 134);
        if (pPrefs->RecogRange == HW_ENGLISH) {
            RctSetRectangle(&rc, 75, 93, 12, 12);
            WinInvertRectangle(&rc, 0);
        }
        WinDrawChars("数", 2, 88, 134);
        if (pPrefs->RecogRange == HW_NUMERIC) {
            RctSetRectangle(&rc, 87, 93, 12, 12);
            WinInvertRectangle(&rc, 0);
        }
        WinDrawChars("符", 2, 100, 134);
        if (pPrefs->RecogRange == HW_SYMBOL) {
            RctSetRectangle(&rc, 99, 133, 12, 12);
            WinInvertRectangle(&rc, 0);
        }
        WinDrawChars("全", 2, 112, 134);
        if (pPrefs->bHalfToFull) {
            RctSetRectangle(&rc, 111, 133, 12, 12);
            WinInvertRectangle(&rc, 0);
        }
        WinDrawChars("窗", 2, 124, 134);
        WinDrawChars("鼠", 2, 136, 134);
        if (pPrefs->bMouse) {
            RctSetRectangle(&rc, 135, 133, 12, 12);
            WinInvertRectangle(&rc, 0);
        }
        WinDrawChars("^", 1, 148, 134);
        WinDrawChars("←", 2, 132, 121);
        WinDrawChars("→", 2, 145, 121);
        d5 = pHWPens->CandiDispOfs * 2;
        ptr = pHWPens->Cands[x];
        // 显示5个候选字
        if (ptr[d5] || ptr[d5 + 1]) {
            for (ofs = d5; ofs < d5 + 10; ofs += 2) {
                if (ptr[ofs]) {
                    WinDrawChars(&ptr[ofs], 2, x, 134);
                    x += 12;
                }
                else {
                    if (ptr[d5 + 1] <= ' ')
                        break;
                    WinDrawChars(&ptr[d5 + 1], 1, x, 134);
                    x += 12;
                }
            }
        }
        // 显示10个联想字
        if (pHWPens->AssocNum) {
            x = 3;
            for (ofs = pHWPens->AssocDispOfs; ofs < pHWPens->AssocOfs + 20; ofs += 2) {
                if (ofs - pHWPens->AssocOfs > pHWPens->AssocNum)
                    break;
                WinDrawChars(&pHWPens->AssocBuffer[ofs], 2, x, 121);
                x += 13;
            }
        }
    }
    else if (pPrefs->MenuMode == FOLDED)
        WinDrawChars("V", 1, 141, 141);
}
void RedrawMenu(HW_PREF* pPrefs, char* pHWPens)
{
    WinHandle winHandle = WinSetDrawWindow(WinGetDisplayWindow());
    ClearMenu(pPrefs->MenuMode);
    DrawMenu(pPrefs, pHWPens);
    WinSetDrawWindow(winHandle);
}
FieldPtr GetCurField(FormPtr frm)
{
    // Too bad to access directly FormType data member. Palm strongly disencourage
    // such behaviors
    if (frm->focus != noFocus &&
        frm->objects[frm->focus].object.field != frmFieldObj&&
        frm->objects[frm->focus].object.field != frmTableObj)
    {
        return TblGetCurrentField(frm->objects[frm->focus].object.field);
    }
    return NULL;
}
void EnqueueChChar(FieldPtr fp, UInt16* pCand, Boolean bBackspace)
{
    MemHandle    memHandle;
    HW_PREF*    pPrefs;
    UInt16        InsPos;
    
    FtrGet('HW99', 10, (UInt32 *)&memHandle);
    pPrefs = (HW_PREF*)MemHandleLock(memHandle); // a2
    InsPos = FldGetInsPtPosition(fp);    // d3
    if (bBackspace)
        FldDelete(fp, InsPos - 2, InsPos);
    FldInsert(fp, pCand, 2);
    if (pPrefs->bReged != 0xff) {
        pPrefs->bReged++;
        pPrefs->bReged %= 10;
        if (pPrefs->bReged == 0)
            ShowNag();
    }
    MemHandleUnlock(memHandle);
    InsPos = FldGetInsPtPosition(fp);
    FldSetSelection(fp, InsPos, InsPos);
}
void GetAssoc(HW_PENS* pHWPens, UInt16 Cand)
{
    pHWPens->AssocNum = 0;
    pHWPens->AssocOfs = 0;
    if (GetAssocFromAssocBuf(pHWPens->AssocBuffer, Cand) > 0) {
        pHWPens->AssocNum = *pHWPens->AssocBuffer;
        pHWPens->AssocBuffer++;
        if (pHWPens->AssocNum == -1) {
            pHWPens->AssocNum += *pHWPens->AssocBuffer;
            pHWPens->AssocBuffer++;
        }
        pHWPens->AssocNum *= 2;
        pHWPens->AssocOfs = 0;
    }
}
void EnqueueInputKeys(FormType* frm, HW_PENS* pHWPens, UInt16 index, BOOL bAssoc)
{
    FieldPtr fp = GetCurField(frm); // a3
    WChar ascii;
    UInt16 InsPos;
    if (fp != NULL) {
        if ((UInt8)pHWPens->Cands[index][0] == 0) {
            ascii = *((UInt8*)&pHWPens->Cands[index][0] + 1);
            if (ascii > ' ') {
                EvtEnqueueKey(ascii, 0, 0);
                if (++pHWPens->index == 20)
                    pHWPens->index = 0;
                pHWPens->CandiDispOfs = 0;
                pHWPens->InsPtPos = FldGetInsPtPosition(fp) + 1;
            }
            else if (ascii == ' ')
                EvtEnqueueKey(32, 0, 0);
            else if (ascii == 8)
                EvtEnqueueKey(backspaceChr, 0, 0);
            else if (ascii == '\n')
                EvtEnqueueKey('\r', 0, 0), EvtEnqueueKey('\n', 0, 0);
        }
        else {
            EnqueueChChar(fp, pHWPens->Cands[index], false);
            if (++pHWPens->index == 20)
                pHWPens->index = 0;
            pHWPens->CandiDispOfs = 0;
            pHWPens->InsPtPos = FldGetInsPtPosition(fp);
            if (bAssoc)
                GetAssoc(pHWPens, pHWPens->Cands[index][0]);
        }
    }
}
void AdjustCandIndex(FormPtr frm, HW_PENS* pHWPens)
{
    UInt16 InsPos = FldGetInsPtPosition(GetCurField(frm)); // d3
    Int16 InsOfs = InsPos - pHWPens->InsPtPos;
    Int16 index;
    pHWPens->InsPtPos = InsPos;
    if (InsOfs > 40 || InsOfs < -40)
        return;
    if (pHWPens->index == 0)
        index = 19;
    else
        index = pHWPens->index - 1; // d3 = index
    if (InsOfs < 0) {
        do {
            if (pHWPens->Cands[index][0] == 0) {
                if (pHWPens->Cands[index][1] == 0) {
                    if (index == 19)
                        pHWPens->index = 0;
                    else
                        pHWPens->index = index + 1;
                    return;
                }
                else {
                    InsOfs++;
                    if (index == 0)
                        index = 19;
                    else
                        index--;
                }
            }
            else {
                InsOfs += 2;
                if (index == 0)
                    index = 19;
                else
                    index--;
            }
        } while (InsOfs < 0); // 5F4C here
    } // goto 5fa2
    else if (InsOfs > 0) {
        do {
            if (pHWPens->Cands[index][0] == 0) {
                if (pHWPens->Cands[index][1] == 0) {
                    if (index == 19)
                        pHWPens->index = 0;
                    else
                        pHWPens->index = index + 1;
                    return;
                }
                else {
                    InsOfs--;
                    if (index == 19)
                        index = 0;
                    else
                        index++;
                }
            }
            else {
                InsOfs  -= 2;
                if (index == 19)
                    index = 0;
                else
                    index++;
            }
        } while (InsOfs > 0);
    }
    if (index == 19)
        pHWPens->index = 0;
    else
        pHWPens->index = index + 1;
}
BOOL OnPenDown(EventPtr eventP, HW_PREF* pPrefs, HW_PENS* pHWPens, HW_TRACE* pHWTrace)
{
    Coord x, y;
    FormPtr frm;
    Int8 MenuMode;
    UInt16 screenX, screenY;
    // d3 = eventP(a6)
    // a2 = pPrefs
    // a3 = pHWPens
    // a4 = pHWTrace
    x = eventP->screenX;
    y = eventP->screenY;
    WinWindowToDisplayPt(&x, &y);
    if (x > 160 || y > 160)
        return 0;
    MenuMode = pPrefs->MenuMode;
    switch (MenuMode)
    {
    case FOLDED:
        if (screenX > 141 && screenX < 151 && screenY > 141 && screenY < 151)
            break;
    case LOWER:
        if (screenY > 120 && screenY < 145)
            break;
    case UPPER:
        if (screenY > 80 && screenY < 105)
            break;
    default:
        if (pPrefs->bMouse)
            return false;
        pHWTrace->b2006 = 0;
        pHWTrace->points[pHWTrace->PtCount].x = screenX;
        pHWTrace->points[pHWTrace->PtCount].y = screenY;
        if (pHWTrace->PtCount == 0)
            pHWTrace->b2007 = 1;
        pHWTrace->PtCount++;
        pHWTrace->dw2002 = 0;
        return true;
    }
    // 如果已有笔迹采样点, 将新点加入笔迹数组.
    if (pHWTrace->PtCount) {
        pHWTrace->points[pHWTrace->PtCount].x = screenX;
        pHWTrace->points[pHWTrace->PtCount].y = screenY;
        pHWTrace->PtCount++;
        return true;
    }
    
    pHWTrace->b2006 = true;
    if (MenuMode == LOWER && x > 3 && x < 63 && y > 134 && y < 146 ||
        MenuMode == UPPER && x > 3 && x < 63 && y > 94 && y < 106)
    {
        UInt16 ofs = (pHWPens->CandiDispOfs + (x - 1)) / 12;
        char* p = (char*)&pHWPens->Cands[pHWPens->index - 1][ofs];
        
        if (*p == 0) {
            if (*(p + 1) == 0)
                return true;
            EvtEnqueueKey(backspaceChr, 0, 0);
            EvtEnqueueKey(*(p + 1), 0, 0);
        }
        else {
            EnqueueChChar(GetCurField(FrmGetActiveForm()), p, true);
            GetAssoc(pHWPens, *(UInt16*)p);
        }
        pPrefs->bRedrawMenu = true;
        return true;
    }

    if (MenuMode == LOWER && x > 3 && x < 133 && y > 121 && y < 133 ||
        MenuMode == UPPER && x > 3 && x < 133 && y > 81 && y < 93) // else goto 6b4a
    {
        UInt16 pos = (x - 1) / 13 * 2;
        if (pHWPens->AssocOfs + pos < pHWPens->AssocNum) {
            EnqueueChChar(GetCurField(FrmGetActiveForm()), pHWPens->AssocBuffer[pos], false);
            pHWPens->AssocNum = 0;
            pHWPens->AssocOfs = 0;
        }
        return true;
    }
    if (MenuMode == LOWER && x > 63 && x < 75 && y > 134 && y < 146 ||
        MenuMode == UPPER && x > 63 && x < 75 && y > 94 && y < 106) // else goto 6be0
    {
        UInt16 ofs = pHWPens->CandiDispOfs + 5;
        if (ofs == 10) {
            pHWPens->CandiDispOfs = 0;
            pPrefs->bRedrawMenu = true;
        }
        else if (pHWPens->Cands[pHWPens->index - 1][ofs] != 0) {
            pHWPens->CandiDispOfs + 5;
            pPrefs->bRedrawMenu = true;
        }
        return true;
    }
    if (MenuMode == LOWER && x > 132 && x < 144 && y > 121 && y < 133 ||
        MenuMode == UPPER && x > 132 && x < 144 && y > 81 && y < 93) // else goto 6c4a
    {
        if (pHWPens->AssocOfs) {
            pHWPens->AssocOfs -= 20;
            pPrefs->bRedrawMenu = true;
        }
        return true;
    }
    if (MenuMode == LOWER && x > 145 && x < 157 && y > 121 && y < 133 ||
        MenuMode == UPPER && x > 145 && x < 157 && y > 81 && y < 93) // else goto 6cba
    {
        if (pHWPens->AssocOfs + 20 < pHWPens->AssocNum) {
            pHWPens->AssocOfs += 20;
            pPrefs->bRedrawMenu = true;
        }
        re

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功