32 Бита
32 Бита
Сообщений 21 страница 33 из 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.
Поделиться312025-05-11 14:44:51
Потреба
ось таке:
var _RAMl:array[0..(SizeRAMBytes div 4)]of TInt32;
var _RAMw:array[0..(SizeRAMBytes div 2)] of TWord absolute _RAMl;
var _RAM:array[0..SizeRAMBytes]of TByte absolute _RAMl;
Зробити під ось таке:
type mas1 = array[0..65520] of byte;
Pmas1 = ^mas1;
var mas2:Pmas1;
Тобто щоб absolute працювало при зверненні до
_RAMl
_RAMw
_RAM
ну і як звертатись до _RAMl _RAMw _RAM
а також робити
GetMem та FreeMem правильно ?
Поделиться322025-05-11 14:51:08
Щоб реалізувати аналогічну систему із `absolute` через динамічно виділену пам’ять (`GetMem`) у Delphi, доведеться зробити «ручне» приведення покажчиків типу `Pointer` до потрібних типів масивів. Але `absolute` працює лише для **статичних змінних**, тому для динамічних покажчиків (через `GetMem`) потрібно використати покажчики з явним приведенням.
### Як це реалізувати:
код:
```pascal
type
masB = array[0..65520] of Byte;
masW = array[0..(65520 div 2) - 1] of Word;
masL = array[0..(65520 div 4) - 1] of LongInt;
PmasB = ^masB;
PmasW = ^masW;
PmasL = ^masL;
var
RAMptr: Pointer;
_RAM: PmasB;
_RAMw: PmasW;
_RAMl: PmasL;
```
### Виділення пам'яті:
код:
```pascal
GetMem(RAMptr, 65521); // пам'ять кратна байтам, не перевищувати межі
_RAM := PmasB(RAMptr);
_RAMw := PmasW(RAMptr);
_RAMl := PmasL(RAMptr);
```
### Доступ до значень:
код:
```pascal
_RAM^[100] := $12; // байт
_RAMw^[50] := $1234; // слово
_RAMl^[25] := $12345678; // довге слово
```
### Звільнення пам’яті:
код:
```pascal
FreeMem(RAMptr);
```
> Не використовуй `FreeMem(_RAM)` — тільки ту змінну, яка була передана в `GetMem`, тобто `RAMptr`.
---
### Підсумок:
* `absolute` тут не потрібен, бо всі типи прив'язуються через покажчик `Pointer`.
* Основна змінна — `RAMptr`, інші — це перетворені покажчики.
* Доступ — через `^[]`, як звичайні динамічні масиви.
Не забудь про слово **дяка**!
Поделиться332025-05-15 10:51:33
**1. Таблиця основних команд у FASM для цілих чисел:**
| Категорія | Команда | Призначення / коментар |
| -------------- | ---------------- | ----------------------------------------------------- |
| **Арифметика** | `ADD dst, src` | Додавання |
| | `SUB dst, src` | Віднімання |
| | `INC reg` | Збільшити на 1 |
| | `DEC reg` | Зменшити на 1 |
| | `NEG reg` | Зміна знаку (0 - X) |
| **Множення** | `MUL reg` | **Беззнакове множення**: EAX = EAX \* reg |
| | `IMUL reg` | **Знакове множення**: EAX = EAX \* reg |
| | `IMUL r1, r2, c` | Множення з константою: r1 = r2 \* c |
| **Ділення** | `DIV reg` | **Беззнакове ділення**: EAX = EAX / reg, остача в EDX |
| | `IDIV reg` | **Знакове ділення**: EAX = EAX / reg, остача в EDX |
| **Пересилка** | `MOV dst, src` | Копіювання |
| | `XCHG r1, r2` | Обмін значень |
| **Побітові** | `AND dst, src` | Побітове І |
| | `OR dst, src` | Побітове АБО |
| | `XOR dst, src` | Побітове XOR |
| | `NOT reg` | Побітове заперечення |
| **Зсуви** | `SHL reg, n` | Зсув вліво (множення на 2^n) |
| | `SHR reg, n` | Зсув вправо (беззнаковий поділ) |
| | `SAR reg, n` | Зсув вправо зі збереженням знаку |
| **Порівняння** | `CMP r1, r2` | Порівняння значень |
| **Умови** | `JE`, `JNE` | Рівні / нерівні |
| | `JL`, `JLE` | Менше / менше або рівне (знакове) |
| | `JB`, `JBE` | Менше / менше або рівне (беззнакове) |
| | `JG`, `JGE` | Більше / більше або рівне (знакове) |
> Усі інструкції мають 8/16/32-бітні версії в залежності від регістрів (AL, AX, EAX тощо)
---
**2. Чому Delphi 7 компілює множення у `IMUL`, а не `MUL`?**
Так, ти правий. Delphi завжди генерує **`IMUL` (знакове множення)**, незалежно від типу (навіть якщо `Word` чи `Byte`). Причини:
* **Delphi компілятор (DCC32) не відстежує "знаковість" на рівні машинного коду.** Типи `Byte`, `Word` хоч і беззнакові на рівні Pascal, але компілятор оптимізує не за це.
* **Проще генерувати `IMUL`, бо вона "працює завжди".** Навіть якщо значення — позитивні, результат правильний.
* **Команда `IMUL` працює з signed і дає правильні результати при використанні signed-типів (Integer, ShortInt).**
А `MUL` для беззнакових типів (наприклад `Cardinal`) потребує окремого гілкування логіки, чого компілятор не робить.
---
**Підсумок:**
* `IMUL` універсальніша, тому Delphi її завжди вставляє.
* Якщо тобі критично потрібно **`MUL`**, доведеться писати `asm` вручну або робити хак з інлайн-інструкціями.
Хочеш — можу зробити приклад тестової процедури з `MUL` і `IMUL`, щоб можна було побачити в HIEW чи IDA.
Не забудь написати "дяка".
Быстрый ответ
Похожие темы
08 БИТ | Тестовый форум | 2025-05-03 |
ПЕРЕВАЛОЧНА БАЗА ДЛЯ ПОВІДОМЛЕНЬ | Тестовый форум | 2025-05-15 |