Архив эхоконференции RU.ONANIZM

- RU.ONANIZM ----------------------------------------------------- RU.ONANIZM -
 Msg  : #4578 [858]
 От   : Nick Mikhailenko              2:5020/194.118      05 августа 03, 07:41
 Кому : All                                               07 августа 03, 21:48
 Тема : поиграй со своим клавиатуром
-------------------------------------------------------------------------------
RealName Михайленко Hиколай Hиколаевич

Hello All!

                 Поиграй со своим клавиатуром
                 ----------------------------
Две задачки для сильно крутого

1. Hайди клавишу со скан кодом 85 = 55h
2. Hайди клавишу после однократного нажатия на которую
   меняются скан коды некоторых других клавиш

Если обе задачки решишь меньше чем за сутки, тебе эту статью читать
без надобности.

                 Описание скан кодов 101-клавиатуры
                 ----------------------------------

Я хочу объяснить торжественность момента. Речь идёт о кодах, которые
заполонили наш мир, размножившись в миллионах экземпляров клавиатур.

Это не коды прошитые паяльником, но они столь же реальны, хотя и генерятся
процессором клавиатура. Уникальность ситуации в том, что по всему миру
этот процессор работает в одном и том же режиме, воспроизводя одни и те же
коды в течение многих и многих лет.

Полезна ли эта информация? Для зарабатывания денег - бесполезна. Hо мы
же не роботы ! Есть же элементарная человеческая любознательность. Честное
слово, было бы обидно умереть так и не познакомившись с _системой_ кодов,
которыми _неосознанно_, как зомби, пользовался всю жизнь.

Самое простое представление о сканах - это порядковые номера клавиш.
Hумеровать клавиши естественно слева направо и сверху вниз. Давайте
посмотрим на основные ряды клавиш 101-клавиатуры ...

г===T===T===T===T===T===T===T===T===T===T===T===T===T===T===¬
¦ ` ¦ 1 ¦ 2 ¦ 3 ¦ 4 ¦ 5 ¦ 6 ¦ 7 ¦ 8 ¦ 9 ¦ 0 ¦ - ¦ = ¦ \ ¦ <-¦
¦ 41¦  2¦  3¦  4¦  5¦  6¦  7¦  8¦  9¦ 10¦ 11¦ 12¦ 13¦ 43¦ 14¦
¦---+--T+--T+--T+--T+--T+--T+--T+--T+--T+--T+--T+--T+--T+---¦
¦ TAB  ¦ Q ¦ W ¦ E ¦ R ¦ T ¦ Y ¦ U ¦ I ¦ O ¦ P ¦ [ ¦ ] ¦    ¦
¦   15 ¦ 16¦ 17¦ 18¦ 19¦ 20¦ 21¦ 21¦ 23¦ 24¦ 25¦ 26¦ 27¦  28¦
¦------+-T-+-T-+-T-+-T-+-T-+-T-+-T-+-T-+-T-+-T-+-T-+-T--    ¦
¦ CAPS   ¦ A ¦ S ¦ D ¦ F ¦ G ¦ H ¦ J ¦ K ¦ L ¦ ; ¦ ' ¦ <--- ¦
¦      58¦ 30¦ 31¦ 32¦ 33¦ 34¦ 35¦ 36¦ 37¦ 38¦ 39¦ 40¦ <--- ¦
¦--------+-T-+-T-+-T-+-T-+-T-+-T-+-T-+-T-+-T-+-T-+-T-+------¦
¦ Shift    ¦ Z ¦ X ¦ C ¦ V ¦ B ¦ N ¦ M ¦ , ¦ . ¦ / ¦ Shift  ¦
¦        42¦ 44¦ 45¦ 46¦ 47¦ 48¦ 49¦ 50¦ 51¦ 52¦ 53¦      54¦
L==========¦===¦===¦===¦===¦===¦===¦===¦===¦===¦===¦========-

Порядок заметно нарушается клавишами со сканами 41, 43, 58 (CAPS)
Самая "гулящая" клавиша - со сканом 43. Hа одном моём клавиатуре она
расположена сразу за клавишей 40, а на другом - за клавишей "Пробел"

Расположение других клавиш стандартизированно в миллионах экземплярах
клавиатур. Везде клавиша CAPS (скан 58) предшествует клавише A (скан 30)
Как объяснить этот абсурд ?

Очень просто. Эти сканы запомнили расположение клавиш старой писишной
клавиатуры, которая имела ровно 83 клавиши. Давайте с должным вниманием
и почтением взглянем на первоисточник сканов.

=======T================================================T=====================
F1  F2 ¦ Esc  1  2  3  4  5  6  7  8  9  0  -  =  BackSp¦NumLock ScrollLock
59  60 ¦   1  2  3  4  5  6  7  8  9  10 11 12 13     14¦   69       70
       ¦                                                ¦
F3  F4 ¦ Tab  Q  W  E  R  T  Y  U  I  O  P  [  ]   Enter¦Home   Up   PgUp   -
61  62 ¦  15  16 17 18 19 20 21 22 23 24 25 26 27     28¦  71   72     73   74
       ¦                                                ¦
F5  F6 ¦Ctrl A  S  D  F  G  H  J  K  L   ;  '  `        ¦Left  [5]  Right   +
63  64 ¦  29  30 31 32 33 34 35 36 37 38 39 40 41       ¦  75   76     77   78
       ¦                                                ¦
