ctrl+s bypasses repurpose of FileSave

Started by paulv45, June 19, 2010, 08:49:21 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

paulv45

I am repurposing the FileSave command using normal XML customization techniques.
Works fine for File menu and Quick Access icon but ctrl+s appears to bypass the repurpose.
http://social.msdn.microsoft.com/Forums/en-US/exceldev/thread/6315b75e-e324-4c2b-a849-c22d4ccb28cb
seems to indicate that as of 6/15/10 this works in Word but is a known bug in other Office apps.  While Visio is not explicitly listed my guess is this is broken there also.
Any thoughts, workarounds?
Thanks.
Paul

JuneTheSecond

#1
I am not good in Ribbon, but I felt something strange when I first heard in the case of Visio customization.
Now, code samples are available in Visio 2010 SDK at
http://blogs.msdn.com/b/visio/archive/2010/05/05/visio-2010-sdk-and-visio-2010-viewer-available-for-download.aspx
The documents that may be useful are
"Custom User Interface Implementation",
"Document Custom User Interface", and
"Ribbon XML".
Best Regards,

Junichi Yoda
http://june.minibird.jp/

JuneTheSecond

And as far as the test using above samples,
not only "Ctrl+s" but also all short cut keys seem to bypass the repurpose. ;) ;)
Best Regards,

Junichi Yoda
http://june.minibird.jp/

paulv45

Thanks for the link and pointers to info, Junichi.
And for what I believe is confirmation that his is broken along with info that all keyboard shortcuts bypassing repurpose.
Paul

JuneTheSecond

I think the system of Visio shortcut keys slightly differs from other Office application.
Visio shortcut keys are in the AccelTabe that is in Visio UIObject.AccelTables.
It seems Ribbon interface has not yet well included UIObject nor AccelTables.  ;) ;) ;)
Best Regards,

Junichi Yoda
http://june.minibird.jp/

Nikolay

#5
Quote from: paulv45 on June 19, 2010, 08:49:21 PM
I am repurposing the FileSave command using normal XML customization techniques.
Works fine for File menu and Quick Access icon but ctrl+s appears to bypass the repurpose.
http://social.msdn.microsoft.com/Forums/en-US/exceldev/thread/6315b75e-e324-4c2b-a849-c22d4ccb28cb
seems to indicate that as of 6/15/10 this works in Word but is a known bug in other Office apps.  While Visio is not explicitly listed my guess is this is broken there also.
Any thoughts, workarounds?
Thanks.
Paul


Hello Paul,
If it is good enough for you to be notified when a document is being saved,
then you could use "BeforeDocumentSaved" event (of the class "Documents") for example.
Means, you could subscribe to this event and monitor it.

Unfortunately unlike "repurposing" this approach wouold not allow you to cancel the default (save) action and do something entirely different instead.

I could suggest the following workaround for this (Ctrl+S) issue - but be prepared, it seems to be a tough one :)
It overwrites Visio's main window proc, and redirects internal "Save" command to the custom handler.
The code assumes you have created a managed code Visio add-in named "Connect", and have something like the following xml in the ribbon definition:

<customUI xmlns="http://bla-bla-bla" >
 <commands>
   <command idMso="FileSave" onAction="ReFileSave"/>
 </commands>


The code


   // redirects Ctrl+S for the ribbon
   public class SubclassVisioWnd : NativeWindow
   {
       protected override void WndProc(ref Message m)
       {
           if (m.Msg == 0x111) // if we have WM_COMMAND
           {
               // if the command is "File Save"
               if ((short)m.WParam == (short)VisUICmds.visCmdFileSave)
               {
                   MessageBox.Show(@"ReFileSave2");
                   return;
               }
           }

           // forward message to base WndProc
           base.WndProc(ref m);
       }
   }

   public class Connect
       : Object
       , IDTExtensibility2
       , IRibbonExtensibility
   {
       private IVApplication _application;
       private SubclassVisioWnd _visioWnd;

       public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
       {
           _application = (IVApplication)application;

           _visioWnd = new SubclassVisioWnd();
           _visioWnd.AssignHandle((IntPtr)_application.WindowHandle32);
       }

       // our repurpose method to be called
       public void ReFileSave(IRibbonControl control, ref bool cancelDefault)
       {
           MessageBox.Show(@"ReFileSave");
       }

       // IRibbonExtensibility implementation
       public string GetCustomUI(string ribbonId)
       {
           return Resources.Ribbon;
       }


NB: the code seems to work for the older Visio versions as well (e.g. 2003, 2007).
Though this is definitely NOT a supported way of working with Visio.

Kind regards, Nikolay.

paulv45

Thanks Nikolay for jumping in here with detailed solution.  It sounds like what I am looking for as workaround.  As you noted, it's pretty aggressive.  It will likely take me a couple of days to digest then I'll get back.
Paul

JuneTheSecond

#7
Here it is another idea, though it is document level written in VBA.  ;) ;) ;)
Best Regards,

Junichi Yoda
http://june.minibird.jp/

paulv45

