The Russian Electronic Developer Magazine | |
Русский электронный журнал разработчика | |
- Доктор, что у меня ? - Вскрытие покажет... |
(c) народное |
Знание формата этого файла может позволить нам изменить существующие или создать новые собственные раскладки клавиатур. Разве это не прекрасно?
Если же мы собираемся написать собственный обработчик клавиатуры (что-нибудь этакое - с преобразованием скэн-кодов в коды символов), то мы тут же ощутим второе преимущество от знания этого формата. В самом деле, зачем изобретать велосипед, самостоятельно расписывая раскладку клавиатуры (довольно скучное занятие - впрочем, на любителя :-)), если у нас уже есть набор готовых раскладок?
Заголовок таблицы указателей раскладок выглядит следующим образом:
typedef struct { WORD EntryCount; WORD EntryLength; } IndexEntryHeader;
Поле | Описание |
EntryCount | Количество записей в таблице указателей раскладок (т.е. число раскладок в файле). |
EntryLength | Длина записи таблицы указателей раскладок (всегда равна 18). |
Непосредственно за заголовком располагается сама таблица указателей раскладок. Каждая запись в таблице (в оригинале - Index Entry) выглядит следующим образом:
typedef struct { BYTE Country[2]; /* например, "US" */ BYTE SubCountryID[4]; /* например, "153 " */ WORD word2; WORD XTableID; /* например, 0x1b5 (437) */ WORD KbdType; /* 0 = 89 кл. 1 = 101/102 кл. */ ULONG HeaderLocation; /* указатель на план раскладки */ UCHAR dflag; /* default translate table for this cp */ UCHAR mflag; /* machine dependent keyboard */ } IndexEntry; #define DFLAG_DEFAULTFORCTRY 0x08 /* Default for country */ /* это означает что раскладка выбирается */ /* в случае, если не указан subcountry, */ /* ну то есть RU, вместо RU441 или RU443 */ #define DFLAG_MULTILAYERED 0x02 /* Multilayered layout */ #define DFLAG_SECONDARY 0x04 /* Secondary multilayered layout */ #define DFLAG_DEFAULTCPAGE 0x01 /* Default codepage for country */ /* означает что это самая раздефолтная */ /* раскладка, т.е. для случая, если даже */ /* неизвестен codepage */ #define MFLAG_MULTIPLE 0x01 /* Multiple layout for country */
Поле | Описание |
Country | Аббревиатура названия страны ("US", "FR", ...). Используется обратный порядок байт - таким образом, первый символ аббревиатуры хранится в Country[1], а второй - в Country[0]. |
SubCountry | Идентификатор конкретной раскладки для данной страны ("153", "189", "120", ...). В некоторых странах (в т.ч. и в России) существует несколько основных раскладок клавиатуры (например, RU441 и RU443). |
word2 | Неизвестно (резерв). |
XTableID | Кодовая страница, используемая данной раскладкой (437, 850, ...). |
KbdType | Тип клавиатуры (0 - для 89 клавишных, 1 - для 101/102 клавишных). |
HeaderLocation | Относительный адрес плана раскладки, т.е. его смещение от начала файла. |
dflag | Таблица трансляции по умолчанию для данной кодовой страницы |
mflag | Несколько раскладок для страны |
Таким образом, мы можем:
<смещение заголовка таблицы указателей раскладок> + EntryCount * EntryLength + sizeof(IndexEntryHeader)
равно длине файла, то можно считать, что формат файла не нарушен (в первом приближении :-)).
typedef struct { WORD XTableID; /* номер кодовой страницы */ /* замечание: поле шириной 32 бита */ struct { /* какой Alt или комбинация клавиш используют Char3 в каждом KeyDef */ BITFIELD ShiftAlt :1; /* Shift-Alt вместо Ctrl-Alt */ BITFIELD AltGrafL :1; /* LeftAlt в качестве AltGraphics */ BITFIELD AltGrafR :1; /* RightAlt в качестве AltGraphics */ /* другие модификаторы */ BITFIELD ShiftLock :1; /* CapsLock рассматривать как ShiftLock */ BITFIELD DefaultTable :1; /* предопределенная таблица для языка */ BITFIELD ShiftToggle :1; /* TRUE:. временно переключающийся, FALSE:. сбрасываемый ShiftLock */ BITFIELD AccentPass :1; /* TRUE:. передать акцентный символ и пискнуть, FALSE:. просто пискнуть */ BITFIELD CapsShift :1; /* CapsShift использует Char5 */ BITFIELD MachDep :1; /* аппаратно-зависимая таблица */ /* модификаторы двунаправленного набора */ BITFIELD RTL :1; /* разрешено переключение между национальной и английской раскладкой */ BITFIELD LangSel :1; /* TRUE:. национальная раскладка FALSE:. английская раскладка */ /* индикатор раскладки, выбираемой по умолчанию */ BITFIELD DefaultLayout:1; /* предопределенная раскладка для страны */ } XTableFlags1; WORD KbdType; /* тип клавиатуры */ WORD KbdSubType; /* подтип клавиатуры */ WORD XtableLen; /* длина плана раскладки */ WORD EntryCount; /* число записей в таблице определения клавиш */ WORD EntryWidth; /* длина записи таблицы определения клавиш */ BYTE Country[2]; /* идентификатор страны, например, "US" */ WORD TableTypeID; /* тип таблицы, 0001=OS/2 */ BYTE SubCountryID[4]; /* идентификатор раскладки, например, "153 " */ WORD Reserved[8]; } XHeader;
Поле | Описание |
XTableID | Кодовая страница, используемая данной раскладкой. |
XTableFlags | Флаги раскладки [см. ниже]. |
KbdType | Тип клавиатуры (0 = 89 клавиш, 1 = 101/102 клавиш). |
KbdSubType | Подтип клавиатуры (??? 0). |
XtableLen | Длина плана раскладки (в байтах), включая этот заголовок. |
EntryCount | Количество записей в таблице определения клавиш. |
EntryWidth | Длина записи определения клавиш (в байтах). |
Country | Аббревиатура названия страны (используется обратный порядок байт - таким образом вы получите "SU" для US). |
TableTypeID | Тип таблицы (1 для OS/2). |
SubCountryID | Идентификатор конкретной раскладки для данной страны ("153 ", "189 ", "120 ", ...). |
Reserved | Неизвестно. |
Следом за этим заголовком располагается таблица определения клавиш из EntryCount записей. Каждая запись таблицы определения клавиш (KeyDef) выглядит следующим образом:
typedef struct { WORD XlateOp; BYTE Char1; BYTE Char2; BYTE Char3; BYTE Char4; BYTE Char5; } KeyDef;
Поле | Описание |
XlateOP | 9 младших бит определяют тип клавиши [см. ниже]. Старшие 7 бит определяют, какой акцент разрешен для данной клавиши. Младший из этих битов определяет использование первой таблицы акцентов, следующий - второй, и т.д. (если установлен старший 7 бит, то для данного символа разрешено больше 6 акцентов и выборка осуществляется из дополнительных таблиц акцентов [см.ниже]). |
Char1 | Стандартное значение |
Char2 | Значение при нажатом Shift (Shifted) |
Char3 | Значение при нажатом Alt (Alted) |
Char4 | |
Char5 |
Содержимое полей charx зависит от значения поля XlateOP (см. [тип клавиши]).
Значение поля EntryWidth (в заголовке) по умолчанию равно 7, но, если это значение
больше, то значит в структуре KeyDef присутствуют дополнительные поля charx (т.е.
у нас есть EntryWidth - sizeof(XlateOP) полей charx, где sizeof(XlateOP) равно 2).
Следом за таблицей определения клавиш длиной EntryCount записей располагаются шесть стандартных таблиц акцентов (по одной на каждый допустимый акцент). Седьмая таблица акцентов располагается после и может содержать дополнительные таблицы акцентов.
Каждая из 6 стандартных таблиц акцентов выглядит следующим образом:
typedef struct { CHAR charOrg; /* ASCII значение клавиши, например "e" */ CHAR charRes; /* результирующее ASCII значение, например "ё" */ } TRANS; typedef struct { BYTE AccentGlyph; /* код символа-акцента (значка акцента) */ BYTE byte1; BYTE byte2; BYTE byte3; BYTE byte4; BYTE byte5; TRANS aTrans[20]; /* разрешенные подстановки */ } AccentTableEntry;Седьмая таблица акцентов имеет слегка отличный формат. Первый байт этой таблицы содержит длину таблицы. Таким образом, если используется меньше 7 акцентов, то первый байт седьмой таблицы содержит значение 0x00. Если же используется больше 6 акцентов, то седьмая таблица акцентов может представлять из себя комбинацию дополнительных акцентных таблиц, построенных следующим образом:
+--+-------------+--+----------------+--+------------ |17| таблица #7 |11| таблица #8 |19| таблица #9 +--+-------------+--+----------------+--+------------ <-- 17 байт ----><-- 11 байт -------><-- 19 байт ----Структура этих дополнительных таблиц аналогична структуре стандартной таблицы. Количество элементов в массиве разрешенных подстановок определяется из длины этой дополнительной таблицы.
Индикатор "конец таблицы" здесь отсутствует. Для его вычисления можно воспользоваться следующим методом:
AccentTableEntryLen = XTableLen - sizeof(XHeader) - EntryCount * EntryWidth,
6*sizeof(AccentTableEntry) = 276 байт,
AccentTableEntryLen - 276 байт,
Таким образом, процесс получения акцентных символов из комбинации нажатий "акцент+символ" достаточно прост:
Флаг | Описание |
ShiftAlt | Когда этот флаг установлен в 1, то комбинация "Shift+Alt" используется вместо комбинации "Ctrl+Alt" для получения alted-значения клавиши (для 89 клавишных клавиатур). |
AltGrL | Когда этот флаг установлен в 1, то левая клавиша "Alt" используется в качестве клавиши "AltGr" (для 101/102 клавишных клавиатур). |
AltGrR | Когда этот флаг установлен в 1, то правая клавиша "Alt" используется в качестве клавиши "AltGr" (для 101/102 клавишных клавиатур). |
ShiftLock | Когда этот флаг установлен в 1, то клавиша "CapsLock" работает
в качестве клавиши "ShiftLock". Таким образом, если CapsLock
установлен в ON, то нажатие клавиши "Shift" сбрасывает это состояние. Если флаг сброшен в 0, то нажатие клавиши "Shift" временно переводит CapsLock в состояние OFF; состояние ON восстанавливается после отпускания клавиши "Shift". |
DefaultTable | Когда этот флаг установлен в 1, то данная раскладка используется для данной кодовой странице в данной стране по умолчанию. |
ShiftToggle | Для 89-клавишных клавиатур этот флаг устанавливается в зависимости от состояния
флага ShiftLock. Если ShiftLock равен 1, то ShiftToggle сбрасывается в 0.
И наоборот, если ShiftLock равен 0, то ShiftToggle устанавливается равным 1. Для 101/102-клавишных клавиатур этот флаг всегда сброшен в 0. |
AccentPass | Когда этот флаг установлен в 1, то клавиши, для которых запрещен данный акцент, формируют последовательность из кода значка акцента и кода символа. |
CapsShift | Когда этот флаг установлен в 1 и если CapsLock находится в состоянии ON,
то в качестве Shifted- значения используется char5, а не char3. Всегда установлен в 1 для всех клавиатур Swiss (Швейцария???) и 0 для всех остальных. |
MachDep | Этот флаг устанавливается в 1, если в данной стране для данной кодовой страницы используется больше, чем одна физическая раскладка клавиатуры. См. описание флага DefaultLayout ниже. |
RTL | Когда этот флаг установлен в 1, то данная раскладка используется при переключении клавиатуры между национальной и английской раскладками. (Martin Lafaix назвал это поле RTL, сокращенно от Right-to-Left, т.е. набор справа налево. Но этот флаг равен 1 не только для арабского и иврита, но и для греческого языка, для всех языков, использующих кириллицу, для языков прибалтийских народов и т.д., т.е. для всех языков, где используется переключение клавиатуры между национальной и английской частями). |
LangSel | Если флаг равен 1, то это национальная раскладка (используется национальный
алфавит), если равен 0 - английская раскладка. Этот флаг неиспользуется и должен быть равен 0, если RTL равен 0. |
DefaultLayout | Если MachDep равен 1, то установка этого флага в 1 сигнализирует, что данная раскладка используется по умолчанию. Иначе должен быть равен 0. |
Тип | Описание |
0x00 | EmptyKey. Нет клавиш, генерирующих этот скэн-код. |
0x01 | AlphaKey. Алфавитная клавиша. Поле char1 содержит стандартный код символа. Поле char2 содержит Shifted код символа. Если акцентные биты не 0, то они определяют разрешенные акценты. Каждая алфавитная клавиша может генерировать Ctrl'ed код символа, если нажата совместно с Ctrl. В этом случае генерируется код символа равный char1-96. |
0x02 | SpecKey. Эта клавиша генерирует стандартный (char1) и Shifted (char2) коды. Она не может генерировать Alt'ed, AltGr'ed или Ctrl'ed коды. |
0x03 | SpecKeyC. Эта клавиша может генерировать AltGr'ed код (содержится в char3). Если char3 содержит 0, AltGr'ed код не генерируется. Значение в char3 в пределах 1...7, считается акцентом. Иначе это обычный символ. Поля char1 и char2 содержат стандартный и Shifted коды, соответственно. Если CapsLock находится в состоянии ON, то назначение полей меняется: char1 - Shifted код, char2 - стандартный. |
0x04 | SpecKeyA. Эта клавиша может генерировать AltGr'ed код (содержится в char3). Поля char1 и char2 содержат стандартный и Shifted коды, соответственно, независимо от состояния CapsLock. Значение char3 в пределах 0...31 считается управляющим кодом (даже в пределах 1...7, в отличие от SpecKeyC). |
0x05 | SpecKeyCA ??? |
0x06 | FuncKey. Функциональная клавиша. Поле char1 содержит номер функциональной клавиши. Остальные поля равны 0. |
0x07 | PadKey. Клавиша дополнительной цифровой клавиатуры. Поле char1 содержит информацию о клавише (0 = "7", 1="8", 2="9", 3="-", 4="4", 5="5", 6="6", 7="+", 8="1", 9="2", 10="3", 11="0" и 12 = "."). Замечание: соответствует раскладке старых (89 клавишных) клавиатур. Поле char2 содержит ASCII символ. Все остальные поля равны 0. |
0x08 | SpecCtlKey. Эта клавиша генерирует управляющие коды (ASCII-коды в границах 0...31). Поля char1 и char2 содержат стандартный и Shifted управляющие коды, соответственно. Все остальные поля равны 0. |
0x09 | Клавиша PrtScrn. |
0x0A | Клавиша SysReq |
0x0B | AccentKey. Эта клавиша генерирует коды акцента (в пределах 1...7). Поля char1, char2 и char3 содержат стандартный, Shifted и Alted акценты, соответственно. Значение поля char5 зависит от содержимого полей char1, char2 и char3. Если какое-либо из них равно 7, то в char5 находится реальный акцент (7, 8, ...) и выборка для данного акцента осуществляется из дополнительных таблиц седьмого акцента (есть исключения [см. выше]). Иначе char5 равно char1. Поле char4 равно 0. |
0x0C | ShiftKey. Клавиша Shift или Ctrl. Если char1 равно 0x01, то это правый Shift. Если char1 равно 0x02, то это левый Shift. Поля char2...char5 равны 0. Если char1 равно 0x04, то это Ctrl (при этом char2 равен 0x01, а char3 равен 0x04). Поля char4...char5 равны 0. |
0x0D | ToggleKey ??? |
0x0E | Клавиша Alt. |
0x0F | Клавиша NumLock. |
0x10 | Клавиша CapsLock. |
0x11 | Клавиша ScrollLock. |
0x12 | XShiftKey ??? |
0x13 | XToggleKey ??? |
0x14 | SpecKeyCS ??? Аналогично SpecKeyC (тип 0x03). |
0x15 | SpecKeyAS ??? Аналогично SpecKeyC (тип 0x03). |
0x1A | ExtExtKey. Новые курсорные клавиши. Отсутствуют на 89-клавишных клавиатурах. |
<другие> | Неизвестно. |
Вот и все, что можно сказать о формате файла KEYBOARD.DCP.
Я не счел необходимым переводить эти части. Желающие могут обратиться к оригиналу.
И напоследок хочу поблагодарить:
Автор: Martin Lafaix
Переводчик: VicTor Smirnoff
Интересные ссылки:
Комментариев к странице: 0 | Добавить комментарий
Редактор: Дмитрий Бан
Оформление: Евгений Кулешов