<<< BACK NEXT >>>

СОБЫТИЯ И УПРАВЛЕНИЕ ИМИ

   CAPER обладает очень мощными средствами инициации вычислений на основе асинхронных событий.
   События в CAPER разделяются на несколько групп:
   - программные события, или события, определяемые значением определенных  арифметических и логических выражений;
   - события виртуального процессора (машины CAPER);
   - события операционной системы. Программные события определяются командами

   WHEN <событие> <DO-запись>

<событие>   - любое логическое или арифметическое выражение.
<DO-запись> - см. описание оператора DO.

   Данной командой предписывается исполнение DO-конструкции всякий раз в случаях, когда возникнет событие-условие. Варианты и возможности обработки событий мы рассмотрим чуть позже.
   Атрибуты WHEN добавляются в список в том порядке, в котором выполняются операторы. При повторном прохождении через оператор WHEN  не выполняется, т.е. описатель события регистрируется единственный раз.
   С целью обслуживания WHEN введены следующие функции среды:
WHENIdent()  - функция, возвращающая внутренний числовой идентификатор события
WHENCount()  - возвращает текущее количество назначенных WHEN-событий
DeleteWHEN( [ <идентификатор события> ] ) - функция удаления события(й); удаляет назначение события, если указан идентификатор, и удаляет все назначения, если идентификатор опущен
FreezeWHEN( [ <идентификатор события> ] ) - "замораживает" событие с указываемым идентификатором;или "замораживает" все события, если идентификатор опущен. Аналогичный результат достигается использованием Set When Off.
DefreezeWhen( [ <идентификатор события> ] ) - обратная FreezeWHEN функция, "размораживающая" события - одно, если указан числовой идентификатор, и все, если нет.Удаление событий приводит к снятию назначений в списке событий. При этом, при назначении новых событий они (новые) могут заиметь идентификатор, который был назначен удаленным. При ошибочном программировании все манипуляции с идентификатором события будут относиться к новому. Эта ситуация трактуется как ошибочная в силу того, что CAPER не дает средств регулирования назначения идентификаторов событий, и новое событий может принять необходимый идентификатор только случайно.
   Замораживание события означает, что до момента "размораживания" данное событие не анализируется, т.е. попросту обходится машиной языка в списке событий.
   Выполнение блока обработки события может осуществиться в любой точке любой параллельной ветви параллельных процессов. В момент инициации обрабатывающего блока событие замораживается. В момент завершения его обработки, если необходимо, событие должно быть "разморожено". Техника "размораживания" событий дана в следующем примере
 . . .
   WHEN var1 > var2 DO block1( pVar1, pVar2 )
   var3 := WHENIdent()
   . . .
   block block1(fVar1, fVar2)
    . . .
    return defreezeWHEN( var3 )
   endblock

   Очень аккуратно можно использовать (как правило, это не годится) прямолинейный вариант:

   block block1(fVar1, fVar2)
     . . .
     defreezeWHEN( var3 )
   endblock

ибо defreezeWHEN( var3 ) - команда, после выполнения которой и до выполнения возврата по endblock, событие может снова выполниться, и block1 будет вызван до собственного завершения (последствия - может быть забит стек вызовов, который ограничен памятью компьютера, если только, конечно, событие не будет сброшено неявным образом - выражение в WHEN станет ложным).
   Выполнение одного из событий не исключает срабатывание других событий в момент обработки первого. Для исключения помех в момент обработки события, CAPER позволяет создание блоков обработки в качестве критических секций или используя функции замораживания событий. Кроме функций замораживания CAPER позволяет вовсе отключать механизм обработки WHEN-событий:
SET WHEN OFF
и включать
SET WHEN ON
В начальный момент работы программы, до первого
SET WHEN ON события могут назначаться, но не будут анализироваться:

Пример:

      WHEN pVar1 DO block1(pVar1, pVar2)
      . . .
      WHEN pVar2 != pVar3 DO block2
      . . .

      Set When On  ;*  Включается механизм обработки событий.
      . . .

   Однако, в случае

   Set When On  ;*  Включается механизм обработки событий.
   WHEN pVar1 DO block1(pVar1, pVar2)

*  Здесь механизм обработки событий CAPER включен, а следовательно, если
*  pVar1 > 0 , то немедленно будет запущен блок block1
   . . .
   WHEN pVar2 != pVar3 DO block2
   . . .

   Второй принципиальной конструкцией CAPER является оператор асинхронного ожидания события

   WAIT <условие> [ BY <имя блока> ]

