(*~\Глагол\Отделы\Обмен\~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
(**)                            ОТДЕЛ КОС;
(*============================================================================*)
(* НАЗНАЧЕНИЕ: взаимодействие с Консольной Оконной Системой (КОС)             *)
(*============================================================================*)

ИСПОЛЬЗУЕТ 
  ОБХОД,
  ЦвЗнак,
  ОС,
  Ввод;

ВИД
                           (* посылки от Win *)
  нОтКлавиш = НАБОР
    вид       :ОБХОД.Цел16;
    прозапас  :ОБХОД.Цел16;
    нажато-   :ЦЕЛ;
    повтор-   :ОБХОД.Цел16;
    код-      :ОБХОД.Цел16;
    мкод-     :ОБХОД.Цел16;
    знак-     :ЗНАК;
    упрКнопки-:МНОЖ;
  КОН;

  нОтМышки = НАБОР
    вид       :ОБХОД.Цел16;
    прозапас  :ОБХОД.Цел16;
    к-        :ОБХОД.Цел16;
    с-        :ОБХОД.Цел16;
    кнопки-   :МНОЖ;
    упрКнопки-:МНОЖ;
    события-  :МНОЖ;
  КОН;

  TIMERPROC=ЗАДАЧА*(uID,uMsg,dwUser,dw1,dw2:ЦЕЛ);

                           (* прямоугольная область экрана *)
  нОбласть = НАБОР
    лк:ОБХОД.Цел16; (* левая колонка  *) 
    вс:ОБХОД.Цел16; (* верхняя строка *) 
    пк:ОБХОД.Цел16; (* правая колонка *) 
    нс:ОБХОД.Цел16; (* нижняя строка  *)
  КОН;
                           (* состояние указки *)
  нСостояниеУказки = НАБОР
    размер,
    видимость:ЦЕЛ
  КОН;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
 *                         Задача выполняющаяся по времени
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ВИД  
                  зЧасы- = ЗАДАЧА(номер:ЦЕЛ);        (* или ПУСТО *)
ПЕР
  Задача_Часы:КОС.зЧасы;                             (* локальная для КОС.отд *)

                              (* используемые Win задачи *)

ЗАДАЧА SetConsoleMode(hConsoleHandle,dwMode:ЦЕЛ); ВЫЗОВ "SetConsoleMode" ИЗ "kernel32.dll";
ЗАДАЧА GetNumberOfConsoleInputEvents(hConsoleInput,lpNumberOfEvents+:ЦЕЛ); ВЫЗОВ "GetNumberOfConsoleInputEvents" ИЗ "kernel32.dll";
ЗАДАЧА ReadConsoleInput(hConsoleInput:ЦЕЛ; lpBuffer+:нОтМышки; nLength,lpNumberOfEventsRead+:ЦЕЛ); ВЫЗОВ "ReadConsoleInputW" ИЗ "kernel32.dll";
ЗАДАЧА WaitForSingleObject(hHandle,dwMilliseconds:ЦЕЛ); ВЫЗОВ "WaitForSingleObject" ИЗ "kernel32.dll";
ЗАДАЧА ReadConsoleOutputCharacter(hConsoleOutput:ЦЕЛ; lpCharacter+:ЗНАК; nLength,dwReadCoord,lpNumberOfCharsRead+:ЦЕЛ); ВЫЗОВ "ReadConsoleOutputCharacterW" ИЗ "kernel32.dll";
ЗАДАЧА WriteConsoleOutputCharacter(hConsoleOutput:ЦЕЛ; lpCharacter+:ЗНАК; nLength,dwWriteCoord,lpNumberOfCharsWritten+:ЦЕЛ); ВЫЗОВ "WriteConsoleOutputCharacterW" ИЗ "kernel32.dll";
ЗАДАЧА ReadConsoleOutputAttribute(hConsoleOutput:ЦЕЛ; lpAttribute+:ЗНАК; nLength,dwReadCoord,lpNumberOfAttrsRead+:ЦЕЛ); ВЫЗОВ "ReadConsoleOutputAttribute" ИЗ "kernel32.dll";
ЗАДАЧА WriteConsoleOutputAttribute(hConsoleOutput:ЦЕЛ; lpAttribute+:ЗНАК; nLength,dwWriteCoord,lpNumberOfAttrsWritten+:ЦЕЛ); ВЫЗОВ "WriteConsoleOutputAttribute" ИЗ "kernel32.dll";
ЗАДАЧА WriteConsoleOutput(hConsoleOutput:ЦЕЛ; lpBuffer-:ЦвЗнак.РядСтрока; dwBufferSize,dwBufferCoord:ЦЕЛ; lpWriteRegion-:нОбласть); ВЫЗОВ "WriteConsoleOutputW" ИЗ "kernel32.dll";
ЗАДАЧА SetConsoleCursorPosition(hConsoleOutput,dwCursorPosition:ЦЕЛ); ВЫЗОВ "SetConsoleCursorPosition" ИЗ "kernel32.dll";
ЗАДАЧА SetConsoleCursorInfo(hConsoleOutput:ЦЕЛ; lpConsoleCursorInfo+:нСостояниеУказки); ВЫЗОВ "SetConsoleCursorInfo" ИЗ "kernel32.dll";
ЗАДАЧА ScrollConsoleScreenBuffer(hConsoleOutput:ЦЕЛ; lpScrollRectangle+,lpClipRectangle+:нОбласть; dwDestinationOrigin:ЦЕЛ; lpFill-:ЦвЗнак.Вид); ВЫЗОВ "ScrollConsoleScreenBufferW" ИЗ "kernel32.dll";
ЗАДАЧА GetLargestConsoleWindowSize(hConsoleOutput:ЦЕЛ):ЦЕЛ; ВЫЗОВ "GetLargestConsoleWindowSize" ИЗ "kernel32.dll";
ЗАДАЧА SetConsoleScreenBufferSize(hConsoleOutput,dwSize:ЦЕЛ); ВЫЗОВ "SetConsoleScreenBufferSize" ИЗ "kernel32.dll";
ЗАДАЧА SetConsoleWindowInfo(hConsoleOutput,bAbsolute:ЦЕЛ; lpConsoleWindow-:нОбласть); ВЫЗОВ "SetConsoleWindowInfo" ИЗ "kernel32.dll";
ЗАДАЧА timeSetEvent(uDelay,uResolution:ЦЕЛ; lpTimerProc:TIMERPROC; dwUser,fuEvent:ЦЕЛ):ЦЕЛ; ВЫЗОВ "timeSetEvent" ИЗ "winmm.dll";
ЗАДАЧА timeKillEvent(uTimerID:ЦЕЛ); ВЫЗОВ "timeKillEvent" ИЗ "winmm.dll";

(*~======================================~общедоступная ЗАДАЧА~==============~*)
ЗАДАЧА* Часы(
              uID,
              uMsg,
              dwUser,
              dw1,dw2:ЦЕЛ
            );                                            (* Вызывается из ОС *)
УКАЗ
  ЕСЛИ
       Задача_Часы # ПУСТО
  ТО
       Задача_Часы(dwUser)
  КОН
КОН Часы;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Подготовить-(задЧасы:КОС.зЧасы);
УКАЗ
       Задача_Часы:=задЧасы
КОН Подготовить;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Отработать-;                       (* заглушка для совместимости с ГОС *)
УКАЗ
КОН Отработать;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ПоказатьОкно-;                     (* заглушка для совместимости с ГОС *)
УКАЗ
КОН ПоказатьОкно;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       СоздатьЧасы-(номер,время:ЦЕЛ):ЦЕЛ;
(*
 * Цель: добавляет новые, или заменяет старые часы
 * До:   <номер> - опознавательный номер часов
 *       <время> - время повторения срабатывания данных часов в мс
 *)
УКАЗ
  ВОЗВРАТ timeSetEvent(время,время,Часы,номер,1)
КОН СоздатьЧасы;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       УдалитьЧасы-(часы:ЦЕЛ);
УКАЗ
  timeKillEvent(часы)
КОН УдалитьЧасы;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       РазмерЭкрана-(строк+,колонок+:ЦЕЛ); (* Цель:  возвращает размер экрана *)
ПЕР
  ск:ЦЕЛ;
УКАЗ
  ск:=GetLargestConsoleWindowSize(ОС.ссылкаНаВывод);
  строк:=ск ДЕЛИТЬ 10000H;
  колонок:=ск ОСТАТОК 10000H
КОН РазмерЭкрана; 

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ИзменитьРазмерОкна-(строк,колонок:ЦЕЛ);
(*
 * Цель:  изменить размер окна приложения
 *)
ПЕР
  область:нОбласть;
  ск:ЦЕЛ;
УКАЗ
                            (* подготовим рабочую область для увеличения окна *)
  ск:=строк*10000H+колонок;
  SetConsoleScreenBufferSize(ОС.ссылкаНаВывод,ск);
                                                 (* изменение видимой области *)
  область.вс:=0;
  область.нс:=УЗК(строк-1);
  область.лк:=0;
  область.пк:=УЗК(колонок-1);
  SetConsoleWindowInfo(ОС.ссылкаНаВывод,1,область);
                              (* поправим рабочую область при уменьшении окна *)
  SetConsoleScreenBufferSize(ОС.ссылкаНаВывод,ск)
КОН ИзменитьРазмерОкна; 

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Опрос-(
                   отКлавиш+:Ввод.нОтКлавиш;
                    отМышки+:Ввод.нОтМышки
             ):ЦЕЛ;
ПЕР
  откуда,посылок:ЦЕЛ;
   ОСотМышки:КОС.нОтМышки;
  ОСотКлавиш:КОС.нОтКлавиш;
УКАЗ
  WaitForSingleObject(ОС.ссылкаНаВвод,-1);
  GetNumberOfConsoleInputEvents(ОС.ссылкаНаВвод,посылок);

                                            (* наверное, это посылка от мышки *)
  ReadConsoleInput(ОС.ссылкаНаВвод,ОСотМышки,1,посылок);
  откуда:=ОСотМышки.вид;
  ЕСЛИ откуда = Ввод.клавиши ТО             (* нет, не от мышки *)

    ОБХОД.Образ(ОБХОД.ПолучитьАдрес(ОСотМышки),
                ОБХОД.ПолучитьАдрес(ОСотКлавиш),20);

                                            (* ждём отпускания клавиши *)
    ЕСЛИ ОСотКлавиш.нажато = 0 ТО
      ВОЗВРАТ Ввод.пустой
    КОН;
    ЕСЛИ  (ОСотКлавиш.код = 10H)            (* просто шифт  SHIFT *)
      ИЛИ (ОСотКлавиш.код = 11H)            (* просто контр CTRL  *)
      ИЛИ (ОСотКлавиш.код = 12H) ТО         (* просто альт  ALT   *)
      ВОЗВРАТ Ввод.пустой
    КОН;

    отКлавиш.код:=ОСотКлавиш.код;
    отКлавиш.мкод:=ОСотКлавиш.мкод;
    отКлавиш.знак:=ОСотКлавиш.знак;
    отКлавиш.упрКнопки:=ОСотКлавиш.упрКнопки;
    отКлавиш.упрШифт:=Ввод.шифт В ОСотКлавиш.упрКнопки;
    отКлавиш.упрКонтр:={Ввод.лКонтр,Ввод.пКонтр}*ОСотКлавиш.упрКнопки # {};
    отКлавиш.упрАльт:={Ввод.лАльт,Ввод.пАльт}*ОСотКлавиш.упрКнопки # {}

  АЕСЛИ откуда = Ввод.мышка ТО

    ЕСЛИ
         Ввод.смещение В ОСотМышки.события
    ТО
      ВОЗВРАТ Ввод.пустой
    КОН;
    отМышки.к:=ОСотМышки.к;
    отМышки.с:=ОСотМышки.с;
    отМышки.кнопки:=ОСотМышки.кнопки;
    отМышки.упрКнопки:=ОСотМышки.упрКнопки;
    отМышки.события:=ОСотМышки.события;
    ЕСЛИ
         Ввод.прокрут В ОСотМышки.события
    ТО
      отМышки.прокрут:=ОБХОД.Значение(ЦЕЛ,отМышки.кнопки) ДЕЛИТЬ (10000H*120)
    ИНАЧЕ
      отМышки.прокрут:=0
    КОН;
      отМышки.отработана:=ОТКЛ

  ИНАЧЕ
    откуда:=Ввод.пустой
  КОН;
  ВОЗВРАТ откуда
КОН Опрос;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ПереместитьУказку-(с,к:ЦЕЛ);
УКАЗ
  SetConsoleCursorPosition(ОС.ссылкаНаВывод,с*10000H+к)
КОН ПереместитьУказку;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       РазмерУказки-(размер:ЦЕЛ);
(*
 * <размер> указывается в процентах,
 * при <размер> = 0 указка убирается с экрана
 *)
ПЕР
  состояние:нСостояниеУказки;
УКАЗ
  ЕСЛИ размер = 0 ТО
    состояние.видимость:=0;
    состояние.размер:=1
  ИНАЧЕ
    состояние.видимость:=1;
    состояние.размер:=размер
  КОН;
  SetConsoleCursorInfo(ОС.ссылкаНаВывод,состояние)
КОН РазмерУказки;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ПисатьЗнак-(с,к:ЦЕЛ; зн:ЗНАК);
ПЕР
  отработано:ЦЕЛ;
УКАЗ
  WriteConsoleOutputCharacter(ОС.ссылкаНаВывод,зн,1,с*10000H+к,отработано)
КОН ПисатьЗнак;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ЧитатьЗнак-(с,к:ЦЕЛ):ЗНАК;
ПЕР
  отработано:ЦЕЛ;
  зн:ЗНАК;
УКАЗ
  ReadConsoleOutputCharacter(ОС.ссылкаНаВывод,зн,1,с*10000H+к,отработано);
  ВОЗВРАТ зн
КОН ЧитатьЗнак;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ПисатьЦвет-(с,к:ЦЕЛ; цв:ЗНАК);
ПЕР
  отработано:ЦЕЛ;
УКАЗ
  WriteConsoleOutputAttribute(ОС.ссылкаНаВывод,цв,1,с*10000H+к,отработано);
КОН ПисатьЦвет;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ЧитатьЦвет-(с,к:ЦЕЛ):ЗНАК;
ПЕР
  отработано:ЦЕЛ;
  цв:ЗНАК;
УКАЗ
  ReadConsoleOutputAttribute(ОС.ссылкаНаВывод,цв,1,с*10000H+к,отработано);
  ВОЗВРАТ цв
КОН ЧитатьЦвет;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Вверх-(вс,лк,нс,пк:ЦЕЛ; новЗнак-:ЦвЗнак.Вид);
(*
 * Цель:  сдвиг содержимого заданной области вверх
 * До:    <вс>,<лк>,<нс>,<пк> - границы области на окне
 *        <новЗнак>           - знак для заполнения освободившегося места
 *)
ПЕР
  область:нОбласть;
УКАЗ
  область.лк:=УЗК(лк);
  область.вс:=УЗК(вс);
  область.пк:=УЗК(пк);
  область.нс:=УЗК(нс);
  ScrollConsoleScreenBuffer(ОС.ссылкаНаВывод,область,область,(вс-1)*10000H+лк,новЗнак)
КОН Вверх;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       Вниз-(вс,лк,нс,пк:ЦЕЛ; новЗнак-:ЦвЗнак.Вид);
(*
 * Цель:  сдвиг содержимого данной области вниз
 * До:    <вс>,<лк>,<нс>,<пк> - границы области на окне
 *        <новЗнак>           - знак для заполнения освободившегося места
 *)
ПЕР
  область:нОбласть;
УКАЗ
  область.лк:=УЗК(лк);
  область.вс:=УЗК(вс);
  область.пк:=УЗК(пк);
  область.нс:=УЗК(нс);
  ScrollConsoleScreenBuffer(ОС.ссылкаНаВывод,область,область,(вс+1)*10000H+лк,новЗнак)
КОН Вниз;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~общедоступная ЗАДАЧА~~~~~~~~~~~~~~~~*)
ЗАДАЧА
       ПисатьСтроку-(цвСтрока-:ЦвЗнак.РядСтрока;
                          с,к,
                        длина :ЦЕЛ);
(*
 * Цель:  отрисовка содержимого строки 
 * До:    <с>,<к> - начало строки на экране
 *        <длина> - длина строки 
*)
ПЕР
  область:нОбласть;
УКАЗ
  область.лк:=УЗК(к);
  область.вс:=УЗК(с);
  область.пк:=УЗК(к+длина-1);
  область.нс:=УЗК(с);
  WriteConsoleOutput(ОС.ссылкаНаВывод,цвСтрока,1*10000H+РАЗМЕР(цвСтрока),0,область)
КОН ПисатьСтроку;

(*-ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss-*)
УКАЗ                                     
  SetConsoleMode(ОС.ссылкаНаВвод,10H)       (* подключаем мышку *)
КОН КОС.
