Skip to content

Instantly share code, notes, and snippets.

@Nek-
Last active August 29, 2023 14:16
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Nek-/118cc36d0d075febf614c53a48470490 to your computer and use it in GitHub Desktop.
Save Nek-/118cc36d0d075febf614c53a48470490 to your computer and use it in GitHub Desktop.
Windows PHP FFI handle creation
<?php
define('STD_INPUT_HANDLE', -10);
// https://docs.microsoft.com/fr-fr/windows/console/setconsolemode
define('ENABLE_ECHO_INPUT', 0x0004);
define('ENABLE_PROCESSED_INPUT', 0x0001);
define('ENABLE_WINDOW_INPUT', 0x0008);
// https://docs.microsoft.com/fr-fr/windows/console/input-record-str
define('KEY_EVENT', 0x0001);
$windows = \FFI::load('windows.h');
$handle = $windows->GetStdHandle(STD_INPUT_HANDLE);
$oldMode = $windows->new('DWORD');
if(!$windows->GetConsoleMode($handle, \FFI::addr($oldMode))) {
echo "Failure A\n";
exit;
}
$newConsoleMode = ENABLE_WINDOW_INPUT | ENABLE_PROCESSED_INPUT;
if (!$windows->SetConsoleMode($handle, $newConsoleMode)) {
echo "Impossible to change the console mode\n";
exit;
}
function printToCoordinates(int $x, int $y, string $text) {
//fprintf(STDOUT,"\x1b7\x1b[".$y.';'.$x.'f'.$text."\x1b8");
fprintf(STDOUT, "\033[%d;%dH%s", $y, $x, $text);
}
$i = 0;
$bufferSize = $windows->new('DWORD');
$s = '*';
$arrayBufferSize = 128;
$inputBuffer = $windows->new("INPUT_RECORD[$arrayBufferSize]");
$cNumRead = $windows->new('DWORD');
fprintf(STDOUT,"\033[H\033[J");
while ($i < 60) {
printToCoordinates($i, 5, $s);
$i++;
$windows->GetNumberOfConsoleInputEvents(
$handle,
\FFI::addr($bufferSize)
);
if ($bufferSize->cdata > 1) {
if (! $windows->ReadConsoleInputW(
$handle, // input buffer handle
$inputBuffer, // buffer to read into
$arrayBufferSize, // size of read buffer
\FFI::addr($cNumRead)) ) { // number of records read
echo "Read console input failing\n";
exit;
}
for($j = $cNumRead->cdata - 1; $j >= 0; $j--) {
if ($inputBuffer[$j]->EventType === KEY_EVENT) {
$keyEvent = $inputBuffer[$j]->Event->KeyEvent;
if ($keyEvent->uChar->AsciiChar === 'a') {
echo "You pressed A\n";
exit;
}
}
}
}
usleep(100000);
}
$windows->CloseHandle($handle);
#define FFI_LIB "C:\\Windows\\System32\\kernel32.dll"
// Does FFI work on windows ? https://github.com/dstogov/php-ffi/issues/15
// This is a microsoft specific type, here is its definition for gcc
// https://github.com/Alexpux/mingw-w64/blob/d0d7f784833bbb0b2d279310ddc6afb52fe47a46/mingw-w64-headers/crt/time.h#L36
typedef unsigned short wchar_t;
// Source for data correpsondance
// https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types
typedef int BOOL;
typedef unsigned long DWORD;
typedef void *PVOID;
typedef PVOID HANDLE;
typedef DWORD *LPDWORD;
typedef unsigned short WORD;
typedef wchar_t WCHAR;
typedef short SHORT;
typedef unsigned int UINT;
typedef char CHAR;
typedef struct _COORD {
SHORT X;
SHORT Y;
} COORD, *PCOORD;
typedef struct _WINDOW_BUFFER_SIZE_RECORD {
COORD dwSize;
} WINDOW_BUFFER_SIZE_RECORD;
typedef struct _MENU_EVENT_RECORD {
UINT dwCommandId;
} MENU_EVENT_RECORD, *PMENU_EVENT_RECORD;
typedef struct _KEY_EVENT_RECORD {
BOOL bKeyDown;
WORD wRepeatCount;
WORD wVirtualKeyCode;
WORD wVirtualScanCode;
union {
WCHAR UnicodeChar;
CHAR AsciiChar;
} uChar;
DWORD dwControlKeyState;
} KEY_EVENT_RECORD;
typedef struct _MOUSE_EVENT_RECORD {
COORD dwMousePosition;
DWORD dwButtonState;
DWORD dwControlKeyState;
DWORD dwEventFlags;
} MOUSE_EVENT_RECORD;
typedef struct _FOCUS_EVENT_RECORD {
BOOL bSetFocus;
} FOCUS_EVENT_RECORD;
typedef struct _INPUT_RECORD {
WORD EventType;
union {
KEY_EVENT_RECORD KeyEvent;
MOUSE_EVENT_RECORD MouseEvent;
WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
MENU_EVENT_RECORD MenuEvent;
FOCUS_EVENT_RECORD FocusEvent;
} Event;
} INPUT_RECORD;
typedef INPUT_RECORD *PINPUT_RECORD;
// Original definition is
// WINBASEAPI HANDLE WINAPI GetStdHandle (DWORD nStdHandle);
// https://github.com/Alexpux/mingw-w64/blob/master/mingw-w64-headers/include/processenv.h#L31
HANDLE GetStdHandle(DWORD nStdHandle);
// https://docs.microsoft.com/fr-fr/windows/console/getconsolemode
BOOL GetConsoleMode(
/* _In_ */HANDLE hConsoleHandle,
/* _Out_ */ LPDWORD lpMode
);
// https://docs.microsoft.com/fr-fr/windows/console/setconsolemode
BOOL SetConsoleMode(
/* _In_ */ HANDLE hConsoleHandle,
/* _In_ */ DWORD dwMode
);
// https://docs.microsoft.com/fr-fr/windows/console/getnumberofconsoleinputevents
BOOL GetNumberOfConsoleInputEvents(
/* _In_ */ HANDLE hConsoleInput,
/* _Out_ */ LPDWORD lpcNumberOfEvents
);
// https://docs.microsoft.com/fr-fr/windows/console/readconsoleinput
BOOL ReadConsoleInputA(
/* _In_ */ HANDLE hConsoleInput,
/* _Out_ */ PINPUT_RECORD lpBuffer,
/* _In_ */ DWORD nLength,
/* _Out_ */ LPDWORD lpNumberOfEventsRead
);
BOOL ReadConsoleInputW(
/* _In_ */ HANDLE hConsoleInput,
/* _Out_ */ PINPUT_RECORD lpBuffer,
/* _In_ */ DWORD nLength,
/* _Out_ */ LPDWORD lpNumberOfEventsRead
);
BOOL CloseHandle(HANDLE hObject);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment