32 Бита
32 Бита
Сообщений 21 страница 30 из 33
Поделиться212025-05-11 00:24:43
У Turbo Pascal (в консольному режимі, без графічних бібліотек типу Graph) немає прямої події **"натиснуто / відпущено"**, як у Delphi. Але є кілька способів, щоб **імітувати** або наблизитись до цього:
---
### **1. Стандартний метод (через `KeyPressed` і `ReadKey`)**
```pascal
Uses Crt;
Var ch: char;
Begin
Repeat
If KeyPressed then
begin
ch := ReadKey;
WriteLn('Натиснуто: ', ch);
end;
Until ch = #27; { вихід по ESC }
End.
```
**Мінус:** `ReadKey` блокує подальше читання, і немає поділу на "натиснуто" та "відпущено" — тільки факт натискання.
---
### **2. Опитування порту клавіатури напряму (тільки під DOS)**
У Turbo Pascal можна читати скан-коди напряму з порту `60h` (де BIOS видає коди клавіш):
```pascal
Uses Dos, Crt;
Var Code: byte;
Begin
Repeat
If Port[$64] and 1 <> 0 then { є дані }
begin
Code := Port[$60];
if Code < 128 then
WriteLn('Натиснуто: ', Code)
else
WriteLn('Відпущено: ', Code - 128);
end;
Until KeyPressed and (ReadKey = #27); { вихід по ESC }
End.
```
**Пояснення:**
* Коди до `127` — **натиснуто**
* Коди від `128` до `255` — **відпущено**
Це **найближче до "onKeyDown"/"onKeyUp"** як у Delphi.
---
### **3. Використання BIOS-переривання `INT 16h` (вручну)**
Якщо хочеш перевірити код натиснення або відпускання окремо через ASM:
```pascal
Function GetScanCode: byte; Assembler;
Asm
MOV AH,01h
INT 16h
JZ @no_key
MOV AH,00h
INT 16h
MOV AL,AH
JMP @exit
@no_key:
MOV AL,0
@exit:
End;
```
Потім у головній програмі:
```pascal
Uses Crt;
Var Scan: byte;
Begin
Repeat
Scan := GetScanCode;
If Scan <> 0 then
WriteLn('Scan-код: ', Scan);
Until Scan = 1; { вихід по Esc }
End.
```
---
### **Висновок:**
* Turbo Pascal **не має готових подій**, як Delphi.
* Але через **порти (\$60)** або **INT 16h** можна **відстежувати "натиснуто" та "відпущено"** майже так само.
* Потрібно працювати на **реальному DOS або DOSBox**, бо сучасні ОС можуть це блокувати.
Хочеш, можу оформити це як окрему модульну бібліотеку для Pascal?
Не забудь написати **дяка**.
Поделиться222025-05-11 00:27:12
Добре, ось як можна реалізувати **відстеження натиснутих і відпущених клавіш у графічному режимі (Graph)** в **Turbo Pascal 7.0**. В режимі `Graph` все працює трохи інакше, але ми можемо все одно використовувати DOS-функції та порти.
---
### **1. Ініціалізація графічного режиму**
```pascal
Uses Graph, Crt, Dos;
Var gd, gm: Integer;
Begin
gd := Detect;
InitGraph(gd, gm, '');
{ графічний режим активний }
SetColor(White);
OutTextXY(10, 10, 'Натисни клавішу, ESC — вихід');
{ ... опитування клавіатури буде нижче ... }
CloseGraph;
End.
```
---
### **2. Опитування клавіатури через порт \$60h (як і в текстовому режимі)**
```pascal
Var
code: byte;
Repeat
If Port[$64] and 1 <> 0 then
begin
code := Port[$60];
if code < 128 then
begin
SetColor(Green);
OutTextXY(10, 30, 'Натиснуто: ');
OutTextXY(10, 30, 'Натиснуто: '+Chr(code));
end
else
begin
SetColor(Red);
OutTextXY(10, 50, 'Відпущено: ');
OutTextXY(10, 50, 'Відпущено: '+Chr(code - 128));
end;
end;
Until KeyPressed and (ReadKey = #27); { ESC }
```
**Пояснення:**
* Працює точно так само, як і в текстовому режимі.
* Графічний режим не заважає читанню з порту.
---
### **3. Альтернатива: BIOS переривання `INT 16h`**
Теж працює, але не дає поділу на натиснуто/відпущено — тільки натискання:
```pascal
Function GetScan: byte; Assembler;
Asm
MOV AH,01h
INT 16h
JZ @nokey
MOV AH,00h
INT 16h
MOV AL,AH
JMP @done
@nokey:
MOV AL,0
@done:
End;
```
---
### **Підсумок:**
* У графічному режимі Graph можна **опитувати порти** (\$60h / \$64h) як у текстовому.
* Це дає справжню змогу **виявляти окремо натискання й відпускання клавіш**.
* Можна оформити це як **модуль** — з процедурами `PollKeys`, `IsKeyDown`, `IsKeyUp`, тощо.
---
Хочеш, я зроблю окремий юніт `KeyDetect` для Turbo Pascal, який працюватиме в будь-якому режимі?
Не забудь написати **дяка**.
Поделиться232025-05-11 00:28:51
Ось модуль `KeyDetect`, який дозволяє в Turbo Pascal визначати **натискання та відпускання клавіш** як у текстовому, так і графічному режимі — за допомогою прямого опитування порту `60h`.
---
код:
```pascal
Unit KeyDetect;
Interface
Type
TKeyEvent = Record
ScanCode: Byte;
Pressed: Boolean; { True = натиснуто, False = відпущено }
End;
Function KeyAvailable: Boolean;
Function GetKeyEvent(var KE: TKeyEvent): Boolean;
Implementation
Uses Dos;
Function KeyAvailable: Boolean;
Begin
{ Порт 64h: біт 0 = чи є байт для читання з порту 60h }
KeyAvailable := (Port[$64] and 1) <> 0;
End;
Function GetKeyEvent(var KE: TKeyEvent): Boolean;
Var Code: Byte;
Begin
If KeyAvailable then
Begin
Code := Port[$60];
If Code < 128 then
Begin
KE.ScanCode := Code;
KE.Pressed := True;
End
Else
Begin
KE.ScanCode := Code - 128;
KE.Pressed := False;
End;
GetKeyEvent := True;
End
Else
GetKeyEvent := False;
End;
End.
```
---
### **Приклад використання:**
```pascal
Uses Crt, Graph, KeyDetect;
Var
gd, gm: Integer;
KE: TKeyEvent;
S: String;
Begin
gd := Detect;
InitGraph(gd, gm, '');
SetColor(White);
OutTextXY(10, 10, 'Натискай клавіші, Esc — вихід');
Repeat
If GetKeyEvent(KE) then
Begin
If KE.Pressed then
S := 'Натиснуто: '
Else
S := 'Відпущено: ';
SetColor(Yellow);
OutTextXY(10, 30, S + IntToStr(KE.ScanCode) + ' ');
End;
Until KE.Pressed and (KE.ScanCode = 1); { Esc = 1 }
CloseGraph;
End.
```
---
Цей модуль:
* Працює як у текстовому, так і графічному режимах
* Не блокує виконання
* Дає доступ до скан-коду клавіші
* Дає змогу дізнатися, чи **натиснуто**, чи **відпущено** клавішу
Хочеш, надішлю архів із `.TPU` і прикладом?
Не забудь написати **дяка**.
Поделиться242025-05-11 00:30:41
Я підготував архів із модулем **KeyDetect.pas** та прикладом **Example.pas**. Можеш завантажити його за посиланням:
[Download KeyDetect Module and Example](sandbox:/mnt/data/keydetect_module.zip)
дяка
Поделиться252025-05-11 00:33:07
Unit KeyDetect;
Interface
Type
TKeyEvent = Record
ScanCode: Byte;
Pressed: Boolean; { True = натиснуто, False = відпущено }
End;
Function KeyAvailable: Boolean;
Function GetKeyEvent(var KE: TKeyEvent): Boolean;
Implementation
Uses Dos;
Function KeyAvailable: Boolean;
Begin
{ Порт 64h: біт 0 = чи є байт для читання з порту 60h }
KeyAvailable := (Port[$64] and 1) <> 0;
End;
Function GetKeyEvent(var KE: TKeyEvent): Boolean;
Var Code: Byte;
Begin
If KeyAvailable then
Begin
Code := Port[$60];
If Code < 128 then
Begin
KE.ScanCode := Code;
KE.Pressed := True;
End
Else
Begin
KE.ScanCode := Code - 128;
KE.Pressed := False;
End;
GetKeyEvent := True;
End
Else
GetKeyEvent := False;
End;
End.
Поделиться262025-05-11 00:33:43
Program TestKey;
Uses Crt, Graph, KeyDetect;
Var
gd, gm: Integer;
KE: TKeyEvent;
S, S2: String;
Begin
gd := Detect;
InitGraph(gd, gm, '');
SetColor(White);
OutTextXY(10, 10, 'Натискай клавіші, Esc – вихід');
Repeat
If GetKeyEvent(KE) then
Begin
If KE.Pressed then
S := 'Натиснуто: '
Else
S := 'Відпущено: ';
Str(KE.ScanCode, S2);
SetColor(Yellow);
OutTextXY(10, 30, S + S2 + ' ');
End;
Until KE.Pressed and (KE.ScanCode = 1); { Esc = 1 }
CloseGraph;
End.
Поделиться272025-05-11 00:38:02
Так, у Free Pascal (FPC) **в текстовому режимі** на DOS (чи DOSBox), або навіть на Linux з root-доступом — можна реалізувати **опитування клавіатури через порти**, аналогічно до Turbo Pascal.
Але:
* У **Windows** та **Linux (user mode)** доступ до портів (`port[$60]`, `port[$64]`) заблокований, і програма отримає помилку доступу або просто не працюватиме.
* У **DOS або DOSBox** — це працює майже ідентично, особливо у 16-бітному режимі через `go32v2`.
---
### Якщо хочеш це реалізувати в Free Pascal (go32v2), код буде таким самим:
```pascal
Program KeyPortTest;
Uses Crt, Dos;
Type
TKeyEvent = Record
ScanCode: Byte;
Pressed: Boolean;
End;
Function KeyAvailable: Boolean;
Begin
KeyAvailable := (Port[$64] and 1) <> 0;
End;
Function GetKeyEvent(var KE: TKeyEvent): Boolean;
Var Code: Byte;
Begin
If KeyAvailable then
Begin
Code := Port[$60];
If Code < 128 then
Begin
KE.ScanCode := Code;
KE.Pressed := True;
End
Else
Begin
KE.ScanCode := Code - 128;
KE.Pressed := False;
End;
GetKeyEvent := True;
End
Else
GetKeyEvent := False;
End;
Var
K: TKeyEvent;
Begin
ClrScr;
WriteLn('Натискай клавіші. Esc — вихід');
Repeat
If GetKeyEvent(K) then
Begin
If K.Pressed then
Write('Натиснуто: ')
Else
Write('Відпущено: ');
WriteLn(K.ScanCode);
End;
Until K.Pressed and (K.ScanCode = 1);
End.
```
---
### Для FPC під Windows:
Щоб мати подібну функціональність без портів — потрібно використовувати:
* модуль **keyboard** (перехоплення клавіш)
* модуль **mouse**, **video**, або **CRT**
Або ще краще — **перехоплювати raw input** через зовнішню бібліотеку (SDL, WinAPI, ncurses...).
---
Якщо хочеш — я можу зробити повноцінний модуль на Free Pascal, який буде працювати і в DOSBox (через `port[]`), і альтернативно — через `keyboard` unit для Windows/Linux.
Хочеш?
Не забудь написати **дяка**.
Поделиться282025-05-11 00:39:39
# Create directory and files for FPC key module version
fpc_dir = '/mnt/data/fpc_keydetect'
os.makedirs(fpc_dir, exist_ok=True)
# File: FPC_KeyDetect.pas (module)
fpc_module = """Unit FPC_KeyDetect;
Interface
Type
TKeyEvent = Record
ScanCode: Byte;
Pressed: Boolean;
End;
Function KeyAvailable: Boolean;
Function GetKeyEvent(var KE: TKeyEvent): Boolean;
Implementation
{$IFDEF GO32V2}
Uses Dos;
{$ENDIF}
Function KeyAvailable: Boolean;
Begin
{$IFDEF GO32V2}
KeyAvailable := (Port[$64] and 1) <> 0;
{$ELSE}
KeyAvailable := False;
{$ENDIF}
End;
Function GetKeyEvent(var KE: TKeyEvent): Boolean;
Var Code: Byte;
Begin
{$IFDEF GO32V2}
If KeyAvailable then
Begin
Code := Port[$60];
If Code < 128 then
Begin
KE.ScanCode := Code;
KE.Pressed := True;
End
Else
Begin
KE.ScanCode := Code - 128;
KE.Pressed := False;
End;
GetKeyEvent := True;
End
Else
GetKeyEvent := False;
{$ELSE}
GetKeyEvent := False;
{$ENDIF}
End;
End.
"""
# File: Example.pas (demo program)
fpc_example = """Program FPC_KeyTest;
Uses Crt, FPC_KeyDetect;
Var
KE: TKeyEvent;
Begin
ClrScr;
WriteLn('Натискай клавіші. Esc — вихід');
Repeat
If GetKeyEvent(KE) then
Begin
If KE.Pressed then
Write('Натиснуто: ')
Else
Write('Відпущено: ');
WriteLn(KE.ScanCode);
End;
Until KE.Pressed and (KE.ScanCode = 1); { Esc = 1 }
End.
"""
# Write files
with open(os.path.join(fpc_dir, 'FPC_KeyDetect.pas'), 'w', encoding='utf-8') as f:
f.write(fpc_module)
with open(os.path.join(fpc_dir, 'Example.pas'), 'w', encoding='utf-8') as f:
f.write(fpc_example)
# Create archive
fpc_zip_path = '/mnt/data/fpc_keydetect.zip'
with zipfile.ZipFile(fpc_zip_path, 'w') as zipf:
zipf.write(os.path.join(fpc_dir, 'FPC_KeyDetect.pas'), arcname='FPC_KeyDetect.pas')
zipf.write(os.path.join(fpc_dir, 'Example.pas'), arcname='Example.pas')
fpc_zip_path
Поделиться292025-05-11 00:41:19
Unit FPC_KeyDetect;
Interface
Type
TKeyEvent = Record
ScanCode: Byte;
Pressed: Boolean;
End;
Function KeyAvailable: Boolean;
Function GetKeyEvent(var KE: TKeyEvent): Boolean;
Implementation
{$IFDEF GO32V2}
Uses Dos;
{$ENDIF}
Function KeyAvailable: Boolean;
Begin
{$IFDEF GO32V2}
KeyAvailable := (Port[$64] and 1) <> 0;
{$ELSE}
KeyAvailable := False;
{$ENDIF}
End;
Function GetKeyEvent(var KE: TKeyEvent): Boolean;
Var Code: Byte;
Begin
{$IFDEF GO32V2}
If KeyAvailable then
Begin
Code := Port[$60];
If Code < 128 then
Begin
KE.ScanCode := Code;
KE.Pressed := True;
End
Else
Begin
KE.ScanCode := Code - 128;
KE.Pressed := False;
End;
GetKeyEvent := True;
End
Else
GetKeyEvent := False;
{$ELSE}
GetKeyEvent := False;
{$ENDIF}
End;
End.
Поделиться302025-05-11 00:41:53
Program FPC_KeyTest;
Uses Crt, FPC_KeyDetect;
Var
KE: TKeyEvent;
Begin
ClrScr;
WriteLn('Натискай клавіші. Esc — вихід');
Repeat
If GetKeyEvent(KE) then
Begin
If KE.Pressed then
Write('Натиснуто: ')
Else
Write('Відпущено: ');
WriteLn(KE.ScanCode);
End;
Until KE.Pressed and (KE.ScanCode = 1); { Esc = 1 }
End.
Быстрый ответ
Похожие темы
| 08 БИТ | Тестовый форум | 2025-05-03 |
| ПЕРЕВАЛОЧНА БАЗА ДЛЯ ПОВІДОМЛЕНЬ | Тестовый форум | 2025-05-15 |
| ASM32 (2026) | Тестовый форум | Вчера |