diff --git a/GraphicsWorkMaterial/ReadmeKeyStatesInventory.xcf b/GraphicsWorkMaterial/ReadmeKeyStatesInventory.xcf new file mode 100644 index 0000000..a61b0a6 Binary files /dev/null and b/GraphicsWorkMaterial/ReadmeKeyStatesInventory.xcf differ diff --git a/GraphicsWorkMaterial/postit-nuke@2x.xcf b/GraphicsWorkMaterial/postit-nuke@2x.xcf new file mode 100644 index 0000000..ffc861e Binary files /dev/null and b/GraphicsWorkMaterial/postit-nuke@2x.xcf differ diff --git a/Sources/MyStreamDeckPlugin.m b/Sources/MyStreamDeckPlugin.m index 75dd7d8..263d91d 100755 --- a/Sources/MyStreamDeckPlugin.m +++ b/Sources/MyStreamDeckPlugin.m @@ -17,6 +17,8 @@ #import "ESDUtilities.h" #import +#define STORE_ACT @"net.localhost.streamdeck.clipboard-buddy" +#define NUKE_ACT @"net.localhost.streamdeck.clipboard-buddy-nuke" #define MIN_LONG_PRESS 0.5 #define SECURE_PRESS 1.0 @@ -241,6 +243,50 @@ static CGImageRef ComposeImage(NSString *inImagePath, NSString *overlayText, NSC } +// +// Utility function to init/reset the storage dict +// +static NSMutableDictionary * ResetDictContent(NSInteger thisDevHeight, NSInteger thisDevWidth) { + + // A basic dict for our row-column to string transformation + NSMutableDictionary * tmpDict = [[NSMutableDictionary alloc] initWithCapacity:1]; + + // The final dict with the default values inside + NSMutableDictionary * rdyDict = [[NSMutableDictionary alloc] initWithCapacity: thisDevWidth*thisDevHeight]; + + // We need to initialize the dict for text (max the whole size of the device) + for (NSInteger row=0; row < thisDevWidth; row++) { + for (NSInteger col=0; col < thisDevHeight; col++) { + // + // We need to fake the usual structure we get while running to use the common keyFromCoord() method + // Unfortunately, a dict requires String or string-like elements so we have to do a formatting :( + // + tmpDict[@"row"] = [NSString stringWithFormat:@"%ld", row]; + tmpDict[@"column"] = [NSString stringWithFormat:@"%ld", col]; + + rdyDict[ keyFromCoord(tmpDict) ] = keyFromCoord(tmpDict); + // using the key as default value should make any code misbehavior visible + } + } + return rdyDict; +} + + +// +// Utility function to properly clear a key (background + title) +// +static BOOL ClearKey(ESDConnectionManager *conMan, id thisContext, NSString *backgroundImage) { + + // Changing the background to convey we have purged the data + [conMan setImage:backgroundImage withContext:thisContext withTarget:kESDSDKTarget_HardwareAndSoftware]; + + // And clearing the text if it was a secure entry + [conMan setTitle:@"" withContext:thisContext withTarget:kESDSDKTarget_HardwareAndSoftware]; + + return true; +} + + // MARK: - MyStreamDeckPlugin @interface MyStreamDeckPlugin () @@ -253,6 +299,8 @@ @interface MyStreamDeckPlugin () // The text we want to hold (one entry per key) @property (strong) NSMutableDictionary *tileText; @property BOOL dictInitialized; +@property (strong) NSMutableDictionary *tileContext; +// The context of each tile to simplify global actions (like the nuke) // The global clipboard @property NSPasteboard *pboard; @@ -268,6 +316,10 @@ @interface MyStreamDeckPlugin () // For secure entries we store objects to reuse @property (strong) NSDateFormatter *daFo; +// The information about the device we use to deal properly with the storage dict +@property NSInteger devHeight; +@property NSInteger devWidth; + @end @@ -328,7 +380,21 @@ - (void)setupIfNeeded - (void)keyDownForAction:(NSString *)action withContext:(id)context withPayload:(NSDictionary *)payload forDevice:(NSString *)deviceID { - _keyPressed = [[NSDate alloc]init]; + // Useful only when dealing with STORE_ACT actions but does not hurt for others + _keyPressed = [[NSDate alloc] init]; + + if([action isEqualToString:NUKE_ACT]) { + + // We check which key holds data and make sure it gets purged properly (visually) + for(NSString * key in [_tileContext allKeys]) { + ClearKey(_connectionManager, _tileContext[key], _base64PostitSleepy); + [_tileContext removeObjectForKey:key]; + } + // At this point, everything should be visually clean and we must ensure the text storage is too ;) + _tileText = [NSMutableDictionary dictionaryWithDictionary:ResetDictContent(_devHeight, _devWidth)]; + + [_connectionManager showOKForContext:context]; + } } @@ -348,6 +414,7 @@ - (void)keyUpForAction:(NSString *)action withContext:(id)context withPayload:(N // Making sure we store the clipboard data into a separate entry specific to our button NSString * dictKey = keyFromCoord(payload[@"coordinates"]); _tileText[dictKey] = clipboardContent; + _tileContext[dictKey] = context; // Picking also a pseudo-random color for the text we will display on the button NSColor *thisColor = _textColorMatrix[ arc4random_uniform(sizeof(_textColorMatrix)) ]; @@ -374,12 +441,9 @@ - (void)keyUpForAction:(NSString *)action withContext:(id)context withPayload:(N // Purging the struct by resetting to the default value NSString * dictKey = keyFromCoord(payload[@"coordinates"]); _tileText[dictKey] = dictKey; + [_tileContext removeObjectForKey:dictKey]; - // Changing the background to convey we have purged the data - [_connectionManager setImage:_base64PostitSleepy withContext:context withTarget:kESDSDKTarget_HardwareAndSoftware]; - - // And clearing the text if it was a secure entry - [_connectionManager setTitle:@"" withContext:context withTarget:kESDSDKTarget_HardwareAndSoftware]; + ClearKey(_connectionManager, context, _base64PostitSleepy); } else { NSString * textToDisplay = _tileText[ keyFromCoord(payload[@"coordinates"]) ]; @@ -463,33 +527,20 @@ - (void)willDisappearForAction:(NSString *)action withContext:(id)context withPa - (void)deviceDidConnect:(NSString *)deviceID withDeviceInfo:(NSDictionary *)deviceInfo { // Relaying the dimensions of the current device as integers - NSInteger devWidth = [deviceInfo[@"size"][@"rows"] integerValue]; - NSInteger devHeight= [deviceInfo[@"size"][@"columns"] integerValue]; + _devHeight= [deviceInfo[@"size"][@"columns"] integerValue]; + _devWidth = [deviceInfo[@"size"][@"rows"] integerValue]; // Making sure we do not loose data if the computer is locked or goes to sleep ;) if( _dictInitialized ) { [_connectionManager logMessage:[NSString stringWithFormat:@"[DID-CONNECT] No need to re-intialize the internal text storage in order to avoid loosing existing data..."]]; } else { - // Preparing our dictionary objects (as we need the device's buttons info) - _tileText = [[NSMutableDictionary alloc] initWithCapacity: devWidth*devHeight]; - NSMutableDictionary * tmpDict = [[NSMutableDictionary alloc] initWithCapacity:1]; - - // We need to initialize the dict for text (max the whole size of the device) - for (NSInteger row=0; row < devWidth; row++) { - for (NSInteger col=0; col < devHeight; col++) { - // - // We need to fake the usual structure we get while running to use the common keyFromCoord() method - // Unfortunately, a dict requires String or string-like elements so we have to do a formatting :( - // - tmpDict[@"row"] = [NSString stringWithFormat:@"%ld", row]; - tmpDict[@"column"] = [NSString stringWithFormat:@"%ld", col]; - - _tileText[ keyFromCoord(tmpDict) ] = keyFromCoord(tmpDict); - // using the key as default value should make any code misbehavior visible - } - } + // Preparing text dictionary (as we need the device's buttons info) + _tileText = [NSMutableDictionary dictionaryWithDictionary:ResetDictContent(_devHeight, _devWidth)]; _dictInitialized = TRUE; + + // Preparing also the context dictionary (without any content for now) + _tileContext = [[NSMutableDictionary alloc] initWithCapacity: _devWidth*_devHeight]; } } diff --git a/Sources/net.localhost.streamdeck.clipboard-buddy.sdPlugin/manifest.json b/Sources/net.localhost.streamdeck.clipboard-buddy.sdPlugin/manifest.json index e5958e5..266d909 100755 --- a/Sources/net.localhost.streamdeck.clipboard-buddy.sdPlugin/manifest.json +++ b/Sources/net.localhost.streamdeck.clipboard-buddy.sdPlugin/manifest.json @@ -14,6 +14,21 @@ "SupportedInMultiActions": false, "Tooltip": "", "UUID": "net.localhost.streamdeck.clipboard-buddy" + }, + { + "Icon": "postit-action", + "Name": "All clear slot", + "States": [ + { + "Image": "postit-nuke", + "TitleAlignment": "middle", + "FontSize": "12", + "TitleColor": "cyan" + } + ], + "SupportedInMultiActions": false, + "Tooltip": "", + "UUID": "net.localhost.streamdeck.clipboard-buddy-nuke" } ], "SDKVersion": 2, diff --git a/Sources/net.localhost.streamdeck.clipboard-buddy.sdPlugin/postit-nuke.png b/Sources/net.localhost.streamdeck.clipboard-buddy.sdPlugin/postit-nuke.png new file mode 100755 index 0000000..bc4cf01 Binary files /dev/null and b/Sources/net.localhost.streamdeck.clipboard-buddy.sdPlugin/postit-nuke.png differ diff --git a/Sources/net.localhost.streamdeck.clipboard-buddy.sdPlugin/postit-nuke@2x.png b/Sources/net.localhost.streamdeck.clipboard-buddy.sdPlugin/postit-nuke@2x.png new file mode 100755 index 0000000..f4a966d Binary files /dev/null and b/Sources/net.localhost.streamdeck.clipboard-buddy.sdPlugin/postit-nuke@2x.png differ diff --git a/Sources/net.localhost.streamdeck.clipboard-buddy.sdPlugin/previews/1-preview.png b/Sources/net.localhost.streamdeck.clipboard-buddy.sdPlugin/previews/1-preview.png index c9d5ff8..e396d07 100644 Binary files a/Sources/net.localhost.streamdeck.clipboard-buddy.sdPlugin/previews/1-preview.png and b/Sources/net.localhost.streamdeck.clipboard-buddy.sdPlugin/previews/1-preview.png differ diff --git a/USAGE.md b/USAGE.md index 5b586c1..1756939 100644 --- a/USAGE.md +++ b/USAGE.md @@ -2,17 +2,18 @@ - [Plugin usage with a Stream Deck device](#plugin-usage-with-a-stream-deck-device) - [Overview](#overview) - - [Step-by-step guides](#step-by-step-guides) + - [Step-by-step guide (for the Clipboard action)](#step-by-step-guide-for-the-clipboard-action) - [Saving text](#saving-text) - [Saving sensitive text](#saving-sensitive-text) - [Clearing a key](#clearing-a-key) + - [Guide for the Clear All action](#guide-for-the-clear-all-action) ## Overview The point of this plugin is to enable you to set aside some **text data** you have in your clipboard for later. Once a key holds some text, you can paste it in most text areas by doing a quick press on the key. -## Step-by-step guides +## Step-by-step guide (for the Clipboard action) ### Saving text @@ -33,3 +34,8 @@ Once a key holds some text, you can paste it in most text areas by doing a quick - First, your key will contain either a regular text ![Regular text](documentation_images/regular-text.png) or secure text ![Secure text](documentation_images/secure-text.png) - Do a long press on the key (**3 seconds or longer**) - When you release the key it should be back to the empty image ![Empty key](documentation_images/unused.png) + +## Guide for the Clear All action + +This action is very simple: you activate it, it clears all the Clipboard actions on the Stream Deck (be careful !). +![Clear All](documentation_images/clear-all.png) diff --git a/documentation_images/clear-all.png b/documentation_images/clear-all.png new file mode 100644 index 0000000..5bd87b7 Binary files /dev/null and b/documentation_images/clear-all.png differ diff --git a/documentation_images/secure-text.png b/documentation_images/secure-text.png index 64db13b..c8236b9 100644 Binary files a/documentation_images/secure-text.png and b/documentation_images/secure-text.png differ diff --git a/preview.png b/preview.png index 959e863..a7e92d5 100644 Binary files a/preview.png and b/preview.png differ diff --git a/scripts/local_test.sh b/scripts/local_test.sh index 6177539..5c75a76 100755 --- a/scripts/local_test.sh +++ b/scripts/local_test.sh @@ -1,5 +1,8 @@ #!/bin/sh +# Let's stop at the first error +set -e + PROJ="Clipboard-Buddy" HERE=$(dirname "$0") @@ -15,4 +18,4 @@ xcodebuild -project "${HERE}/../Sources/${PROJ}.xcodeproj" -alltargets -configur "${HERE}/_deploy-plugin-dev.sh" # 4) RE-OPEN STREAM DECK TO LOAD THE LATEST VERSION OF THE PLUGIN -open "/Applications/Stream Deck.app" +open "/Applications/Elgato Stream Deck.app"