Click here to Skip to main content
14,298,693 members

Transform Clipboard Contents Between Copy and Paste

Rate this:
4.98 (34 votes)
Please Sign up or sign in to vote.
4.98 (34 votes)
15 Sep 2019CPOL
Alter your clipboard contents before pasting to automate tasks

Introduction

This Windows desktop application, while running, monitors your clipboard, and allows you to alter the contents before you paste. This can be quite powerful, for example, copying a range of data in Excel (unformatted) and then transforming it into a pretty table to be pasted into an email. Or, splitting a string of numbers and getting a distinct, sorted subset for analysis on paste. One of my favorites is copying the top row of a SQL result set from MS SQL Server Management Studio, and transforming it into a column list to make selecting and re-arranging the columns easier. The most powerful one is taking an Excel sheet and transforming it into a SQL temp table script. All with the push of a button.

Image 1

Major Update (6.1)

Finally getting around to some long desired improvements, including...

  • JSON Transmogrifiers: Until now, custom transmogrifiers were only in XML, now you can write them in JSON. Files must use the .json extension and live in or below the /Transformers/ directory. See Sample.json for an example transmogifier and you can use TransmogrifierConverter (in the UnitTest project) to convert between XML and JSON to your desired format. See changes to SerializationToolsFactory and ISerializationTools to see abstraction of the serialization logic.
  • Favorites & User Specific Settings:

    Image 2

    Your most often used transformations bubble up to the top to make the app easier to use. The number of favorites to save is adjustable in the app.config. The favorites file is user specific in the users %APPDATA% folder, which opens up opportunities to save other details by user. See Favorites for details.
  • Search Filter Improved: Matches on any words (e.g., "A B", will match on "A or B").)
  • Compound Transmogrifiers: One transmogrifier can call another before/after the current execution. You will need to be mindful of recursive calls (A calls B calls A) to prevent unexpected transformations. See CommasToVerticalQuotedTrimmedList.xml for an example of this new feature. Hopefully, this will allow easier construction of more complicated transformations?! Note the change of adding TransformClipboard.PostLoadedInit so transformers can be aware of each other, and TransformReferenceTransformations to execute the transformation(s).
  • 1:1 Transformation Matrix: I realized a lot of my transformers were simple replaces (comma with tab, tab with space, etc.). There is a list of common replace characters (CharReplacers.json) that will resolve to a grid of all possible replacements. This was a long journey where I experimented with all sorts of options, notably a grid with "from" characters on the left and "to" characters on the top, but I found it more complicated to use than the solution presented of just including all permutations in line. As such, most of the changes are incorporated into CharReplacerLib.
  • Color Coded Group Names: Groups can define a color for the header (made for color coding the favorites and 1:1 matrix transformations easier).
  • Minor Bug Fixes and Speed Improvements: Several small bug fixes like, reduced debugging impact (improved startup/shutdown time), help formatting improvements, better error logging, SKIP_MASK_LAST_CELL option, Moved several code blocks around to support different features.
  • (Possible Breaking Change) Re-Organized Transformers: Moved and renamed several transformers to take advantage of the new features. Note that with the Compound Transmogrifiers feature, the GroupCode is now more important, and sensitive to directory locations since it is used to link transformations.

Major Update (4.0)

