@mcesystems/usb-device-listener 1.0.94 → 1.0.96

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,15 +1,15 @@
1
- ISC License
2
-
3
- Copyright (c) 2025 MCE Systems
4
-
5
- Permission to use, copy, modify, and/or distribute this software for any
6
- purpose with or without fee is hereby granted, provided that the above
7
- copyright notice and this permission notice appear in all copies.
8
-
9
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1
+ ISC License
2
+
3
+ Copyright (c) 2025 MCE Systems
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/binding.gyp CHANGED
@@ -1,67 +1,67 @@
1
- {
2
- "targets": [
3
- {
4
- "target_name": "usb_device_listener",
5
- "sources": [
6
- "native/addon.cc"
7
- ],
8
- "include_dirs": [
9
- "<!@(node -p \"require('node-addon-api').include\")"
10
- ],
11
- "dependencies": [
12
- "<!(node -p \"require('node-addon-api').gyp\")"
13
- ],
14
- "defines": [
15
- "NAPI_DISABLE_CPP_EXCEPTIONS"
16
- ],
17
- "conditions": [
18
- [
19
- "OS=='win'",
20
- {
21
- "sources": [
22
- "native/usb_listener_win.cc"
23
- ],
24
- "defines": [
25
- "UNICODE",
26
- "_UNICODE"
27
- ],
28
- "libraries": [
29
- "Setupapi.lib",
30
- "Cfgmgr32.lib"
31
- ],
32
- "msvs_settings": {
33
- "VCCLCompilerTool": {
34
- "ExceptionHandling": 1,
35
- "AdditionalOptions": [
36
- "/std:c++20"
37
- ]
38
- }
39
- }
40
- }
41
- ],
42
- [
43
- "OS=='mac'",
44
- {
45
- "sources": [
46
- "native/usb_listener_mac.cc"
47
- ],
48
- "xcode_settings": {
49
- "GCC_ENABLE_CPP_EXCEPTIONS": "YES",
50
- "CLANG_CXX_LANGUAGE_STANDARD": "c++20",
51
- "MACOSX_DEPLOYMENT_TARGET": "10.15",
52
- "OTHER_CFLAGS": [
53
- "-fno-strict-aliasing"
54
- ]
55
- },
56
- "link_settings": {
57
- "libraries": [
58
- "-framework CoreFoundation",
59
- "-framework IOKit"
60
- ]
61
- }
62
- }
63
- ]
64
- ]
65
- }
66
- ]
67
- }
1
+ {
2
+ "targets": [
3
+ {
4
+ "target_name": "usb_device_listener",
5
+ "sources": [
6
+ "native/addon.cc"
7
+ ],
8
+ "include_dirs": [
9
+ "<!@(node -p \"require('node-addon-api').include\")"
10
+ ],
11
+ "dependencies": [
12
+ "<!(node -p \"require('node-addon-api').gyp\")"
13
+ ],
14
+ "defines": [
15
+ "NAPI_DISABLE_CPP_EXCEPTIONS"
16
+ ],
17
+ "conditions": [
18
+ [
19
+ "OS=='win'",
20
+ {
21
+ "sources": [
22
+ "native/usb_listener_win.cc"
23
+ ],
24
+ "defines": [
25
+ "UNICODE",
26
+ "_UNICODE"
27
+ ],
28
+ "libraries": [
29
+ "Setupapi.lib",
30
+ "Cfgmgr32.lib"
31
+ ],
32
+ "msvs_settings": {
33
+ "VCCLCompilerTool": {
34
+ "ExceptionHandling": 1,
35
+ "AdditionalOptions": [
36
+ "/std:c++20"
37
+ ]
38
+ }
39
+ }
40
+ }
41
+ ],
42
+ [
43
+ "OS=='mac'",
44
+ {
45
+ "sources": [
46
+ "native/usb_listener_mac.cc"
47
+ ],
48
+ "xcode_settings": {
49
+ "GCC_ENABLE_CPP_EXCEPTIONS": "YES",
50
+ "CLANG_CXX_LANGUAGE_STANDARD": "c++20",
51
+ "MACOSX_DEPLOYMENT_TARGET": "10.15",
52
+ "OTHER_CFLAGS": [
53
+ "-fno-strict-aliasing"
54
+ ]
55
+ },
56
+ "link_settings": {
57
+ "libraries": [
58
+ "-framework CoreFoundation",
59
+ "-framework IOKit"
60
+ ]
61
+ }
62
+ }
63
+ ]
64
+ ]
65
+ }
66
+ ]
67
+ }
package/native/addon.cc CHANGED
@@ -1,129 +1,129 @@
1
- #include <napi.h>
2
- #include "usb_listener.h"
3
- #include <memory>
4
-
5
- static std::unique_ptr<USBListener> g_listener;
6
-
7
- Napi::Value StartListening(const Napi::CallbackInfo& info) {
8
- Napi::Env env = info.Env();
9
-
10
- if (!g_listener) {
11
- g_listener = std::make_unique<USBListener>();
12
- }
13
-
14
- std::string errorMsg;
15
- if (!g_listener->StartListening(errorMsg)) {
16
- Napi::Error::New(env, errorMsg).ThrowAsJavaScriptException();
17
- return env.Undefined();
18
- }
19
-
20
- return env.Undefined();
21
- }
22
-
23
- Napi::Value StopListening(const Napi::CallbackInfo& info) {
24
- Napi::Env env = info.Env();
25
-
26
- if (g_listener) {
27
- g_listener->StopListening();
28
- }
29
-
30
- return env.Undefined();
31
- }
32
-
33
- Napi::Value OnDeviceAdd(const Napi::CallbackInfo& info) {
34
- Napi::Env env = info.Env();
35
-
36
- if (info.Length() < 1 || !info[0].IsFunction()) {
37
- Napi::TypeError::New(env, "Callback function expected").ThrowAsJavaScriptException();
38
- return env.Undefined();
39
- }
40
-
41
- Napi::Function callback = info[0].As<Napi::Function>();
42
-
43
- if (!g_listener) {
44
- g_listener = std::make_unique<USBListener>();
45
- }
46
-
47
- Napi::ThreadSafeFunction tsfn = Napi::ThreadSafeFunction::New(
48
- env,
49
- callback,
50
- "DeviceAddCallback",
51
- 0,
52
- 1
53
- );
54
-
55
- g_listener->SetAddCallback(tsfn);
56
-
57
- return env.Undefined();
58
- }
59
-
60
- Napi::Value OnDeviceRemove(const Napi::CallbackInfo& info) {
61
- Napi::Env env = info.Env();
62
-
63
- if (info.Length() < 1 || !info[0].IsFunction()) {
64
- Napi::TypeError::New(env, "Callback function expected").ThrowAsJavaScriptException();
65
- return env.Undefined();
66
- }
67
-
68
- Napi::Function callback = info[0].As<Napi::Function>();
69
-
70
- if (!g_listener) {
71
- g_listener = std::make_unique<USBListener>();
72
- }
73
-
74
- Napi::ThreadSafeFunction tsfn = Napi::ThreadSafeFunction::New(
75
- env,
76
- callback,
77
- "DeviceRemoveCallback",
78
- 0,
79
- 1
80
- );
81
-
82
- g_listener->SetRemoveCallback(tsfn);
83
-
84
- return env.Undefined();
85
- }
86
-
87
- Napi::Value ListDevices(const Napi::CallbackInfo& info) {
88
- Napi::Env env = info.Env();
89
-
90
- if (!g_listener) {
91
- g_listener = std::make_unique<USBListener>();
92
- }
93
-
94
- std::vector<DeviceInfo> devices = g_listener->ListAllDevices();
95
-
96
- Napi::Array result = Napi::Array::New(env, devices.size());
97
- for (size_t i = 0; i < devices.size(); i++) {
98
- const DeviceInfo& d = devices[i];
99
- Napi::Object obj = Napi::Object::New(env);
100
- obj.Set("deviceId", Napi::String::New(env, d.deviceId));
101
- obj.Set("serialNumber", Napi::String::New(env, d.serialNumber));
102
- obj.Set("deviceName", Napi::String::New(env, d.deviceName));
103
- obj.Set("vid", Napi::Number::New(env, d.vid));
104
- obj.Set("pid", Napi::Number::New(env, d.pid));
105
- obj.Set("locationInfo", Napi::String::New(env, d.locationInfo));
106
- obj.Set("logicalPort", env.Null());
107
- Napi::Array pathArr = Napi::Array::New(env, d.portPath.size());
108
- for (size_t j = 0; j < d.portPath.size(); j++) {
109
- pathArr[j] = Napi::Number::New(env, d.portPath[j]);
110
- }
111
- obj.Set("portPath", pathArr);
112
- obj.Set("parentHubVid", Napi::Number::New(env, d.parentHubVid));
113
- obj.Set("parentHubPid", Napi::Number::New(env, d.parentHubPid));
114
- result[i] = obj;
115
- }
116
-
117
- return result;
118
- }
119
-
120
- Napi::Object Init(Napi::Env env, Napi::Object exports) {
121
- exports.Set("startListening", Napi::Function::New(env, StartListening));
122
- exports.Set("stopListening", Napi::Function::New(env, StopListening));
123
- exports.Set("onDeviceAdd", Napi::Function::New(env, OnDeviceAdd));
124
- exports.Set("onDeviceRemove", Napi::Function::New(env, OnDeviceRemove));
125
- exports.Set("listDevices", Napi::Function::New(env, ListDevices));
126
- return exports;
127
- }
128
-
129
- NODE_API_MODULE(usb_device_listener, Init)
1
+ #include <napi.h>
2
+ #include "usb_listener.h"
3
+ #include <memory>
4
+
5
+ static std::unique_ptr<USBListener> g_listener;
6
+
7
+ Napi::Value StartListening(const Napi::CallbackInfo& info) {
8
+ Napi::Env env = info.Env();
9
+
10
+ if (!g_listener) {
11
+ g_listener = std::make_unique<USBListener>();
12
+ }
13
+
14
+ std::string errorMsg;
15
+ if (!g_listener->StartListening(errorMsg)) {
16
+ Napi::Error::New(env, errorMsg).ThrowAsJavaScriptException();
17
+ return env.Undefined();
18
+ }
19
+
20
+ return env.Undefined();
21
+ }
22
+
23
+ Napi::Value StopListening(const Napi::CallbackInfo& info) {
24
+ Napi::Env env = info.Env();
25
+
26
+ if (g_listener) {
27
+ g_listener->StopListening();
28
+ }
29
+
30
+ return env.Undefined();
31
+ }
32
+
33
+ Napi::Value OnDeviceAdd(const Napi::CallbackInfo& info) {
34
+ Napi::Env env = info.Env();
35
+
36
+ if (info.Length() < 1 || !info[0].IsFunction()) {
37
+ Napi::TypeError::New(env, "Callback function expected").ThrowAsJavaScriptException();
38
+ return env.Undefined();
39
+ }
40
+
41
+ Napi::Function callback = info[0].As<Napi::Function>();
42
+
43
+ if (!g_listener) {
44
+ g_listener = std::make_unique<USBListener>();
45
+ }
46
+
47
+ Napi::ThreadSafeFunction tsfn = Napi::ThreadSafeFunction::New(
48
+ env,
49
+ callback,
50
+ "DeviceAddCallback",
51
+ 0,
52
+ 1
53
+ );
54
+
55
+ g_listener->SetAddCallback(tsfn);
56
+
57
+ return env.Undefined();
58
+ }
59
+
60
+ Napi::Value OnDeviceRemove(const Napi::CallbackInfo& info) {
61
+ Napi::Env env = info.Env();
62
+
63
+ if (info.Length() < 1 || !info[0].IsFunction()) {
64
+ Napi::TypeError::New(env, "Callback function expected").ThrowAsJavaScriptException();
65
+ return env.Undefined();
66
+ }
67
+
68
+ Napi::Function callback = info[0].As<Napi::Function>();
69
+
70
+ if (!g_listener) {
71
+ g_listener = std::make_unique<USBListener>();
72
+ }
73
+
74
+ Napi::ThreadSafeFunction tsfn = Napi::ThreadSafeFunction::New(
75
+ env,
76
+ callback,
77
+ "DeviceRemoveCallback",
78
+ 0,
79
+ 1
80
+ );
81
+
82
+ g_listener->SetRemoveCallback(tsfn);
83
+
84
+ return env.Undefined();
85
+ }
86
+
87
+ Napi::Value ListDevices(const Napi::CallbackInfo& info) {
88
+ Napi::Env env = info.Env();
89
+
90
+ if (!g_listener) {
91
+ g_listener = std::make_unique<USBListener>();
92
+ }
93
+
94
+ std::vector<DeviceInfo> devices = g_listener->ListAllDevices();
95
+
96
+ Napi::Array result = Napi::Array::New(env, devices.size());
97
+ for (size_t i = 0; i < devices.size(); i++) {
98
+ const DeviceInfo& d = devices[i];
99
+ Napi::Object obj = Napi::Object::New(env);
100
+ obj.Set("deviceId", Napi::String::New(env, d.deviceId));
101
+ obj.Set("serialNumber", Napi::String::New(env, d.serialNumber));
102
+ obj.Set("deviceName", Napi::String::New(env, d.deviceName));
103
+ obj.Set("vid", Napi::Number::New(env, d.vid));
104
+ obj.Set("pid", Napi::Number::New(env, d.pid));
105
+ obj.Set("locationInfo", Napi::String::New(env, d.locationInfo));
106
+ obj.Set("logicalPort", env.Null());
107
+ Napi::Array pathArr = Napi::Array::New(env, d.portPath.size());
108
+ for (size_t j = 0; j < d.portPath.size(); j++) {
109
+ pathArr[j] = Napi::Number::New(env, d.portPath[j]);
110
+ }
111
+ obj.Set("portPath", pathArr);
112
+ obj.Set("parentHubVid", Napi::Number::New(env, d.parentHubVid));
113
+ obj.Set("parentHubPid", Napi::Number::New(env, d.parentHubPid));
114
+ result[i] = obj;
115
+ }
116
+
117
+ return result;
118
+ }
119
+
120
+ Napi::Object Init(Napi::Env env, Napi::Object exports) {
121
+ exports.Set("startListening", Napi::Function::New(env, StartListening));
122
+ exports.Set("stopListening", Napi::Function::New(env, StopListening));
123
+ exports.Set("onDeviceAdd", Napi::Function::New(env, OnDeviceAdd));
124
+ exports.Set("onDeviceRemove", Napi::Function::New(env, OnDeviceRemove));
125
+ exports.Set("listDevices", Napi::Function::New(env, ListDevices));
126
+ return exports;
127
+ }
128
+
129
+ NODE_API_MODULE(usb_device_listener, Init)
@@ -1,22 +1,22 @@
1
- #ifndef USB_LISTENER_H
2
- #define USB_LISTENER_H
3
-
4
- /**
5
- * Platform-specific USB Listener
6
- *
7
- * This header includes the appropriate platform-specific implementation
8
- * based on the target OS. Both implementations expose the same USBListener class
9
- * that inherits from USBListenerBase.
10
- */
11
-
12
- #include "usb_listener_common.h"
13
-
14
- #if defined(_WIN32) || defined(_WIN64)
15
- #include "usb_listener_win.h"
16
- #elif defined(__APPLE__)
17
- #include "usb_listener_mac.h"
18
- #else
19
- #error "Unsupported platform. Only Windows and macOS are supported."
20
- #endif
21
-
22
- #endif // USB_LISTENER_H
1
+ #ifndef USB_LISTENER_H
2
+ #define USB_LISTENER_H
3
+
4
+ /**
5
+ * Platform-specific USB Listener
6
+ *
7
+ * This header includes the appropriate platform-specific implementation
8
+ * based on the target OS. Both implementations expose the same USBListener class
9
+ * that inherits from USBListenerBase.
10
+ */
11
+
12
+ #include "usb_listener_common.h"
13
+
14
+ #if defined(_WIN32) || defined(_WIN64)
15
+ #include "usb_listener_win.h"
16
+ #elif defined(__APPLE__)
17
+ #include "usb_listener_mac.h"
18
+ #else
19
+ #error "Unsupported platform. Only Windows and macOS are supported."
20
+ #endif
21
+
22
+ #endif // USB_LISTENER_H
@@ -1,56 +1,56 @@
1
- #ifndef USB_LISTENER_COMMON_H
2
- #define USB_LISTENER_COMMON_H
3
-
4
- #include <napi.h>
5
- #include <string>
6
- #include <vector>
7
- #include <unordered_map>
8
- #include <atomic>
9
- #include <shared_mutex>
10
-
11
- /**
12
- * Device information structure
13
- * Contains all relevant USB device identification and location data
14
- * Platform-agnostic: used by both Windows and macOS implementations
15
- */
16
- struct DeviceInfo {
17
- std::string deviceId; // Device ID (serial number if available, otherwise platform-specific)
18
- std::string serialNumber; // USB serial number (raw, without formatting)
19
- std::string deviceName; // USB product name / device description
20
- uint16_t vid{0}; // Vendor ID
21
- uint16_t pid{0}; // Product ID
22
- std::string locationInfo; // Physical port location (platform-specific format)
23
- int logicalPort{-1}; // User-defined logical port number (-1 if not mapped)
24
- std::vector<int> portPath; // Port numbers from root to device (e.g. [2, 3, 1])
25
- uint16_t parentHubVid{0}; // VID of hub device is directly connected to (0 if on root)
26
- uint16_t parentHubPid{0}; // PID of that hub
27
- };
28
-
29
- /**
30
- * Abstract USB Device Listener Interface
31
- *
32
- * Defines the common interface for platform-specific implementations.
33
- * Each platform (Windows, macOS) provides its own implementation.
34
- */
35
- class USBListenerBase {
36
- public:
37
- virtual ~USBListenerBase() = default;
38
-
39
- // Start monitoring USB device events
40
- virtual bool StartListening(std::string& errorMsg) = 0;
41
-
42
- // Stop monitoring and clean up resources
43
- virtual void StopListening() = 0;
44
-
45
- // Set callback for device connection events
46
- virtual void SetAddCallback(Napi::ThreadSafeFunction callback) = 0;
47
-
48
- // Set callback for device disconnection events
49
- virtual void SetRemoveCallback(Napi::ThreadSafeFunction callback) = 0;
50
-
51
- // Get list of all currently connected USB devices
52
- virtual std::vector<DeviceInfo> ListAllDevices() = 0;
53
- };
54
-
55
- #endif // USB_LISTENER_COMMON_H
56
-
1
+ #ifndef USB_LISTENER_COMMON_H
2
+ #define USB_LISTENER_COMMON_H
3
+
4
+ #include <napi.h>
5
+ #include <string>
6
+ #include <vector>
7
+ #include <unordered_map>
8
+ #include <atomic>
9
+ #include <shared_mutex>
10
+
11
+ /**
12
+ * Device information structure
13
+ * Contains all relevant USB device identification and location data
14
+ * Platform-agnostic: used by both Windows and macOS implementations
15
+ */
16
+ struct DeviceInfo {
17
+ std::string deviceId; // Device ID (serial number if available, otherwise platform-specific)
18
+ std::string serialNumber; // USB serial number (raw, without formatting)
19
+ std::string deviceName; // USB product name / device description
20
+ uint16_t vid{0}; // Vendor ID
21
+ uint16_t pid{0}; // Product ID
22
+ std::string locationInfo; // Physical port location (platform-specific format)
23
+ int logicalPort{-1}; // User-defined logical port number (-1 if not mapped)
24
+ std::vector<int> portPath; // Port numbers from root to device (e.g. [2, 3, 1])
25
+ uint16_t parentHubVid{0}; // VID of hub device is directly connected to (0 if on root)
26
+ uint16_t parentHubPid{0}; // PID of that hub
27
+ };
28
+
29
+ /**
30
+ * Abstract USB Device Listener Interface
31
+ *
32
+ * Defines the common interface for platform-specific implementations.
33
+ * Each platform (Windows, macOS) provides its own implementation.
34
+ */
35
+ class USBListenerBase {
36
+ public:
37
+ virtual ~USBListenerBase() = default;
38
+
39
+ // Start monitoring USB device events
40
+ virtual bool StartListening(std::string& errorMsg) = 0;
41
+
42
+ // Stop monitoring and clean up resources
43
+ virtual void StopListening() = 0;
44
+
45
+ // Set callback for device connection events
46
+ virtual void SetAddCallback(Napi::ThreadSafeFunction callback) = 0;
47
+
48
+ // Set callback for device disconnection events
49
+ virtual void SetRemoveCallback(Napi::ThreadSafeFunction callback) = 0;
50
+
51
+ // Get list of all currently connected USB devices
52
+ virtual std::vector<DeviceInfo> ListAllDevices() = 0;
53
+ };
54
+
55
+ #endif // USB_LISTENER_COMMON_H
56
+