1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/plugins/test/mochitest/dialog_watcher.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,184 @@ 1.4 +const EVENT_OBJECT_SHOW = 0x8002; 1.5 +const EVENT_OBJECT_HIDE = 0x8003; 1.6 +const WINEVENT_OUTOFCONTEXT = 0; 1.7 +const WINEVENT_SKIPOWNPROCESS = 2; 1.8 +const QS_ALLINPUT = 0x04FF; 1.9 +const INFINITE = 0xFFFFFFFF; 1.10 +const WAIT_OBJECT_0 = 0; 1.11 +const WAIT_TIMEOUT = 258; 1.12 +const PM_NOREMOVE = 0; 1.13 + 1.14 +function DialogWatcher(titleText, onDialogStart, onDialogEnd) { 1.15 + this.titleText = titleText; 1.16 + this.onDialogStart = onDialogStart; 1.17 + this.onDialogEnd = onDialogEnd; 1.18 +} 1.19 + 1.20 +DialogWatcher.prototype.init = function() { 1.21 + this.hwnd = undefined; 1.22 + if (!this.user32) { 1.23 + this.user32 = ctypes.open("user32.dll"); 1.24 + } 1.25 + if (!this.findWindow) { 1.26 + this.findWindow = user32.declare("FindWindowW", 1.27 + ctypes.winapi_abi, 1.28 + ctypes.uintptr_t, 1.29 + ctypes.jschar.ptr, 1.30 + ctypes.jschar.ptr); 1.31 + } 1.32 + if (!this.winEventProcType) { 1.33 + this.winEventProcType = ctypes.FunctionType(ctypes.stdcall_abi, 1.34 + ctypes.void_t, 1.35 + [ctypes.uintptr_t, 1.36 + ctypes.uint32_t, 1.37 + ctypes.uintptr_t, 1.38 + ctypes.long, 1.39 + ctypes.long, 1.40 + ctypes.uint32_t, 1.41 + ctypes.uint32_t]).ptr; 1.42 + } 1.43 + if (!this.setWinEventHook) { 1.44 + this.setWinEventHook = user32.declare("SetWinEventHook", 1.45 + ctypes.winapi_abi, 1.46 + ctypes.uintptr_t, 1.47 + ctypes.uint32_t, 1.48 + ctypes.uint32_t, 1.49 + ctypes.uintptr_t, 1.50 + this.winEventProcType, 1.51 + ctypes.uint32_t, 1.52 + ctypes.uint32_t, 1.53 + ctypes.uint32_t); 1.54 + } 1.55 + if (!this.unhookWinEvent) { 1.56 + this.unhookWinEvent = user32.declare("UnhookWinEvent", 1.57 + ctypes.winapi_abi, 1.58 + ctypes.int, 1.59 + ctypes.uintptr_t); 1.60 + } 1.61 + if (!this.pointType) { 1.62 + this.pointType = ctypes.StructType("tagPOINT", 1.63 + [ { "x": ctypes.long }, 1.64 + { "y": ctypes.long } ] ); 1.65 + } 1.66 + if (!this.msgType) { 1.67 + this.msgType = ctypes.StructType("tagMSG", 1.68 + [ { "hwnd": ctypes.uintptr_t }, 1.69 + { "message": ctypes.uint32_t }, 1.70 + { "wParam": ctypes.uintptr_t }, 1.71 + { "lParam": ctypes.intptr_t }, 1.72 + { "time": ctypes.uint32_t }, 1.73 + { "pt": this.pointType } ] ); 1.74 + } 1.75 + if (!this.peekMessage) { 1.76 + this.peekMessage = user32.declare("PeekMessageW", 1.77 + ctypes.winapi_abi, 1.78 + ctypes.int, 1.79 + this.msgType.ptr, 1.80 + ctypes.uintptr_t, 1.81 + ctypes.uint32_t, 1.82 + ctypes.uint32_t, 1.83 + ctypes.uint32_t); 1.84 + } 1.85 + if (!this.msgWaitForMultipleObjects) { 1.86 + this.msgWaitForMultipleObjects = user32.declare("MsgWaitForMultipleObjects", 1.87 + ctypes.winapi_abi, 1.88 + ctypes.uint32_t, 1.89 + ctypes.uint32_t, 1.90 + ctypes.uintptr_t.ptr, 1.91 + ctypes.int, 1.92 + ctypes.uint32_t, 1.93 + ctypes.uint32_t); 1.94 + } 1.95 + if (!this.getWindowTextW) { 1.96 + this.getWindowTextW = user32.declare("GetWindowTextW", 1.97 + ctypes.winapi_abi, 1.98 + ctypes.int, 1.99 + ctypes.uintptr_t, 1.100 + ctypes.jschar.ptr, 1.101 + ctypes.int); 1.102 + } 1.103 + if (!this.messageBox) { 1.104 + // Handy for debugging this code 1.105 + this.messageBox = user32.declare("MessageBoxW", 1.106 + ctypes.winapi_abi, 1.107 + ctypes.int, 1.108 + ctypes.uintptr_t, 1.109 + ctypes.jschar.ptr, 1.110 + ctypes.jschar.ptr, 1.111 + ctypes.uint32_t); 1.112 + } 1.113 +}; 1.114 + 1.115 +DialogWatcher.prototype.getWindowText = function(hwnd) { 1.116 + var bufType = ctypes.ArrayType(ctypes.jschar); 1.117 + var buffer = new bufType(256); 1.118 + 1.119 + if (this.getWindowTextW(hwnd, buffer, buffer.length)) { 1.120 + return buffer.readString(); 1.121 + } 1.122 +}; 1.123 + 1.124 +DialogWatcher.prototype.processWindowEvents = function(timeout) { 1.125 + var onWinEvent = function(self, hook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime) { 1.126 + var nhwnd = Number(hwnd) 1.127 + if (event == EVENT_OBJECT_SHOW) { 1.128 + if (nhwnd == self.hwnd) { 1.129 + // We've already picked up this event via FindWindow 1.130 + return; 1.131 + } 1.132 + var windowText = self.getWindowText(hwnd); 1.133 + if (windowText == self.titleText && self.onDialogStart) { 1.134 + self.hwnd = nhwnd; 1.135 + self.onDialogStart(nhwnd); 1.136 + } 1.137 + } else if (event == EVENT_OBJECT_HIDE && nhwnd == self.hwnd && self.onDialogEnd) { 1.138 + self.onDialogEnd(); 1.139 + self.hwnd = null; 1.140 + } 1.141 + }; 1.142 + var self = this; 1.143 + var callback = this.winEventProcType(function(hook, event, hwnd, idObject, 1.144 + idChild, dwEventThread, 1.145 + dwmsEventTime) { 1.146 + onWinEvent(self, hook, event, hwnd, idObject, idChild, dwEventThread, 1.147 + dwmsEventTime); 1.148 + } ); 1.149 + var hook = this.setWinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE, 1.150 + 0, callback, 0, 0, 1.151 + WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); 1.152 + if (!hook) { 1.153 + return; 1.154 + } 1.155 + // Check if the window is already showing 1.156 + var hwnd = this.findWindow(null, this.titleText); 1.157 + if (hwnd && hwnd > 0) { 1.158 + this.hwnd = Number(hwnd); 1.159 + if (this.onDialogStart) { 1.160 + this.onDialogStart(this.hwnd); 1.161 + } 1.162 + } 1.163 + 1.164 + if (!timeout) { 1.165 + timeout = INFINITE; 1.166 + } 1.167 + 1.168 + var waitStatus = WAIT_OBJECT_0; 1.169 + var expectingStart = this.onDialogStart && this.hwnd === undefined; 1.170 + var startWaitTime = Date.now(); 1.171 + while (this.hwnd === undefined || this.onDialogEnd && this.hwnd) { 1.172 + waitStatus = this.msgWaitForMultipleObjects(0, null, 0, expectingStart ? 1.173 + INFINITE : timeout, 0); 1.174 + if (waitStatus == WAIT_OBJECT_0) { 1.175 + var msg = new this.msgType; 1.176 + this.peekMessage(msg.address(), 0, 0, 0, PM_NOREMOVE); 1.177 + } 1.178 + if (waitStatus == WAIT_TIMEOUT || (Date.now() - startWaitTime) >= timeout) { 1.179 + break; 1.180 + } 1.181 + } 1.182 + 1.183 + this.unhookWinEvent(hook); 1.184 + // Returns true if the hook was successful, something was found, and we never timed out 1.185 + return this.hwnd !== undefined && waitStatus == WAIT_OBJECT_0; 1.186 +}; 1.187 +