gecko/dom/plugins/test/mochitest/dialog_watcher.js

173 lines
6.9 KiB
JavaScript

const EVENT_OBJECT_SHOW = 0x8002;
const EVENT_OBJECT_HIDE = 0x8003;
const WINEVENT_OUTOFCONTEXT = 0;
const WINEVENT_SKIPOWNPROCESS = 2;
const QS_ALLINPUT = 0x04FF;
const INFINITE = 0xFFFFFFFF;
const WAIT_OBJECT_0 = 0;
const WAIT_TIMEOUT = 258;
const PM_NOREMOVE = 0;
function DialogWatcher(titleText, onDialogStart, onDialogEnd) {
this.titleText = titleText;
this.onDialogStart = onDialogStart;
this.onDialogEnd = onDialogEnd;
}
DialogWatcher.prototype.init = function() {
this.hwnd = undefined;
if (!this.user32) {
this.user32 = ctypes.open("user32.dll");
}
if (!this.findWindow) {
this.findWindow = user32.declare("FindWindowW",
ctypes.winapi_abi,
ctypes.uintptr_t,
ctypes.jschar.ptr,
ctypes.jschar.ptr);
}
if (!this.winEventProcType) {
this.winEventProcType = ctypes.FunctionType(ctypes.stdcall_abi,
ctypes.void_t,
[ctypes.uintptr_t,
ctypes.uint32_t,
ctypes.uintptr_t,
ctypes.long,
ctypes.long,
ctypes.uint32_t,
ctypes.uint32_t]).ptr;
}
if (!this.setWinEventHook) {
this.setWinEventHook = user32.declare("SetWinEventHook",
ctypes.winapi_abi,
ctypes.uintptr_t,
ctypes.uint32_t,
ctypes.uint32_t,
ctypes.uintptr_t,
this.winEventProcType,
ctypes.uint32_t,
ctypes.uint32_t,
ctypes.uint32_t);
}
if (!this.unhookWinEvent) {
this.unhookWinEvent = user32.declare("UnhookWinEvent",
ctypes.winapi_abi,
ctypes.int,
ctypes.uintptr_t);
}
if (!this.pointType) {
this.pointType = ctypes.StructType("tagPOINT",
[ { "x": ctypes.long },
{ "y": ctypes.long } ] );
}
if (!this.msgType) {
this.msgType = ctypes.StructType("tagMSG",
[ { "hwnd": ctypes.uintptr_t },
{ "message": ctypes.uint32_t },
{ "wParam": ctypes.uintptr_t },
{ "lParam": ctypes.intptr_t },
{ "time": ctypes.uint32_t },
{ "pt": this.pointType } ] );
}
if (!this.peekMessage) {
this.peekMessage = user32.declare("PeekMessageW",
ctypes.winapi_abi,
ctypes.int,
this.msgType.ptr,
ctypes.uintptr_t,
ctypes.uint32_t,
ctypes.uint32_t,
ctypes.uint32_t);
}
if (!this.msgWaitForMultipleObjects) {
this.msgWaitForMultipleObjects = user32.declare("MsgWaitForMultipleObjects",
ctypes.winapi_abi,
ctypes.uint32_t,
ctypes.uint32_t,
ctypes.uintptr_t.ptr,
ctypes.int,
ctypes.uint32_t,
ctypes.uint32_t);
}
if (!this.getWindowTextW) {
this.getWindowTextW = user32.declare("GetWindowTextW",
ctypes.winapi_abi,
ctypes.int,
ctypes.uintptr_t,
ctypes.jschar.ptr,
ctypes.int);
}
};
DialogWatcher.prototype.getWindowText = function(hwnd) {
var bufType = ctypes.ArrayType(ctypes.jschar);
var buffer = new bufType(256);
if (this.getWindowTextW(hwnd, buffer, buffer.length)) {
return buffer.readString();
}
};
DialogWatcher.prototype.processWindowEvents = function(timeout) {
var onWinEvent = function(self, hook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime) {
var nhwnd = Number(hwnd)
if (event == EVENT_OBJECT_SHOW) {
if (nhwnd == self.hwnd) {
// We've already picked up this event via FindWindow
return;
}
var windowText = self.getWindowText(hwnd);
if (windowText == self.titleText && self.onDialogStart) {
self.hwnd = nhwnd;
self.onDialogStart(nhwnd);
}
} else if (event == EVENT_OBJECT_HIDE && nhwnd == self.hwnd && self.onDialogEnd) {
self.onDialogEnd();
self.hwnd = null;
}
};
var self = this;
var callback = this.winEventProcType(function(hook, event, hwnd, idObject,
idChild, dwEventThread,
dwmsEventTime) {
onWinEvent(self, hook, event, hwnd, idObject, idChild, dwEventThread,
dwmsEventTime);
} );
var hook = this.setWinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE,
0, callback, 0, 0,
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
if (!hook) {
return;
}
// Check if the window is already showing
var hwnd = this.findWindow(null, this.titleText);
if (hwnd && hwnd > 0) {
this.hwnd = Number(hwnd);
if (this.onDialogStart) {
this.onDialogStart(this.hwnd);
}
}
if (!timeout) {
timeout = INFINITE;
}
var waitStatus = WAIT_OBJECT_0;
var expectingStart = this.onDialogStart && this.hwnd === undefined;
while (this.hwnd === undefined || this.onDialogEnd && this.hwnd) {
waitStatus = this.msgWaitForMultipleObjects(0, null, 0, expectingStart ?
INFINITE : timeout, 0);
if (waitStatus == WAIT_OBJECT_0) {
var msg = new this.msgType;
this.peekMessage(msg.address(), 0, 0, 0, PM_NOREMOVE);
} else if (waitStatus == WAIT_TIMEOUT) {
break;
}
}
this.unhookWinEvent(hook);
// Returns true if the hook was successful, something was found, and we never timed out
return this.hwnd !== undefined && waitStatus == WAIT_OBJECT_0;
};