Aby uczynić swój program bardziej atrakcyjnym wzrokowo i pochwalić się swoimi umiejętnościami,
można sprawić, aby diody na klawiaturze wskazujące stan
Num Lock, Caps Lock, Scroll Lock zaczęły migotać w jakimś rytmie.
Teraz pokażę, jak to zrobić.
Do manipulowania urządzeniem znakowym (klawiaturą) posłużymy się funkcją systemową sys_ioctl (numer 54). Najpierw jednak trzeba się dowiedzieć, jakich komend możemy używać. W tym celu udajemy się do pliku /usr/include/linux/kd.h lub do manuala, jeśli mamy w nim stronę ioctl_list, a w nim mamy (po angielsku):
#define KDGETLED 0x4B31 /*zwróć bieżący stan diód */ #define KDSETLED 0x4B32 /*ustaw stan diód (światełek, nie flag)*/ #define LED_SCR 0x01 /*dioda scroll lock */ #define LED_NUM 0x02 /*dioda num lock */ #define LED_CAP 0x04 /*dioda caps lock */
Jedną z tych dwóch pierwszych wartości
wpiszemy do ECX.
Tymczasem w EBX musimy mieć deskryptor otwartego
pliku /dev/console (do zapisu) lub wartość 1, która oznacza standardowe urządzenie
wyjścia - STDOUT.
W EDX podajemy ostatni parametr: wartość 0-7 jeśli ustawiamy stan diód lub wskaźnik (adres)
na zmienną typu DWORD, która otrzyma bieżąca wartość stanu diód (także 0-7).
Widać więc, co musi zrobić nasz program: zachować bieżący stan diód, dowolnie je pozmieniać
(i zadbać by efekt był widoczny - robić pauzy), po czym przywrócić poprzedni stan.
Oto, jak taki program mógłby wyglądać (używanie załączników z mojej biblioteki nie jest
konieczne - w kodzie mówię, jak i co zamienić).
; Program manipuluje diodami klawiatury ; ; Autor: Bogdan D. ; Kontakt: bogdandr (at) op (dot) pl ; ; nasm -f elf klaw.asm ; ld -s -o klaw klaw.o section .text ; nie musicie z tego korzystać: %include "bibl/incl/linuxbsd/nasm/n_system.inc" %include "bibl/incl/linuxbsd/nasm/n_const.inc" %define KDGETLED 0x4b31 %define KDSETLED 0x4b32 global _start _start: ; 1. otwieramy /dev/console, w trybie tylko do zapisu lub ; korzystamy ze STDOUT mov eax, sys_open ; sys_open = 5 (otwieramy plik) mov ebx, konsola ; adres nazwy pliku mov ecx, O_WRONLY ; O_WRONLY = 01 mov edx, 777q ; RWX dla wszystkich int 80h cmp eax, 0 jge .ok ; jak nie ma błędu, to jedziemy dalej ; w przypadku błędu korzystamy ze STDOUT mov eax, stdout ; stdout = 1 ; 2. pobieramy aktualny stan diód .ok: mov ebx, eax ; EBX = deskryptor pliku mov eax, sys_ioctl ; sys_ioctl = 54 - manipulacja urządzeniem mov ecx, KDGETLED ; pobierz stan diód mov edx, stare_diody ; adres DWORDa, który otrzyma ; aktualny stan diód int 80h mov eax, sys_ioctl ; sys_ioctl = 54 mov ecx, KDSETLED ; ustawiamy stan diód mov edx, 7 ; wszystkie włączone int 80h mov cx, 7 mov dx, 0a120h ; opóźnienie pół sekundy call pauza ; przywracamy poprzedni stan diód mov eax, sys_ioctl mov ecx, KDSETLED ; ustawiamy stan diód mov edx, [stare_diody] ; EDX = poprzedni stan diód int 80h cmp ebx, stdout ; czy otworzyliśmy konsolę, czy STDOUT? jle .koniec ; nie zamykamy STDOUT mov eax, sys_close ; zamykamy otwarty plik konsoli int 80h .koniec: wyjscie ; czyli ; mov eax, 1 ; xor ebx, ebx ; int 80h pauza: ; procedura pauzująca przez CX:DX milisekund push ebx push ecx push edx mov ax, cx shl eax, 16 mov ebx, 1000000 mov ax, dx ; EAX = CX:DX xor edx, edx div ebx ; CX:DX dzielimy przez milion mov [t1 + timespec.tv_sec], eax ; EAX = liczba sekund mov ebx, 1000 mov eax, edx ; EAX = pozostała liczba mikrosekund mul ebx mov [t1 + timespec.tv_nsec], eax ; EAX = liczba nanosekund mov eax, sys_nanosleep ; funkcja numer 162 mov ebx, t1 mov ecx, t2 int 80h pop edx pop ecx pop ebx ret section .data stare_diody dd 0 konsola db "/dev/console",0 ; Struktura timespec jest zdefiniowana w pliku n_system.inc ;struc timespec ; .tv_sec: resd 1 ; .tv_nsec: resd 1 ;endstruc t1 istruc timespec t2 istruc timespec
Dalsze eksperymenty pozostawiam czytelnikom. Pamiętajcie, że istnieje aż 8 różnych kombinacji stanów diód i można przecież robić różne odstępy czasowe między zmianą stanu.
Miłej zabawy.