Zdarzenie (informatyka)

Zdarzenie (ang. event) – zapis zajścia w systemie komputerowym określonej sytuacji.

Zdarzenia w programowaniu zdarzeniowym

Zdarzenia generowane są na przykład podczas poruszania myszką, kończenia otwierania dokumentu lub naciśnięcia klawisza na klawiaturze. Mogą być powodowane przez sprzęt (zdarzenia sprzętowe), system (systemowe), bądź oprogramowanie (programowe).

Zdarzenia w postaci specjalnych rekordów są przechowywane przez system operacyjny w tzw. kolejkach zdarzeń (ang. event queues) zbudowanych w oparciu o strukturę FIFO. Kolejki są na ogół przypisane po jednej do wątku (każda aplikacja ma choć jeden). System operacyjny utrzymuje też własne kolejki zdarzeń. Każde zdarzenie wpada do jednej lub większej liczby kolejek. Np. zdarzenia klawiatury wpadają tylko do kolejki aktywnej aplikacji, a zapytanie o możliwość zamknięcia systemu do kolejek wszystkich aplikacji.

Aplikacja odczytuje swoją kolejkę zdarzeń i podejmuje odpowiednie akcje określone przez programistę. Aplikacje na ogół ograniczają się tylko do reagowania na zdarzenia uzyskiwane z systemu operacyjnego (tzw. programowanie zdarzeniowe), nie wykonując żadnego kodu gdy nie ma dla nich żadnych nowych zdarzeń.

Można też skorzystać z mechanizmu tzw. event hooks, dzięki którym aplikacja „podsłuchuje” zdarzenia innej aplikacji lub całego systemu. Jest to stosowane przez debuggery i aplikacje hackerskie (np. keylogger może podglądać hasła wpisywane przez użytkownika przechwytując zdarzenia klawiatury), odtwarzacz muzyki może skorzystać z mechanizmu hooków aby możliwe było sterowanie odtwarzaniem przy pomocy klawiatury i bez konieczności przełączania się do jego okna.

Zobacz też: Programowanie zdarzeniowe.

Zdarzenia w systemie Windows

W Windows kolejki zdarzeń są przypisane do wątków, jednak każde zdarzenie zawiera uchwyt okna, w związku z czym bywają one określane jako window message. Pojęcie okna w systemie Windows obejmuje nie tylko okienko na ekranie. Oddzielnymi „oknami” są też np. wnętrze okna, dowolny element okna (każdy przycisk czy tekst), tło ekranu.

Definicja zdarzenia w systemie Windows, tak jak widzi je aplikacja:

typedef struct tagMSG {
  HWND hwnd;      /*Uchwyt okna docelowego*/
  UINT message;   /*Kod określający rodzaj zdarzenia (zobacz niżej)*/
  WPARAM wParam;  /*Parametr – interpretacja zależna od rodzaju zdarzenia*/
  LPARAM lParam;  /*Parametr – interpretacja zależna od rodzaju zdarzenia*/
  DWORD time;     /*Czas zdarzenia*/
  POINT pt;       /*Punkt ekranu związany z danym zdarzeniem*/
} MSG;

Rodzajów zdarzeń są tysiące. Oto kilka przykładów:

  • WM_KEYDOWN – wciśnięto przycisk na klawiaturze
  • WM_KEYUP – puszczono przycisk na klawiaturze
  • WM_MOUSEOVER – przesunięto myszkę, gdy jest na tle danego okna
  • WM_INITDIALOG – zdarzenie generowane przed pokazaniem okna dialogowego w celu poinformowania go, że powinno ustawić wszystkie swoje zmienne na wartości początkowe.
  • WM_COMMAND – zdarzenie komendy wywoływane przez opcje menu, przyciski okna dialogowego i akceleratory.
  • WM_CREATE – utworzono okno
  • WM_SIZE – zmieniono rozmiar okna
  • WM_PAINT – nakaz odrysowania się dla okna
  • WM_CLOSE – informacja dla okna, że będzie zamknięte. Okno aplikacji może się na przykład zapytać użytkownika, czy zapisać pliki. Ma jeszcze możliwość odwołania zamknięcia.
  • WM_QUIT – bezwarunkowe zamknięcie aplikacji (bez pytania jej o zgodę)
  • WM_TIMER – system informuje o upływie pewnego czasu (na wcześniejsze żądanie programu)
  • WM_QUERYENDSESSION – zapytanie wszystkich aplikacji, czy zgadzają się na zamknięcie sesji systemu operacyjnego.

Obsługując zdarzenie aplikacja może zwrócić do nadawcy (systemu lub innego procesu) liczbę, która będzie jakoś zinterpretowana w zależności od rodzaju zdarzenia. Może to być na przykład odpowiedź, czy udało się zainicjować zmienne, albo czy jest zgoda na zamknięcie systemu.

Można też definiować własne zdarzenia, i np. komunikować się przy ich pomocy między okienkami lub procesami.

Do programowego tworzenia zdarzeń służą dwie funkcje:

  • SendMessage – tworzy zdarzenie i wstrzymuje wykonanie do czasu jego przetworzenia przez adresata. Zwraca odpowiedź adresata.
  • PostMessage – dopisuje zdarzenie do kolejki adresata bez oczekiwania na jego przetworzenie

Istnieją tzw. okna modalne, wstrzymujące przetwarzanie zdarzeń przez pozostałe okna danej aplikacji (np. okno z pytaniem na które należy odpowiedzieć tak/nie). Istnieją też systemowe okna modalne, wstrzymujące przetwarzanie zdarzeń przez wszystkie inne okna (np. pytanie o potwierdzenie zamknięcia systemu).