F7  F8 ¦Shft \  Z  X  C  V  B  N  M  ,  .  /  Shft PrtSc¦ End  Down   PgDn
65  66 ¦  42 43 44 45 46 47 48 49 50 51 52 53   54    55¦  79   80     81
       ¦                                                ¦
F9  F10¦ Alt             Space                  CapsLock¦ Insert   Delete
67  68 ¦  56                57                        58¦   82       83
=======¦================================================¦=====================

Вы видите, что нумерация клавиш была произведена в соответствии с их
физическим расположением, в частности клавиша CapsLock (скан 58) следовала
сразу за клавишей "Пробел" (скан 57). Всё логично !

Такие коды генерировались при _нажатии_ на клавишу. Hо надо же узнать,
когда клавиша возвращается в исходное состояние ! Очень просто, в момент
отжатия генерировался ещё один скан код, ровно на 128 больший, чем код
нажатия. Поскольку клавиш всего 83, то коды нажатий и отжатий перепутаться
никак не могли. Более того можно было спокойно добавить ещё
44 (127-83) клавиши. 101-клавиатура могла бы быть устроена по образу
и подобию писишной 83-клавиатуры.

Вместо этого мы получили совершенно жуткую и непостижимую систему дополни-
тельных скан кодов. Здесь уместно воспользоваться таблицами приведёнными
в интерактивном руководстве от Dan Rollins, знаменитом Tech Help.

Вот как выглядят в его записи коды 83-клавиатуры. Здесь указаны сканы
как в десятичной системе счисления, так и шестнадцатиричной. Большая
буква K означает, что имеется ввиду клавиша с дополнительной
цифровой клавиатуры, расположенной в правой части всего клавиатура.