I still use this tool almost every day, both at home and work, and have found some opportunities to improve upon this code. The updated code has several major changes, including:

  • Filter/Search: Start typing to filter transformers. Backspace/Delete to clear. Current filter and the count of matches shown in the upper right corner of the transformer list.

    Image 3

  • Many New Transformers: Escape XML, Remove HTML Tags, and more. The bigger change is that almost all but a handful of transformations are now done using the .xml file based transformation, as opposed to being coded in C#. Feel free to use any of the existing transformations as an example or extend upon them to meet your needs.
  • Configurable Groups: Moved group name and sort order to a configuration file (Groups.xml). You can add/remove/re-arrange groups as you see fit. There are still constants (GroupSortOrder. CannedGroups.*) that map to values for use in coded transformers in case you need them, but they are not required. This removed the notion of "group rank", which was previously used to group items together. Now, a group's sort order is determined by the order in which it appears in the Groups.xml file. Items with an unknown group added to the top or bottom of the list based on the app.config setting UNKNOWN_GROUPS_TO_TOP.
  • In-Line Unit Testing: Since we can add a new transformer by just dropping a text file in the app folder, it made sense that we should be able to just drop the unit tests in as well. Now, both coded transformers and XML transformers have their unit tests in line. See any of the Transmogifier XML files for examples, or Sample.xml for more details. To run the tests, run the application with either the /DEBUG or /TEST startup flag, or run the unit test InLineUnitTestRunAll.

    Image 4

  • ListBoxTransformerItem.ItemType: There was too much confusion around what each list item was (a section header?, a horizontal rule?, an actual transformer?, etc.), so that logic is now encapsulated into ListBoxTransformerItem.ItemType. This made figuring out what to show and hide in the list box much cleaner when filtering.
  • Serialization Tools: Broke the Serializer calls into its own class, SerializationTools. Why I did not do this years ago (or why this is not baked into the .NET Framework) -- I am not sure! This is code I will certainly reuse.
  • Debugging Window: Added a debugging window, visible with the /DEBUG flag. This can be useful for diagnosing issues with a failed transformation.

    Image 5

XML-based Transformer Updates

All of the remaining changes centered on extending the XML-based transformation feature. Broadly speaking, these are now way more powerful than before, and almost all of the default transformations are done with just the XML files. Unfortunately, this is a breaking change from the old XML file format. If you need help converting your old transformations to the new format, feel free to contact me. See "Transformers\Transmogrifiers\Sample.xml" for details on all the options, but an overview of the changes includes:

  • Specify output case (lower, UPPER, Title, None)
  • Split by chars, strings or regular expressions
  • Find and Replace by string or regular expression, including found regular expression patterns (see TransmogifierReplaceTest for an example)
  • Regular expressions now support additional options (like toggling case sensitivity)
  • Input is always assumed to be a "grid" (rows x columns), where a single string is treated as a single cell in the grid. This added WAY more flexibility in transforming complex data. You can split rows and columns in different ways, act on the split cells, and re-assemble them in different ways. See Sample.xml for details.
  • Canned options to make several operations easier and giving you more flexibility in the transformation process. Including:
    • When and how to trim text (Per row? Per cell? Etc.). See options: TRIM_ON_SPLIT_ROW,TRIM_ON_SPLIT_COL, REMOVE_EMPTY_ROWS, REMOVE_EMPTY_CELLS for more details.
    • How to deal with different types of line breaks. (Can treat \r, \n and \r\n all the same!) See option: NORMALIZE_NEW_LINES for more details.
    • How to deal with different types of spaces. (Can treat Ascii(32) the same as  !) See option: NORMALIZE_SPACES for more details.
    • Row based operation like sorting, top and distinct. See options: DISTINCT_ROWS, SORT_ROWS, GRIDIFY and the property TopRows for more details.
    • I found working with XML escape sequences challenging, especially for new line and tabs. I have created an option of USE_COMMON_ESCAPE_CHARS that will pre-process the XML file swapping out \n, \r, \t and \l (custom tag that maps to Environment.NewLine) with their XML escape sequences. It just made working with the transformation files easier.
  • Support for raw XLST transformations. Assuming the input is valid XML, you can just apply an XSLT transformation. An included sample is used to convert the XML help text generated by Microsoft Visual Studio into HTML. Thanks to Emma Burrows for Simple XSLT stylesheet for Visual Studio .NET XML Documentation.
  • Group is inferred based on directory structure, unless explicitly set. It just felt more natural that way.
  • Transmogifier process is broken into several steps to make working with the code easier. See Transmogifier.Transform for details.
  • Two stage sorting. Primary sorting of list items is by group, ordered in the order in which they appear in the Groups.xml file. If a Rank is specified, it will be used to position items within the group, the finally sorting by name.