(вариант WAIT SYNCH в прошлой версии [3] заменен на WAIT IsSynch(); см. ниже).
   Данный оператор переводит выполнение программы или ветви параллельных процессов в режим ожидания события до момента выполнения логического условия, причем процесс ожидания может сопровождаться выполнением блока, указываемого после спецификатора BY. Как правило, такой блок должен быть организован как
критическая секция.
   WAIT IsSynch() предназначен для ожидания завершения параллельно запущенных процессов командой DO ASYNCH блоков.Комбинация операторов WHEN и WAIT позволяет определить очень комфортный стиль программирования:

Пример:

   private pVar1 := 0, pVar2, pVar3 := 1
   . . .
   WHEN  pVar1 > pVar3 DO block1
   WHEN  pVar2         DO block2
   set when on
   . . .
   Wait 0 By Bl_Wait
   . . .
   Block Bl_Wait
     . . .
     pVar1 := . . .
     . . .
     pVar2 := . . .
     . . .
     pVar3 := . . .
     . . .
   Endblock

   Block block1 ;* блок обработки события pVar1 > pVar3 - истинно
     . . .
   Endblock

   Block block2 ;* блок обработки события pVar2 - истинно (pVar2 > 0)
     . . .
   Endblock

Либо,

   private pVar1 := 0, pVar2, pVar3 := 1
   . . .
   WHEN  pVar1 > pVar3 DO block1
   WHEN  pVar2         DO block2
   set when on
   . . .
   do aSynch block3(. . .), block4(. . .), block5(. . .)
   . . .
   Wait 0 By Bl_Wait
   . . .

Здесь будут выполняться четыре параллельных процесса, один из которых (инициатор) будет переведен в режим асинхронного ожидания, причем, в силу тождественной "лжи" в условии, будет снят только экстраординарными мерами -

   PARABREAK TO <номер процесса>

<номер процесса> должен быть меньше 4; либо с помощью

   Quit

   Третьим типом асинхронных событий являются события операционной системы.
Этот вид событий поддержан в данной версии CAPER набором функций среды, которые обеспечивают определение событий и регулирования их активности. Реализация событий ОС во многом зависит от специфики той или иной операционной системы, а потому описываемые ниже функции будут наиболее подвержены модификациям в интерпретации и исполнении. Здесь же они сориентированы на операционную среду Win 32.

   События ОС классифицированы

   - на события клавиатуры;
   - события "мышки";
   - события таймеров;
   - служебные события ОС;
   - программные события;
   - исключительные события ОС.

 

   В данном перечне не исключено появление в будущем событий ввода-вывода в целом, с классификацией этих событий.
   Назначение блока-обработчика событий осуществляется функцией

   SetOSEvent( <тип событий>, <имя блока обработки> [, <номер процесса> ]  )

   <тип событий> - числовой идентификатор типа
   1 - события клавиатуры;
   2 - события "мышки";
   3 - события таймеров;
   4 - служебные события ОС;
   5 - исключительные события ОС.
   0 - все события.

   Программные события определяются отдельным набором функций: для назначения обработчиков исключительных ситуаций виртуального процессора -

   SetProgErrBlock( <имя блока обработки>, [<имя файла объектного модуля>] )

   <имя блока обработки> - строковый литерал -  имя блока CAPER, вызов которого
будет осуществлен немедленно при возникновении события в любой точке параллельного или последовательного выполнения процессов.
   Обработчик события будет запущен обычным для CAPER вызовом блока. Процесс, выполняемый в данный момент времени, будет приостановлен до завершения обработки.
   Если речь идет о параллельном процессе, то будет приостановлена текущая ветвь, остальные будут продолжать выполняться, если только блок-обработчик не откомпилирован в стиле критического фрагмента (о стилистике компиляции - позже).
   Событие будет обрабатываться сразу после назначения. Вызываемый блок должен быть определен с параметрами, количество которых зависит от типа обрабатываемого события и значения которых машина CAPER разместит в момент вызова. Параметры могут быть поименованы как угодно.

block EventsBlock( par1, par2, par3, par4, par5, par6, par7, par8 )
  . . .
endblock

и которые будут иметь описываемые далее значения: для всех событий -
 1-ый параметр - числовой идентификатор события.
 2-ой параметр - внутренний (ОС) описатель события
