@@ -141,14 +141,14 @@ Napi::Value moveMouseSmoothWrapper(const Napi::CallbackInfo& info)
141141 Napi::Error::New (env, " Invalid number of arguments." ).ThrowAsJavaScriptException ();
142142return env.Null ();
143143 }
144- size_t x = static_cast < size_t >( info[0 ].ToNumber ().Int32Value () );
145- size_t y = static_cast < size_t >( info[1 ].ToNumber ().Int32Value () );
144+ int32_t x = info[0 ].ToNumber ().Int32Value ();
145+ int32_t y = info[1 ].ToNumber ().Int32Value ();
146146
147- MMPoint point;
148- point = MMPointMake (x, y);
147+ MMSignedPoint point;
148+ point = MMSignedPointMake (x, y);
149149 if (info.Length () == 3 )
150150 {
151- size_t speed = static_cast < size_t >( info[2 ].ToNumber ().Int32Value () );
151+ double speed = info[2 ].ToNumber ().DoubleValue ( );
152152 smoothlyMoveMouse (point, speed);
153153 }
154154 else
@@ -785,6 +785,75 @@ static bool parseSizeT(Napi::Env env, Napi::Value value, const char *name, size_
785785 return true ;
786786}
787787
788+ static bool parseInt32 (Napi::Env env, Napi::Value value, const char *name, int32_t *result)
789+ {
790+ if (!value.IsNumber ()) {
791+ Napi::Error::New (env, std::string (name) + " must be a number." )
792+ .ThrowAsJavaScriptException ();
793+ return false ;
794+ }
795+
796+ double number = value.As <Napi::Number>().DoubleValue ();
797+ if (number < static_cast <double >(INT32_MIN ) ||
798+ number > static_cast <double >(INT32_MAX )) {
799+ Napi::Error::New (env, std::string (name) + " is outside the supported range." )
800+ .ThrowAsJavaScriptException ();
801+ return false ;
802+ }
803+
804+ *result = static_cast <int32_t >(number);
805+ return true ;
806+ }
807+
808+ static bool rectFitsOnDisplay (MMDisplay display, int32_t x, int32_t y,
809+ size_t width, size_t height, MMRect *localRect)
810+ {
811+ if (width == 0 || height == 0 ||
812+ width > static_cast <size_t >(INT64_MAX ) ||
813+ height > static_cast <size_t >(INT64_MAX )) {
814+ return false ;
815+ }
816+
817+ const int64_t left = x;
818+ const int64_t top = y;
819+ const int64_t right = left + static_cast <int64_t >(width);
820+ const int64_t bottom = top + static_cast <int64_t >(height);
821+ const int64_t displayLeft = display.x ;
822+ const int64_t displayTop = display.y ;
823+ const int64_t displayRight = displayLeft + static_cast <int64_t >(display.width );
824+ const int64_t displayBottom = displayTop + static_cast <int64_t >(display.height );
825+
826+ if (left < displayLeft || top < displayTop ||
827+ right > displayRight || bottom > displayBottom) {
828+ return false ;
829+ }
830+
831+ if (localRect != NULL ) {
832+ *localRect = MMRectMake (static_cast <size_t >(left - displayLeft),
833+ static_cast <size_t >(top - displayTop),
834+ width,
835+ height);
836+ }
837+
838+ return true ;
839+ }
840+
841+ static bool findDisplayForRect (const MMDisplay *displayList, size_t displayCount,
842+ int32_t x, int32_t y, size_t width, size_t height,
843+ MMDisplay *display, MMRect *localRect)
844+ {
845+ for (size_t index = 0 ; index < displayCount; ++index) {
846+ if (rectFitsOnDisplay (displayList[index], x, y, width, height, localRect)) {
847+ if (display != NULL ) {
848+ *display = displayList[index];
849+ }
850+ return true ;
851+ }
852+ }
853+
854+ return false ;
855+ }
856+
788857static bool parseToleranceOption (Napi::Env env, Napi::Object options, float *tolerance)
789858{
790859 if (!options.Has (" tolerance" )) {
@@ -1132,6 +1201,35 @@ Napi::Value getScreenSizeWrapper(const Napi::CallbackInfo& info)
11321201 return obj;
11331202}
11341203
1204+ Napi::Value getDisplaysWrapper (const Napi::CallbackInfo& info)
1205+ {
1206+ Napi::Env env = info.Env ();
1207+ size_t displayCount = 0 ;
1208+ MMDisplay *displayList = getDisplayList (&displayCount);
1209+
1210+ if (displayList == NULL || displayCount == 0 ) {
1211+ Napi::Error::New (env, " Failed to enumerate active displays." )
1212+ .ThrowAsJavaScriptException ();
1213+ return env.Null ();
1214+ }
1215+
1216+ Napi::Array displays = Napi::Array::New (env, displayCount);
1217+
1218+ for (size_t index = 0 ; index < displayCount; ++index) {
1219+ Napi::Object display = Napi::Object::New (env);
1220+ display.Set (" id" , Napi::Number::New (env, displayList[index].id ));
1221+ display.Set (" x" , Napi::Number::New (env, displayList[index].x ));
1222+ display.Set (" y" , Napi::Number::New (env, displayList[index].y ));
1223+ display.Set (" width" , Napi::Number::New (env, displayList[index].width ));
1224+ display.Set (" height" , Napi::Number::New (env, displayList[index].height ));
1225+ display.Set (" isMain" , Napi::Boolean::New (env, displayList[index].isMain ));
1226+ displays.Set (index, display);
1227+ }
1228+
1229+ destroyDisplayList (displayList);
1230+ return displays;
1231+ }
1232+
11351233Napi::Value getXDisplayNameWrapper (const Napi::CallbackInfo& info)
11361234{
11371235 Napi::Env env = info.Env ();
@@ -1162,24 +1260,26 @@ Napi::Value setXDisplayNameWrapper(const Napi::CallbackInfo& info)
11621260Napi::Value captureScreenWrapper (const Napi::CallbackInfo& info)
11631261{
11641262 Napi::Env env = info.Env ();
1165- size_t x = 0 ;
1166- size_t y = 0 ;
1263+ int32_t x = 0 ;
1264+ int32_t y = 0 ;
11671265 size_t w;
11681266 size_t h;
1169- MMSize displaySize = getMainDisplaySize () ;
1267+ bool hasBounds = false ;
11701268
11711269 // If user has provided screen coords, use them!
11721270 if (info.Length () == 4 )
11731271 {
1174- if (!parseSizeT (env, info[0 ], " x" , &x) ||
1175- !parseSizeT (env, info[1 ], " y" , &y) ||
1272+ hasBounds = true ;
1273+ if (!parseInt32 (env, info[0 ], " x" , &x) ||
1274+ !parseInt32 (env, info[1 ], " y" , &y) ||
11761275 !parseSizeT (env, info[2 ], " width" , &w) ||
11771276 !parseSizeT (env, info[3 ], " height" , &h)) {
11781277 return env.Null ();
11791278 }
11801279 }
11811280 else if (info.Length () == 0 )
11821281 {
1282+ MMSize displaySize = getMainDisplaySize ();
11831283 // We're getting the full screen.
11841284 w = displaySize.width ;
11851285 h = displaySize.height ;
@@ -1190,15 +1290,39 @@ Napi::Value captureScreenWrapper(const Napi::CallbackInfo& info)
11901290 return env.Null ();
11911291 }
11921292
1193- if (w == 0 || h == 0 ||
1194- x > displaySize.width || y > displaySize.height ||
1195- w > displaySize.width - x || h > displaySize.height - y) {
1196- Napi::Error::New (env, " Requested capture rect is outside the main screen's dimensions." )
1293+ if (w == 0 || h == 0 ) {
1294+ Napi::Error::New (env, " Requested capture rect is outside the active displays' dimensions." )
11971295 .ThrowAsJavaScriptException ();
11981296 return env.Null ();
11991297 }
12001298
1201- MMBitmapRef bitmap = copyMMBitmapFromDisplayInRect (MMRectMake (x, y, w, h));
1299+ MMBitmapRef bitmap = NULL ;
1300+
1301+ if (hasBounds) {
1302+ size_t displayCount = 0 ;
1303+ MMDisplay *displayList = getDisplayList (&displayCount);
1304+ MMDisplay display;
1305+ MMRect localRect;
1306+
1307+ if (displayList == NULL || displayCount == 0 ) {
1308+ Napi::Error::New (env, " Failed to enumerate active displays." )
1309+ .ThrowAsJavaScriptException ();
1310+ return env.Null ();
1311+ }
1312+
1313+ if (!findDisplayForRect (displayList, displayCount, x, y, w, h, &display, &localRect)) {
1314+ destroyDisplayList (displayList);
1315+ Napi::Error::New (env, " Requested capture rect is outside the active displays' dimensions." )
1316+ .ThrowAsJavaScriptException ();
1317+ return env.Null ();
1318+ }
1319+
1320+ bitmap = copyMMBitmapFromDisplayInRectOnDisplay (display, localRect);
1321+ destroyDisplayList (displayList);
1322+ } else {
1323+ bitmap = copyMMBitmapFromDisplayInRect (MMRectMake (0 , 0 , w, h));
1324+ }
1325+
12021326 if (bitmap == NULL ) {
12031327 Napi::Error::New (env, " Failed to capture the requested screen rect." )
12041328 .ThrowAsJavaScriptException ();
@@ -1657,6 +1781,9 @@ Napi::Object InitAll(Napi::Env env, Napi::Object exports)
16571781 exports.Set (Napi::String::New (env, " getScreenSize" ),
16581782 Napi::Function::New (env, getScreenSizeWrapper));
16591783
1784+ exports.Set (Napi::String::New (env, " getDisplays" ),
1785+ Napi::Function::New (env, getDisplaysWrapper));
1786+
16601787 exports.Set (Napi::String::New (env, " captureScreen" ),
16611788 Napi::Function::New (env, captureScreenWrapper));
16621789
0 commit comments