/* -*- mode: C++; tab-width: 4 -*- */ /* ===================================================================== *\ Copyright (c) 1998-2001 Palm, Inc. or its subsidiaries. All rights reserved. This file is part of the Palm OS Emulator. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. \* ===================================================================== */ #include "EmCommon.h" #include // needed for sprintf. #include // needed for rand and srand #include // needed for strcpy and friends #ifdef forSimulator #define PILOT_PRECOMPILED_HEADERS_OFF // Palm Includes #include #ifdef HAS_LOCAL_BUILD_DEFAULTS #include "LocalBuildDefaults.h" #endif #include #include #include #include #include #include #include #include #include #include "CGremlinsStubs.h" #include "CGremlins.h" #include "Hardware.h" #include #define NON_PORTABLE #include "SystemPrv.h" #include "DataPrv.h" #include "SysEvtPrv.h" #include #include "ShellCmd.h" #else // !forSimulator #include "EmBankRegs.h" // RegsBank #include "EmEventPlayback.h" // RecordPenEvent, etc. #include "EmMemory.h" // EmMemPut16, EmMemPut32 #include "EmPalmStructs.h" // EmAliasPenBtnInfoType #include "EmPatchState.h" // GetCurrentAppInfo #include "EmSession.h" // gSession, ScheduleAutoSaveState #include "ErrorHandling.h" // Errors::ThrowIfPalmError #include "Hordes.h" // Hordes::IsOn, TurnOn #include "Logging.h" #include "PreferenceMgr.h" // Preference #include "ROMStubs.h" // FtrGet, TxtGetNextChar, TxtCharBounds, TxtByteAddr, FrmGetActiveForm... #include "SessionFile.h" // SessionFile #include "Strings.r.h" // kStr_ values #include "EmLowMem.h" // EmLowMem_SetGlobal for setting battery level /////////////////////////////////////////////////////////////////////////////////// // Private function declarations // (actually just some operator override declarations we'll need) static EmStream& operator >> (EmStream&, DatabaseInfo&); static EmStream& operator << (EmStream&, const DatabaseInfo&); static EmStream& operator >> (EmStream&, GremlinInfo&); static EmStream& operator << (EmStream&, const GremlinInfo&); /////////////////////////////////////////////////////////////////////////////////// // Private globals static int gIntlMgrExists = -1; /////////////////////////////////////////////////////////////////////////////////// // Private functions static Bool IntlMgrExists (void) { if (gIntlMgrExists < 0) { // Note that we need to check by calling the feature manager rather than // checking to see if the trap is implemented. sysTrapIntlDispatch is // sysTrapPsrInit on 1.0 systems and sysUnused2 on intermediate systems. // That means that the trap IS implemented, but just not the one we want. UInt32 data; Err err = FtrGet (sysFtrCreator, sysFtrNumIntlMgr, &data); gIntlMgrExists = !err && (data & intlMgrExists) != 0; } return gIntlMgrExists != 0; } static UInt16 _TxtGetNextChar (const Char *inText, UInt32 inOffset, WChar *outChar) { if (IntlMgrExists ()) { return TxtGetNextChar (inText, inOffset, outChar); } if (outChar) *outChar = (UInt8) inText[inOffset]; return sizeof (Char); } static WChar _TxtCharBounds (const Char *inText, UInt32 inOffset, UInt32 *outStart, UInt32 *outEnd) { if (IntlMgrExists ()) { return TxtCharBounds (inText, inOffset, outStart, outEnd); } if (outStart) *outStart = inOffset; if (outEnd) *outEnd = inOffset + 1; return inText[inOffset]; } static UInt8 _TxtByteAttr (UInt8 inByte) { if (IntlMgrExists ()) { return TxtByteAttr (inByte); } return byteAttrSingle; } #define TxtGetNextChar _TxtGetNextChar #define TxtCharBounds _TxtCharBounds #define TxtByteAttr _TxtByteAttr #include "CGremlins.h" #include "CGremlinsStubs.h" #define PRINTF if (!LogGremlins ()) ; else LogAppendMsg // Use our own versions of rand() and srand() so that we generate the // same numbers on both platforms. #undef RAND_MAX #define RAND_MAX 0x7fff #define rand Gremlin_rand #define srand Gremlin_srand unsigned long int gGremlinNext = 1; static int rand(void) { // gGremlinNext = gGremlinNext * 1103515245 + 12345; // MSL numbers gGremlinNext = gGremlinNext * 214013L + 2531011L; // VC++ numbers PRINTF ("--- gGremlinNext == 0x%08X", (long) gGremlinNext); return ((gGremlinNext >> 16) & 0x7FFF); } static void srand(unsigned int seed) { gGremlinNext = seed; } #endif //#define randN(N) ((N) ? rand() / (RAND_MAX / (N)) : (0)) #define randN(N) ((int) (((long) rand() * (N)) / ((long) RAND_MAX + 1))) #define randPercent (randN(100)) #ifndef forSimulator #undef randN inline int randN (long N) { int result = ((int) (((long) rand() * (N)) / ((long) RAND_MAX + 1))); PRINTF ("--- randN(%ld) == 0x%08X", N, (long) result); return result; } #endif #define PEN_MOVE_CHANCE 50 // 50% move pen else pen up #define PEN_BIG_MOVE_CHANCE 5 // 5% move pen really far #define KEY_DOWN_EVENT_WITHOUT_FOCUS_CHANCE 10 #define KEY_DOWN_EVENT_WITH_FOCUS_CHANCE 40 #define PEN_DOWN_EVENT_CHANCE (70 + KEY_DOWN_EVENT_WITHOUT_FOCUS_CHANCE) #define MENU_EVENT_CHANCE (PEN_DOWN_EVENT_CHANCE + 4) #define FIND_EVENT_CHANCE (MENU_EVENT_CHANCE + 2) #define KEYBOARD_EVENT_CHANCE (FIND_EVENT_CHANCE + 1) #define LOW_BATTERY_EVENT_CHANCE (KEYBOARD_EVENT_CHANCE + 2) #define APP_SWITCH_EVENT_CHANCE (LOW_BATTERY_EVENT_CHANCE + 4) // #define POWER_OFF_CHANCE (APP_SWITCH_EVENT_CHANCE + 1) #define LAUNCHER_EVENT_CHANCE 0 // percent of APP_SWITCH_EVENT_CHANCE #define commandKeyMask 0x0008 #define TYPE_QUOTE_CHANCE 10 #define MAX_SEED_VALUE 1000 // Max. # of seed values allowed. #define INITIAL_SEED 1 #define LETTER_PROB 60 // Chars less often than a letter #define SYMBOL_PROB (LETTER_PROB / 10) #define EXT_LTTR_PROB (LETTER_PROB / 3) #define EXTENDED_PROB (LETTER_PROB / 5) #define CONTROL_PROB (LETTER_PROB / 2) #define MENU_PROB (LETTER_PROB / 10) #define KBRD_PROB 1 // The formula results in 0 // ((LETTER_PROB / 30) / 3) // three chars to activate keyboard #define NXTFLD_PROB (LETTER_PROB / 10) #define SEND_DATA_PROB (LETTER_PROB / 60) // Chars more often than a letter #define SPACE_PROB (LETTER_PROB * 5) #define TAB_PROB (LETTER_PROB * 2) #define BACKSPACE_PROB (LETTER_PROB * 3) #define RETURN_PROB ((LETTER_PROB * 10) * 1) // extra exercise //Global variables Gremlins* TheGremlinsP; // Pointer to the Gremlins class. long IdleTimeCheck; // Tick count for the next idle query // Array of probabilities of a key being pressed for gremlin mode. #define NUM_OF_KEYS 0x110 static const int chanceForKey[NUM_OF_KEYS] = { 0, 0, 0, 0, 0, 0, 0, 0, // 0x00 - 0x07 BACKSPACE_PROB, TAB_PROB, RETURN_PROB, CONTROL_PROB, CONTROL_PROB, 0, 0, 0, // 0x08 - 0x0F 0, 0, 0, 0, 0, 0, 0, 0, // 0x10 - 0x17 0, 0, 0, 0, CONTROL_PROB, CONTROL_PROB, CONTROL_PROB, CONTROL_PROB, // 0x18 - 0x1F // Symbols SPACE_PROB, SYMBOL_PROB, SYMBOL_PROB, SYMBOL_PROB, // 0x20 - 0x23 SYMBOL_PROB, SYMBOL_PROB, SYMBOL_PROB, SYMBOL_PROB, // 0x24 - 0x27 SYMBOL_PROB, SYMBOL_PROB, SYMBOL_PROB, SYMBOL_PROB, // 0x28 - 0x2B SYMBOL_PROB, SYMBOL_PROB, SYMBOL_PROB, SYMBOL_PROB, // 0x2C - 0x2F SYMBOL_PROB, SYMBOL_PROB, SYMBOL_PROB, SYMBOL_PROB, // 0x30 - 0x33 SYMBOL_PROB, SYMBOL_PROB, SYMBOL_PROB, SYMBOL_PROB, // 0x34 - 0x37 SYMBOL_PROB, SYMBOL_PROB, SYMBOL_PROB, SYMBOL_PROB, // 0x38 - 0x3B SYMBOL_PROB, SYMBOL_PROB, SYMBOL_PROB, SYMBOL_PROB, // 0x3C - 0x3F // Uppercase LETTER_PROB, LETTER_PROB, LETTER_PROB, LETTER_PROB, // 0x40 - 0x43 LETTER_PROB, LETTER_PROB, LETTER_PROB, LETTER_PROB, // 0x44 - 0x47 LETTER_PROB, LETTER_PROB, LETTER_PROB, LETTER_PROB, // 0x48 - 0x4B LETTER_PROB, LETTER_PROB, LETTER_PROB, LETTER_PROB, // 0x4C - 0x4F LETTER_PROB, LETTER_PROB, LETTER_PROB, LETTER_PROB, // 0x50 - 0x53 LETTER_PROB, LETTER_PROB, LETTER_PROB, LETTER_PROB, // 0x54 - 0x57 LETTER_PROB, LETTER_PROB, LETTER_PROB, LETTER_PROB, // 0x58 - 0x5B LETTER_PROB, LETTER_PROB, LETTER_PROB, LETTER_PROB, // 0x5C - 0x5F // Lowercase LETTER_PROB, LETTER_PROB, LETTER_PROB, LETTER_PROB, // 0x60 - 0x63 LETTER_PROB, LETTER_PROB, LETTER_PROB, LETTER_PROB, // 0x64 - 0x67 LETTER_PROB, LETTER_PROB, LETTER_PROB, LETTER_PROB, // 0x68 - 0x6B LETTER_PROB, LETTER_PROB, LETTER_PROB, LETTER_PROB, // 0x6C - 0x6F LETTER_PROB, LETTER_PROB, LETTER_PROB, LETTER_PROB, // 0x70 - 0x73 LETTER_PROB, LETTER_PROB, LETTER_PROB, LETTER_PROB, // 0x74 - 0x77 LETTER_PROB, LETTER_PROB, LETTER_PROB, LETTER_PROB, // 0x78 - 0x8B LETTER_PROB, LETTER_PROB, LETTER_PROB, LETTER_PROB, // 0x7C - 0x7F EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0x80 - 0x83 EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0x84 - 0x87 EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0x88 - 0x8B EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0x8C - 0x8F EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0x90 - 0x93 EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0x94 - 0x97 EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0x98 - 0x9B EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0x9C - 0x9F EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xA0 - 0xA3 EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xA4 - 0xA7 EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xA8 - 0xAB EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xAC - 0xAF EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xB0 - 0xB3 EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xB4 - 0xB7 EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xB8 - 0xBB EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xBC - 0xBF EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xC0 - 0xC3 EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xC4 - 0xC7 EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xC8 - 0xCB EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xCC - 0xCF EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xD0 - 0xD3 EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xD4 - 0xD7 EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xD8 - 0xDB EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xDC - 0xDF EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xE0 - 0xE3 EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xE4 - 0xE7 EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xE8 - 0xEB EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xEC - 0xEF EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xF0 - 0xF3 EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xF4 - 0xF7 EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xF8 - 0xFB EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, EXTENDED_PROB, // 0xFC - 0xFF // Virtual events // DOLATER kwk - Why not generate keyboardAlphaChr (0x110) & keyboardNumericChr (0x111)? 0, 0, 0, NXTFLD_PROB, 0, MENU_PROB, CONTROL_PROB, 0, // 0x100 - 0x107 CONTROL_PROB, KBRD_PROB, CONTROL_PROB, 0, NXTFLD_PROB, 0, 0, 0, // 0x108 - 0x10f }; #define NUM_OF_QUOTES 18 // Shakespearean quotes used by Gremlins for English text static const char * kAsciiQuotes[NUM_OF_QUOTES] = { "Out out damn spot!", "Et tu, Brute?", "When in disgrace with fortune and mens' eyes " "I all alone beweep my outcast state. " "And trouble deaf heaven with my bootless cries and " "look upon myself and curse my fate. " "Wishing me like to one more rich in hope, " "featured like him, like him with friends possest, " "desiring this man's art and that man's scope, " "with what I most enjoy contented least;" "\n" "Yet in these thoughts myself almost despising- " "haply I think on thee: and then my state, " "like to the lark at break of day arising " "from sullen earth, sings hymns at Heaven's gate; " "for thy sweet love rememb'red such wealth brings " "that then I scorn to change my state with kings.", "I think my wife is honest, and think she is not; " "I think that thou art just, and think thou art not.", "O that this too too sullied flesh would melt, thaw, " "and resolve itself into a dew, " "or that the Everlasting had not fixed " "His canon 'gainst self-slaughter.", "Come, you spirits that tend on mortal thoughts, unsex me here, " "and fill me from the crown to the toe top-full " "of direst cruelty.", "I do not think but Desdemona's honest.", "That I did love the Moor to live with him", "What a piece of work is a man", "Fair is foul, and foul is fair.", "All hail, Macbeth, that shalt be King hereafter!", "What's Montague?", "To a nunnery, go, and quickly too.", "I'll have some proof.", "Now are we well resolved, and by God's help and yours, " "the noble sinews of our power, France being ours, " "we'll bend it to our awe or break it all to pieces.", "Tennis balls, my liege.", "De Sin: le col de Nick, le menton de Sin.", "But swords I smile at, weapons laugh to scorn, " "brandished by man that's of a woman born." }; static const char * kShiftJISQuotes[NUM_OF_QUOTES] = { "人は、かつて森の神を殺した", "もののけ姫", "人面と獣の身体、樹木の角を持つ森の神・シシ神を" "人は何故殺さねばならなかったのか−" "この時代、人間がふえ、多くの原生林が拓かれたとはいえ、" "まだ人を寄せつけぬ太古の森があちこちに残っていた" "\n" "それぞれの森は、猪や山犬など" "巨大で賢かった獣たちが必死になって守っていた" "そして、聖域を侵す人間達を襲い" "荒ぶる神々と恐れられていた" "その獣達を従えていたのが、シシ神である" "荒ぶる神々を最も激しく戦っていたのは" "タタラ者と呼ばれる製鉄集団だった", "女の身でタタラ集団を率いるエボシ御前" "彼女は己が信念で、森を切り拓いていた", "その配下で、御前を敬い慕う、ゴンザにおトキと甲六" "シシ神をねらう正体不明の坊主・ジコ坊" "北の地の果ての隠れ里に住む老巫女・ヒイさま" "乙事主、ナゴの神、モロなど森を守る神獣たち", "それに森の精霊・コダマたち…少女サンは人間の" "子でありながら山犬モロに育てられた「もののけ姫」", "だったサンは、森を侵す人間を激しく憎", "んでいたそして、人間と荒ぶる神々の最後", "の大決戦に巻き込まれる少年", "アシタカ彼は、死の呪いを", "かけられたがゆえに穢れを浄める方法を探しに、", "旅に出た少年だった", "少年と少女は惨劇の中で出会い、", "次第に心を通わせ", "てゆくふたりが憎悪と殺戮の果てに見いだした" "希望とは何だったのか少年と少女の愛" "を横糸にシシ神をめぐる人間と獣たち", "の戦いを縦糸に", "波瀾万丈の一大叙事詩が、展開されていく…", "原作・脚本  :宮崎 駿製 作    :氏家齊一郎・成田 豊製作総指揮  " ":徳間康快プロデューサー:鈴木敏夫" }; static const char * kBig5Quotes[NUM_OF_QUOTES] = { "ヲケカ}ィイト、@ヲ^、]。Cァ@", "ェフヲロカウ。Gヲ]エソ", "セ荵L、@オfケレ、ロ、ァォ癸AャGアNッuィニチ・h。Aヲモュノ\"ウqニF\"" "、ァサ。。Aシカヲケ、@ョム、]。CャG、鷭"コツ、hチ\"、ェ、ェ。C" "ヲョム、、ゥメーOヲィニヲ、H。Hヲロ、Sカウ。G、オュキケミクLクL。A、@ィニオLヲィ。A", "ゥソゥタ、ホキ、鬩メヲウ、ァ、k、l。A、@、@イモヲメク・h。A" "トアィ荐讀ィ」テム。Aャメ・Xゥァレ、ァ、W。Cヲァレーーナスャワ。A" "クロ、」ュYゥシクネウヲォv。Hケキ\\ォhヲウセl。Aョャ、SオLッq、ァ、jオL・iヲpヲ、ァ" "、鬢]。Iキヲケ。AォhヲロアアN、wゥケゥメソ爨ムョヲッェシw。AタAヲ醪K、ァ" "ョノ。Aワョ・フナ茗ホ、ァ、鬘AュI、・Sアミィ|、ァョヲ。Aュtョv " "\n" "、ヘウWスヘ、ァシw。A・Hヲワ、オ、鬢@ァ゙オLヲィ。A・b・ヘシ罸ヒ、ァクo。Aスs " "ュz、@カー。A・Hァi、ム、U、H。Gァレ、ァクoゥT、」ァK。AオMサモサユ、、" "・サヲロセセヲウ、H。AクU、」・iヲ]ァレ、ァ、」ィv。Aヲロナ@、vオu " "。A、@ィヨィマィ茗{キタ、]。Cチ、オ、鬢ァュTンワスエシ。A・ヒ_テキァノ。Aィ " "ア皃iュキナS。Aカ・ャhョxェ癸A・逾シヲウァォァレ、ァテフテhオァセ・ェフ。Cチァレ " "・シセヌ。A、UオァオL、蝪A、Sヲァォ・ホーイサyァィ・。Aシナコt・X、@ャqャGィニ" "ィモ。A・逾iィマサモサユャLカヌ。Aスニ・iョョ・@、ァ・リ。Aッ}、HキTエe。A、」・ " "ゥy・G。HャG、鷭"クォBァ\"、ェ、ェ。Cヲケヲ^、、、Z・ホ\"ケレ\"・ホ\"、ロ\"", "オ・ヲr。AャOエ」ソセ\\ェフイエ・リ。A・隨Oヲケョム・゚キN・サヲョ。CヲCヲャンゥx。GァA" "ケDヲケョムアqヲヲモィモ。Hサ。ー_ョレ・ムチェッ " "ュ。Aイモォォhイ`ヲウスィ。Cォンヲb、UアNヲケィモセェ`ゥ" "ュィモ、kエE、キメ・ロクノ、ム、ァョノ。Aゥ、jッ、s", "オLス]アVスmヲィーェクg、Q、G、V。A、雕g、G、Q・|、Vケx・ロ、TクU、サ、d、ュヲハケs、@カ。CエEャモ" "、・u・ホ、F、TクU、サ、d、ュヲハカ。A・uウ豕豕ム、F、@カ・シ・ホ。AォK" "アヲbヲケ、sォCョGョp、U。C", "スヨェセヲケ・ロヲロクgキメ、ァォ癸AニFゥハ、wウq。Aヲ]ィ」_・ロ", "ュムアoクノ、ム。AソWヲロ、vオLァ、」ウ、Jソ。AケEヲロォ隕ロシロ", "。A、鬩]エdクケコFキ\\。C、@、鬘A・ソキカリ", "ア・、ァサレ。AォXィ」、@ケャ、@ケDサキサキヲモィモ。A", "・ヘアoーゥョ讀」、Z。Aツラッォュ~イァ。Aサ。サ。ッコッコィモヲワョp、U。Aァ、、_・ロ", "テ莢ェスヘァヨスラ。C・ャO", "サ。ィヌカウ、sテョッォ・P・ネ、ロ、ァィニ。Aォ皚Kサ。ィ", "ャケミ、、コaオリエIカQ。Cヲケ・ロ", "ナ・、F。A、」トア・エーハ、Z、゚。A、]キQュnィ、Hカ。・hィノ、@ィノウoコaオリエIカQ。Aヲ" "ヲロォイハト。A、」アo、w。AォK、fヲR、Hィ・。AヲVィコケャケDサ。ケD。G、jョv。A" "ァフ、lトェォ。A、」ッ爲」ツァ、F。CセAサD、Gヲスヘィコ、H・@カ。コaト」チcオリ。A", "、゚、チシ}、ァ。Cァフ、lス霖イハト", "。Aゥハォoオyウq。Aェpィ」、Gョv・PァホケDナ鬘AゥwォD、Zォ~。A・イ", "ヲウクノ、ムタル・@、ァァ。AァQェォタル、H、ァシw。CヲpサXオo、@ツIキO、゚。A" "ト箜aァフ、lアo、Jャケミ。AヲbィコエIカQウ、、。AキナャXカmィス" }; static const char * kGB2312Quotes[NUM_OF_QUOTES] = { "エヒソェセオレメササリメイ。」ラ", "ユ゚ラヤヤニ」コメヤ", "タケメサキャテホサテヨョコ」ャケハスォユ賁ツメネ・」ャカス陦ーヘィチ鬘ア" "ヨョヒオ」ャラォエヒメサハ鰓イ。」ケハヤサ。ーユ醋ソメ。アヤニヤニ。」" "オォハ鰒ミヒシヌコホハツコホネヒ」ソラヤモヨヤニ」コスキ邉セツオツオ」ャメサハツボウノ」ャ", "コトシーオアネユヒモミヨョナョラモ」ャメサメサマクソシスマネ・」ャ" "セニ菻ミヨケシハカ」ャスヤウモレホメヨョノマ。」コホホメフテフテミテシ」ャ" "ウマイサネアヒネケホヤユ」ソハオタ「ヤモミモ爛ャサレモヨボメ贍ョエボソノネ郤ホヨョ" "ネユメイ」。オアエヒ」ャヤラヤモスォメムヘヒタオフカラ豬ツ」ャスメツヨョ" "ハア」ャ簑クハミキハヨョネユ」ャアウククミヨスフモヨョカ」ャクコハヲ" "\n" "モムケ賣クヨョオツ」ャメヤヨチスネユメサシシボウノ」ャーノチハオケヨョラ」ャア" "ハメサシッ」ャメヤク賣マツネヒ」コホメヨョラケフイサテ筌ャネサケクヨミ" "アセラヤタタモミネヒ」ャヘイサソノメホメヨョイサミ、」ャラヤサ、シコカフ" "」ャメサイ「ハケニ蒹テメイ。」ヒ菴ネユヨョテゥエェナサ」ャペヤノエイ」ャニ" "ウソマヲキ酊カ」ャスラチヘ・サィ」ャメ猥エモミキチホメヨョスサウアハトォユ゚。」ヒ萸メ" "ホエムァ」ャマツアハボホト」ャモヨコホキチモテシルモエ衽ヤ」ャキムンウメサカホケハハツ" "タエ」ャメ狒ノハケケクユムエォ」ャクエソノヤテハタヨョトソ」ャニニネヒウテニ」ャイサメ" "メヒコ」ソケハヤサ。ーシヨモエ蝪アヤニヤニ。」エヒサリヨミキイモテ。ーテホ。アモテ。ーサテ。ア", "オネラヨ」ャハヌフ瞎ムヤトユ゚ムロトソ」ャメ猝ヌエヒハ鮹「メ箜セヨシ。」チミホサソエケル」コト" "オタエヒハ魘モコホカタエ」ソヒオニクモノヒ菴サト" "フニ」ャマクーエヤノモミネ、ホカ。」エヤレマツスォエヒタエタラ「テ" "ヤュタエナョ豢ハマチカハッイケフヨョハア」ャモレエサトノス", "ボサムツチキウノク゚セュハョカユノ」ャキスセュカハョヒトユノヘ醋ッネヘチヌァホ蟆ルチ耡サソ鬘」豢サハ" "ハマヨサモテチヒネヘチヌァホ蟆ルソ鬟ャヨサオ・オ・ハ」チヒメサソ鯰エモテ」ャア" "ニヤレエヒノスヌ犹。キ袞ツ。」", "ヒュヨェエヒハッラヤセュチカヨョコ」ャチ鰔ヤメムヘィ」ャメシヨレハッ", "セ羞テイケフ」ャカタラヤシコボイトイサソーネム。」ャヒラヤヤケラヤフセ", "」ャネユメケアッコナイムタ「。」メサネユ」ャユオア犒", "オソヨョシハ」ャカシメサノョメサオタヤカヤカカタエ」ャ", "ノオテケヌクイサキイ」ャキ睨蠧メ」ャヒオヒオミヲミヲタエヨチキ袞ツ」ャラモレハッ", "ア゚ク゚フクソツロ。」マネハヌ", "ヒオミゥヤニノスホコ」ノマノミサテヨョハツ」ャコア耆オオス", "コウセヨミネルサェクサケ。」エヒハッ", "フチヒ」ャイサセエカッキイミト」ャメイマメェオスネヒシ菠・マメサマユ篳ルサェクサケ」ャオォ" "ラヤゴエヨエタ」ャイサオテメム」ャア譱レヘツネヒムヤ」ャマトヌノョオタヒオオタ」コエハヲ」ャ" "オワラモエタホ」ャイサトワシタチヒ。」ハハホナカホサフクトヌネヒハタシ菠ルメォキアサェ」ャ", "ミトヌミトスヨョ。」オワラモヨハヒ莇ヨエタ", "」ャミヤネエノヤヘィ」ャソシカハヲマノミホオタフ螢ャカィキヌキイニキ」ャアリ", "モミイケフシテハタヨョイト」ャタホシテネヒヨョオツ。」ネ酖ノキ「メサオ羔ネミト」ャ" "ミッエオワラモオテネコウセ」ャヤレトヌクサケウ。ヨミ」ャホツネ睹鄲" }; typedef struct { UInt16 charEncoding; const char** strings; } QuotesInfoType; static const QuotesInfoType kQuotesInfo[] = { { charEncodingPalmSJIS, kShiftJISQuotes }, // All of the possible Traditional Chinese encodings. { charEncodingBig5, kBig5Quotes }, { charEncodingBig5_HKSCS, kBig5Quotes }, { charEncodingBig5Plus, kBig5Quotes }, { charEncodingPalmBig5, kBig5Quotes }, // All of the possible Simplified Chinese encodings. { charEncodingGB2312, kGB2312Quotes }, { charEncodingGBK, kGB2312Quotes }, { charEncodingPalmGB, kGB2312Quotes } }; /*********************************************************************** * * FUNCTION: GetFocusObject * * DESCRIPTION: Return whether the current form has the focus. * * CALLED BY: here * * PARAMETERS: none * * RETURNED: TRUE if the form has a focus set and FALSE if not * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * roger 8/25/95 Initial Revision * roger 11/27/95 Ignored not editable fields. * ***********************************************************************/ static FieldPtr GetFocusObject() { FormPtr frm; UInt16 focusObj; FieldPtr textFieldP; // Pick a point within one of the current form's objects frm = FrmGetActiveForm (); // The active window will not be the active form // if a popup list of a menu is displayed. if ((! frm) || (FrmGetWindowHandle (frm) != WinGetActiveWindow ()) || ((focusObj = FrmGetFocus(frm)) == noFocus)) { if (!frm) PRINTF ("--- GetFocusObject == NULL (FrmGetActiveForm () == NULL)"); else if (FrmGetWindowHandle (frm) != WinGetActiveWindow ()) PRINTF ("--- GetFocusObject == NULL (FrmGetWindowHandle () != WinGetActiveWindow ())"); else PRINTF ("--- GetFocusObject == NULL (FrmGetFocus () == noFocus)"); return NULL; } // Get the field. If it's a table get it's field. if (FrmGetObjectType(frm, focusObj) == frmTableObj) { textFieldP = TblGetCurrentField((TablePtr) FrmGetObjectPtr(frm, focusObj)); if (textFieldP == NULL) { PRINTF ("--- GetFocusObject == NULL (TblGetCurrentField () == NULL)"); return NULL; } } else { textFieldP = (FieldPtr) FrmGetObjectPtr(frm, focusObj); if (textFieldP == NULL) { PRINTF ("--- GetFocusObject == NULL (FrmGetObjectPtr () == NULL)"); } } return textFieldP; } /*********************************************************************** * * FUNCTION: IsFocus * * DESCRIPTION: Return whether the current form has the focus. * * CALLED BY: EmGremlins.cp * * PARAMETERS: none * * RETURNED: TRUE if the form has a focus set and FALSE if not * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * roger 8/25/95 Initial Revision * roger 11/27/95 Ignored not editable fields, broke out GetFocusObject * ***********************************************************************/ static int IsFocus() { FieldPtr textFieldP; FieldAttrType attr; textFieldP = GetFocusObject(); if (textFieldP == NULL) { PRINTF ("--- IsFocus == false (textFieldP == NULL)"); return false; } // Now make sure that the field is editable. FldGetAttributes(textFieldP, &attr); if (!attr.editable) { PRINTF ("--- IsFocus == false (!attr.editable 0x%04X)", (uint32) *(uint16*) &attr); return false; } PRINTF ("--- IsFocus == true"); return true; } /*********************************************************************** * * FUNCTION: SpaceLeftInFocus * * DESCRIPTION: Return the number of characters which can be added to * the object with the focus. * * CALLED BY: EmGremlins.cp * * PARAMETERS: none * * RETURNED: The number of characters which can be added to * the object with the focus. * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * roger 11/27/95 Initial Revision * ***********************************************************************/ static int SpaceLeftInFocus() { FieldPtr textFieldP; FieldAttrType attr; textFieldP = GetFocusObject(); if (textFieldP == NULL) return 0; // Now make sure that the field is editable. FldGetAttributes(textFieldP, &attr); if (!attr.editable) return 0; return FldGetMaxChars(textFieldP) - FldGetTextLength(textFieldP); } /*********************************************************************** * * FUNCTION: FakeLocalMovement * * DESCRIPTION: Generate a random point within the vicinity of the last * point. * * CALLED BY: EmGremlins.cp * * PARAMETERS: currentX - the new x-coordinate of a pen movement. * currentY - the new y-coordinate of a pen movement. * lastX - the last x-coordinate of a pen movement. * lastY - the last y-coordinate of a pen movement. * * RETURNED: Nothing. * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * David 8/15/95 Initial Revision * ***********************************************************************/ static void FakeLocalMovement(Int16* currentX, Int16* currentY, Int16 lastX, Int16 lastY) { Int16 winWidth, winHeight; *currentX = lastX + (randN(FntLineHeight() * 2) - FntLineHeight()); *currentY = lastY + (randN(FntLineHeight() * 2) - FntLineHeight()); // FntLineHeight // Note: This code was incorrectly using Hwr Display constants to determine screen size. // The approved of method is to use the size of the current window, which may also be // the screen, however, this may not be correct for what gremilns needs to do. // Something needs to be done for now just to get it to work. BRM 6/30/99 WinGetDisplayExtent(&winWidth, &winHeight); // Clip to screen bounds // // KAAR: In original Gremlins, the point was pinned to [-1...winWidth/Height]. // That doesn't seem right, especially since -1 is used as a pen up indicator. // So now I clip to [0...winWidth/Height). if (*currentX < 0) *currentX = 0; if (*currentX >= winWidth) *currentX = winWidth - 1; if (*currentY < 0) *currentY = 0; if (*currentY >= winHeight) *currentY = winHeight = 1; } /*********************************************************************** * * FUNCTION: RandomScreenXY * * DESCRIPTION: Generate a random point. * * CALLED BY: EmGremlins.cp * * PARAMETERS: x - the x-coordinate of a pen movement. * y - the y-coordinate of a pen movement. * * RETURNED: Nothing. * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * David 8/15/95 Initial Revision * ***********************************************************************/ static void RandomScreenXY(Int16* x, Int16* y) { #ifdef __DEBUGGER_APPLICATION__ // Since the WinGetDisplayExtent() trap doesn't exist in all versions // of the Palm OS, the debugger can't rely on it being around. So, // for the debugger version of this build, we explicitely set the // old screen width. // // DOLATER: Figure out a way to determine if the WinGetDisplayExtent() // is around. If it is, then call it. Otherwise, revert to the // old constants. // #define hwrDisplayWidth 160 #define hwrDisplayHeight 160 *x = randN(hwrDisplayWidth); *y = randN(hwrDisplayHeight); #else Int16 winWidth, winHeight; WinGetDisplayExtent(&winWidth, &winHeight); *x = randN(winWidth); *y = randN(winHeight); #endif } /*********************************************************************** * * FUNCTION: RandomWindowXY * * DESCRIPTION: Generate a random point. * * CALLED BY: EmGremlins.cp * * PARAMETERS: x - the x-coordinate of a pen movement. * y - the y-coordinate of a pen movement. * * RETURNED: Nothing. * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * Keith 11/11/99 Initial Revision * ***********************************************************************/ static void RandomWindowXY(Int16* x, Int16* y) { // Every so often tap anywhere on the screen (10%) if ((randN(10) == 1) || (WinGetActiveWindow () == NULL)) { RandomScreenXY(x, y); } else { // We want to tap in the active window. However, WinGetWindowBounds // works against the draw window, which is not necessarily the active // window. Make it so. WinHandle oldDraw = WinSetDrawWindow (WinGetActiveWindow()); RectangleType bounds; WinGetWindowBounds (&bounds); *x = bounds.topLeft.x + randN(bounds.extent.x); *y = bounds.topLeft.y + randN(bounds.extent.y); WinSetDrawWindow (oldDraw); } } /*********************************************************************** * * FUNCTION: FakeEventXY * * DESCRIPTION: Generate random (x,y) coordindates to produce an event. * * CALLED BY: EmGremlins.cp * * PARAMETERS: x - x-coordinate of a pen down. * y - y-coordinate of a pen down. * * RETURNED: * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * David 08/15/95 Initial Revision * kwk 07/17/98 10% of the time, generate tap in silkscreen btn. * kwk 08/04/99 Cranked percentage down to 5%, since otherwise * we're always just bringing up the keyboard or * the Find form. * ***********************************************************************/ static void FakeEventXY(Int16* x, Int16* y) { FormPtr frm; Int16 objIndex; RectangleType bounds; #ifndef forSimulator // Every so often tap anywhere on the screen (2%) if (randN(100) < 2) { RandomScreenXY(x, y); return; } #endif // Pick a point within one of the current form's objects frm = FrmGetActiveForm (); // First see if we want to generate a tap in a silkscreen button. If not, then // generate a point in the draw window if there no active form, or the active form // is not the the active window.. The active window will not be the active form // if a popup list of a menu is displayed. // // Also do this if there aren't any objects in the form. if (randN(20) == 1) { UInt16 numButtons; const PenBtnInfoType* buttonListP = EvtGetPenBtnList(&numButtons); const size_t size = EmAliasPenBtnInfoType::GetSize (); emuptr addr = ((emuptr) buttonListP) + randN(numButtons) * size; EmAliasPenBtnInfoType button (addr); RectangleType randButtonRect; randButtonRect.topLeft.x = button.boundsR.topLeft.x; randButtonRect.topLeft.y = button.boundsR.topLeft.y; randButtonRect.extent.x = button.boundsR.extent.x; randButtonRect.extent.y = button.boundsR.extent.y; *x = randButtonRect.topLeft.x + (randButtonRect.extent.x / 2); *y = randButtonRect.topLeft.y + (randButtonRect.extent.y / 2); } else if ((frm == NULL) || (FrmGetWindowHandle (frm) != WinGetActiveWindow ())) { RandomWindowXY (x, y); } else { // Generate a point in an one of the form's objects that we expect // can do something with the point (i.e. labels are ignored). #ifdef forSimulator do { objIndex = randN(numObjects); switch (FrmGetObjectType (frm, objIndex)) { case frmBitmapObj: case frmLineObj: case frmFrameObj: case frmRectangleObj: case frmLabelObj: case frmTitleObj: case frmPopupObj: // do nothing for these objIndex = -1; break; default: FrmGetObjectBounds (frm, objIndex, &bounds); *x = bounds.topLeft.x + randN(bounds.extent.x); *y = bounds.topLeft.y + randN(bounds.extent.y); WinWindowToDisplayPt(x, y); if ( *x < -1 || *x > 1000 || *y < -1 || *y > 1000) ErrDisplay("Invalid point made"); break; } // end switch } while (objIndex == -1); // don't leave until we found a useful object #else // Get the list of objects we can click on. vector okObjects; ::CollectOKObjects (frm, okObjects); // If there are no such objects, just generate a random point. if (okObjects.size () == 0) { RandomWindowXY (x, y); } // If there are such objects, pick one and click on it. else { objIndex = okObjects[randN(okObjects.size ())]; FrmGetObjectBounds (frm, objIndex, &bounds); Int16 winWidth, winHeight; ::WinGetDisplayExtent(&winWidth, &winHeight); if (bounds.topLeft.x < 0) bounds.topLeft.x = 0; if (bounds.topLeft.y < 0) bounds.topLeft.y = 0; if (bounds.extent.x > winWidth - bounds.topLeft.x - 1) bounds.extent.x = winWidth - bounds.topLeft.x - 1; if (bounds.extent.y > winHeight - bounds.topLeft.y - 1) bounds.extent.y = winHeight - bounds.topLeft.y - 1; *x = bounds.topLeft.x + randN(bounds.extent.x); *y = bounds.topLeft.y + randN(bounds.extent.y); WinWindowToDisplayPt(x, y); } #endif } // end else } /************************************************************ * * FUNCTION: GremlinsSendEvent * * DESCRIPTION: Send a synthesized event to the device if it's * idle. * * PARAMETERS: nothing * * RETURNS: nothing * * CALLED BY: the debugger's console object * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * art 11/2/95 Created. * dia 8/26/98 Added try/catch block. * *************************************************************/ #ifdef forSimulator void GremlinsSendEvent (void) { // long tick; // Boolean idle; // LowMemType* lowMemP = (LowMemType*)PilotGlobalsP; // SysEvtMgrGlobalsPtr sysEvtMgrGlobalsP; if (!TheGremlinsP->IsInitialized() || !StubGremlinsIsOn()) return; ErrTry { #if EMULATION_LEVEL == EMULATION_WINDOWS TheGremlinsP->GetFakeEvent(); #else // This makes it go faster, but it is much less careful (not as reproducable). // The code was left here for future reference / fixing. // // If accessing remote device, low memory is at 0... // #if MEMORY_TYPE == MEMORY_REMOTE // lowMemP = (LowMemType*)0; // #endif // // // Find out if the device is idle. // tick = StubTimGetTicks(); // if ((tick - IdleTimeCheck) >= 0) // { // sysEvtMgrGlobalsP = (SysEvtMgrGlobalsPtr)ShlDWord(&lowMemP->fixed.globals.sysEvtMgrGlobalsP); // idle = ShlByte(&sysEvtMgrGlobalsP->idle); // if (!idle) // { // IdleTimeCheck = tick + 12; // 10 times a second // return; // } // else // // Clear the idle bit so the the device will not send us another idle packet. // // Send an event // IdleTimeCheck = 0; // TheGremlinsP->GetFakeEvent(); // } #endif } ErrCatch (inErr) { if (inErr != -1) { char text[256]; UInt32 step; // Print error & stop... TheGremlinsP->Status (NULL, &step, NULL); sprintf(text, "Error #%lx occurred while sending. Gremlins at %ld. Stopping.\n", inErr, step); DbgMessage(text); StubAppGremlinsOff(); } } ErrEndCatch } #endif /************************************************************ * * FUNCTION: GremlinsProcessPacket * * DESCRIPTION: Send a synthesized event to the device if it's * idle. * * PARAMETERS: bodyP - pointer to Gremlins packet from device. * * RETURNS: nothing * * CALLED BY: the debugger's console object * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * art 11/2/95 Created. * dia 8/26/98 Added try/catch block. * *************************************************************/ #ifdef forSimulator void GremlinsProcessPacket (void* bodyParamP) { UInt8 flags; SysPktGremlinsCmdType* bodyP = (SysPktGremlinsCmdType*)bodyParamP; LowMemType* lowMemP = (LowMemType*)PilotGlobalsP; SysEvtMgrGlobalsPtr sysEvtMgrGlobalsP; if (!TheGremlinsP->IsInitialized()) return; ErrTry { // See which action code got sent us if (bodyP->action == sysPktGremlinsIdle) { // If accessing remote device, low memory is at 0... #if MEMORY_TYPE == MEMORY_REMOTE lowMemP = (LowMemType*)0; #endif // Clear the idle bit so the the device will not send us another idle packet. // Send an event TheGremlinsP->GetFakeEvent(); // Turn the idle bit back on. sysEvtMgrGlobalsP = (SysEvtMgrGlobalsPtr)ShlDWord((void *)&lowMemP->fixed.globals.sysEvtMgrGlobalsP); flags = ShlByte((void *)&sysEvtMgrGlobalsP->gremlinsFlags); flags |= grmGremlinsIdle; ShlWriteMem (&flags, (UInt32)&sysEvtMgrGlobalsP->gremlinsFlags, sizeof(UInt8)); // flags = ShlByte(&sysEvtMgrGlobalsP->gremlinsFlags); // ErrFatalDisplayIf (!(flags & grmGremlinsIdle), "Invalid flags"); } else ErrDisplay("Invalid action code"); } ErrCatch (inErr) { if (inErr != -1) { char text[256]; UInt32 step; // Print error & stop... TheGremlinsP->Status (NULL, &step, NULL); sprintf(text, "Error #%lx occurred while processing. Gremlins at %ld. Stopping.\n", inErr, step); DbgMessage(text); StubAppGremlinsOff(); } } ErrEndCatch } #endif // --------------------------------------------------------------------------- // ・ operator >> (EmStream&, DatabaseInfo&) // --------------------------------------------------------------------------- EmStream& operator >> (EmStream& inStream, DatabaseInfo& outInfo) { inStream >> outInfo.creator; inStream >> outInfo.type; inStream >> outInfo.version; inStream >> outInfo.dbID; inStream >> outInfo.cardNo; inStream >> outInfo.modDate; inStream >> outInfo.dbAttrs; inStream >> outInfo.name; outInfo.dbName[0] = 0; return inStream; } // --------------------------------------------------------------------------- // ・ operator << (EmStream&, const DatabaseInfo&) // --------------------------------------------------------------------------- EmStream& operator << (EmStream& inStream, const DatabaseInfo& inInfo) { LocalID dbID = 0; UInt16 cardNo = 0; UInt32 modDate = 0; UInt16 dbAttrs = 0; char name[dmDBNameLength] = {0}; inStream << inInfo.creator; inStream << inInfo.type; inStream << inInfo.version; // I have no idea why dummy values are written out for these fields. // But it sure causes us problems later when we need to access them! // See the code in Hordes::GetAppList that needs to patch up the missing // information. inStream << dbID; inStream << cardNo; inStream << modDate; inStream << dbAttrs; inStream << name; return inStream; } // --------------------------------------------------------------------------- // ・ operator >> (EmStream&, AppPreferences::GremlinInfo&) // --------------------------------------------------------------------------- EmStream& operator >> (EmStream& inStream, GremlinInfo& outInfo) { bool dummy; inStream >> outInfo.fNumber; inStream >> outInfo.fSteps; inStream >> outInfo.fAppList; inStream >> dummy; // forward compatibility: this field was // fContinuePastWarnings inStream >> dummy; inStream >> dummy; return inStream; } // --------------------------------------------------------------------------- // ・ operator << (EmStream&, const AppPreferences::GremlinInfo&) // --------------------------------------------------------------------------- EmStream& operator << (EmStream& inStream, const GremlinInfo& inInfo) { bool dummy = false; inStream << inInfo.fNumber; inStream << inInfo.fSteps; inStream << inInfo.fAppList; inStream << dummy; // backward compatibility: this field was // fContinuePastWarnings inStream << dummy; inStream << dummy; return inStream; } /************************************************************ * * FUNCTION: Default Constructor * * DESCRIPTION: Finds the key probablilities sum. * * PARAMETERS: None. * * RETURNS: Nothing. * * CALLED BY: main() of EmEmulatorApp.cp * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * David 08/01/95 Created. * kwk 07/17/98 Moved key probability init into run-time * section. * *************************************************************/ Gremlins::Gremlins() { keyProbabilitiesSum = 0; inited = false; #ifdef forSimulator number = -1; #else number = ~0; #endif } /************************************************************ * * FUNCTION: Destructor * * DESCRIPTION: Any necessary deallocation or cleanup. * * PARAMETERS: None. * * RETURNS: Nothing. * * CALLED BY: main() of EmEmulatorApp.cp * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * David 8/1/95 Created. * *************************************************************/ Gremlins::~Gremlins() { } /************************************************************ * * FUNCTION: IsInitialized * * DESCRIPTION: Returns whether or not Gremlins has be initialized. * * PARAMETERS: None. * * RETURNS: TRUE - has been initialized, FALSE - has not been initialized. * * CALLED BY: FindCommandStatus() in EmEmulatorApp.cp. * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * David 8/1/95 Created. * *************************************************************/ Boolean Gremlins::IsInitialized() const { return inited; } /************************************************************ * * FUNCTION: Initialize * * DESCRIPTION: Initialize the gremlins class. * * PARAMETERS: None. * * RETURNS: Nothing. * * CALLED BY: ObeyCommand() in EmEmulatorApp.cp. * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * David 8/1/95 Created. * *************************************************************/ void Gremlins::Initialize(UInt16 newNumber, UInt32 untilStep, UInt32 finalVal) { #ifndef forSimulator gIntlMgrExists = -1; ::ResetCalibrationInfo(); ::ResetClocks (); EmLowMem_SetGlobal (hwrBatteryLevel, 255); EmLowMem_SetGlobal (hwrBatteryPercent, 100); #endif counter = 0; until = untilStep; finalUntil = finalVal; #ifndef forSimulator saveUntil = until; #endif catchUp = false; needPenUp = false; charsToType[0] = '\0'; inited = true; #ifdef forSimulator // removed...test will always fail because newNumber is unsigned... // if (newNumber == -1) // newNumber = INITIAL_SEED; //newNumber = clock() % MAX_SEED_VALUE + 1; #endif number = newNumber; srand(number); IdleTimeCheck = 0; // Update menus (needed when init. called from console) StubAppGremlinsOn (); } /************************************************************ * * FUNCTION: Reset * * DESCRIPTION: Un-initialize the gremlins class. * * PARAMETERS: None. * * RETURNS: Nothing. * *************************************************************/ void Gremlins::Reset(void) { inited = false; } /************************************************************ * * FUNCTION: New * * DESCRIPTION: Start new Gremlins * * PARAMETERS: GremlinInfo info * * RETURNS: Nothing. * *************************************************************/ void Gremlins::New (const GremlinInfo& info) { if (LogGremlins ()) { string templ = Platform::GetString (kStr_GremlinStarted); LogAppendMsg (templ.c_str (), (int) info.fNumber, info.fSteps); } // If needed, switch to an "approved" application. // This code roughly follows that in AppsViewSwitchApp in Launcher. if (info.fAppList.size () > 0) { // Switch to the first on the list. DatabaseInfo dbInfo = *(info.fAppList.begin ()); //--------------------------------------------------------------------- // If this is an executable, call SysUIAppSwitch //--------------------------------------------------------------------- if (::IsExecutable (dbInfo.type, dbInfo.creator, dbInfo.dbAttrs)) { Err err = ::SysUIAppSwitch (dbInfo.cardNo, dbInfo.dbID, sysAppLaunchCmdNormalLaunch, NULL); Errors::ThrowIfPalmError (err); } //--------------------------------------------------------------------- // else, this must be a launchable data database. Find it's owner app // and launch it with a pointer to the data database name. //--------------------------------------------------------------------- else { DmSearchStateType searchState; UInt16 cardNo; LocalID dbID; Err err = ::DmGetNextDatabaseByTypeCreator (true, &searchState, sysFileTApplication, dbInfo.creator, true, &cardNo, &dbID); Errors::ThrowIfPalmError (err); // Create the param block emuptr cmdPBP = (emuptr) ::MemPtrNew (sizeof (SysAppLaunchCmdOpenDBType)); Errors::ThrowIfNULL ((void*) cmdPBP); // Fill it in ::MemPtrSetOwner ((MemPtr) cmdPBP, 0); EmMemPut16 (cmdPBP + offsetof (SysAppLaunchCmdOpenDBType, cardNo), dbInfo.cardNo); EmMemPut32 (cmdPBP + offsetof (SysAppLaunchCmdOpenDBType, dbID), dbInfo.dbID); // Switch now err = ::SysUIAppSwitch (cardNo, dbID, sysAppLaunchCmdOpenDB, (MemPtr) cmdPBP); Errors::ThrowIfPalmError (err); } } this->Initialize (info.fNumber, info.fSteps, info.fFinal); gremlinStartTime = Platform::GetMilliseconds (); // Make sure the app's awake. Normally, we post events on a patch to // SysEvGroupWait. However, if the Palm device is already waiting, // then that trap will never get called. By calling EvtWakeup now, // we'll wake up the Palm device from its nap. Errors::ThrowIfPalmError (EvtWakeup ()); Hordes::TurnOn(true); if (info.fSaveFrequency != 0) { EmAssert (gSession); gSession->ScheduleAutoSaveState (); } } /************************************************************ * * FUNCTION: Save * * DESCRIPTION: Saves Gremlin Info * * PARAMETERS: SessionFile to write to. * * RETURNS: Nothing. * *************************************************************/ void Gremlins::Save (SessionFile& f) { gremlinStopTime = Platform::GetMilliseconds (); const long kCurrentVersion = 2; Chunk chunk; EmStreamChunk s (chunk); Bool hordesIsOn = Hordes::IsOn (); s << kCurrentVersion; s << keyProbabilitiesSum; s << lastPointY; s << lastPointX; s << lastPenDown; s << number; s << counter; s << finalUntil; s << saveUntil; s << inited; s << catchUp; s << needPenUp; s << charsToType; s << (hordesIsOn != false); s << gremlinStartTime; s << gremlinStopTime; s << gGremlinNext; GremlinInfo info; info.fAppList = gGremlinAppList; info.fNumber = number; info.fSaveFrequency = gGremlinSaveFrequency; info.fSteps = until; info.fFinal = finalUntil; s << info; f.WriteGremlinInfo (chunk); } /************************************************************ * * FUNCTION: Load * * DESCRIPTION: Loads Gremlin Info * * PARAMETERS: SessionFile to read from. * * RETURNS: TRUE if a Gremlin state have been loaded and it * is ON. * FALSE otherwise. * *************************************************************/ Boolean Gremlins::Load (SessionFile& f) { Chunk chunk; bool fHordesOn; if (f.ReadGremlinInfo (chunk)) { long version; EmStreamChunk s (chunk); s >> version; if (version >= 1) { s >> keyProbabilitiesSum; s >> lastPointY; s >> lastPointX; s >> lastPenDown; s >> number; s >> counter; s >> finalUntil; s >> saveUntil; s >> inited; s >> catchUp; s >> needPenUp; s >> charsToType; s >> fHordesOn; s >> gremlinStartTime; s >> gremlinStopTime; s >> gGremlinNext; // sync until to finalUntil until = finalUntil; // Patch up the start and stop times. int32 delta = gremlinStopTime - gremlinStartTime; gremlinStopTime = Platform::GetMilliseconds (); gremlinStartTime = gremlinStopTime - delta; // Reset keyProbabilitiesSum to zero so that it gets // recalculated. Writing it out to the session file // was a bad idea. The value written out may not be // appropriate for the version of Poser reading it in. keyProbabilitiesSum = 0; } if (version >= 2) { GremlinInfo info; s >> info; Preference pref (kPrefKeyGremlinInfo); pref = info; } } return fHordesOn; } /************************************************************ * * FUNCTION: Status * * DESCRIPTION: Return the gremlin number and counter. * * PARAMETERS: None. * * RETURNS: Nothing. * * CALLED BY: DoGremlins() in ShellCmdSys.cpp. * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * roger 8/4/95 Created. * dia 9/1/98 Allows for NULL parameters. * *************************************************************/ void Gremlins::Status(UInt16 *currentNumber, UInt32 *currentStep, UInt32 *currentUntil) { if (currentNumber) *currentNumber = number; if (currentStep) *currentStep = counter; if (currentUntil) *currentUntil = until; } /************************************************************ * * FUNCTION: SetSeed * * DESCRIPTION: Allows the user to set the seed to be used. * * PARAMETERS: newSeed - the new value of the seed. * * RETURNS: TRUE - seed value set to new seed, FALSE - value not set. * * CALLED BY: Uncalled. (to be called from Debug Console) * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * David 8/2/95 Created. * *************************************************************/ Boolean Gremlins::SetSeed(UInt32 newSeed) { if (newSeed > MAX_SEED_VALUE) return false; else { number = (UInt16) newSeed; srand(number); return true; } } /************************************************************ * * FUNCTION: SetUntil * * DESCRIPTION: Allows the user to set the until value to be used. * * PARAMETERS: newUntil - the new value of until. * * RETURNS: Nothing. * * CALLED BY: Hordes::Step * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * David 8/2/95 Created. * *************************************************************/ void Gremlins::SetUntil(UInt32 newUntil) { until = newUntil; #ifndef forSimulator saveUntil = until; #endif } /************************************************************ * * FUNCTION: RestoreFinalUntil * * DESCRIPTION: Restores the original max gremlins limit. * * CALLED BY: Hordes::Resume * *************************************************************/ void Gremlins::RestoreFinalUntil (void) { until = finalUntil; } /************************************************************ * * FUNCTION: Step * * DESCRIPTION: Allows Gremlins to go on step further then its * set maximum. * * PARAMETERS: None. * * RETURNS: Nothing. * * CALLED BY: ObeyCommand() in EmEmulatorApp.cp. * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * David 8/1/95 Created. * *************************************************************/ void Gremlins::Step() { #ifndef forSimulator saveUntil = until; #endif until = counter + 1; } /************************************************************ * * FUNCTION: Resume * * DESCRIPTION: Resumes Gremlin * * PARAMETERS: None. * * RETURNS: Nothing. * *************************************************************/ void Gremlins::Resume (void) { gremlinStartTime = Platform::GetMilliseconds () - (gremlinStopTime - gremlinStartTime); // Make sure we're all on the same page... ::ResetCalibrationInfo (); // Make sure the app's awake. Normally, we post events on a patch to // SysEvGroupWait. However, if the Palm device is already waiting, // then that trap will never get called. By calling EvtWakeup now, // we'll wake up the Palm device from its nap. Errors::ThrowIfPalmError (EvtWakeup ()); } /************************************************************ * * FUNCTION: Stop * * DESCRIPTION: Stops Gremlin * * PARAMETERS: None. * * RETURNS: Nothing. * *************************************************************/ void Gremlins::Stop (void) { if (Hordes::IsOn()) { Hordes::TurnOn(false); gremlinStopTime = Platform::GetMilliseconds (); unsigned short number; unsigned long step; unsigned long until; this->Status (&number, &step, &until); if (LogGremlins ()) { string templ = Platform::GetString (kStr_GremlinEnded); LogAppendMsg (templ.c_str (), (int) number, step, until, (gremlinStopTime - gremlinStartTime)); } LogDump (); } } /************************************************************ * * FUNCTION: SendCharsToType * * DESCRIPTION: Send a char to the emulator if any are pending. * * PARAMETERS: None. * * RETURNS: true if a char was sent. * * CALLED BY: GetFakeEvent * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * roger 10/04/95 Created. * kwk 07/28/98 Queue double-byte characters correctly. * *************************************************************/ Boolean Gremlins::SendCharsToType() { if (charsToType[0] != '\0') { WChar theChar; UInt16 charSize = TxtGetNextChar(charsToType, 0, &theChar); EmEventPlayback::RecordKeyEvent (theChar, 0, 0); StubAppEnqueueKey(theChar, 0, 0); PRINTF ("--- Gremlin #%ld Gremlins::SendCharsToType: key = %ld", (long) number, (long) theChar); strcpy(&charsToType[0], &charsToType[charSize]); return true; } return false; } /************************************************************ * * FUNCTION: GetFakeEvent * * DESCRIPTION: Make a phony event for gremlin mode. * * PARAMETERS: None * * RETURNS: TRUE if a key or point was enqueued, FALSE otherwise. * * CALLED BY: TDEProcessMacEvents in EmEmulatorEvents.cp. * * REVISION HISTORY: * 06/01/95 rsf Created by Roger Flores. * 07/31/95 David Moved to emulator level. * 08/28/98 kwk Removed usage of TxtCharIsVirtual macro. * 07/03/99 kwk Set command bit for page up/page down keydown * events, since these are virtual (to match Graffiti behavior). * 06/04/01 kwk Add support for Big-5 char encoding (Trad. Chinese). * *************************************************************/ Boolean Gremlins::GetFakeEvent() { int chance; int i; int spaceLeft; PointType pen; const char *quote; PRINTF ("--- Gremlin #%ld Gremlins::GetFakeEvent: Entering", (long) number); if (! inited) { PRINTF ("--- Gremlin #%ld Gremlins::GetFakeEvent: not initialized; leaving", (long) number); return false; } // check to see if Gremlins has produced its max. # of "events." if (counter > until) { StubAppGremlinsOff (); PRINTF ("--- Gremlin #%ld Gremlins::GetFakeEvent: End of Days; leaving", (long) number); return false; } // Added - during Gremlin runs, we found that the timeout // could get set to 30 seconds and that a Gremlin may type // characters for more than 30 seconds at a time. EvtEnqueueKey // doesn't reset the event timer, so it was possible for the // device to go to sleep, even when typing was occuring. ::EvtResetAutoOffTimer (); // check to see if the event loop needs time to catch up. if (catchUp) { EmEventPlayback::RecordNullEvent (); catchUp = false; PRINTF ("--- Gremlin #%ld Gremlins::GetFakeEvent: playing catchup; leaving", (long) number); return false; } #ifdef forSimulator counter++; #endif // if no control object was entered, return a pen up. if (needPenUp) { pen.x = -1; pen.y = -1; lastPointX = pen.x; lastPointY = pen.y; lastPenDown = false; needPenUp = false; EmEventPlayback::RecordPenEvent (pen); StubAppEnqueuePt(&pen); PRINTF ("--- Gremlin #%ld Gremlins::GetFakeEvent: posted pen up; leaving", (long) number); return true; } // If we've queued up a quote string, and there are still characters to // send, do so now. if (SendCharsToType()) { PRINTF ("--- Gremlin #%ld Gremlins::GetFakeEvent: sent chars to type (1); leaving", (long) number); return true; } chance = randPercent; // Now fake an input if ((chance < KEY_DOWN_EVENT_WITHOUT_FOCUS_CHANCE) || (chance < KEY_DOWN_EVENT_WITH_FOCUS_CHANCE && IsFocus())) { if ((randPercent < TYPE_QUOTE_CHANCE) && IsFocus()) { const char** quoteArray = kAsciiQuotes; // 80% of the time we'll use text that's appropriate for the device's // character encoding. The other 20%, we'll use 7-bit ASCII. if (randN(10) < 8) { UInt32 encoding; if (FtrGet(sysFtrCreator, sysFtrNumEncoding, &encoding) != errNone) { encoding = charEncodingPalmLatin; } for (UInt16 i = 0; i < sizeof(kQuotesInfo) / sizeof(QuotesInfoType); i++) { if (kQuotesInfo[i].charEncoding == encoding) { quoteArray = kQuotesInfo[i].strings; break; } } } quote = quoteArray[randN(NUM_OF_QUOTES)]; strcat(charsToType, quote); // The full field functionality doesn't need to be tested much // If charsToType is more than the space remaining in the current // field, then for each char past the full point give 1/3 chance to // stop at that char. spaceLeft = SpaceLeftInFocus(); if (strlen(charsToType) > (size_t) spaceLeft) { UInt32 charStart, charEnd; TxtCharBounds(charsToType, spaceLeft, &charStart, &charEnd); i = charStart; while (charsToType[i] != '\0') { if (randPercent < 33) { charsToType[i] = '\0'; break; } else { i += TxtNextCharSize(charsToType, i); } } } Bool result = SendCharsToType (); if (!result) EmEventPlayback::RecordNullEvent (); PRINTF ("--- Gremlin #%ld Gremlins::GetFakeEvent: sent chars to type (2); leaving", (long) number); return result; } else { if (keyProbabilitiesSum == 0) { for (Int16 i = 0; i < NUM_OF_KEYS; i++) { if ((i > 0x00FF) || ((TxtByteAttr(i) & byteAttrSingle) != 0)) { keyProbabilitiesSum += chanceForKey[i]; } } } chance = randN(keyProbabilitiesSum); // Skip chars which cannot be single-byte, since we don't want to // generate bogus high-byte values. for (i = 0; i < NUM_OF_KEYS; i++) { if ((i < 0x0100) && ((TxtByteAttr(i) & byteAttrSingle) == 0)) { continue; } else if (chance < chanceForKey[i]) { break; } else { chance -= chanceForKey[i]; } } // There's a fractional chance for a greater number to be generated. If // so we do nothing. if (i >= NUM_OF_KEYS) return false; if ((i > 255) || (i == chrPageUp) || (i == chrPageDown)) { EmEventPlayback::RecordKeyEvent (i, 0, commandKeyMask); StubAppEnqueueKey(i, 0, commandKeyMask); } else { EmEventPlayback::RecordKeyEvent (i, 0, 0); StubAppEnqueueKey(i, 0, 0); } PRINTF ("--- Gremlin #%ld Gremlins::GetFakeEvent: posted key = %ld; leaving", (long) number, i); return true; } } else if (chance < PEN_DOWN_EVENT_CHANCE) { needPenUp = true; FakeEventXY(&pen.x, &pen.y); lastPointX = pen.x; lastPointY = pen.y; lastPenDown = true; EmEventPlayback::RecordPenEvent (pen); StubAppEnqueuePt(&pen); PRINTF ("--- Gremlin #%ld Gremlins::GetFakeEvent: posted pen event = (%ld, %ld), leaving", (long) number, (long) pen.x, (long) pen.y); // Draw a test pixel on the overlay StubViewDrawPixel(pen.x, pen.y); return true; } else if (chance < MENU_EVENT_CHANCE) { EmEventPlayback::RecordKeyEvent (vchrMenu, vchrMenu, commandKeyMask); StubAppEnqueueKey(vchrMenu, vchrMenu, commandKeyMask); PRINTF ("--- Gremlin #%ld Gremlins::GetFakeEvent: posted key = vchrMenu, leaving", (long) number); return true; } else if (chance < FIND_EVENT_CHANCE) { EmEventPlayback::RecordKeyEvent (vchrFind, vchrFind, commandKeyMask); StubAppEnqueueKey(vchrFind, vchrFind, commandKeyMask); PRINTF ("--- Gremlin #%ld Gremlins::GetFakeEvent: posted key = vchrFind, leaving", (long) number); return true; } else if (chance < KEYBOARD_EVENT_CHANCE) { EmEventPlayback::RecordKeyEvent (vchrKeyboard, vchrKeyboard, commandKeyMask); StubAppEnqueueKey(vchrKeyboard, vchrKeyboard, commandKeyMask); PRINTF ("--- Gremlin #%ld Gremlins::GetFakeEvent: posted key = vchrKeyboard, leaving", (long) number); return true; } else if (chance < LOW_BATTERY_EVENT_CHANCE) { EmEventPlayback::RecordKeyEvent (vchrLowBattery, vchrLowBattery, commandKeyMask); StubAppEnqueueKey(vchrLowBattery, vchrLowBattery, commandKeyMask); PRINTF ("--- Gremlin #%ld Gremlins::GetFakeEvent: posted key = vchrLowBattery, leaving", (long) number); return true; } else if (chance < APP_SWITCH_EVENT_CHANCE) { // Modify the standard APP_SWITCH_EVENT_CHANCE by another factor // of 5%. Without it, we enter this code way too often, and // Gremlins slows down a LOT! (Like, by a factor of 2.3). if (randPercent < 5) { DatabaseInfoList appList = Hordes::GetAppList (); if (appList.size () > 0) { // Switch to a random app on the list. DatabaseInfo& dbInfo = appList [randN (appList.size ())]; //--------------------------------------------------------------------- // If this is an executable, call SysUIAppSwitch //--------------------------------------------------------------------- if (::IsExecutable (dbInfo.type, dbInfo.creator, dbInfo.dbAttrs)) { EmuAppInfo currentApp = EmPatchState::GetCurrentAppInfo (); EmEventPlayback::RecordSwitchEvent (dbInfo.cardNo, dbInfo.dbID, currentApp.fCardNo, currentApp.fDBID); Err err = ::SysUIAppSwitch (dbInfo.cardNo, dbInfo.dbID, sysAppLaunchCmdNormalLaunch, NULL); Errors::ThrowIfPalmError (err); PRINTF ("--- Gremlin #%ld Gremlins::GetFakeEvent: switched to app %s, leaving", (long) number, dbInfo.name); return true; } //--------------------------------------------------------------------- // else, say we tried and call it quits by falling through //--------------------------------------------------------------------- } } } /* else if (chance < POWER_OFF_CHANCE) { EmEventPlayback::RecordKeyEvent (vchrAutoOff, vchrAutoOff, commandKeyMask); StubAppEnqueueKey(vchrAutoOff, vchrAutoOff, commandKeyMask); PRINTF ("--- Gremlin #%ld Gremlins::GetFakeEvent: posted key = vchrAutoOff, leaving", (long) number); return true; } */ PRINTF ("--- Gremlin #%ld Gremlins::GetFakeEvent: exiting with no event.", (long) number); // If nothing happened fall out to generate a nilEvent EmEventPlayback::RecordNullEvent (); return false; } /************************************************************ * * FUNCTION: GetPenMovement * * DESCRIPTION: Make a phony pen movement. * * PARAMETERS: None. * * RETURNS: Nothing. * * CALLED BY: * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * Roger 6/1/95 Created. * David 7/31/95 Moved to emulator level. * *************************************************************/ void Gremlins::GetPenMovement() { // This function is not called anywhere that I can see. And since it // calls FakeLocalMovement, which calls WinGetDisplayExtent, which // doesn't exist in PalmDebugger, out it goes... #ifndef __DEBUGGER_APPLICATION__ PointType pen; // check to see if Gremlins has produced its max. # of "events." /* if (counter > until) { testMode &= ~gremlinsOn; theApp->UpdateMenus(); } */ #ifdef forSimulator counter++; #endif needPenUp = false; if (randPercent < PEN_MOVE_CHANCE) { if (lastPenDown) { // move a small distance from the last pen position if (randPercent < PEN_BIG_MOVE_CHANCE) { RandomScreenXY(&pen.x, &pen.y); } else { FakeLocalMovement(&pen.x, &pen.y, lastPointX, lastPointY); } } else { // start the pen anywhere! RandomScreenXY(&pen.x, &pen.y); } StubViewDrawLine(pen.x, pen.y, lastPointX, lastPointY); } else { lastPenDown = false; pen.x = -1; pen.y = -1; catchUp = true; } lastPointX = pen.x; lastPointY = pen.y; EmEventPlayback::RecordPenEvent (pen); StubAppEnqueuePt(&pen); #endif PRINTF ("--- Gremlin #%ld Gremlins::GetPenMovement: pen = (%ld, %ld)", (long) number, (long) pen.x, (long) pen.y); } /************************************************************ * * FUNCTION: BumpCounter * * DESCRIPTION: Bumps Gremlin event counter * * PARAMETERS: None. * * RETURNS: Nothing. * *************************************************************/ void Gremlins::BumpCounter() { PRINTF ("--- Gremlin #%ld: bumping counter", (long) number); ++counter; }