Background

Repetitive tasks drive me nuts. After having to alter text to make it fit some need over and over and over again, I finally realized what I need to do is be able to programmatically alter the text in my clipboard without having to go to some intermediate tool.

For example, without this tool, to send results from SQL Server Management Studio to my co-worker, I would copy the results with headers, launch MS Excel, paste into Excel, format in Excel, copy from Excel, paste into the email to be sent. That's a lot of busy work just to display a table of data. Given I was doing that many times a day, I needed a solution! This is that solution.

Conversely, I would regularly get Excel workbooks from users asking me to import/export/explain some piece of data. To get that into our production database on the other side of the firewall was a pain. The Excel to SQL transformation takes the Excel input and makes it simple to paste that Excel data into a SQL #Temp table, which I can then use to import or analyze the issue.

After using this tool for several years, and sharing with my co-workers, it seemed a proper time to share with the rest of the world. Enjoy!

Using the Code

This posting is more about making the tool available for others to enjoy. To use, launch the executable, copy something into your clipboard, select the transformation(s), apply and paste. That's it! For common transformations that you use every day, you can create a shortcut macro on your desktop (or quick launch bar) to apply the transformation with a single click. See the About section of the application for more details.

Exploring the Code

This application is a standard WPF desktop application that, for the most part, is unremarkable. However, if you are interested in extending the code to meet your own needs, it would be helpful to understand some of the moving parts.

Overview

The general design is a ViewModel bound WPF application. On startup, we use reflection to find all classes that implement TextTransformerBase in the currently loaded assembly, we then add those classes to the list of transformers displayed in the application. On transform, we capture the user's clipboard, and apply the transformations (calling Transform(ref text) on each selected transformer), then write the result back to the clipboard, finally closing the application.

As with most WPF application, we start in App.xaml.cs, in Application_Startup, we parse the command line to see if we are running in UI mode (display a list of possible transformations) or command line mode (a canned list of transformers was passed in, so just transform and exit -- no UI). In either case, the core initialization happens in TextTransformerBase.AllTransformers, where we parse assemblies looking for transformers, returning them as a collection. They are then wrapped in ListBoxTransformerItem, which keeps track of selection sort order and other UI features, finally being added to an ObservableCollection that is rendered into the UI.

On selection of any item, we DoPreview() to display what the output of the transformation will look like. Ultimately, if the user clicks apply, we basically just do VM.ClipboardText = VM.Transform(); and close the application.

All that said, there is quite a bit of code to make the systray bubble work.

Image 6

Problem 1: Integrating into Win32 components! This code was entirely grafted from the internet (clipboard-event-c-sharp) thanks to dbkk!

Problem 2: How to display the bubble for the right amount of time after the transformation, but before the application closes (removing the bubble and systray icon)? Most of the logic around this is in MainWindowVM.DisplayTransformComplete. If we pass in delegate function (onDoneHandler), we wire it in to a 3 second timer to be called on done. In most cases, this basically calls VM.Quit() to shut the app down. In any case, no matter what apply mode we are in, as soon as the "apply" starts, we hide the main window to make it "look" like the application has shut down while we display the popup bubble.

The remaining code that is noteworthy is really the transformer code. My hope in posting this is that developers take this code and create their own transformers!

Implementing Custom Transformers

