@@ -51,8 +51,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
5151// Measure constructor
5252Measure::Measure () : rm(nullptr ), skin(nullptr ), skinWindow(nullptr ),
5353 measureName(nullptr ),
54- width(800 ), height(600 ), x(0 ), y(0 ),
55- visible(true ), initialized(false ), clickthrough(false ), webMessageToken{}
54+ width(800 ), height(600 ), x(0 ), y(0 ), zoomFactor( 1.0 ),
55+ visible(true ), initialized(false ), clickthrough(false ), allowDualControl( true ), webMessageToken{}
5656{
5757 // Initialize COM for this thread if not already done
5858 if (!g_comInitialized)
@@ -129,6 +129,54 @@ void UpdateClickthrough(Measure* measure)
129129 }
130130}
131131
132+ // Inject AllowDualControl script into the WebView
133+ void InjectAllowDualControl (Measure* measure)
134+ {
135+ if (!measure->webView ) return ;
136+ // Inject script to capture page load events for drag/move and context menu
137+ measure->webView ->ExecuteScript (
138+ L"let rm_AllowDualControl=false,rm_AllowDualControlOn=false,rm_AllowDualControlClientX=0,rm_AllowDualControlClientY=0;function rm_SetAllowDualControl(v){rm_AllowDualControl=!!v;if(!rm_AllowDualControl)rm_AllowDualControlOn=false;}document.body.onpointerdown=e=>{if(!rm_AllowDualControl)return;if(e.button===0&&e.ctrlKey){e.preventDefault();e.stopImmediatePropagation();rm_AllowDualControlOn=true;rm_AllowDualControlClientX=e.clientX;rm_AllowDualControlClientY=e.clientY;try{document.body.setPointerCapture(e.pointerId);}catch{}}};document.body.onpointermove=e=>{if(!rm_AllowDualControl||!rm_AllowDualControlOn)return;e.preventDefault();RainmeterAPI.Bang('[!Move '+(e.screenX-RainmeterAPI.ReadFormula('X',0)-rm_AllowDualControlClientX)+' '+(e.screenY-RainmeterAPI.ReadFormula('Y',0)-rm_AllowDualControlClientY)+']');};document.body.onpointerup=e=>{if(!rm_AllowDualControl)return;if(e.button===0){e.preventDefault();rm_AllowDualControlOn=false;try{document.body.releasePointerCapture(e.pointerId);}catch{}}};document.body.oncontextmenu=e=>{if(!rm_AllowDualControl)return;if(e.button===2&&e.ctrlKey){e.preventDefault();RainmeterAPI.Bang('[!SkinMenu]');}};",
139+ Callback<ICoreWebView2ExecuteScriptCompletedHandler>(
140+ [measure](HRESULT errorCode, LPCWSTR resultObjectAsJson) -> HRESULT
141+ {
142+ return S_OK;
143+ }
144+ ).Get ()
145+ );
146+ measure->isAllowDualControlInjected = true ;
147+ UpdateAllowDualControl (measure);
148+ }
149+
150+ // Update AllowDualControl state in the WebView
151+ void UpdateAllowDualControl (Measure* measure)
152+ {
153+ if (!measure->webView ) return ;
154+
155+ if (measure->allowDualControl )
156+ {
157+ measure->webView ->ExecuteScript (
158+ L" rm_SetAllowDualControl(true);" ,
159+ Callback<ICoreWebView2ExecuteScriptCompletedHandler>(
160+ [measure](HRESULT errorCode, LPCWSTR resultObjectAsJson) -> HRESULT
161+ {
162+ return S_OK;
163+ }
164+ ).Get ()
165+ );
166+ }
167+ else {
168+ measure->webView ->ExecuteScript (
169+ L" rm_SetAllowDualControl(false);" ,
170+ Callback<ICoreWebView2ExecuteScriptCompletedHandler>(
171+ [measure](HRESULT errorCode, LPCWSTR resultObjectAsJson) -> HRESULT
172+ {
173+ return S_OK;
174+ }
175+ ).Get ()
176+ );
177+ }
178+ }
179+
132180PLUGIN_EXPORT void Reload (void * data, void * rm, double * maxValue)
133181{
134182 Measure* measure = (Measure*)data;
@@ -182,12 +230,72 @@ PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
182230 int newHeight = RmReadInt (rm, L" H" , 600 );
183231 int newX = RmReadInt (rm, L" X" , 0 );
184232 int newY = RmReadInt (rm, L" Y" , 0 );
185- bool newVisible = RmReadInt (rm, L" Hidden" , 0 ) == 0 ;
186- bool newClickthrough = RmReadInt (rm, L" Clickthrough" , 0 ) != 0 ;
187-
233+ double newZoomFactor = RmReadFormula (rm, L" ZoomFactor" , 1.0 );
234+ bool newVisible = RmReadInt (rm, L" Hidden" , 0 ) <= 0 ;
235+ bool newClickthrough = RmReadInt (rm, L" Clickthrough" , 0 ) >= 1 ;
236+
237+ // Read AllowDualControl for Yincognito's script injection
238+ bool newAllowDualControl = RmReadInt (rm, L" AllowDualControl" , 1 ) >= 1 ;
239+
240+ // Read OnWebViewLoadAction
241+ std::wstring newOnWebViewLoadAction;
242+ LPCWSTR onWebViewLoadOption = RmReadString (rm, L" OnWebViewLoadAction" , L" " , FALSE );
243+ if (onWebViewLoadOption && wcslen (onWebViewLoadOption) > 0 )
244+ {
245+ newOnWebViewLoadAction = onWebViewLoadOption;
246+ }
247+
248+ // Read OnWebViewFailAction
249+ std::wstring newOnWebViewFailAction;
250+ LPCWSTR onWebViewFailOption = RmReadString (rm, L" OnWebViewFailAction" , L" " , FALSE );
251+ if (onWebViewFailOption && wcslen (onWebViewFailOption) > 0 )
252+ {
253+ newOnWebViewFailAction = onWebViewFailOption;
254+ }
255+
256+ // Read OnPageLoadStartAction
257+ std::wstring newOnPageLoadStartAction;
258+ LPCWSTR onPageLoadStartOption = RmReadString (rm, L" OnPageLoadStartAction" , L" " , FALSE );
259+ if (onPageLoadStartOption && wcslen (onPageLoadStartOption) > 0 )
260+ {
261+ newOnPageLoadStartAction = onPageLoadStartOption;
262+ }
263+
264+ // Read OnPageLoadingAction
265+ std::wstring newOnPageLoadingAction;
266+ LPCWSTR onPageLoadingOption = RmReadString (rm, L" OnPageLoadingAction" , L" " , FALSE );
267+ if (onPageLoadingOption && wcslen (onPageLoadingOption) > 0 )
268+ {
269+ newOnPageLoadingAction = onPageLoadingOption;
270+ }
271+
272+ // Read OnPageLoadFinishAction
273+ std::wstring newOnPageLoadFinishAction;
274+ LPCWSTR onPageLoadFinishOption = RmReadString (rm, L" OnPageLoadFinishAction" , L" " , FALSE );
275+ if (onPageLoadFinishOption && wcslen (onPageLoadFinishOption) > 0 )
276+ {
277+ newOnPageLoadFinishAction = onPageLoadFinishOption;
278+ }
279+
280+ // Read OnPageFirstLoadAction
281+ std::wstring newOnPageFirstLoadAction;
282+ LPCWSTR onPageFirstLoadOption = RmReadString (rm, L" OnPageFirstLoadAction" , L" " , FALSE );
283+ if (onPageFirstLoadOption && wcslen (onPageFirstLoadOption) > 0 )
284+ {
285+ newOnPageFirstLoadAction = onPageFirstLoadOption;
286+ }
287+
288+ // Read OnPageReloadAction
289+ std::wstring newOnPageReloadAction;
290+ LPCWSTR onPageReloadOption = RmReadString (rm, L" OnPageReloadAction" , L" " , FALSE );
291+ if (onPageReloadOption && wcslen (onPageReloadOption) > 0 )
292+ {
293+ newOnPageReloadAction = onPageReloadOption;
294+ }
295+
188296 // Check if URL has changed (requires recreation)
189297 bool urlChanged = (newUrl != measure->url );
190-
298+
191299 // Check if dimensions or position changed (can be updated dynamically)
192300 bool dimensionsChanged = (newWidth != measure->width ||
193301 newHeight != measure->height ||
@@ -196,16 +304,27 @@ PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
196304
197305 bool visibilityChanged = (newVisible != measure->visible );
198306 bool clickthroughChanged = (newClickthrough != measure->clickthrough );
199-
307+ bool allowDualControlChanged = (newAllowDualControl != measure->allowDualControl );
308+ bool zoomFactorChanged = (newZoomFactor != measure->zoomFactor );
309+
200310 // Update stored values
201311 measure->url = newUrl;
202312 measure->width = newWidth;
203313 measure->height = newHeight;
204314 measure->x = newX;
205315 measure->y = newY;
316+ measure->zoomFactor = newZoomFactor;
206317 measure->visible = newVisible;
207318 measure->clickthrough = newClickthrough;
208-
319+ measure->allowDualControl = newAllowDualControl;
320+ measure->onWebViewLoadAction = newOnWebViewLoadAction;
321+ measure->onWebViewFailAction = newOnWebViewFailAction;
322+ measure->onPageLoadStartAction = newOnPageLoadStartAction;
323+ measure->onPageLoadingAction = newOnPageLoadingAction;
324+ measure->onPageLoadFinishAction = newOnPageLoadFinishAction;
325+ measure->onPageFirstLoadAction = newOnPageFirstLoadAction;
326+ measure->onPageReloadAction = newOnPageReloadAction;
327+
209328 // Only create WebView2 if not initialized OR if URL changed
210329 if (!measure->initialized || urlChanged)
211330 {
@@ -220,6 +339,11 @@ PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
220339 else
221340 {
222341 // First initialization - create WebView2
342+ if (measure->isCreationInProgress )
343+ {
344+ // Avoid re-entrancy if creation is already in progress
345+ return ;
346+ }
223347 CreateWebView2 (measure);
224348 }
225349 }
@@ -241,11 +365,26 @@ PLUGIN_EXPORT void Reload(void* data, void* rm, double* maxValue)
241365 {
242366 measure->webViewController ->put_IsVisible (measure->visible ? TRUE : FALSE );
243367 }
368+
369+ if (zoomFactorChanged && measure->webViewController )
370+ {
371+ measure->webViewController ->put_ZoomFactor (measure->zoomFactor );
372+ }
244373
245374 if (clickthroughChanged)
246375 {
247376 UpdateClickthrough (measure);
248377 }
378+
379+ if (allowDualControlChanged)
380+ {
381+ if (!measure->isAllowDualControlInjected )
382+ {
383+ InjectAllowDualControl (measure);
384+ }
385+ else
386+ UpdateAllowDualControl (measure);
387+ }
249388 }
250389}
251390
@@ -275,13 +414,6 @@ PLUGIN_EXPORT double Update(void* data)
275414 {
276415 measure->callbackResult = result;
277416 }
278-
279- // Trigger Rainmeter redraw after callback completes
280- if (measure->skin )
281- {
282- RmExecute (measure->skin , L" !UpdateMeter *" );
283- RmExecute (measure->skin , L" !Redraw" );
284- }
285417 }
286418 return S_OK;
287419 }
@@ -304,6 +436,7 @@ PLUGIN_EXPORT LPCWSTR GetString(void* data)
304436
305437 return L" 0" ;
306438}
439+
307440PLUGIN_EXPORT void ExecuteBang (void * data, LPCWSTR args)
308441{
309442 Measure* measure = (Measure*)data;
0 commit comments