-
-
Save Noitidart/b7cbb80622241c249961 to your computer and use it in GitHub Desktop.
Cu.import('resource://gre/modules/ctypes.jsm'); | |
var lib = { | |
user32: ctypes.open('user32.dll') | |
} | |
var NULL = ctypes.cast(ctypes.uint64_t(0x0), ctypes.voidptr_t); | |
/* http://msdn.microsoft.com/en-us/library/ms633514%28VS.85%29.aspx | |
* HWND WINAPI GetTopWindow( | |
* __in_opt_ HWND hWnd | |
* ); | |
*/ | |
var GetTopWindow = lib.user32.declare('GetTopWindow', ctypes.winapi_abi, ctypes.voidptr_t, | |
ctypes.voidptr_t | |
); | |
/* http://msdn.microsoft.com/en-us/library/ms633515%28v=vs.85%29.aspx | |
* I was trying to use GetNextWindow however that is not available through DLL, but that just calls GetWindow so am using GetWindow with GW_HWNDNEXT instead | |
* HWND WINAPI GetWindow( | |
* __in_ HWND hWnd, | |
* __in_ UINT wCmd | |
* ); | |
*/ | |
var GetWindow = lib.user32.declare('GetWindow', ctypes.winapi_abi, ctypes.voidptr_t, | |
ctypes.voidptr_t, | |
ctypes.unsigned_int | |
); | |
var GW_HWNDNEXT = 2; | |
/* http://msdn.microsoft.com/en-us/library/ms633515%28v=vs.85%29.aspx | |
* LONG_PTR WINAPI GetWindowLongPtr( | |
* __in_ HWND hWnd, | |
* __in_ int nIndex | |
* ); | |
*/ | |
if (ctypes.voidptr_t.size == 4 /* 32-bit */) { | |
var GetWindowLong = lib.user32.declare('GetWindowLongW', ctypes.winapi_abi, ctypes.unsigned_long, | |
ctypes.voidptr_t, | |
ctypes.int | |
); | |
} else if (ctypes.voidptr_t.size == 8 /* 64-bit */) { | |
var GetWindowLong = lib.user32.declare('GetWindowLongPtrW', ctypes.winapi_abi, ctypes.unsigned_long.ptr, | |
ctypes.voidptr_t, | |
ctypes.int | |
); | |
} | |
var GWL_STYLE = -16; | |
var WS_VISIBLE = 0x10000000; | |
var WS_CAPTION = 0x00C00000; | |
var styleIsInAltTab = WS_VISIBLE | WS_CAPTION; | |
var GetClassName = lib.user32.declare('GetClassNameW', ctypes.winapi_abi, ctypes.int, | |
ctypes.voidptr_t, // HWND | |
ctypes.jschar.ptr, // LPTSTR | |
ctypes.int | |
); | |
/* http://msdn.microsoft.com/en-us/library/windows/desktop/ms633522%28v=vs.85%29.aspx | |
* DWORD WINAPI GetWindowThreadProcessId( | |
* __in_ HWND hWnd, | |
* __out_opt_ LPDWORD lpdwProcessId | |
* ); | |
*/ | |
var GetWindowThreadProcessId = lib.user32.declare('GetWindowThreadProcessId', ctypes.winapi_abi, ctypes.unsigned_long, //DWORD | |
ctypes.voidptr_t, //ctypes.uint32_t, //HWND | |
ctypes.uint32_t.ptr //LPDWORD | |
); | |
/* http://msdn.microsoft.com/en-us/library/ms633539%28v=vs.85%29.aspx | |
* BOOL WINAPI SetForegroundWindow( | |
* __in HWND hWnd | |
* ); | |
*/ | |
var SetForegroundWindow = lib.user32.declare('SetForegroundWindow', ctypes.winapi_abi, ctypes.bool, | |
ctypes.voidptr_t // HWND | |
); | |
/* http://msdn.microsoft.com/en-us/library/windows/desktop/ms633507%28v=vs.85%29.aspx | |
* BOOL WINAPI IsIconic( | |
* __in HWND hWnd | |
* ); | |
*/ | |
var IsIconic = lib.user32.declare('IsIconic', ctypes.winapi_abi, ctypes.bool, // BOOL | |
ctypes.voidptr_t // HWND | |
); | |
/* http://msdn.microsoft.com/en-us/library/windows/desktop/ms633507%28v=vs.85%29.aspx | |
* BOOL WINAPI ShowWindow( | |
* __in HWND hWnd | |
* __in INT nCmdShow | |
* ); | |
*/ | |
var ShowWindow = lib.user32.declare('ShowWindow', ctypes.winapi_abi, ctypes.bool, // BOOL | |
ctypes.voidptr_t, // HWND | |
ctypes.int // INT | |
); | |
var SW_RESTORE = 9; | |
function winFocusWindow(hwnd) { | |
if (IsIconic(hwnd)) { | |
console.warn('its minimized so un-minimize it'); | |
//its minimized so unminimize it | |
var rez = ShowWindow(hwnd, SW_RESTORE); | |
if (!rez) { | |
throw new Error('Failed to un-minimize window'); | |
} | |
} | |
var rez = SetForegroundWindow(hwnd); | |
if (!rez) { | |
console.log('could not set to foreground window for a reason other than minimized, maybe process is not foreground, lets try that now'); | |
/* | |
var cPid = ctypes.cast(ctypes.voidptr_t(0), ctypes.unsigned_long); | |
var rez = GetWindowThreadProcessId(hwnd, cPid.address()); | |
if (!rez) { | |
throw new Error('Failed to get PID'); | |
} else { | |
console.log('trying to set pid to foreground process'); | |
return false; | |
} | |
*/ | |
} else { | |
return rez; | |
} | |
} | |
var hwndC = GetTopWindow(null); | |
var hwndStyle; | |
var i = 0; | |
var buf; | |
var PID = new ctypes.uint32_t; | |
var skipThisMany = 3; | |
var skipped = 0; | |
while (hwndC != NULL) { | |
//console.log('i:', i); | |
hwndC = GetWindow(hwndC, GW_HWNDNEXT); | |
var rez_GWTPI = GetWindowThreadProcessId(hwndC, PID.address()); | |
//console.log(i, 'rez_GWTPI:', rez_GWTPI.toString(), 'pid:', PID.value); | |
if (rez_GWTPI > 0 && PID.value == 4764) { | |
//console.log('pid found:', PID.value); | |
hwndStyle = GetWindowLong(hwndC, GWL_STYLE); | |
if ('contents' in hwndStyle) { | |
hwndStyle = hwndStyle.contents; //handles 64 bit //untested but im pretty sure (99%) it will get the uint64 like it is for 32bit | |
} | |
//console.log('hwndStyle', hwndStyle.toString()); | |
if (hwndStyle & WS_VISIBLE) { | |
var rez_WFW = winFocusWindow(hwndC); | |
console.log('rez_WFW:', rez_WFW); | |
if (!rez_WFW) { | |
throw new Error('failed to focus most recent window'); | |
} | |
break; | |
} | |
} | |
/* | |
buf = new new ctypes.ArrayType(ctypes.jschar, 255); | |
GetClassName(hwndC, buf, 255); | |
var className = buf.readString(); | |
hwndStyle = GetWindowLong(hwndC, GWL_STYLE); | |
if (className == 'MozillaWindowClass') { | |
var rez = GetWindowThreadProcessId(hwndC, PID.address()); | |
console.log(PID.value); | |
if (PID.value == 4764) { | |
if (skipped == skipThisMany) { | |
var rez_SFW = SetForegroundWindow(hwndC); | |
console.log('rez_SFW:', rez_SFW); | |
break; | |
} else { | |
console.log('SKIPPING ', skipped); | |
skipped++; | |
} | |
} | |
}; | |
*/ | |
i++; | |
if (i >= 3000) { | |
console.warn('breaking because went through too many windows, i:', i); | |
throw new Error('could not find most recent window of this pid') | |
break; | |
} | |
} | |
console.log('hwndC:', hwndC); | |
for (var l in lib) { | |
lib[l].close(); | |
} |
behavior research:
win81:
- works as expected, it focuses the most recently used window EVEN IF minmized
win7 and winxp:
learned that when minimized it has WS_ICONIC and WS_MINIMIZED flags while still having the WS_CAPTION and WS_VISIBLE flags
-
focused browser, minimized, so last focus was browser. scratch is currently non-minimized. test result :: clicked focus most rec win profilist : it focuses scratch, and the hwnd of browser does not occur before the hwnd of scratch (i was hoping it would occur before scratch but would have WS_MINIMIZED-or-something and just be missing WS_VISIBLE or something)
//hwnds 0x240de4 //scratch 0x110e30 //browser
-
if all windows minimized: it focuses the window that was FIRST minimized
- this one i can fix by seeing if the first hwnd found with WS_VISIBLE and WS_CAPTION has minimized flags, if it does then keep going till it finds the last WS_VISIBLE and WS_CAPTION one (im pretty sure all the ones after it will have the minimized flags, really very sure as it looks like when minimize it gets thrown to end [right in alt+tab menu] of array (unlike when focus non-minimized it gets moved to top of array [left in alt tab]))
i posted this on stackoverflow:
This is analysis on differetn Windows versions of the code by @CoryNelson (huge thanks to him for the help)
behavior research via physical testing:
NOTE learned that when minimized hwnd
has WS_ICONIC
and WS_MINIMIZED
flags while still having the WS_CAPTION
and WS_VISIBLE
flags
win81:
- works as expected, it focuses the most recently used window EVEN IF minmized
win7 and winxp:
-
focused browser, minimized, so last focus was browser. scratch is currently non-minimized. test result :: clicked focus most rec win profilist : it focuses scratch, and the hwnd of browser does not occur before the hwnd of scratch (i was hoping it would occur before scratch but would have WS_MINIMIZED-or-something and just be missing WS_VISIBLE or something)
//hwnds 0x240de4 //scratch 0x110e30 //browser
- FIX: i dont know how to fix this one yet, anyone any ideas other than hooking? ill keep thinking, mainly posting this here for myself, but if anyone wants to apply thoughts more then welcome!!
-
if all windows minimized: it focuses the window that was FIRST minimized
- FIX: this one i can fix by seeing if the first hwnd found with WS_VISIBLE and WS_CAPTION has minimized flags, if it does then keep going till it finds the last WS_VISIBLE and WS_CAPTION one (im pretty sure all the ones after it will have the minimized flags, really very sure as it looks like when minimize it gets thrown to end [right in alt+tab menu] of array (unlike when focus non-minimized it gets moved to top of array [left in alt tab]))
GUESSES as i cant physically test these
win8
- im guessing win8 behaves as win81
winvista
- im guessing winVist behaves as winxp and win7 as its in between
README
Rev1 - Rev1
Forked from _ff-addon-snippet-FocusWindowHwndCTypes.js
Rev2
Rev3
Rev4
null
works in place ofNULL
Rev5