Przykład pętli obsługi zdarzeń:

    MSG msg;
    while(GetMessage(&msg, NULL, 0, 0))
    {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }

Przetwarzanie zdarzeń przez aplikację polega na wykonywaniu w pętli funkcji:

  • GetMessage – pobiera zdarzenie z kolejki
  • TranslateMessage – tłumaczy niektóre zdarzenia dotyczące wciśnięcia przycisków klawiatury
  • DispatchMessage – pobrane zdarzenie jest kierowane do wcześniej zdefiniowanej procedury docelowego okna, która je obsługuje (tzw. window procedure). Procedura ta jest definiowana podczas tworzenia okna.

Istnieje też funkcja PeekMessage którą można podglądać zdarzenia w kolejce bez pobierania ich.

Przykładowa aplikacja Windows działająca zdarzeniowo

#include <windows.h>

static TCHAR lpszAppName[] = TEXT( "API Windows" );

LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{
    //reakcje na poszczególne zdarzenia wysyłane przez użytkownika
    switch (uMsg)
    {
        case WM_CREATE:
             break;

        case WM_DESTROY:
             PostQuitMessage(0);
             break;

        case WM_KEYDOWN:
             break;

        default:
             return (DefWindowProc(hWnd, uMsg, wParam, lParam));

    }
    return(0L);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{

    MSG msg;
    WNDCLASS wndclass;
    HWND hWnd;

    //definicja okna
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc = MainWndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = NULL;
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = lpszAppName;

    if(RegisterClass(&wndclass) == 0)
        return FALSE;

    hWnd = CreateWindow(lpszAppName, lpszAppName,
                        WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
                        CW_USEDEFAULT, CW_USEDEFAULT,
                        CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
    if(hWnd == NULL)
        return FALSE;

    //pokazanie okna
    ShowWindow(hWnd, SW_SHOW);
    UpdateWindow(hWnd);

    //pętla oczekująca na przychodzące zdarzenia
    while(GetMessage(&msg, NULL, 0, 0))
    {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }

    return msg.wParam;
}

Zdarzenia w systemie Mac OS

Definicja zdarzenia w systemie Mac OS:

struct EventRecord {
   EventKind         what;
   UInt32            message;
   UInt32            when;
   Point             where;
   EventModifiers    modifiers;
};

Opis pól:

  • what – pole opisujące rodzaj zdarzenia, np.
    • 0 nullEvent
    • 1 mouseDown
    • 2 mouseUp
    • 3 keyDown
    • 4 keyUp
    • 5 autoKey
    • 6 updateEvt
    • 7 diskEvt
    • 8 activateEvt
    • 15 osEvt
    • 23 kHighLevelEvent
  • message – dodatkowa informacja zależna od rodzaju zdarzenia
  • when – czas (liczba ticków) od startu systemu
  • where – pozycja myszy
  • modifiers – dodatkowe flagi

Zdarzenia w systemie X Window System

Wszystkie zdarzenia w systemie X Window System mają następujące wspólne pola:

       typedef struct {
            int type;                /* typ zdarzenia*/
            unsigned long serial;    /* liczba ostatnich zleceń przetworzonych przez serwer */
            Bool send_event;         /* true jeśli pochodzi z wywołania SendEvent */
            Display *display;        /* Display z którego zdarzenie zostało odczytane */
            Window window;
       } XAnyEvent;

Dla poszczególnych zdarzeń zdefiniowane są osobne struktury. Unia XEvent łączy je w jedno:

       typedef union _XEvent {
            int type;
            XAnyEvent xany;
            XKeyEvent xkey;
            XButtonEvent xbutton;
            XMotionEvent xmotion;
            XCrossingEvent xcrossing;
            XFocusChangeEvent xfocus;
            XExposeEvent xexpose;
            XGraphicsExposeEvent xgraphicsexpose;
            XNoExposeEvent xnoexpose;
            XVisibilityEvent xvisibility;
            XCreateWindowEvent xcreatewindow;
            XDestroyWindowEvent xdestroywindow;
            XUnmapEvent xunmap;
            XMapEvent xmap;
            XMapRequestEvent xmaprequest;
            XReparentEvent xreparent;
            XConfigureEvent xconfigure;
            XGravityEvent xgravity;
            XResizeRequestEvent xresizerequest;
            XConfigureRequestEvent xconfigurerequest;
            XCirculateEvent xcirculate;
            XCirculateRequestEvent xcirculaterequest;
            XPropertyEvent xproperty;
            XSelectionClearEvent xselectionclear;
            XSelectionRequestEvent xselectionrequest;
            XSelectionEvent xselection;
            XColormapEvent xcolormap;
            XClientMessageEvent xclient;
            XMappingEvent xmapping;
            XErrorEvent xerror;
            XKeymapEvent xkeymap;
            long pad[24];
       } XEvent;

Zobacz też: manual do struktury XEvent

Zdarzenia z dziennika zdarzeń

Drugim, zupełnie odrębnym znaczeniem słowa „zdarzenie” w informatyce jest wpis w dzienniku zdarzeń. Dziennik jest aplikacją systemową, dzięki której administrator może kontrolować bieżącą pracę systemu. Zapisywane są w nim zdarzenia takie jak np. brak możliwości uruchomienia sterownika, albo zalogowanie na konto administratora. Zdarzenia w tym sensie nie mają żadnego związku z wcześniej wymienionym znaczeniem.

Linki zewnętrzne