For the most power, it may be easiest to write your own transformers depending on your needs. I did try to write the code so you can just include another assembly (.dll) below the application root and if it contained a transformer, you could use it. This proved somewhat problematic when it came to security, and that code is currently commented out (TextTransformerBase.AllTransformers - #if false section).

There are two basic options to create your own transformers.

Option 1 - Transmogrifier (XML-based Transformers)

On startup, Transmogrifier.GetAllTransmogrifiers parse the application directory (and sub directories) for *.xml files that contain XML-based (serialized) transformation. See Sample.xml for full details, but the gist is: if your transformation is not too complex, then you can just create a Transmogrifier. The biggest advantage is that there is no need to re-compile code, just create the XML (text) file and include it below the application root. Note that you can also include unit tests in the XML file as well, again avoiding the need to actually compile code.

Option 2 - Custom .NET Transformers

To create your own custom transformer, create a class that implements the abstract base class TextTransformerBase. The semantics are pretty simple (I hope), where the constructor defines the basics (name, group, description, ...), and then overrides Transform (ref string str) with your custom code.

Example
public class ToUpper : TextTransformerBase
    {
        public ToUpper()
            : base(
                GROUP_SORT_ORDER.STRING_CASE, // Group in which to include this transformer
                "To Upper",                   // Name to display
                "Make all characters UPPER case." // Tool tip and Help file text
            ) { }
        override public void Transform(ref string str)
        {
            str = str.ToUpper();
        }
    }

There are checks in place to ensure str is never null, so you should just be able to write whatever transformations you desire.

Points of Interest

Disable Preview: While working on this post, I had cause to transform a very large SQL result set (> 100 MB). It was SLOOOOW! After a little debugging, I realized that the issue was solely with the rendering to the UI. As such, I have added a "Disable Preview" option that will trigger if it thinks the amount of data in your clipboard is too big.

ClipboardFormat: There are some transformers that return HTML. HTML in the clipboard gets tricky. You have to provide these index positions of where the pasted HTML lives, which is somewhat cumbersome to compute. If you need to return an HTML result, I would recommend you use HTMLClipboardHelper.HTMLToClipboardFormattedText to provide the result.

Desktop Shortcuts: I have used this app for years, and I always just create macro shortcuts to it by hand, but that's pretty lame. So with the help of the internet (create-shortcut-on-desktop-c-sharp) and thanks to Simon Mourier, I was able to wire in a simple button to do so. See ShortcutHelper.CreateShortcut for the "fun" code.

Event Log: Meaningful, but non-crashing, errors are logged to the Windows Event Log. This can be helpful when debugging XML Transformer issues when you don't have a debugger attached.

KeyHelper: This class is silly, but I couldn't think of a better way to solve the problem of cherry picking what sets of keys are viable for a subset of actions.

GroupSortOrder: This seemed a practical solution for a user configurable arbitrarily re-sortable list of items. This is likely code I will use again in the future in some manner or another.

InLineUnitTest: Given we are really just testing text transformations, the unit testing of that is pretty simple string before/after pair testing. I think this solution worked out well for this use case and lends quite a bit of durability to custom transformers.

Help: I worked hard to have the help be included in-line in a seamless way, which is why TextTransformerBase has a HelpText property. The styling and other details are defined in Help.html, which is what is ultimately rendered out to the help window.

History

  • Version 6.2 (15 September, 2019): Typo Fixes, Requested Transformer
    • Typo fixes throughout.
    • "englebart" requested a SQL parameter substitution transformer.
    • Removed NuGet pacakges from uploaded source code (much smaller upload)
  • Version 6.1 (2 September, 2019): New Features
    • Favorites! Your most commonly used bubble to the top. Click favorites header to clear.
    • User Specific Settings. Favorites stored in user-specific folder.
    • Search Filter Improved. Matches on any words (e.g. "A B", will match on "(A or B)).")
    • Compound Transmogrifiers! Can call other Transmogrifiers before/after the current transmogrifier.
    • 1:1 Transformation Matrix. I realized a lot of my transformers were simple replaces (comma with tab, tab with space, etc...). There is list of common replace characters that will resolve to a grid of all possible replacements.
    • Color codes in list of transformers.
    • JSON Transformers. Why? Why not!
    • SKIP_MASK_LAST_CELL option. When processing cells, optionally skip the last one, which is helpful for assembling comma lists leaving off the last comma.
    • Breaking Change - Re-organized many of the transformers to work better with the new features.
    • Bug Fixes.
  • Version 5 (6 March, 2019): Bug Fixes
    • Fixed bug in Serializable Dictionary that was preventing some transmogrifiers from working correctly
    • Added debugging aids to both the serialization processes and transmogrify unit tests
    • Fixed bug in Strip HTML transformer
    • Fixed bug in Replace Smart Quote transformer
    • Breaking Change - Removed "Root" element from serializable dictionary by default. To fix your custom transmogrifiers, remove the <r> and tags in your XML transmogrifies.
    • Added some fun on the help page
  • Version 4 (5 February, 2019): Major Updates
    • New Transformers
    • Grouping in Config File
    • In Line Unit Testing
    • Filter/Find Transformers (just start typing)
    • Declarative Item Type (made the code way easier to work with)
    • SerializationTools broken out to own class (reusable!)
    • Debugging window. Appears by default in DEBUG mode, or show with /DEBUG command line switch.
    • Major Overhaul to XML-based Transformers (renamed to Transmogrifier)
  • Version 3 (26 August, 2016): First Public Offering
  • Version 1-2 (12 December, 2013): Untracked -- I just made it for me to use! :-)

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Brad Joss
Software Developer (Senior)
United States United States
No Biography provided

