@@ -11,7 +11,7 @@ namespace KeyCodeInfoPlugin
1111 internal class Measure
1212 {
1313 private API _api ;
14-
14+
1515 private static IntPtr _hookID = IntPtr . Zero ;
1616 private static LowLevelKeyboardProc _proc = HookCallback ;
1717 private static Measure instance ;
@@ -26,6 +26,12 @@ internal class Measure
2626 private const int WM_SYSKEYDOWN = 0x0104 ;
2727 private const int WM_KEYUP = 0x0101 ;
2828 private const int WM_SYSKEYUP = 0x0105 ;
29+ private static string lastCombo = "" ;
30+
31+ // New field for the OnReleaseKeyAction parameter.
32+ private string onReleaseKeyAction = "" ;
33+ // Flag to ensure the release action is triggered only once per key press cycle.
34+ private bool releaseActionTriggered = false ;
2935
3036 // Parameters:
3137 // showCodeMode:
@@ -35,30 +41,29 @@ internal class Measure
3541 // 4 = return key combination (e.g., "Ctrl + Alt + A") in order of press.
3642 private int showCodeMode ;
3743 // hideForce: for modes 0, 1, and 3, if true the stored key is cleared immediately.
38- // For mode 4 (combination), keys remain until they are released.
44+ // For mode 4 (combination), keys remain until released.
3945 private bool hideForce ;
4046
4147 /// <summary>
4248 /// Reload is called when Rainmeter reloads the skin.
43- /// It reads ShowCode and HideForce options and resets stored key data.
49+ /// It reads ShowCode, HideForce, and OnReleaseKeyAction options and resets stored key data.
4450 /// (Note: the hook and update timer are not started automatically.)
4551 /// </summary>
4652 internal void Reload ( API api , ref double maxValue )
4753 {
4854 _api = api ;
49- // Store the instance reference for use in the static hook callback.
5055 instance = this ;
5156
52- // Read ShowCode parameter; default is 1 (numeric).
53- // Other supported values: 3 for hex, 0 for friendly names, 4 for combination.
5457 showCodeMode = api . ReadInt ( "ShowCode" , 1 ) ;
55- // Read HideForce parameter; default is 1 (clear immediately).
5658 hideForce = api . ReadInt ( "HideForce" , 1 ) == 1 ;
59+ // Read the new OnReleaseKeyAction parameter (default to empty string).
60+ onReleaseKeyAction = api . ReadString ( "OnReleaseKeyAction" , "" ) ;
5761
58- // Reset stored key data.
5962 lastKeyCode = 0 ;
6063 pressedKeyEvents . Clear ( ) ;
6164 pressedKeyOrder . Clear ( ) ;
65+ // Reset the release flag
66+ releaseActionTriggered = false ;
6267
6368 _api . Log ( API . LogType . Debug , "KeyCodeInfo.dll: Plugin reloaded in stopped state." ) ;
6469 }
@@ -85,9 +90,14 @@ internal string GetString()
8590 {
8691 if ( showCodeMode == 4 )
8792 {
88- // Build combination string using press order.
93+ // If no keys are currently pressed, and HideForce is off,
94+ // return the last stored combination.
8995 if ( pressedKeyOrder . Count == 0 )
96+ {
97+ if ( ! hideForce && ! string . IsNullOrEmpty ( lastCombo ) )
98+ return lastCombo ;
9099 return "" ;
100+ }
91101 List < string > comboNames = new List < string > ( ) ;
92102 foreach ( int key in pressedKeyOrder )
93103 {
@@ -101,7 +111,8 @@ internal string GetString()
101111 comboNames . Add ( keyName ) ;
102112 }
103113 }
104- return string . Join ( " + " , comboNames ) ;
114+ lastCombo = string . Join ( " + " , comboNames ) ;
115+ return lastCombo ;
105116 }
106117 else
107118 {
@@ -170,13 +181,12 @@ internal void ExecuteCommand(string command)
170181 // Start the update timer if not already running.
171182 if ( updateTimer == null )
172183 {
173- updateTimer = new Timer ( 50 ) ; // Timer interval in milliseconds.
184+ updateTimer = new Timer ( 100 ) ; // Timer interval in milliseconds.
174185 updateTimer . Elapsed += ( sender , e ) =>
175186 {
176187 _api . Execute ( $ "!UpdateMeasure \" { measureName } \" ") ;
177188 _api . Execute ( $ "!UpdateMeter *") ;
178189 _api . Execute ( $ "!Redraw") ;
179- // _api.Execute($"!Log \"Updating : {measureName}\"");
180190 } ;
181191 updateTimer . AutoReset = true ;
182192 updateTimer . Start ( ) ;
@@ -230,6 +240,7 @@ internal void Unload()
230240 updateTimer = null ;
231241 _api . Log ( API . LogType . Debug , "KeyCodeInfo.dll: Update timer stopped on Unload." ) ;
232242 }
243+ lastCombo = "" ;
233244 }
234245
235246 // Sets up the low-level keyboard hook.
@@ -255,19 +266,20 @@ private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
255266 int key = ( int ) kbStruct . vkCode ;
256267 lastKeyCode = key ;
257268 lastKeyEvent = kbStruct ;
258- // If the active instance is in combination mode, update tracking.
269+ // Reset the release flag for every key press
270+ if ( instance != null )
271+ instance . releaseActionTriggered = false ;
272+ // For combination mode, update tracking.
259273 if ( instance != null && instance . showCodeMode == 4 )
260274 {
261275 if ( pressedKeyEvents . ContainsKey ( key ) )
262276 {
263- // Remove the key from the order list so it can be re-added at the end.
264277 pressedKeyOrder . Remove ( key ) ;
265278 }
266279 pressedKeyEvents [ key ] = kbStruct ;
267280 pressedKeyOrder . Add ( key ) ;
268281 }
269282 }
270- // Handle key-up events.
271283 else if ( wParam == ( IntPtr ) WM_KEYUP || wParam == ( IntPtr ) WM_SYSKEYUP )
272284 {
273285 KBDLLHOOKSTRUCT kbStruct = ( KBDLLHOOKSTRUCT ) Marshal . PtrToStructure ( lParam , typeof ( KBDLLHOOKSTRUCT ) ) ;
@@ -279,6 +291,22 @@ private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
279291 pressedKeyEvents . Remove ( key ) ;
280292 }
281293 pressedKeyOrder . Remove ( key ) ;
294+ // In combination mode, trigger the action only when all keys are released.
295+ if ( pressedKeyEvents . Count == 0 && ! instance . releaseActionTriggered && ! string . IsNullOrEmpty ( instance . onReleaseKeyAction ) )
296+ {
297+ instance . _api . Execute ( instance . onReleaseKeyAction ) ;
298+ instance . releaseActionTriggered = true ;
299+ }
300+ }
301+ else if ( instance != null )
302+ {
303+ // For non-combination modes, trigger the action on every key-up,
304+ // but only once per key press cycle.
305+ if ( ! instance . releaseActionTriggered && ! string . IsNullOrEmpty ( instance . onReleaseKeyAction ) )
306+ {
307+ instance . _api . Execute ( instance . onReleaseKeyAction ) ;
308+ instance . releaseActionTriggered = true ;
309+ }
282310 }
283311 }
284312 }
0 commit comments