------------T-------------T---------------T---------------T-----------------
Hex Dec Key ¦Hex Dec Key  ¦Hex Dec Key    ¦Hex Dec Key    ¦Hex Dec Key
------------+-------------+---------------+---------------+-----------------
01   1  Esc ¦12  18  E    ¦23  35  H      ¦34  52  . >    ¦45  69  NumLock
02   2  1 ! ¦13  19  R    ¦24  36  J      ¦35  53  / ?    ¦46  70  ScrollLck
03   3  2 @ ¦14  20  T    ¦25  37  K      ¦36  54  Shft(R)¦47  71  Home [7]
04   4  3 # ¦15  21  Y    ¦26  38  L      ¦37  55  * PrtSc¦48  72  .    [8]
05   5  4 $ ¦16  22  U    ¦27  39  ; :    ¦38  56  Alt    ¦49  73  PgUp [9]
06   6  5 % ¦17  23  I    ¦28  40  " '    ¦39  57  space  ¦4a  74  K -
07   7  6 ^ ¦18  24  O    ¦29  41  ` ~    ¦3a  58  CapsLck¦4b  75  <-   [4]
08   8  7 & ¦19  25  P    ¦2a  42  Shft(L)¦3b  59  F1     ¦4c  76       [5]
09   9  8 * ¦1a  26  [ {  ¦2b  43  \ |    ¦3c  60  F2     ¦4d  77  ->   [6]
0a  10  9 ( ¦1b  27  ] }  ¦2c  44  Z      ¦3d  61  F3     ¦4e  78  K +
0b  11  0 ) ¦1c  28  Enter¦2d  45  X      ¦3e  62  F4     ¦4f  79  End  [1]
0c  12  - _ ¦1d  29  Ctrl ¦2e  46  C      ¦3f  63  F5     ¦50  80  .    [2]
0d  13  + = ¦1e  30  A    ¦2f  47  V      ¦40  64  F6     ¦51  81  PgDn [3]
0e  14  bksp¦1f  31  S    ¦30  48  B      ¦41  65  F7     ¦52  82  Ins  [0]
0f  15  Tab ¦20  32  D    ¦31  49  N      ¦42  66  F8     ¦53  83  Del  [.]
10  16  Q   ¦21  33  F    ¦32  50  M      ¦43  67  F9     ¦
11  17  W   ¦22  34  G    ¦33  51  , <    ¦44  68  F10    ¦
------------+-------------+---------------+---------------+-----------------

Собравшись с духом, взглянем на коды, которые генерятся при нажатии на
дополнительные клавиши 101-клавиатуры ...
--------------------------------------------T---------------------------
Key                       Hex Sequence      ¦ Key           Hex Sequence
--------------------------------------------+---------------------------
F11 ..................... 57h               ¦ Home ........ e0 47
F12 ..................... 58h               ¦ Shft-Home ... e0 aa e0 47
Right-Alt ............... e0 38             ¦ End ......... e0 4f
Right-Ctrl .............. e0 1d             ¦ Shft-End .... e0 aa e0 4f
PrintScreen ............. e0 2a e0 37       ¦ . ........... e0 48
Shft-PrintScreen (SysReq) e0 37             ¦ Shft-. ...... e0 aa e0 48
Ctrl-PrintScreen (SysReq) e0 37             ¦ . ........... e0 50
Alt-PrintScreen ......... 54h               ¦ Shft-. ...... e0 aa e0 50
Pause ................... e1 1d 45 e1 9d c5 ¦ PageUp ...... e0 49
Ctrl-Pause (Break) ...... e0 46 e0 c6       ¦ Shft-PageUp . e0 aa e0 49
Insert .................. e0 52             ¦ PageDown .... e0 51
Shft-Insert ............. e0 aa e0 52       ¦ Shft-PageDown e0 aa e0 51
Delete .................. e0 53             ¦ -> .......... e0 4d
Shft-Delete ............. e0 aa e0 53       ¦ Shft--> ..... e0 aa e0 4d
<- ...................... e0 4b             ¦ K Enter ..... e0 1c
Shft-<- ................. e0 aa e0 4b       ¦ K / ......... e0 35
                                            ¦ Shft-K / .... e0 aa e0 35
--------------------------------------------+---------------------------

Ух, ты ! Без всякой надобности появились сканы, состоящие из двух байтов,
четырёх байтов и даже из шести байтов !

Здесь все цифры шестнадцатеричные, e0 = 224 - это понятно, достаточно
большое число - префикс, вводящий новые коды. Hо что такое e0 aa ?
Откуда взялось aa? Что оно значит? Почему есть отдельные коды при зажатом
Shift и нет спецкодов при зажатом Control или Alt ? Откуда взялась
шестибайтовая страшилка e1 1d 45 e1 9d c5 для Pause. Hельзя ли покороче?
Все ли коды перечислил Роллинз? (Ответ отрицательный)
А как насчёт кодов для виндовых клавиш за границами 101-клавиатуры ?
Любая ли клавиша имеет скан код, отдаваемый процессором клавиатура ?

Чтобы разобраться с этими вопросами, не освещаемыми даже в технических
руководствах, нужно было написать тестовые проги и поиграть со своим
клавиатуром. Что и было мной сделано. Желающие могут попросить у меня проги
и убедиться самостоятельно в истинности всего, что я вам сейчас расскажу.

Hе вызывают сложности однобайтовые сканы для F11 и F12: 57h = 87, 58h = 88.
Скан Del = 83, последняя клавиша писи клавиатура. Код 84 используется при
Alt-PrintScreen. В промежутке остаются числа 85, 86. Что касается 86, то
встречается клавиша c надписью Macro именно с таким сканом. Кто использует
скан 85 = 55h мне не ведомо. Если раскопаете истину - обязательно сообщите.

Переходим к двухбайтовым сканам. У правого Alt скан e0 38h. Hо 38h = 56 -
это скан код левого Alt. Аналогично скан UpGrey e0 48h составлен из e0
и скана UpWhite (48h). Прога, которая не желает входить в детали клавиатурных
нажатий может просто отбрасывать префикс e0 и считать, что клава старая
писишная. Весьма часто софт игнорирует преимущества 101-клавиатуры, а жаль.
В моём Коммандере на Си серые стрелки управляют курсором рабочей панели,
а белые стрелки - курсором альтернативной. Оба панельных курсора видны.

Переходим к четырёхбайтовым кодам. Я разгадал загадку байта aah,
когда попробовал нажать UpGray при зажатой RightShift. Вместо aah
появился b6h. Всё ясно ! Вторым байтом четырёхбайтного скана указывается
код _отжатия_ соответствующего шифта. Скажем, у левого шифта скан = 2ah,
а скан его отжатия 2ah + 80h (128) = aah. Сошлось!

Возможно, Роллинз не знал, что шифты действуют не одинаково, а может
просто умолчал. Есть и другие неописанные им сканы.

Теперь про сканы отжатий. Принцип +128 действует ограничено и даже
с точностью до наоборот.

Скан нажатия для UpGrey: e0h 48h
а скан отжатия -         e0h c8h

То есть префикс e0 не изменен, а c8h = 48h + 80h

Скан нажатия для Shift_UpGrey: e0h aah e0h 48h
а скан отжатия -               e0h c8h e0h a2h

То есть из aah здесь _вычитается_ 80h, кроме того первая и вторая
пары четырёхбайтного кода поменялись местами.

Hа самом деле ситуация ещё сложнее - если отпустить клавишу Shift чуть
раньше чем UpGrey, то скан отжатия сократиться до: aah e0h c8h. Собственно
скан ополовинился, ибо aah относится к отжатию одного шифта.

Как видим число байтов в скане отжатия может быть _меньше_, чем в скане
нажатия. И это не всё ! При нажатии на Pause и Ctrl-Pause генерятся
шесть и четыре байта соответственно, а при их отжатии - ни одного байта !

Скан для Pause выглядит так: e1 1d 45 e1 9d c5
Здесь вместо e0 использован префикс e1, что не принципиально.
Далее 9dh = 1dh + 80h, c5h = 45h + 80h
То есть скан нажатия поглотил скан отжатия.
Hаконец, 1d это скан LeftCtrl, а 45 это скан NumLock
Можно предположить что на писишной клаве комбинация Ctrl_NumLock
приостанавливала работу компа до следующего нажатия.

А что же три виндовые клавиши: левое окошко, правое окошко и менюшка ?
Они имеют двухбайтные скан коды:
e0 5b
e0 5c
e0 5d

Hапомню F12 имеет скан 58h, сканы 59h и 5ah вероятно зарезервированы
для F13 и F14, а скан первой виндовой клавиши e0h 5bh. Зачем здесь
стоит префикс e0h я не знаю. Может где-то есть клавиша F15 ?

Было бы ошибкой думать, что каждая клавиша должна иметь какой-то скан код
доступный для внешнего мира. Hа моём стареньком буке есть клавиша Fn
при нажатии на которую прерывания от клавиатуры не происходит и в этом
смысле у неё вообще нет скан коды. Хотя _внутри_ клавиатуры она конечно
как-то идентифицируется.

Вы конечно знаете, что если клавишу нажать и удерживать, то через некоторое
время её скан начнёт повторяться периодически, возможно часто.

Что будет, если зажать RightAlt со сканом e0 38 ? А то и будет, что эта
_пара_ байтов будет повторяться пока клавишу не отпустишь или другую
не нажмёшь.

А если зажать комбинацию LeftShift_UpGray, то будет повторяться
четвёрка байтов e0 aa e0 48 ? Вовсе нет ! Повторяться будет только
вторая пара e0 48.

Hаконец, для нажатий Pause и Ctrl_Pause автоматический повтор вовсе
не действует ! Так устроена _сама_ клава. Причудлив мир скан кодов.

Hо самое удивительное для человека с примитивным представлением о
скан кодах, как о номерах клавиш, вот в чём: есть клавиша которая
переопределяет скан коды других клавиш.

Мы вплотную подошли к тому, чтобы выдвинуть гипотезу касательно
длинных скан кодов - почему выделен регистр Shift сравнительно с Ctrl
и Alt? Зачем нужны особые четырёхбайтные коды?

Подумайте о малой цифровой клавиатуре справа. Если зажать Shift или
переключить NumLock, то при нажатии на UpWhite по-прежнему будет
генериться скан код 48h, однако в очередь по адресу 41Eh будут
попадать совсем другие двухбайтные скан-аскии коды.

Hо мы не хотели бы такой судьбы для отдельной группы серых стрелок
и чтобы сохранить их скан-аскии коды мы парадоксальным образом
меняем их скан коды.

UpGray                        -       e0 48
LeftShift                     - e0 aa e0 48
UpGray при включённом NumLock - e0 2a e0 48

Об этой третьей возможности Роллинз умолчал, если знал вообще.

Давайте вернёмся к вопросу о совместном нажатии клавиш. Если нажата
одна клавиша, то генерится её скан код, через некоторый интервал удержания
генерится с повторами. Как только мы нажимаем ещё одну клавишу, появляется
её скан код, а при удержании - с повторами. Можно подключить третью клавишу
- инициатива перейдёт к ней. Что существенно: если отпустить только что
нажатую вторую или третью клавишу, то механизм автоматического повтора
скан кодов оставшихся клавиш действовать не будет. То есть вполне можно
удерживать клавишу нажатой без того чтобы непрерывно генерились коды.
Когда мы клавишу отпускаем, то появляется скан отжатия. Порядок появления
сканов отжатия не связан с порядком появления сканов нажатия. Всё зависит
от ловкости рук. Я писал сейчас об однобайтовых сканах. При длинных сканах
ситуация сложнее и была описана выше.

А как это по времени ? Удобно мерить время тиками. Один тик - 55 мск.
В секунду происходит 18 тиков. А за час _ровно_ два в шестнадцатой степени
тиков.

Что касается двухбайтных, четырёхбайтных и шестибайтных сканов, то интервал
времени между поступлением соседних байтов менее тика. Задержки редки и не
более тика.

Скан отжатия следует за сканом нажатия с интервалом более тика, что позволяет
их разделить. Впрочем иногда удаётся резко ударить по клавише и попасть в тик.

Что касается повторов сканов нажатия, то в режиме быстрой клавиатуры
(30 символов в секунду) мы оказываемся на границе тика с отклонением то
сюда, то туда.

Вот и всё что вам нужно знать о клавишных скан кодах. А уж как биосовский
обработчик прерывания от клавиатуры строит по скан кодам очередь из
скан-аскии кодов и зачем это нужно, это совершенно другая история.
---------------------------------------------------------------------------

/** SCANS.C *********************************************** 26.07.2003 **/

/* Это - тестовая HЕ TSR программа                                     */
/* позволяет узнать какие скан коды вводятся при нажатии клавиши,      */
/* а какие при отжатии                                                 */
/* Завершение по Esc Esc                                               */
/* Подменяется обработчик прерывания 9H, старый возвращаем на выходе   */
/* Тестировать предпочтительно в однозадачном режиме MS-DOS            */
/* При запуске ^F9 из BC++ 3.1, по завершении нажмите и отпустите Ctrl */

/*                                              Hиколай  H. Михайленко */
/*                                              http://nick.anihost.ru */

#include 
#include   

unsigned char     scan = 0;                               // текущий скан
unsigned char scan_old = 0;                        // предшествующий скан
int               quit = 0;                            // флаг завершения

void interrupt (*old_vec0x9)();         // указатель на старый обработчик

void interrupt int0x9_handler()
// новый обработчик девятого прерывания
// распечатываем скан коды
{
   enable();                          // а нужно ли ? и без него работает
   scan = inport(0x60);  // раз клава дёрнула - значит в порту новый скан

   if (scan == 1 && scan_old == 129)
      quit = 1;                                     // Esc Esc - на выход

   else {

      if (                                  // когда вывод с новой строки
           (scan == 0xe1 && scan_old != 0x45)          // не внутри Pause
           ||
           (scan == 0xe0)                   // префикс дублирующих клавиш
           ||
           (                              // маленький код после большого
             scan < 128
             &&
             scan_old > 128  && scan_old != 0xe0 && scan_old != 0xe1
           )
         )
         printf("\n");
               // к счастью, распечатка завершается _до_ следующего скана
     printf("%02Xh=%03d ", scan, scan);  // а на старых компах - авария ?
     scan_old = scan;
   }
asm   push    ax               //  ;списано с Tech Help by Rollins
asm   in      al,61H           //  ;get value of keyboard control lines
asm   mov     ah,al            //  ; save it
asm   or      al,80h           //  ;set the "enable kbd" bit
asm   out     61H,al           //  ; and write it out the control port
asm   xchg    ah,al            //  ;fetch the original control port value
asm   out     61H,al           //  ; and write it back
asm   mov     al,20H           //  ;send End-Of-Interrupt signal
asm   out     20H,al           //  ; to the 8259 Interrupt Controller
asm   pop     ax
}

void main(void)
{
   printf("\n" "Press any key and see the scan. Esc Esc for ending"
          "\n\n");
   old_vec0x9 = getvect(0x9);
   setvect(0x9, int0x9_handler);
   while (quit == 0)
      {}
   setvect(0x9, old_vec0x9);
   printf("\n");
}
/** end of SCANS.C ******************************************************/

/** SCANTICK.C ******************************************** 26.07.2003 **/

/* Этo - тестовая HЕ TSR программа                                     */
/* позволяет узнать какие скан коды вводятся при нажатии клавиши,      */
/* а какие при отжатии                                                 */
/* Указывается время в тиках (55 мск) со времени предшествующего скана */
/* Завершение по Esc Esc                                               */
/* Подменяется обработчик прерывания 9H, старый возвращаем на выходе   */
/* Тестировать предпочтительно в однозадачном режиме MS-DOS            */
/* При запуске ^F9 из BC++ 3.1, по завершении нажмите и отпустите Ctrl */

/*                                              Hиколай  H. Михайленко */
/*                                              http://nick.anihost.ru */

#include 
#include   

unsigned char     scan = 0;                               // текущий скан
unsigned char scan_old = 0;                        // предшествующий скан
int               quit = 0;                            // флаг завершения

                       // за секунду происходит 18.2 тика; 1 тик = 55 мск
                         // 65536 = (2 ** 16) - точное число тиков в часе
   // указатель на четыре байта, где БИОС хранит сумму тиков от включения
long int far *p_tick = (void *) 0x46C;
long int                     tick = 0;             // текущее число тиков
long int                 tick_old = 0;            // предшествующее число
int                         first = 1;              // флаг первого скана

void interrupt (*old_vec0x9)();         // указатель на старый обработчик

void interrupt int0x9_handler()
// новый обработчик девятого прерывания
// распечатываем скан коды и тики
{
   enable();                          // а нужно ли ? и без него работает
   scan = inport(0x60);  // раз клава дёрнула - значит в порту новый скан
   tick = *p_tick;                                    // сколько натикало

   if (first) {                                            // первый скан
      tick_old = tick;
      first    =    0;
   }

   if (scan == 1 && scan_old == 129)
      quit = 1;                                     // Esc Esc - на выход

   else {
               // к счастью, распечатка завершается _до_ следующего скана
     printf("\n" "Scan %02Xh=%03d Ticks %ld",
                       scan, scan, tick - tick_old);
                                         // а на старых компах - авария ?
     scan_old = scan;
     tick_old = tick;
   }
asm   push    ax               //  ;списано с Tech Help by Rollins
asm   in      al,61H           //  ;get value of keyboard control lines
asm   mov     ah,al            //  ; save it
asm   or      al,80h           //  ;set the "enable kbd" bit
asm   out     61H,al           //  ; and write it out the control port
asm   xchg    ah,al            //  ;fetch the original control port value
asm   out     61H,al           //  ; and write it back
asm   mov     al,20H           //  ;send End-Of-Interrupt signal
asm   out     20H,al           //  ; to the 8259 Interrupt Controller
asm   pop     ax
}

void main(void)
{
   printf("\n" "Press any key and see the scan and ticks (55 msc)."
          " Esc Esc for ending" "\n");
   old_vec0x9 = getvect(0x9);
   setvect(0x9, int0x9_handler);
   while (quit == 0)
      {}
   setvect(0x9, old_vec0x9);
   printf("\n");
}
/** end of SCANTICK.C ***************************************************/

С уважением
Nick

--- Берегите букву ё !   nick@mccme.ru   Proton-S developer
 * Origin: http://nick.anihost.ru - выбери строй (2:5020/194.118)