длясобытий клавиатуры:
 3-ий параметр - числовой код клавиши (коды клавиш отличаются для нажатий,отжатий и пр.)
 4-ый параметр - количество сигналов действий с клавишей ("нажатий").
 6-ой параметр - код;
 8-ой параметр - собственный идентификатор события;
 для событий "мышки":
 3-ий параметр - числовой код клавиши мышки (коды клавиш отличаются для нажатий,отжатий и пр.)
 4-ый параметр - позиция курсора "мышки" по вертикали;
 5-ый параметр - позиция курсора "мышки" по горизонтали;
 6-ой параметр - расширенная информация о нажатих клавишах;
 7-ой параметр - внутренний идентификатор события;
 8-ой параметр - собственный идентификатор события;
 для событий таймеров:
 3-ий параметр - номер таймера;
 К служебным событиям ОС отнесены события Win 32, связанные с окном Windows:  блоку обработки передается информация о закрытии, свертке и развертке окна,  перемещении, изменении размеров и др. -
 3-ий параметр - код события окна;
 4-ый параметр - lParam       CALLBACK функций Win 32;
 5-ый параметр - wParam     CALLBACK функций Win 32.

 По исключительным событиям Win 32 параметры имеют следующие значения:

 1-ый параметр - числовой идентификатор события;
 2-ой параметр - описатель события - код исключительной ситуации;
 3-ий параметр - символическое имя блока, в момент выполнения которого возникла исключительная ситуация;
 4-ый параметр - номер команды блока;
 5-ый параметр - номер команды виртуального процессора.

   Если назначен блок обработки всех событий, то в каждом конкретном случае значения параметров блока будут соответсвовать событиям.
   Итак, если по SetOSEvent назначен блок для конкретного типа события, то данный вид событий будет обрабатывать именно данный блок. При этом, отдельные типы событий могут обрабатываться отдельными блоками. Виды событий перечислены в порядке их приоритетов, т.е. наименее приоритетными являются события от клавиатуры, наиболее приоритетными - события по исключительным ситуациям ОС. Все события устанавливаются и классифицируются внутри CAPER-машины. Запуск обрабатывающего блока будет осуществлен по наиболее приоритетному событию в момент внутренней синхронизации виртуального процессора после выполнения очередной команды программы. Остальные, менее приоритетные события не будут сбрасываться, если только это не будет сделано принудительно функцией ClearOSEvent.

   ClearOSEvent( [ <тип событий> ] )

   Если параметр опущен, NULL или 1 - сбрасываются все события, если указан идентификатор конкретного типа, то будет сброшено событие именнно данного типа, если числовой идентификатор не совпадает с перечисленными - вырабатывается
программное аварийное событие, функция не осуществит сброса и вернет отрицательное числовое значение.

   DelOSEvent( [ <тип событий> ] )

удаляет назначение обработчика событий. Как и для ClearOSEvent( [ <тип событий> ] ), действие функции распространяется на конкретный тип, либо на все, либо она возвращает отрицательное число по некорректному числу.

   FreezeOSEV( [ <тип событий> ] )

"замораживает" указываемый тип событий, либо все, если <тип событий> опущен, NULL или 1, либо возвращает отрицательное число, если параметр не соответствует типу.

   DefreezeOS( [ <тип событий> ] )

размораживает событие(я) указываемого типа.

   CreateOSEv( <тип событий> [,<параметр 1>] [,<параметр 2>] . . . [,<параметр
               N>])

порождает событие указываемого типа и со значениями параметров для вызываемых блоков (см. выше): ни одного или то количество, которое будет необходимым.
   В данную версию CAPER введены специальные функции, обеспечивающие "регионализацию" событий "мышки". Они позволяют асинхронным образом обрабатывать события "мыши", которые возникают в конкретных прямоугольных регионах нахождения ее курсора. По-прежнему в наименованиях всех функций присутствует инфикс OS,
который подчеркивает, что данная функция в существенной мере зависит от реализации CAPER в среде конкретной операционной системе или среде.

   SetOSEventRgn( <Y0>, <X0>, <Y1>, <X1>, <имя блока>
                  [ , <фильтр> [,  <R-признак> [, <собственный признак> ] ] ] )

<Y0>, <X0>  - координаты левого верхнего угла прямоугольника региона.
<Y1>, <X1>  - координаты правого нижнего угла прямоугольника региона.
<имя блока> - имя блока обработки
<фильтр>    - фильтр набора событий, на которые машина CAPER должна отреагировать вызовом блока; он может быть определен посредством булевого сложения (ИЛИ) перечисленных выше макроопределений или прямым заданием
полуслова:

#macro LBUTTONDOWN    0x0001'H
#macro LBUTTONUP      0x0002'H
#macro LBUTTONDBLCLK  0x0004'H
#macro RBUTTONDOWN    0x0008'H
#macro RBUTTONUP      0x0010'H
#macro RBUTTONDBLCLK  0x0020'H
#macro MBUTTONDOWN    0x0040'H
#macro MBUTTONUP      0x0080'H
#macro MBUTTONDBLCLK  0x0100'H