I have tried the "JuneTheSecond" solution and it appears to work beautifully.
I dropped the code into the Ribbon onLoad for my ribbon and presto.
Thanks, Junichi!!!
One small gotcha...
Be aware that the ribbon and shortcut callback signatures are different.
If the repurpose XML is something like:
  <commands>
     <command idMso="FileSave" onAction="MySave"/>
  </commands
The ctrl+s will be something like:
  vsoAccelItem.AddOnName = "MySave2"
And the supporting code:

Public Sub MySave(ByVal control As IRibbonControl, ByRef cancelDefault)
   Debug.Print "MySave"
   MySave2
   cancelDefault = False
End Sub

Public Sub MySave2()
   Debug.Print "MySave2"
End Sub

Unfortunately the shortcut override fails silently if the signature is wrong.

Paul

JuneTheSecond

#9
Please, forget my idea. Shortcut is not RibbonUI, but AccelTable.  ;) ;) ;)
You need to run "AccelItems_Example" to reporpose file save shortcut.
Best Regards,

Junichi Yoda
http://june.minibird.jp/

paulv45

Here's the "AccelItems_Example" I believe Junichi referenced:
http://help.outlook.com/en-us/140/ms427953.aspx
Based on that and some previous accelerator override experience, I created the following document level VBA code that seems to do the trick.  I submit it for review and critique.
Paul


Public Sub RepurposeFileSave()
   'As of 6/24/10 there is a Visio bug where shortcut (accelerator) keys bypass repurpose.
   'This is a purposed workaround.
   'Before running RepurposeFileSave note that "File, Save" from ribbon and "ctrl+s"
   'both save the document.
   'Run RepurposeFileSave, save the file, close, and reopen.
   '(The ribbon repurpose does not take effect until you close and reopen the file.)
   '"File, Save" from ribbon shows "MySave" and "MySave2" in immediate window.
   '"ctrl+s" shows "MySave2" in immediate window.
   'Run UnRepurposeFileSave, save (from VBA), close, and reopen to restore normal "File Save"
   '& ctrl+s operation.

   'Repurpose Ribbon Visio FileSave
   ThisDocument.CustomUI = _
       "<?xml version=""1.0"" encoding=""UTF-8""?> " _
       & "<customUI " _
       & "onLoad=""RepurposeAcceleratorFileSave"" " _
       & "xmlns=""http://schemas.microsoft.com/office/2006/01/customui""> " _
       & "   <commands> " _
       & "      <command idMso=""FileSave"" onAction=""MySave""/> " _
       & "   </commands> " _
       & "</customUI>"
End Sub

Public Sub UnRepurposeFileSave()
   ThisDocument.CustomUI = ""
End Sub

Public Sub RepurposeAcceleratorFileSave(ribbon As IRibbonUI)
   
   Dim vsoUIObject As Visio.UIObject
   Dim vsoAccelTable As Visio.AccelTable
   Dim vsoAccelItems As Visio.AccelItems
   Dim vsoAccelItem As Visio.AccelItem
   Dim intCounter As Integer
   
   'Repurpose Accelerator FileSave
   Set vsoUIObject = Visio.Application.BuiltInMenus
   Set vsoAccelTable = vsoUIObject.AccelTables.ItemAtID(visUIObjSetDrawing)
   Set vsoAccelItems = vsoAccelTable.AccelItems
   For intCounter = 0 To vsoAccelItems.Count - 1
       Set vsoAccelItem = vsoAccelItems.Item(intCounter)
       If vsoAccelItem.CmdNum = Visio.visCmdFileSave Then
           'Send any key the does a VisioSave to MySave2.
           'Most likely just ctrl+s
           vsoAccelItem.AddOnName = "MySave2"
       End If
   Next intCounter
   
   ThisDocument.SetCustomMenus vsoUIObject
   vsoUIObject.UpdateUI
End Sub

Public Sub MySave(ByVal control As IRibbonControl, ByRef cancelDefault)
   'Note there are 2 versions of MySave due to procedure signiture differences
   'between repurposed command and accelerator.
   Debug.Print "MySave"
   MySave2
   cancelDefault = True
End Sub

Public Sub MySave2()
   'Accelerator ctrl+s repurpose
   Debug.Print "MySave2"
End Sub

JuneTheSecond

#11
Very Cool, Paul!
Thank you for a fine code.
Though it is too late, now I studied about CustomUI and onload property.

By the way, you don't need to reopen document,
if you start "RepurposeAcceleratorFileSave" at onload in  RegisterRibbonX method.
But reopen is not problem, because Document.CustomUI is saved in the Visio drawing.
Every time you open the drawing, filesave and its shortcut key are always repurposed.

Because I could not find "unload" or "offload" property in Ribbon XML,
I could not find elegant way to offload "RepurposeAcceleratorFileSave" when loaded in RegisterRibbonX method.
Best Regards,

Junichi Yoda
http://june.minibird.jp/

paulv45

Thanks for your kind words, Junichi.
I looked a bit at the Application.RegisterRibbonX Method you talked about.
My reading leads me to believe this is strictly for COM add-ins.
My eventual application is an add-in delivered as VBA in a stencil so I don't think the RegisterRibbonX method applies.
Am I thinking straight here?
Thanks.
Paul