Dalam beberapa kasus, kita mungkin perlu mengatur fokus pada jendela yang tidak sedang di-foreground. Namun, jika proses yang menggilakan fungsi SetForegroundWindow
bukanlah proses yang sedang difokus, maka fungsi tersebut akan gagal melakukan perubahan.
Dalam artikel ini, kita akan menggunakan Ctypes dan API Windows untuk menguak keterbatasan pada SetForegroundWindow
. Kita juga akan menggunakan Ctypes untuk menghubungkan dengan fungsi-fungsi lainnya, seperti SendInput
dan GetCursorPos
.
Menggunakan Ctypes
Ctypes adalah sebuah biblika yang memungkinkan kita untuk mendefinisikan fungsi-fungsi dari bahasa pemrograman lainnya (misalnya C) dalam program JavaScript. Dalam kasus ini, kita akan menggunakan Ctypes untuk menghubungkan dengan API Windows.
Berikut adalah kode Ctypes yang digunakan:
// Define input structure
typedef struct {
DWORD type;
union {
MOUSEINPUT mi;
KEYBDINPUT ki;
HARDWAREINPUT hi;
} input;
} INPUT;
// Declare SendInput function
void SendInput(INT nInputs, INPUT* pInputs, INT dwSize);
// Define mouse event flags
const int MOUSEEVENTF_LEFTDOWN = 2;
const int MOUSEEVENTF_LEFTUP = 4;
const int MOUSEEVENTF_ABSOLUTE = 0x8000;
Menggunakan API Windows
Kita akan menggunakan fungsi SetForegroundWindow
untuk mengatur fokus pada jendela yang diinginkan. Namun, seperti yang disebutkan sebelumnya, fungsi ini hanya berhasil jika proses yang menggilakan fungsi tersebut adalah proses yang sedang difokus.
Sebagai gantinya, kita akan menggunakan fungsi SetWindowPos
untuk mengatur jendela menjadi "always on top". Fungsi ini juga memerlukan parameter HWND_TOP
, yang mewakili handle jendela yang diinginkan.
Berikut adalah kode JavaScript yang digunakan:
// Pick a browser window to focus
var browserWindow = Services.wm.getMostRecentWindow('navigator:browser');
if (!browserWindow) {
throw new Error('No browser window found');
}
// Convert DOM window to HWND
var baseWindow = browserWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIBaseWindow);
var hwndString = baseWindow.nativeHandle;
var hwnd = ctypes.voidptr_t(ctypes.UInt64(hwndString));
// Focus on the window
browserWindow.focus();
// Set window to "always on top"
var rez_SetWindowPos = user32.SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
console.log('rez_SetWindowPos:', rez_SetWindowPos);
// Get window rectangle
var myRect = RECT();
var rez_GetWindowRect = user32.GetWindowRect(hwnd, myRect.address());
console.log('rez_GetWindowRect:', rez_GetWindowRect);
// Move cursor to desired position
var myPoint = POINT();
var rez_GetCursorPos = user32.GetCursorPos(myPoint.address());
console.log('rez_GetCursorPos:', rez_GetCursorPos);
user32.SetCursorPos(myRect.left, myRect.top);
// Simulate mouse click
var js_pInputs = [
INPUT(INPUT_MOUSE, MOUSEINPUT(myRectLeft, myRectTop, 0, MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE, 0, 0)),
INPUT(INPUT_MOUSE, MOUSEINPUT(myRectLeft, myRectTop, 0, MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE, 0, 0))
];
var pInputs = INPUT.array()(js_pInputs);
var rez_SI = user32.SendInput(pInputs.length, pInputs, INPUT.size);
console.log('rez_SI:', rez_SI.toString());
// End of simulation
user32.close();
Kelebihan dan Keterbatasan
Dengan menggunakan Ctypes dan API Windows, kita dapat menguak keterbatasan pada SetForegroundWindow
dan melakukan perubahan fokus pada jendela yang diinginkan. Namun, perlu diingat bahwa fungsi SendInput
hanya berhasil jika proses yang menggilakan fungsi tersebut adalah proses yang sedang difokus.
Dalam kasus tertentu, kita mungkin perlu menggunakan metode lain untuk melakukan perubahan fokus pada jendela. Namun, dengan menggunakan Ctypes dan API Windows, kita dapat mencapai tujuan tersebut dalam beberapa langkah sederhana.