<R-признак> - положительное значение или NULL означают, что номер параллельного процесса будет учтен событийным механизмом и указанный блок будет вызван именно из параллельной ветки, из которой было описано и установлено
событие, 0 - обработчик события запускается из  любого процесса. <собственный признак> - значение (в том числе, коллекция, блок, массив), которое будет возвращено восьмым параметром в вызываемый на обработку блока.
   Функция SetOSEventRgn возвращает внутренний числовой идентификатор регистрируемого обработчика событий, либо отрицательное число в случае неуспеха регистрации.    Пример определения фильтра:

    SetOSEventRgn( 20, 30, 400, 500, "Block_Ev", LBUTTONDOWN | RBUTTONDOWN  )

или

    SetOSEventRgn( 20, 30, 400, 500, "Block_Ev", 0x0009'H  )

   CAPER не проверяет на пересечение определяемых регионов (соответственно, на вхождение региона в регион). Машина CAPER отстартует блок, если курсор находится в регионе и фильтр отвечает событию. При этом, при пересечении регионов активным окажется тот, фильтр которого будет отвечать событию:

    SetOSEventRgn( 20, 30, 400, 500, "Block_1", LBUTTONDOWN | RBUTTONDOWN  )
    SetOSEventRgn( 20, 30, 40, 80, "Block_2", LBUTTONUP | RBUTTONUP  )

Здесь нажатие клавиши при координатах курсора, к примеру, ( 30 , 30 ), будет вызван Block_1, в то время как отжатие приведет к вызову Block_2. Если же

    SetOSEventRgn( 20, 30, 400, 500, "Block_1", LBUTTONDOWN | RBUTTONDOWN  )
    SetOSEventRgn( 20, 30, 40, 80, "Block_2", LBUTTONDOWN  )

всегда будет запускаться Block_1.     Если определено, к примеру,

    do asynch block1, block2( p1, p2 ), block3( p3, p4 ), block4
    . . .
    block block2( p1, p2 )
      . . .
      SetOSEventRgn( 200, 300, 400, 500, "Block_1", LBUTTONDOWN, 1  )
      . . .
    endblock

    block3( p1, p2 )
      . . .
      SetOSEventRgn( 20, 30, 40, 50, "Block_2", LBUTTONDOWN, 1  )
      . . .
    endblock

 

то Block_1 будет запущен из текущего для процесса с номером 2 блока, в то время как Block_2 будет отстартован из процесса (потока) с номером 3 (отметим, что всего параллельных процессов 5).     Если же задано

    . . .
    SetOSEventRgn( 200, 300, 400, 500, "Block_1", LBUTTONDOWN, null, 100  )
    . . .
    block_1 testBlock( par1, par2, par3, par4, par5, par6, par7, par8 )
     local TF := 0
     TF := ( par8 == 100 ) ;* TF == 1, т.к. par8 == 100
    endblock

    DelOSEventRgn( [ <идентификатор регистрации> ] )

функция удаления зарегистрированных событий.

<идентификатор регистрации> - числовой идентификатор, возвращаемый функцией SetOSEventRgn. Если он опущен или NULL, то удаляются все регистрации обработчиков событий в регионах. Если такой идентификатор указан, то описатель
региона и обработчика удаляются из списка.

   FreezeEventRgn( [ <идентификатор регистрации> ] )
и
   DefreezeEventRg( [ <идентификатор регистрации> ] )

соответственно "замораживают" и "размораживают" обработку событий в регионе.

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

   SetKeybRgn( <Y0>, <X0>, <Y1>, <X1>, <имя блока>
               [ , <фильтр> [,  <R-признак> [, <собственный признак> ] ] ]
             )
<Y0>, <X0>  - координаты левого верхнего угла прямоугольника региона.
<Y1>, <X1>  - координаты правого нижнего угла прямоугольника региона.
<имя блока> - имя блока обработки
<фильтр>    - фильтр набора клавишей, на которые машина CAPER должна отреагировать вызовом блока; он должен быть определен посредством указания элемента массива типа 'H', в котором перечислены коды клавиш.
<R-признак> - признак учета номера параллельного потока, в котором осуществлена
установка данного региона. Если признак - ненулевое число или NULL, то номер потока учитывается, и при возникновении события машина CAPER переключит потоки и запустит указываемый блок обработки в данном потоке, если <R-признак> равен 0, то обработчик событий будет запущен в процессе с любым номером.
   Функция возвращает внутренний номер регистрации региона. <собственный признак> - число, которое будет возвращено восьмым параметром в вызываемый на обработку блока.
DelOSKeybRgn( [<номер>] )  - удаляет обработчик события с указываемым номером, или, если номер отсутствует, то все назначенные обработчики.
FreezeKeybRgn( [<номер>] ) - замораживает обработчик события с указываемым номером, или, если номер отсутствует, то все назначенные обработчики.
DeFreezeKeybRgn( [<номер>] ) - размораживает обработчик события с указываемым номером, или, если номер отсутствует, то все назначенные обработчики.

   Что касается событий ОС, то CAPER, в отличие от WHEN-событий, не блокирует событие, вызвавшее инициацию блока обработки, а следовательно, это, при необходимости, нужно сделать в вызванном блоке. Сделано это из пока априорных
предположений, что в обработке данных событий чаще придется выбирать стиль нейтрализации ненужных повторных вызовов блоков обработки событий - блокировкой, сбросом или отсутствием их, если обрабатывающий блок откомпилирован как критический фрагмент  FreezeProcKey( <число> ) – замораживает обработку событий от клавиатуры,
причем если параметр отсутствует, то события клавиатуры замораживаются длявсех событий, если задано число, то замораживаются только события, связанные с процессом, указываемым числом.    DelProcKey( <число> ) - удаляет обработку событий для процесса <число>; опущенный параметр вызывает удаление обработки всех событий клавиатуры.
   DeFreezeProcKey( <число> ) – размораживает события согласно логике FreezeProcKey.

Примеры:
   Здесь же заметим, что события, связанные с клавиатурой, "мышкой" или таймерами могут фиксироваться и обрабатываться с помощью WHEN и функций выбора координат курсора и клавиш клавиатуры, мышки, функций выбора времени и состояний таймеров, другие:

   private CodeKey := 0

   WHEN ( (CodeKey:=GetKeyb()) == 32 )  || ( CodeKey == 13 )  =>
   DO EntryBlock

   . . .

   WHEN (msX :=MouseX()) >= 100 && msX <= 200 && =>
        (msY :=MouseY()) >= 200 && msY <= 400 && =>
        ( ms_Key := MouseKey()) == ms_LBut || ms_Key == ms_LButP ) =>
   DO MouseEvBlock( ms_Key, msY, msX )

   . . .
   SetTimer( 3, 1000) ;* Устанавливаем таймер с номером 3 на 1000 миллисекунд

   WHEN TimeIsZero( 3 ) Do TimerClosed

 

   Использование регионов событий влечет одну существенную проблему: реакцию на события, области которых пересекаются. С целью обеспечения предопределенной реакции в CAPER введены функции монополизации регионов

   SetMouseMono( <Y0>, <X0>, <Y1>, <X1>, <идентификатор события> )
   SetKeybMono( <Y0>, <X0>, <Y1>, <X1>, <идентификатор события> )

