Files
wine-access/tests/scintilla_fixture.c

141 lines
6.0 KiB
C

// SPDX-License-Identifier: LGPL-2.1-or-later
// Drive an actual Notepad++ instance in the runner's disposable Wine prefix.
#include <windows.h>
#include "../scintilla_messages.h"
static DWORD editorPid;
static HWND editor, owner;
static BOOL CALLBACK find_editor(HWND window, LPARAM unused) {
(void)unused;
WCHAR name[64];
if (IsWindowVisible(window) && GetClassNameW(window, name, 64) &&
!lstrcmpW(name, L"Scintilla")) {
editor = window;
return FALSE;
}
return TRUE;
}
static BOOL CALLBACK find_owner(HWND window, LPARAM unused) {
(void)unused;
DWORD pid;
GetWindowThreadProcessId(window, &pid);
if (pid == editorPid && IsWindowVisible(window)) {
EnumChildWindows(window, find_editor, 0);
if (editor) { owner = window; return FALSE; }
}
return TRUE;
}
static void key(WORD vk, BOOL control, BOOL shift) {
INPUT input[6] = {0};
UINT count = 0;
if (control) { input[count].ki.wVk = VK_CONTROL; ++count; }
if (shift) { input[count].ki.wVk = VK_SHIFT; ++count; }
input[count].ki.wVk = vk; ++count;
input[count].ki.wVk = vk; input[count].ki.dwFlags = KEYEVENTF_KEYUP; ++count;
if (shift) { input[count].ki.wVk = VK_SHIFT; input[count].ki.dwFlags = KEYEVENTF_KEYUP; ++count; }
if (control) { input[count].ki.wVk = VK_CONTROL; input[count].ki.dwFlags = KEYEVENTF_KEYUP; ++count; }
for (UINT i = 0; i < count; ++i) input[i].type = INPUT_KEYBOARD;
if (SendInput(count, input, sizeof(INPUT)) != count) ExitProcess(3);
Sleep(200);
}
static void move_to(ptrdiff_t position) {
SendMessageW(editor, SCI_SETSEL, position, position);
Sleep(100);
}
int WINAPI WinMain(HINSTANCE instance, HINSTANCE previous, LPSTR args, int show) {
(void)instance; (void)previous; (void)args; (void)show;
WCHAR executable[2048], document[2048], command[4600];
if (!GetEnvironmentVariableW(L"WINE_ACCESS_NOTEPADPP_EXE", executable, 2048) ||
!GetEnvironmentVariableW(L"WINE_ACCESS_SCINTILLA_DOCUMENT", document, 2048)) return 2;
wsprintfW(command, L"\"%s\" -multiInst -nosession -noPlugin \"%s\"", executable, document);
STARTUPINFOW startup = {0};
PROCESS_INFORMATION process = {0};
startup.cb = sizeof(startup);
if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &process)) return 2;
editorPid = process.dwProcessId;
for (int i = 0; i < 100 && !editor; ++i) { EnumWindows(find_owner, 0); Sleep(50); }
if (!editor || SendMessageW(editor, SCI_GETLENGTH, 0, 0) < 40) return 2;
ptrdiff_t originalLength = SendMessageW(editor, SCI_GETLENGTH, 0, 0);
SetForegroundWindow(owner);
key(VK_HOME, TRUE, FALSE);
WCHAR ready[1024];
if (GetEnvironmentVariableW(L"WINE_ACCESS_FIXTURE_READY", ready, 1024)) {
HANDLE file = CreateFileW(ready, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
if (file == INVALID_HANDLE_VALUE) return 2;
CloseHandle(file);
}
Sleep(1500);
key(VK_RIGHT, FALSE, FALSE); // e
key(VK_RIGHT, FALSE, FALSE); // l
key(VK_RIGHT, FALSE, FALSE); // l
key(VK_RIGHT, TRUE, FALSE); // beta
key(VK_LEFT, TRUE, FALSE); // hello plus trailing space
key(VK_RIGHT, TRUE, FALSE);
key(VK_DOWN, FALSE, FALSE); // Scintilla second line
key(VK_UP, FALSE, FALSE); // hello beta
key(VK_DOWN, FALSE, FALSE);
key(VK_HOME, FALSE, FALSE);
key(VK_RIGHT, FALSE, TRUE); // S selected
key(VK_RIGHT, FALSE, TRUE); // c selected
key(VK_LEFT, FALSE, TRUE); // c unselected
key(VK_LEFT, FALSE, FALSE); // S unselected
key(VK_DELETE, FALSE, FALSE);// S deleted
key(VK_RIGHT, FALSE, FALSE);
key(VK_BACK, FALSE, FALSE); // c (without deleted suffix)
key(VK_MENU, FALSE, FALSE);
key(VK_ESCAPE, FALSE, FALSE);
key(VK_ESCAPE, FALSE, FALSE);// return at "intilla second line"
key('Z', TRUE, FALSE); // undo c
key('Z', TRUE, FALSE); // undo S
key(VK_HOME, FALSE, FALSE);
key(VK_RIGHT, FALSE, FALSE);// c from restored document
SendMessageW(editor, SCI_SETSEL, 12, 21); // Scintilla selected
Sleep(100);
key('X', TRUE, FALSE); // Scintilla deleted
key('Z', TRUE, FALSE);
key(VK_HOME, FALSE, FALSE);
key(VK_DOWN, FALSE, FALSE); // café 😀 tail
ptrdiff_t lineStart = SendMessageW(editor, SCI_POSITIONFROMLINE, 2, 0);
move_to(lineStart + 2);
key(VK_RIGHT, FALSE, FALSE);// é (two UTF-8 bytes)
move_to(lineStart + 6);
key(VK_LEFT, FALSE, FALSE); // space
key(VK_RIGHT, FALSE, FALSE);// 😀 (four UTF-8 bytes)
key(VK_RIGHT, FALSE, TRUE); // 😀 selected
key(VK_LEFT, FALSE, TRUE); // 😀 unselected
key(VK_DELETE, FALSE, FALSE);// 😀 deleted
key('Z', TRUE, FALSE);
move_to(lineStart + 10);
key(VK_BACK, FALSE, FALSE); // 😀
key('Z', TRUE, FALSE);
SendMessageW(editor, 2171 /* SCI_SETREADONLY */, TRUE, 0);
SendMessageW(editor, RegisterWindowMessageW(L"CthulhuWineEditFocus"), 0, 0);
key(VK_DELETE, FALSE, FALSE);// read-only: must leave document unchanged
if (SendMessageW(editor, SCI_GETLENGTH, 0, 0) != originalLength) return 4;
SendMessageW(editor, 2171 /* SCI_SETREADONLY */, FALSE, 0);
move_to(SendMessageW(editor, SCI_POSITIONFROMLINE, 3, 0));
key(VK_END, TRUE, FALSE); // truncate before a surrogate pair in the last line
key(VK_UP, FALSE, FALSE);// very large document line, bounded range read
move_to(0);
LRESULT codePage = SendMessageW(editor, SCI_GETCODEPAGE, 0, 0);
SendMessageW(editor, 2037 /* SCI_SETCODEPAGE */, 0, 0);
SendMessageW(editor, 2066 /* SCI_STYLESETCHARACTERSET */, 32, DEFAULT_CHARSET);
SendMessageW(editor, RegisterWindowMessageW(L"CthulhuWineEditFocus"), 0, 0);
Sleep(100);
SendMessageW(editor, 2066 /* SCI_STYLESETCHARACTERSET */, 32, ANSI_CHARSET);
SendMessageW(editor, RegisterWindowMessageW(L"CthulhuWineEditFocus"), 0, 0);
Sleep(100);
SendMessageW(editor, 2037 /* SCI_SETCODEPAGE */, codePage, 0);
// Mark this disposable document clean to close without a save prompt.
SendMessageW(editor, 2014 /* SCI_SETSAVEPOINT */, 0, 0);
PostMessageW(owner, WM_CLOSE, 0, 0);
int result = WaitForSingleObject(process.hProcess, 3000) == WAIT_OBJECT_0 ? 0 : 2;
CloseHandle(process.hThread); CloseHandle(process.hProcess);
return result;
}