Visio Cut/Copy/Paste Shape Text Only

70 Views Asked by At

tl;dr Can I repurpose Cut/Copy/Paste in Visio to transfer text only?

I have some Shapes in Visio that users have frequent repeated data on (Ex: blocks for Date/Time). It's intuitive to use standard copy/paste methods to fill these blocks, resulting in inadvertent shape duplication. In some cases, the Shape is protected and require an Undo to remove, which is frustrating. I'd like to be able to toggle the Ctrl + C/X/V (and preferably the UI elements as well) functionality to transfer Shape Text only to avoid this frustration.

I'm currently using the Window.KeyUp event to handle this. Here's a simplified version of the code:

Private Sub vsoWindow_KeyUp(ByVal KeyCode As Long, ByVal KeyButtonState As Long, CancelDefault As Boolean)
    Dim shp as Visio.Shape: Set shp = ActiveWindow.Selection.PrimaryItem
    
    If shp is Nothing Then Exit Sub                           'Nothing is selected
    If KeyButtonState <> visKeyControl Then Exit Sub          'Ctrl isn't held
    
    Select Case KeyCode
        Case vbKeyC: CopyShapeText shp
        Case vbKeyX: CutShapeText shp                         'Doesn't work, Shape Protection intercepts
        Case vbKeyV: PasteShapeText shp
    End Select
End Sub

With the workers in a module:

Private Declare PtrSafe Function OpenClipboard Lib "User32" (ByVal hwnd As Long) As Long
Private Declare PtrSafe Function EmptyClipboard Lib "User32" () As Long
Private Declare PtrSafe Function CloseClipboard Lib "User32" () As Long
Private shpText as String

Sub CopyShapeText(shp As Visio.Shape)
    shpText = shp.Text
    ClearClipboard
End Sub

Sub CutShapeText(shp as Visio.Shape)
    shpText = shp.Text
    shp.Text = ""
    ClearClipboard
End Sub

Sub PasteShapeText(shp as Visio.Shape)
    shp.Text = shpText
End Sub

Sub ClearClipboard()
    DoEvents
    OpenClipboard 0
    EmptyClipboard
    CloseClipboard
End Sub

Copy/Paste works but is rather clunky. Sometimes it doesn't fire, despite CTRL being held. Cut doesn't work because the Shape gets stored before the event is triggered.

I attempted to use the KeyDown event, but this fails to trigger at all (detects CTRL but not CTRL + C) and would probably fail to properly clear the clipboard. I also attempted to use Application.EnterScope but ran into the same problems and an inconsistent ScopeID when pasting.

The straightforward approach is to use new keyboard shortcuts to control the operations. This works, but users didn't like it.

Is there a way to do this?

UPDATE: After thinking about it, I decided to implement the straightforward solution and utilize CTRL+Shift+C/X/V shortcuts to give users flexibility. I've posted an answer below going into greater detail. My actual question about intercepting the operations remains unanswered.

1

There are 1 best solutions below

0
Vince On

A similar question was asked several years ago and I was a bit disappointed that it never received a proper answer. The OP ended up using a solution that avoided the problem by utilizing the Document.ShapeAdded event.

In the same vein, I've decided to go with the straightforward solution and added keyboard shortcuts CTRL+Shift+C/X/V to trigger these features. While users didn't like the shortcut in testing, it seems more foolproof than having a toggle which will inevitably lead to mistakes. For the sake of an answer, here's the full code for the simplified test case presented:

Private shpText as String 

Function ActiveShape() as Visio.Shape
    Set ActiveShape = ActiveWindow.Selection.PrimaryItem
End Function

Sub CopyShapeText()
    If ActiveShape is Nothing then Exit Sub
    shpText = ActiveShape.Text
End Sub

Sub CutShapeText()
    If ActiveShape is Nothing then Exit Sub
    shpText = ActiveShape.Text
    ActiveShape.Text = ""
End Sub

Sub PasteShapeText()
    If ActiveShape is Nothing then Exit Sub
    ActiveShape.Text = shpText
End Sub

Although my problem is solved, my question isn't. For the sake of curiosity, I think it's worthwhile to know whether it's possible to intercept these operations.

Aside: I ended up using the Developer > Macros dialog to set the keyboard shortcuts. Can this be accomplished programmatically without the Application.OnKey event? I ended up putting comments in the code to indicate the shortcuts, but it'd be nicer to have it directly in code.