Comments and Discussions

 
Praisethumbs up Pin
Member 1458526112-Sep-19 13:30
memberMember 1458526112-Sep-19 13:30 
QuestionVery nice! Pin
DrWicked12-Sep-19 5:22
memberDrWicked12-Sep-19 5:22 
AnswerRe: Very nice! Pin
Brad Joss12-Sep-19 7:15
professionalBrad Joss12-Sep-19 7:15 
PraiseVery usefull, thanks Pin
Arturo Martinez R12-Mar-19 21:05
memberArturo Martinez R12-Mar-19 21:05 
QuestionSuggestions Pin
qmartens10-Mar-19 14:29
memberqmartens10-Mar-19 14:29 
GeneralRe: Suggestions Pin
Brad Joss29-Mar-19 18:11
professionalBrad Joss29-Mar-19 18:11 
PraiseTransform Clipboard Pin
Member 107254399-Mar-19 3:28
memberMember 107254399-Mar-19 3:28 
QuestionMore clipboard tricks Pin
englebart8-Mar-19 8:47
memberenglebart8-Mar-19 8:47 
GeneralRe: More clipboard tricks Pin
Brad Joss29-Mar-19 18:00
professionalBrad Joss29-Mar-19 18:00 
GeneralRe: More clipboard tricks Pin
englebart16-Apr-19 2:19
memberenglebart16-Apr-19 2:19 
GeneralRe: More clipboard tricks Pin
Brad Joss15-Sep-19 10:18
professionalBrad Joss15-Sep-19 10:18 
PraiseNice work Pin
Mike Hankey8-Mar-19 7:27
professionalMike Hankey8-Mar-19 7:27 
PraiseNice Pin
Roberto Mazzone8-Mar-19 3:12
memberRoberto Mazzone8-Mar-19 3:12 
PraiseNice job! Pin
Ravi Bhavnani7-Mar-19 6:14
professionalRavi Bhavnani7-Mar-19 6:14 
QuestionGood Work Pin
Nirmala Gokidi7-Feb-19 6:28
memberNirmala Gokidi7-Feb-19 6:28 
QuestionExcellent Pin
feelyd6-Feb-19 5:42
memberfeelyd6-Feb-19 5:42 
AnswerRe: Excellent Pin
Brad Joss6-Feb-19 16:19
professionalBrad Joss6-Feb-19 16:19 
GeneralMy vote of 5 Pin
Carsten V2.029-Aug-16 23:15
memberCarsten V2.029-Aug-16 23:15 
PraiseTransform Clipboard Contents Between Copy and Paste Pin
ArtemDaemon27-Aug-16 21:15
memberArtemDaemon27-Aug-16 21:15 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Article
Posted 25 Aug 2016

Stats

27.5K views
1.7K downloads
53 bookmarked