которые предопределяют обработку события с <идентификатор события> для мышки и клавиатуры соответственно, если оно произошло в заданной <Y0>, <X0>, <Y1>, <X1> области. Естественно, что события должны быть предварительно определены. Функции возвращают числовой идентификатор монопольного региона.Для отмены монополизации региона должны использоваться функции

   DelMouseMono( [<идентификатор монополизированного региона>] )
   DelKeybMono( [<идентификатор монополизированного региона>] )

для мышки и клавиатуры соответственно. Опущенные параметры влекут отмену всех регионов.

   FreezeProcRgn([<номер параллельного процесса>]) - замораживает все события процесса.

   DeFreezeProcRgn([<номер параллельного процесса>]) - размораживает все события процесса.
Если параметр опущен, то замораживает все события.
   DelProcRgn([<номер параллельного процесса>])
   IsAlive(<номер процесса>) - живой ли процесс (1, если процесс активен, 0, если нет (пассивен или завершен) )
   GetProcessStat(<номер процесса>)- возвращает статус процесса: 1, если процесс активен, 0, если завершен, 3 - пассивен;
   GetCurrStat() – возвращает статус текущего процесса;
<числовой идентификатор события> := SetUserEvent( <числовой идентификатор   USEREVENT>)
   DelUserEvent(<числовой идентификатор события>)
   FreezeUserEvent(<числовой идентификатор события>)
   DeFreezeUserEv(<числовой идентификатор события>)
   InitUserEvent(<числовой идентификатор USEREVENT>) – инициирует пользовательское событие.
   <числовой идентификатор USEREVENT> := IsUserEvent()
   ClearUserEvent() - обнуляет USEREVENT

<<< BACK NEXT >>>