FAQ для начинающих программистов на Palm v0.02
1. Можно-ли писать ПО для Palm, не имея реального устройства?
Теоретически можно. На практике, эмулятор имеет существенные недостатки. Он не позволяет оценить реальную скорость работы программы, а также её внешний вид (как она будет выглядеть на реальном LCD). Звук практически не эмулируется. Отлаживать программу, использующую прямой доступ к железу, также нельзя. Зато отлаживать программы без такого доступа удобнее именно на эмуляторе (помимо прочего, он позволяет протестировать программу на большом количестве версий PalmOS).2. Вставил в ресурсы программы графику для 2bpp/4bpp, а она отображается как 1bpp. Что делать?
При старте программы нужно определить, какая глубина цвета поддерживается этим устройством, и выбрать наибольшую (если графика нарисована подо все глубины цвета) или требуемую. На выходе из программы необходимо восстановить предыдущий видеорежим. Примерно так:// здесь храним старый режим, глобальная переменная UInt32 old_dpt; // старт UInt32 sup_dpt,new_dpt,romVer; FtrGet(sysFtrCreator,sysFtrNumROMVersion,&romVer); if(romVer>=0x03003000) { if(WinScreenMode(winScreenModeGet,NULL,NULL,&old_dpt,NULL)==errNone) { WinScreenMode(winScreenModeGetSupportedDepths,NULL,NULL,&sup_dpt,NULL); new_dpt=1; // по умолчанию - доступен 1bpp if((sup_dpt&8)!=0) new_dpt=8; // доступен 8bpp if((sup_dpt&8)==0&&(sup_dpt&2)!=0) new_dpt=2; // доступен 2bpp WinScreenMode(winScreenModeSet,NULL,NULL,&new_dpt,NULL); } } else old_dpt=16523; // выход if(old_dpt!=16523) WinScreenMode(winScreenModeSet,NULL,NULL,&old_dpt,NULL);Данный код проверяет: если версия PalmOS меньше чем 3.0 - значит доступна только 1bpp графика, и режим отображения не меняется вообще. Иначе - определяется доступная глубина цвета, и выбирается максимальная. Код проверен на всех PalmOS от 2.0 до 4.0. Режим 4bpp игнорируется (легко добавить и его).
3. А как вообще поддержать все режимы цвета?
Очень просто. Вместо Bitmap нужно всюду использовать BitmapFamily. Создаём в конструкторе ресурсов BitmapFamily. В ней создаём столько обьектов, сколько цветовых режимов желаем поддержать. Скажем, мы нарисовали графику для режимов 1,2,8bpp. Создаём три обьекта. Выбираем значение Depth для первого 1bpp, для второго 2bpp, и так по возрастающей. Назначаем каждому из обьектов соответствующий bitmap. Важный момент: если нужно поддерживать PalmOS менее 3.0 - нельзя выбирать Compression более чем ScanLine. Для FormBitmap нужно будет указывать BitmapResource не Bitmap, а созданной BitmapFamily (для этого нужно дать ей ID заведомо не совпадающий с обычными Bitmap`ами). Проиллюстрировать создание BitmapFamily может созданная wizard`ом иконка приложения.4. Как сохранить какие-либо настройки программы без использования внешних записей?
Для этого существуют функции PrefGetAppPreferences(..)/PrefSetAppPreferences(..). Обьявляем структуру, описывающую сохраняемые данные, и идентификатор записи (вместо PROG впишите нужный набор букв, 4 символа):#define pref_IDname PROG typedef struct { // любые типы, массивы, и т.д. - которые надо сохранить int tipa; } MyPreferenceType;При старте программы загружаем данные, либо узнаём, что их нет, и нужно установить значения по default:
MyPreferenceType prefs; UInt16 prefSize; Int16 prefsVersion; prefSize=sizeof(MyPreferenceType); // читаем preferences prefsVersion=PrefGetAppPreferences(pref_IDname,1,&prefs,&prefSize,true); // нашлись или нет? if (prefsVersion!=noPreferenceFound) { // не нашли - заполняем prefs по умолчанию prefs.tipa=0; } // прочесть из prefs уже в структуры/массивы/переменные программы some_var=prefs.tipa;А при выходе из программы - сохраняем:
MyPreferenceType prefs; // заполняем поля prefs prefs.tipa=some_var; // сохраняем prefs PrefSetAppPreferences (pref_IDname,1,1,&prefs,sizeof(MyPreferenceType),true);Визард CodeWarrior делает работу за вас - в создаваемом .h файле проекта уже есть структура g_prefs (Internal structures), идентификатор вставляется автоматом, а функции AppStart и AppStop основного файла уже содержат скелеты чтения/записи preferences.
5. Как узнать, куда я ткнул стилусом?
Проанализируйте свои ощущения. Если вы ощущаете некоторый дискомфорт вследствие давления маленького тупого твёрдого предмета в области тела - значит вы ткнули в себя. Более точно место тычка укажет вмятина красноватого цвета на коже;) В противном случае вы, скорее всего, ткнули в экран Palm`а. Значит, пришёл event, указывающий на этот прискорбный факт. Точнее, есть три типа event`а, которые указывают на: опускание стилуса на экран, перемещение стилуса, отрыв стилуса от экрана:// стилус опущен, в pen_x и pen_y получаем координаты точки if(event.eType==penDownEvent) { pen_x=event.screenX; pen_y=event.screenY; } // стилус перемещается, в pen_x и pen_y получаем координаты новой точки if(event.eType==penMoveEvent) { pen_x=event.screenX; pen_y=event.screenY; } // стилус поднят, в pen_x и pen_y получаем координаты точки отрыва if(event.eType==penUpEvent) { pen_x=event.screenX; pen_y=event.screenY; }Разумеется, этот код должен находиться в event loop. Все получаемые координаты - в координатах окна, не экрана. Кроме этого, возможно получение дополнительной информации - читайте
6. Кто украл stdlib.h?! Как-же мне получить random-число?
Действительно, привычные библиотеки С при написании под PalmOS отсутствуют. Неудивительно - ведь специфика платформы совершенно другая. Random-число можно получить с помощью API-вызова SysRandom(..). А именно, так:// таким образом можно установить начало последовательности // это лучше всего сделать при запуске программы SysRandom(TimGetTicks()); // а это определение полностью заменит нам привычный random(..); #define random(N) ((((Int32)SysRandom(0))*N)/((Int32)sysRandomMax+1))
7. А что насчёт синхронизации программы, для вывода анимации например?
Довольно легко можно сделать, чтобы event`ы приходили периодически. Смотрим, как сделана синхронизация в примерах игрушек из CW8 examples, делаем нечто подобное:// здесь мы будем хранить следующее значение времени UInt32 nextPeriodTime; // частота прихода event`ов, чем меньше значение - тем чаще event`ы #define advanceTimeInterval 4 // инициализация 'таймера' static void SyncNew(void) { nextPeriodTime=TimGetTicks()+advanceTimeInterval; } // сам 'таймер' static Int32 SyncWait(void) { Int32 timeRemaining; if(**игра на паузе**) return evtWaitForever; // можно и не делать:) timeRemaining=nextPeriodTime - TimGetTicks(); if(timeRemaining<0) timeRemaining = 0; return timeRemaining; }Для того, чтобы воспользоваться этим кодом, нужно: вставить до начала цикла приёма event`ов вызов SyncNew();, а внутри цикла сделать так:
// вместо EvtGetEvent(&event,evtWaitForever); EvtGetEvent(&event,SyncWait()); if(SyncWait()==0) { SyncNew(); // выполнить те действия, для которых всё и затевалось // например, обновить состояние игры и экран }SyncNew(); должен вызываться до требуемых действий , иначе частота прихода event`ов будет плавать в зависимости от скорости их выполнения.
8. Хочу для пробы написать простую игрушку. Как мне выводить графику?
Для начала нужно оговориться, что выводить графику крайне рекомендуется стандартными средствами, не используя прямой доступ к железу (запись в видеопамять, ассемблерные вставки) - в целях обеспечения совместимости (которой, безусловно, иногда приходится жертвовать в погоне за скоростью). PalmOS предоставляет два способа вывода графики: с помощью WinDrawBitmap(..) и с помощью WinCopyRectangle(..). Оба метода имеют автоматический клиппинг для краёв. Первый метод наиболее подходит для вывода нечасто обновляющихся элементов изображения, а также для компрессированных картинок (медленнее).MemHandle bitmapHnd; BitmapPtr bitmapPtr; // получаем указатель на bitmap в ресурсах bitmapHnd=DmGetResource(bitmapRsc,**имя bitmap`а, или ID**); ErrFatalDisplayIf(!bitmapHnd,"Missing bitmap"); // не найден такой bitmap if(bitmapHnd) // найден, выводим (в координаты coord_X, coord_Y) { bitmapPtr=(BitmapPtr)MemHandleLock(bitmapHnd); WinDrawBitmap(bitmapPtr,coord_X,coord_Y); MemHandleUnlock(bitmapHnd); DmReleaseResource(bitmapHnd); }Главный недостаток WinDrawBitmap(..) - в невозможности вывести (быстро) часть картинки. Вывод частей картинки может быть необходим при большом (от десятка и до беспредела) количестве спрайтов, которые будет очень неудобно редактировать, если хранить (и выводить, хотя с этим проще) их по одному. WinCopyRectangle(..) позволяет выводить произвольную часть картинки в нужное место экрана, но занимает место в оперативной памяти. Идея такова: при старте программы создаём внеэкранное окно (OffscreenWindow), на которое выводим наш большой bitmap со всеми спрайтами. Когда нужно вывести какую-либо его часть - используем WinCopyRectangle(..). По завершении программы освобождаем занятую память. В целом, такой подход напоминает работу с surfaces в DDraw.
// глобальный указатель на offscreen-окно WinHandle name_surf; // размеры будущего offscreen-окна (не стоит делать больше, чем требуется) #define w_wdt 160 #define w_hgt 160 static void prog_start(void) // вызываем на старте программы { UInt16 err; name_surf=WinCreateOffscreenWindow(w_wdt,w_hgt,genericFormat,&err); if(err!=errNone) ErrFatalDisplayIf(true,"No memory"); WinHandle oldw=WinSetDrawWindow(name_surf); // выводим с помощью WinDrawBitmap(..) наш Bitmap на это окно // (как это делается - в примере выше) WinSetDrawWindow(oldw); } static void prog_kill(void) // это вызываем на выходе из программы { WinDeleteWindow(name_surf,false); } static void draw_sprite(int X,int Y) { WinHandle drw=WinGetDrawWindow(); RectangleType rect; // эти параметры нужно модифицировать так, как требуется - например, // находить их по номеру требуемого спрайта rect.extent.x=16; // ширина выводимого спрайта rect.extent.y=16; // высота выводимого спрайта rect.topLeft.x=0; // смещение начала спрайта по X (внутри offscreen-окна) rect.topLeft.y=0; // смещение начала спрайта по Y (внутри offscreen-окна) // последний параметр (winPaint) - режим вывода, см. документацию WinCopyRectangle(name_surf,drw,&rect,X,Y,winPaint); }Все функции рисования примитивов и работы с окнами описаны в
9. Как можно сделать простое окно, наподобие about box (с одной кнопкой)?
Вообще, для подобных 'окон' есть Alert`ы. Но если нужна, например, modal`ная плашка с названием программы и текстом (about), которая имеет единственную, закрывающую её кнопку - это можно сделать очень просто. Создаём эту форму в редакторе ресурсов, в программе вызываем её в нужный момент так:FormType *frmP; frmP=FrmInitForm(NameForm); // Name - это имя нашей формы в редакторе ресурсов FrmDoDialog(frmP); FrmDeleteForm(frmP);Обработчик для закрытия формы писать не нужно - любой button формы, если ему не сделать обработчик, закрывает её.
10. Можно-ли, имея только SDK4.0, писать программы под более младшие версии PalmOS?
Да, безусловно. Важно лишь учитывать, что некоторых функций в младших версиях PalmOS просто нет, и избегать их использования (читайте референс, графа Compatibility у каждой из функций). Некоторые функции были переименованы - это также нужно учитывать. Также, нельзя использовать некоторые методы сжатия картинок в ресурсах. Начиная с версии 2.0 поддерживается ScanLine-сжатие, с версии 3.5 появилось RLE-сжатие, с версии 4.0 введен метод сжатия PackBits. Неплохо-бы проверить программу на всех версиях PalmOS (с помощью POSE), чтобы избежать накладок. Одна из накладок, связанная с отображением иконки приложения, проявится в PalmOS 2.0. О том, как решить эту проблему - читайте в отдельном вопросе этого FAQ. Версию ОС, при необходимости, можно узнать так:UInt32 romVer; //в romVer будет версия. Например, 0x03003000 - 3.3 FtrGet(sysFtrCreator,sysFtrNumROMVersion,&romVer);Для пользователей CodeWarrior: при создании проекта визард спрашивает версию ОС, под которую разрабатывается проект - нужно указать её правильной, т.к. для RomVersionCompatible(..) он берёт именно это, указанное значение.
11. Что за ерунда - сквозь созданную форму просвечивает предыдущая?
Такая проблема может возникнуть, если в редакторе формы не поставить галку на 'Save behind'. В PalmOS 3.5 и выше форма будет выводиться нормально, а в более младших её фон будет считаться прозрачным, и предыдущее изображение будет 'просвечивать'.12. Как узнать, что юзер нажал на button, который я положил на форму?
Узнать о нажатии на button, или любой другой control можно по пришедшему событию ctlSelectEvent, в функции FormHandleEvent (CW):case ctlSelectEvent: // пришло событие выбора control`а // определяем, какой из control`ов был нажат switch (eventP->data.ctlSelect.controlID) { case FormOneButton: // была нажата кнопка с именем One, на форме с именем Form handled=true; break; case FormTwoCheckbox: // был нажат checkbox с именем Two, на форме с именем Form handled=true; break; default: break; }О том, каким образом получаются имена control`ов в CodeWarrior - смотрите следующий вопрос.
13. Как программно установить/сбросить Checkbox?
Установить/сбросить галку на CheckBox, а также изменить значения других control`ов можно функцией FrmSetControlValue(..). Пример:FormType *frmP=FrmGetActiveForm(); // считаем, что checkbox на текущей форме UInt16 controlID=FrmGetObjectIndex(frmP,MainMyCheckbox); // узнаём ID control`а FrmSetControlValue(frmP,controlID,0); // сбрасываем галку (1 для установки)MainMyCheckbox - имя control`а. Редактор ресурсов CodeWarrior`а генерирует его следующим образом. Сначала идёт имя формы (Main). Потом имя, указанное при создании control`а (автоматом назначается UnnamedNNNN, в примере - My). Последним идёт тип control`а (в нашем случае - Checkbox).
14. Помогите! Иконка приложения в PalmOS 2.0 сползает вниз!
Эта проблема целый день морочила мне голову, пока в15. Как-бы мне клавиши опросить?
По нажатию любых клавиш (включая и Power) приходит событие keyDownEvent. С помощью функции KeyCurrentState() можно узнать, какие из клавиш нажаты в момент вызова функции:if(event.eType == keyDownEvent) { UInt32 key_state=KeyCurrentState(); if(key_state & keyBitPower) // Power key if(key_state & keyBitPageUp) // Page-up if(key_state & keyBitPageDown) // Page-down if(key_state & keyBitHard1) // App #1 if(key_state & keyBitHard2) // App #2 if(key_state & keyBitHard3) // App #3 if(key_state & keyBitHard4) // App #4 if(key_state & keyBitCradle) // Button on cradle if(key_state & keyBitAntenna) // Antenna "key"Чтобы уменьшить количество ненужных event`ов (и сэкономить ресурсы процессора, как пишут в документации:), с версии PalmOS 2.0 можно замаскировать неиспользуемые клавиши - они не будут генерировать keyDownEvent. По завершении программы маску следует снять:if(key_state & keyBitContrast) // Contrast key if(key_state & keyBitsAll) // any key }
UInt32 new_mask=keyBitHard1 | keyBitHard4; // event`ы только от App #1 и App#4 UInt32 old_mask=KeySetMask(new_mask); // восстановить маску можно и используя old_mask, и так: KeySetMask(keyBitsAll);Возможно, для игровых задач опрашивать клавиши будет удобнее не по keyDownEvent, а по таймеру - в момент отрисовки экрана. В этом случае стоит установить скорость автоповтора клавиш на минимум. Старую скорость следует запомнить, и восстановить на выходе из программы:
// узнаём старые значения UInt16 old_delay,old_period,old_dtap; bool old_queue; KeyRates(false,&old_delay,&old_period,&old_dtap,&old_queue); // устанавливаем новые значения UInt16 initDelay=slowestKeyDelayRate; // минимальная задержка после нажатия UInt16 period=slowestKeyPeriodRate; // минимальная скорость повтора UInt16 queueAhead=false; KeyRates(true,&initDelay,&period,&period,&queueAhead) // восстанавливаем старые значения KeyRates(true,&old_delay,&old_period,&old_dtap,&old_queue);В любом случае, крайне неудобно будет то, что по клавишам App #N будет происходить переключение на различные приложения:) Чтобы избавиться от этого, нужно незамедлительно прерывать обработку event`а, если это был keyDownEvent от любой из опрашиваемых клавиш (просто continue; в цикле обработки event`ов).
16. А как обстоят на Palm дела со звуком?
Примерно как на PC-XT или Spectrum 48:) Т.е. есть только один канал, который может генерировать square-tone, с заданной частотой, длительностью и громкостью. Простые звуки можно извлекать так:SndCommandType sndCmd; sndCmd.cmd=sndCmdFrqOn; // только для PalmOS 3.0 и выше! sndCmd.param1=440; // частота в герцах sndCmd.param2=100; // длительность в миллисекундах sndCmd.param3=10; // громкость, от 0 до sndMaxAmp SndDoCmd(NULL,&sndCmd,0);Следует учитывать, что для версий PalmOS ниже 3.0 доступна только команда sndCmdFreqDurationAmp (её параметры аналогичны sndCmdFrqOn). Она работает только синхронно (прерывает программу). sndCmdFrqOn и sndCmdNoteOn (аналогично sndCmdFrqOn, но param1 - номер midi-клавиши) работают асинхронно. Но на POSE правильно услышать результаты их работы невозможно - sndCmdFrqOn работает синхронно с неустранимой дополнительной задержкой после звука; sndCmdNoteOn не работает вообще.
UInt16 GameAmp=PrefGetPreference(prefGameSoundVolume);Функции операционной системы позволяют играть лишь простые звуки, либо - с версии PalmOS 3.5 - стандартные (хотя это ещё вопрос;) midi-файлы (*.smf). Последние представляют собой просто одноголосые мелодии, записанные в определённом формате. Подробнее про работу со звуком можно прочесть в
17. Что нового в PalmOS 5, почему я не нашёл ROMa с ней для POSE?
POSE не поддерживает, и не может поддерживать PalmOS 5, так как она использует совершенно иную, новую аппаратную базу, и - как следствие - является несовместимой с предыдущими версиями PalmOS. В новых моделях Palm, рассчитаных на PalmOS 5, применяются процессоры типа Intel Strong ARM, Texas Instruments OMAP, Motorola Dragonball MX. Все они работают на частотах около 200 мегагерц. Возможность запускать программы, созданные для старых версий PalmOS, всё-же есть - для этого используется, по сути, эмулятор младших Palm - PACE (Palm Application Compatibility Environment). Для отладки ПО под PalmOS 5, насколько я знаю, существует PalmOS 5 Simulator. Его, и информацию по разработке под PalmOS 5, ищите на http://palmos.com.18. Какова вообще специфика разработки ПО, и в частности игр, под Palm?
Она вытекает из технических возможностей этой платформы. Это, прежде всего, процессор, совместимый с Motorola 68000 (использовался в огромном количестве компьютеров и игровых платформ 90-х годов). В худшем случае на частоте 16mhz, в лучшем - 33mhz. Для сравнения, в Sega Genesis, младших Amiga, младших AtariST процессор работал на частоте 6-8mhz. Но динамичная графика там обеспечивалась не столько процессором, сколько мощными видеоконтроллерами. В целом, по вычислительной мощности (учитывая то, что программы пишутся на языках высокого уровня) Palm можно сравнить с 386-486SX PC. Для логических игр мощности вполне хватает, чтобы не писать их на ассемблере. Для динамических игрушек-же практически не обойтись без прямой работы с железом (и вытекающих отсюда проблем с совместимостью), и написания всей или части программы на ассемблере. Зато подобные средства позволяют добиваться неплохих результатов (до 30-40fps во всяких бегалках-леталках), хотя и не таких, как на тех-же видеоприставках.19. Сконвертированная из TrueColor картинка в 8bpp-режиме выглядит ужасно!
Чтобы уменьшить искажения цвета при вставке цветного изображения в ресурсы для Palm-программы, нужно заранее сконвертировать его в 256-цветное, используя default-палитру PalmOS. По умолчанию PalmOS использует палитру, соответствующаю стандартной web-palette с небольшим расширением. Эта палитра представляет собой все сочетания из 6 градаций яркости каждой составляющей (R,G,B). Расширение - это еще 10 добавочных градаций серого.RGBColorType *pCTable=ColorTableEntries(BmpGetColortable(pBmp)); WinPalette(winPaletteSet,0,BmpColortableSize(pBmp),pCTable);Подробности читайте в
20. Как проще всего сделать Help/Instructions?
Для этого имеется функция FrmHelp(..);. Создаём в ресурсах String, содержащую текст (можно использовать переводы строк, по необходимости). Когда нужно отобразить текст - вызываем FrmHelp(**идентификатор строки**);. Текст будет показан в modal`ном окне с названием Tips и кнопкой Done для выхода. Если текст не помещается в окне - появятся также кнопки для его прокрутки. При выводе автоматически выполняется перенос по словам.21. Хочу вывести 8bpp картинку, а она выводится как 1bpp (проект для CodeWarrior).
Для редактора ресурсов, входящего в CodeWarrior, необходимо создавать BitmapFamily для любых картинок, содержащих более 2-х цветов (т.к. редактор ресурсов не позволяет задавать одиночным Bitmap`ам значение глубины цвета). Т.е., даже если требуется хранить всего-лишь один Bitmap с глубиной цвета 8bpp - придётся создать для него BitmapFamily, иначе он будет отображаться как 1bpp. При создании окна нужно не забыть установить для него требуемую глубину цвета (см. вопрос номер 2).22. С выводом графики понятно, а как вывести текст или число?
Для вывода текстовых строк предназначена функция WinDrawChars(const char *chars, Int16 len, Coord x,Coord Y);. Её параметры: *chars - указатель на строку; len - длина строки (функция выводит только указанное количество символов, не использует нулевой терминатор); x,y - координаты в текущем окне. Текст будет выведен в текущее окно, установленными для этого окна цветами textcolor и backcolor. Подробности на стр. 1030 (1046)const char *text="Test string"; // текст для вывода WinDrawChars(text,StrLen(text),0,0); // вывести в левый верхний угол окнаТекст можно выводить также инвертированными цветами - функция WinDrawInvertedChars(...); и с подчёркиванием - WinSetUnderlineMode(...). В качестве её параметра можно передавать: noUnderline, grayUnderline, solidUnderline, colorUnderline (не подчёркивать, подчёркивать прерывистой линией, полной линией, линией с цветом foreground color окна).
char numstr[20]; // строка для хранения числа, заведомо больше количества разрядов char *numptr=numstr; // получаем указатель на строку numptr=StrIToA(text,12345); // переводим число в строку (в примере - число 12345) WinDrawChars(numptr,StrLen(numptr),0,0); // выводим число
23. Как мне вывести картинку с "дырками" (прозрачными пикселями)?
Наиболее универсальный (и наименее удобный) способ - работающий во всех версиях PalmOS - раздельное хранение маски (силуэта) и собственно изображения. Сначала устанавливаем операцию стирания - WinSetDrawMode(winErase); - и выводим маску; потом устанавливаем операцию наложения - WinSetMode(winOverlay); - и выводим само изображение. Подобный подход применяется в example-игрушках, идущих в поставке CodeWarrior`а (SubHunt, например - для изображения взрыва).24. Хочу вывести надписи серым цветом под PalmOS <3.5...
Прямой возможности для этого не существует. Сама по себе поддержка серого цвета появилась в PalmOS 3.0, однако возможности для его полноценного использования были реализованы лишь в версии PalmOS 3.5.25. Чьи это файлы: *.mcp, *.rcp, *.rsrc, ... ?
*.mcp - Metrowerks Codewarrior Project (проект).26. Как сделать таймер или что-то подобное?
Прямой возможности для этого не существует. Но есть две неявных возможности. Первая - заставить систему через определённые промежутки времени генерировать nilEvent:static void EventLoop(void) { Word err; EventType event; UInt16 ticks_for_wait=SysTicksPerSecond(); // период равен секунде // если нужно сделать период равным 0.1 секунды - делим значение на 10, и т.п. do { EvtGetEvent(&event,ticks_for_wait); // вместо evtWaitForever if(!SysHandleEvent (&event)) if(!MenuHandleEvent (NULL,&event,&err)) if(!ApplicationHandleEvent(&event)) FrmDispatchEvent(&event); } while(event.eType!=appStopEvent); }В обработчике событий нужно будет добавить case nilEvent:. Этот метод был использован в вопросе номер 7.
27. Как выбрать другой шрифт для вывода текста?
Для выбора шрифта служит функция FntSetFont(FontID);. В качестве FontID можно использовать следующие имена, определённые для стандартных шрифтов:28. Есть-ли у каждого экземпляра Palm`а свой уникальный номер, и как мне его получить?
Уникальный номер для каждого устройства (серийный номер программно) Документация - раздел System Features (Retrieving the ROM Serial Number) Palm OS Companion.pdf, стр. 304. Там-же пример. В// x,y - координаты сообщения на экране // noNumberMessage - cтрока с сообщением об отсутствии серийного номера static void DrawSerialNumOrMessage(Int16 x,Int16 y,char *noNumberMessage) { char *bufP; UInt16 *bufLen; Err retval; Int16 count; UInt8 checkSum; char checksumStr[2]; retval=SysGetROMToken(0,sysROMTokenSnum,(UInt8**)&bufP,&bufLen); if((!retval)&&(bufP)&&((UInt8)*bufP!=0xFF)) // правильный номер { checkSum=0; for(count=0;countНе забывайте, что функция SysGetROMToken существует только в версиях PalmOS 3.0 и выше.>7); } checkSum=((checkSum>>4)&0x0F)+(checkSum&0x0F)+2; WinDrawChars(bufP,bufLen,x,y); // вывели номер x+=FntCharsWidth(bufP,bufLen); checksumStr[0]='-'; checksumStr[1]=((checkSum<10)?(checkSum+'0'):(checkSum-10+'A')); WinDrawChars(checksumStr,2,x,y,); // вывели контрольную сумму } else // нет серийного номера if(noNumberMessage) WinDrawChars(noNumberMessage,StrLen(noNumberMessage),x,y); }
N. Всё прочёл, ничего не понял. Так с чего-же мне начать?!
Для начала нужно определиться с инструментарием. Выбор есть - кросс-компиляторы C\C++: PRC-Tools, Falch.net, CodeWarrior for PalmOS (бесплатный только первый, он-же самый сложный в освоении); кроссассемблер PilA. Далее, понадобится SDK под нужную версию PalmOS, эмулятор POSE, образы ROM с нужными версиями PalmOS. Желательно, но не обязательно, иметь под рукой как можно больше различных моделей реального Palm (особенно при работе с железом напрямую). Необходимая документация входит в состав упомянутых пакетов, также она доступна на сайте разработчика PalmOS. Все нужные ссылки можно найти в конце данного FAQ (кроме ссылок на ROMs - ищите их сами, либо скачайте с помощью POSE и линк-кабеля с реального Palm).M. Мне-бы ссылочек...
Англоязычные ресурсы: