Skip to content

Instantly share code, notes, and snippets.

@Noitidart
Last active August 27, 2015 21:48
Show Gist options
  • Select an option

  • Save Noitidart/5c6ff7a7552277fa52e4 to your computer and use it in GitHub Desktop.

Select an option

Save Noitidart/5c6ff7a7552277fa52e4 to your computer and use it in GitHub Desktop.
_ff-addon-snippet-winapi_setMouseHook - Uses js-ctypes to set a mouse hook. [jsctypes] [winapi]
Cu.import('resource://gre/modules/ctypes.jsm');
var is64bit = ctypes.voidptr_t.size == 4 ? false : true;
var ifdef_UNICODE = true;
var TYPES = {
ABI: is64bit ? ctypes.default_abi : ctypes.winapi_abi,
CALLBACK_ABI: is64bit ? ctypes.default_abi : ctypes.stdcall_abi,
BOOL: ctypes.bool,
CHAR: ctypes.char,
DWORD: ctypes.uint32_t,
INT: ctypes.int,
LONG: ctypes.long,
LONG_PTR: is64bit ? ctypes.int64_t : ctypes.long,
PVOID: ctypes.voidptr_t,
UINT_PTR: is64bit ? ctypes.uint64_t : ctypes.unsigned_int,
ULONG_PTR: is64bit ? ctypes.uint64_t : ctypes.unsigned_long,
};
// advanced types - based on simple types
TYPES.HANDLE = TYPES.PVOID;
TYPES.LPARAM = TYPES.LONG_PTR;
TYPES.LRESULT = TYPES.LONG_PTR;
TYPES.WPARAM = TYPES.UINT_PTR;
// advanced advanced types - based on advanced types
TYPES.HHOOK = TYPES.HANDLE;
TYPES.HINSTANCE = TYPES.HANDLE;
TYPES.HWND = TYPES.HANDLE;
// simple structs
TYPES.POINT = ctypes.StructType('_tagPOINT', [
{ x: TYPES.LONG },
{ y: TYPES.LONG }
]);
TYPES.MSLLHOOKSTRUCT = ctypes.StructType('tagMSLLHOOKSTRUCT', [
{ pt: TYPES.POINT },
{ mouseData: TYPES.DWORD },
{ flags: TYPES.DWORD },
{ time: TYPES.DWORD },
{ dwExtraInfo: TYPES.ULONG_PTR }
]);
// simple callbacks
TYPES.LowLevelMouseProc = ctypes.FunctionType(TYPES.CALLBACK_ABI, TYPES.LRESULT, [TYPES.INT, TYPES.WPARAM, TYPES.LPARAM]);
// guess types
TYPES.HOOKPROC = TYPES.LowLevelMouseProc.ptr; // not a guess really, as this is the hook type i use, so yeah it has to be a pointer to it
var CONST = {
WH_MOUSE_LL: 14
};
var justMouseConsts = {
WM_MOUSEMOVE: 0x200,
WM_LBUTTONDOWN: 0x201,
WM_LBUTTONUP: 0x202,
WM_LBUTTONDBLCLK: 0x203,
WM_RBUTTONDOWN: 0x204,
WM_RBUTTONUP: 0x205,
WM_RBUTTONDBLCLK: 0x206,
WM_MBUTTONDOWN: 0x207,
WM_MBUTTONUP: 0x208,
WM_MBUTTONDBLCLK: 0x209,
WM_MOUSEWHEEL: 0x20A,
WM_XBUTTONDOWN: 0x20B,
WM_XBUTTONUP: 0x20C,
WM_XBUTTONDBLCLK: 0x20D,
WM_MOUSEHWHEEL: 0x20E
}
var user32 = ctypes.open('user32');
var SetWindowsHookEx = user32.declare(ifdef_UNICODE ? 'SetWindowsHookExW' : 'SetWindowsHookExA', TYPES.ABI, TYPES.HHOOK, TYPES.INT, TYPES.HOOKPROC, TYPES.HINSTANCE, TYPES.DWORD);
var UnhookWindowsHookEx = user32.declare('UnhookWindowsHookEx', TYPES.ABI, TYPES.BOOL, TYPES.HHOOK);
var CallNextHookEx = user32.declare('CallNextHookEx', TYPES.ABI, TYPES.LRESULT, TYPES.HHOOK, TYPES.INT, TYPES.WPARAM, TYPES.LPARAM);
try {
var cancelFinally = false;
var myLLMouseHook_js = function(nCode, wParam, lParam) {
var eventType;
for (var p in justMouseConsts) {
if (justMouseConsts[p] == wParam) {
eventType = p;
break;
}
}
var mhs = TYPES.MSLLHOOKSTRUCT.ptr(ctypes.UInt64(lParam));
console.info('myLLMouseHook | ', eventType, 'nCode:', nCode, nCode.toString(), 'wParam:', wParam, wParam.toString(), 'lParam:', lParam, lParam.toString(), 'mhs.contents:', mhs.contents, mhs.contents.toString());
var rez_CallNext = CallNextHookEx(null, nCode, wParam, lParam);
// console.info('rez_CallNext:', rez_CallNext, rez_CallNext.toString());
return rez_CallNext;
};
var myLLMouseHook_c = TYPES.LowLevelMouseProc.ptr(myLLMouseHook_js);
var aHhk = SetWindowsHookEx(CONST.WH_MOUSE_LL, myLLMouseHook_c, null, 0);
console.info('aHhk:', aHhk, aHhk.toString());
if (aHhk.isNull()) {
console.error('failed to set hook, winLastError:', ctypes.winLastError);
throw new Error('failed to set hook');
}
cancelFinally = true; // cancel as i will handle it in the setTimeout
setTimeout(function() {
var rez_Unhook = UnhookWindowsHookEx(aHhk);
console.info('rez_Unhook:', rez_Unhook);
user32.close();
console.log('user32 closed');
}, 5000);
} finally {
if (!cancelFinally) {
user32.close();
console.log('user32 closed');
}
}
@Noitidart
Copy link
Author

README

Rev1

  • Works baby! Took less than half hour to write up after last year of js-ctypes learning goodness! Was stuck on it previously since before November 2012! That's over 3 years ago! No one helped in over 3 years for such a simple piece of code my goodness! I help people on stackoverflow with way more complicated js-ctypes haha feeling soooo cool now.

Rev2

  • Corrected so eventType is logged
  • And added the middle mouse button constants and others that were not there previously, the docs on MSDN were incomplete, a guy in the comments of https://msdn.microsoft.com/en-us/library/ms644986%28v=vs.85%29.aspx detailed all the constants
  • Through trial I found that returning -1 blocks the input, but I need to research on if I should call CallNextHookEx and still return -1 or just return without calling to CallNextHookEx. And I haven't found documented anywhere yet that returning -1 is the proper way to block. Once I find proper way to block then I can write about that here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment