diff options
-rw-r--r-- | filter/inc/filter/msfilter/msvbahelper.hxx | 4 | ||||
-rw-r--r-- | filter/source/msfilter/msvbahelper.cxx | 128 | ||||
-rw-r--r-- | oovbaapi/ooo/vba/XApplicationBase.idl | 2 | ||||
-rw-r--r-- | vbahelper/inc/vbahelper/vbaapplicationbase.hxx | 1 | ||||
-rw-r--r-- | vbahelper/source/vbahelper/vbaapplicationbase.cxx | 49 |
5 files changed, 181 insertions, 3 deletions
diff --git a/filter/inc/filter/msfilter/msvbahelper.hxx b/filter/inc/filter/msfilter/msvbahelper.hxx index affc8b227346..99b20c152400 100644 --- a/filter/inc/filter/msfilter/msvbahelper.hxx +++ b/filter/inc/filter/msfilter/msvbahelper.hxx @@ -33,8 +33,8 @@ #include <com/sun/star/lang/XInitialization.hpp> #include <com/sun/star/lang/XServiceInfo.hpp> #include <com/sun/star/script/vba/XVBAMacroResolver.hpp> +#include <com/sun/star/awt/KeyEvent.hpp> #include "filter/msfilter/msfilterdllapi.h" - namespace ooo { namespace vba { @@ -55,7 +55,7 @@ MSFILTER_DLLPUBLIC ::rtl::OUString getDefaultProjectName( SfxObjectShell* pShell MSFILTER_DLLPUBLIC ::rtl::OUString resolveVBAMacro( SfxObjectShell* pShell, const ::rtl::OUString& rLibName, const ::rtl::OUString& rModuleName, const ::rtl::OUString& rMacroName ); MSFILTER_DLLPUBLIC MacroResolvedInfo resolveVBAMacro( SfxObjectShell* pShell, const ::rtl::OUString& rMacroName, bool bSearchGlobalTemplates = false ); MSFILTER_DLLPUBLIC sal_Bool executeMacro( SfxObjectShell* pShell, const String& sMacroName, com::sun::star::uno::Sequence< com::sun::star::uno::Any >& aArgs, com::sun::star::uno::Any& aRet, const com::sun::star::uno::Any& aCaller ); - +MSFILTER_DLLPUBLIC ::com::sun::star::awt::KeyEvent parseKeyEvent( const ::rtl::OUString& sKey ) throw (::com::sun::star::uno::RuntimeException); // ============================================================================ typedef ::cppu::WeakImplHelper3< diff --git a/filter/source/msfilter/msvbahelper.cxx b/filter/source/msfilter/msvbahelper.cxx index 07a40c05092b..fb4fd3d40939 100644 --- a/filter/source/msfilter/msvbahelper.cxx +++ b/filter/source/msfilter/msvbahelper.cxx @@ -42,6 +42,10 @@ #include <osl/file.hxx> #include <unotools/pathoptions.hxx> +#include <com/sun/star/awt/KeyModifier.hpp> +#include <svtools/acceleratorexecute.hxx> +#include <map> + using namespace ::com::sun::star; namespace ooo { @@ -580,6 +584,130 @@ void SAL_CALL VBAMacroResolver::initialize( const uno::Sequence< uno::Any >& rAr OSL_ENSURE( false, "VBAMacroResolver::resolveScriptURLtoVBAMacro - not implemented" ); throw uno::RuntimeException(); } +bool getModifier( char c, sal_uInt16& mod ) +{ + static const char modifiers[] = "+^%"; + static const sal_uInt16 KEY_MODS[] = {KEY_SHIFT, KEY_MOD1, KEY_MOD2}; + + for ( unsigned int i=0; i<SAL_N_ELEMENTS(modifiers); ++i ) + { + if ( c == modifiers[i] ) + { + mod = mod | KEY_MODS[ i ]; + return true; + } + } + return false; +} + +typedef std::map< rtl::OUString, sal_uInt16 > MSKeyCodeMap; + +sal_uInt16 parseChar( char c ) throw ( uno::RuntimeException ) +{ + sal_uInt16 nVclKey = 0; + // do we care about locale here for isupper etc. ? probably not + if ( isalpha( c ) ) + nVclKey |= ( toupper( c ) - 'A' ) + KEY_A; + else if ( isdigit( c ) ) + nVclKey |= ( c - '0' ) + KEY_0; + else if ( c == '~' ) // special case + nVclKey = KEY_RETURN; + else // I guess we have a problem ( but not sure if locale specific keys might come into play here ) + throw uno::RuntimeException(); + return nVclKey; +} + +struct KeyCodeEntry +{ + const char* sName; + sal_uInt16 nCode; +}; + +KeyCodeEntry aMSKeyCodesData[] = { + { "BACKSPACE", KEY_BACKSPACE }, + { "BS", KEY_BACKSPACE }, + { "DELETE", KEY_DELETE }, + { "DEL", KEY_DELETE }, + { "DOWN", KEY_DOWN }, + { "UP", KEY_UP }, + { "LEFT", KEY_LEFT }, + { "RIGHT", KEY_RIGHT }, + { "END", KEY_END }, + { "ESCAPE", KEY_ESCAPE }, + { "ESC", KEY_ESCAPE }, + { "HELP", KEY_HELP }, + { "HOME", KEY_HOME }, + { "PGDN", KEY_PAGEDOWN }, + { "PGUP", KEY_PAGEUP }, + { "INSERT", KEY_INSERT }, + { "F1", KEY_F1 }, + { "F2", KEY_F2 }, + { "F3", KEY_F3 }, + { "F4", KEY_F4 }, + { "F5", KEY_F5 }, + { "F6", KEY_F6 }, + { "F7", KEY_F7 }, + { "F8", KEY_F8 }, + { "F9", KEY_F1 }, + { "F10", KEY_F10 }, + { "F11", KEY_F11 }, + { "F12", KEY_F12 }, + { "F13", KEY_F13 }, + { "F14", KEY_F14 }, + { "F15", KEY_F15 }, +}; + +awt::KeyEvent parseKeyEvent( const ::rtl::OUString& Key ) throw ( uno::RuntimeException ) +{ + static MSKeyCodeMap msKeyCodes; + if ( msKeyCodes.empty() ) + { + for ( unsigned int i = 0; i < SAL_N_ELEMENTS( aMSKeyCodesData ); ++i ) + { + msKeyCodes[ rtl::OUString::createFromAscii( aMSKeyCodesData[ i ].sName ) ] = aMSKeyCodesData[ i ].nCode; + } + } + rtl::OUString sKeyCode; + sal_uInt16 nVclKey = 0; + + // parse the modifier if any + for ( int i=0; i<Key.getLength(); ++i ) + { + if ( ! getModifier( Key[ i ], nVclKey ) ) + { + sKeyCode = Key.copy( i ).trim(); + break; + } + } + + // check if keycode is surrounded by '{}', if so scoop out the contents + // else it should be just one char of ( 'a-z,A-Z,0-9' ) + if ( sKeyCode.getLength() == 1 ) // ( a single char ) + { + char c = (char)( sKeyCode[ 0 ] ); + nVclKey |= parseChar( c ); + } + else // key should be enclosed in '{}' + { + if ( sKeyCode.getLength() < 3 || !( sKeyCode[0] == '{' && sKeyCode[sKeyCode.getLength() - 1 ] == '}' ) ) + throw uno::RuntimeException(); + + sKeyCode = sKeyCode.copy(1, sKeyCode.getLength() - 2 ); + + if ( sKeyCode.getLength() == 1 ) + nVclKey |= parseChar( (char)( sKeyCode[ 0 ] ) ); + else + { + MSKeyCodeMap::iterator it = msKeyCodes.find( sKeyCode ); + if ( it == msKeyCodes.end() ) // unknown or unsupported + throw uno::RuntimeException(); + nVclKey |= it->second; + } + } + + awt::KeyEvent aKeyEvent = svt::AcceleratorExecute::st_VCLKey2AWTKey( KeyCode( nVclKey ) ); + return aKeyEvent; +} // ============================================================================ diff --git a/oovbaapi/ooo/vba/XApplicationBase.idl b/oovbaapi/ooo/vba/XApplicationBase.idl index d46eb2446e31..93f39aed3ff7 100644 --- a/oovbaapi/ooo/vba/XApplicationBase.idl +++ b/oovbaapi/ooo/vba/XApplicationBase.idl @@ -47,7 +47,7 @@ interface XApplicationBase [attribute, readonly] any VBE; void Quit(); - + void OnKey( [in] string Key, [in] any Procedure ); any CommandBars( [in] any Index ); any Run([in] string MacroName, [in] /*Optional*/ any varg1, [in] /*Optional*/ any varg2, [in] /*Optional*/ any varg3, [in] /*Optional*/ any varg4, [in] /*Optional*/ any varg5, [in] /*Optional*/ any varg6, [in] /*Optional*/ any varg7, [in] /*Optional*/ any varg8, [in] /*Optional*/ any varg9, [in] /*Optional*/ any varg10, [in] /*Optional*/ any varg11, [in] /*Optional*/ any varg12, [in] /*Optional*/ any varg13, [in] /*Optional*/ any varg14, [in] /*Optional*/ any varg15, [in] /*Optional*/ any varg16, [in] /*Optional*/ any varg17, [in] /*Optional*/ any varg18, [in] /*Optional*/ any varg19, [in] /*Optional*/ any varg20, [in] /*Optional*/ any varg21, [in] /*Optional*/ any varg22, [in] /*Optional*/ any varg23, [in] /*Optional*/ any varg24, [in] /*Optional*/ any varg25, [in] /*Optional*/ any varg26, [in] /*Optional*/ any varg27, [in] /*Optional*/ any varg28, [in] /*Optional*/ any varg29, [in] /*Optional*/ any varg30); void OnTime( [in] any EarliestTime, [in] string Procedure, [in] any LatestTime, [in] any Schedule ); diff --git a/vbahelper/inc/vbahelper/vbaapplicationbase.hxx b/vbahelper/inc/vbahelper/vbaapplicationbase.hxx index 7d21d3ed453b..a27afa5d5b01 100644 --- a/vbahelper/inc/vbahelper/vbaapplicationbase.hxx +++ b/vbahelper/inc/vbahelper/vbaapplicationbase.hxx @@ -58,6 +58,7 @@ public: virtual void SAL_CALL setInteractive( ::sal_Bool bInteractive ) throw (css::uno::RuntimeException); virtual ::sal_Bool SAL_CALL getVisible() throw (css::uno::RuntimeException); virtual void SAL_CALL setVisible( ::sal_Bool bVisible ) throw (css::uno::RuntimeException); + virtual void SAL_CALL OnKey( const ::rtl::OUString& Key, const ::com::sun::star::uno::Any& Procedure ) throw (::com::sun::star::uno::RuntimeException); virtual css::uno::Any SAL_CALL CommandBars( const css::uno::Any& aIndex ) throw (css::uno::RuntimeException); virtual ::rtl::OUString SAL_CALL getVersion() throw (css::uno::RuntimeException); virtual css::uno::Any SAL_CALL getVBE() throw (css::uno::RuntimeException); diff --git a/vbahelper/source/vbahelper/vbaapplicationbase.cxx b/vbahelper/source/vbahelper/vbaapplicationbase.cxx index 293d6b0eaaf6..f1ec673e8270 100644 --- a/vbahelper/source/vbahelper/vbaapplicationbase.cxx +++ b/vbahelper/source/vbahelper/vbaapplicationbase.cxx @@ -42,7 +42,10 @@ #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> #include <com/sun/star/document/XEmbeddedScripts.hpp> #include <com/sun/star/awt/XWindow2.hpp> +#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp> +#include <com/sun/star/ui/XUIConfigurationManager.hpp> +#include <svtools/acceleratorexecute.hxx> #include <boost/unordered_map.hpp> #include <filter/msfilter/msvbahelper.hxx> #include <tools/datetime.hxx> @@ -277,6 +280,52 @@ void SAL_CALL VbaApplicationBase::setVisible( sal_Bool bVisible ) throw (uno::Ru m_pImpl->mbVisible = bVisible; // dummy implementation } + +void SAL_CALL +VbaApplicationBase::OnKey( const ::rtl::OUString& Key, const uno::Any& Procedure ) throw (uno::RuntimeException) +{ + // parse the Key & modifiers + awt::KeyEvent aKeyEvent = parseKeyEvent( Key ); + rtl::OUString MacroName; + Procedure >>= MacroName; + uno::Reference< frame::XModel > xModel; + SbMethod* pMeth = StarBASIC::GetActiveMethod(); + if ( pMeth ) + { + SbModule* pMod = dynamic_cast< SbModule* >( pMeth->GetParent() ); + if ( pMod ) + xModel = StarBASIC::GetModelFromBasic( pMod ); + } + + if ( !xModel.is() ) + xModel = getCurrentDocument(); + + if ( !MacroName.isEmpty() ) + { + ::rtl::OUString sSeparator(RTL_CONSTASCII_USTRINGPARAM("/")); + ::rtl::OUString sMacroSeparator(RTL_CONSTASCII_USTRINGPARAM("!")); + ::rtl::OUString aMacroName = MacroName.trim(); + if (0 == aMacroName.indexOf('!')) + MacroName = aMacroName.copy(1).trim(); + + MacroResolvedInfo aMacroInfo = resolveVBAMacro( getSfxObjShell( xModel ), aMacroName ); + if( !aMacroInfo.mbFound ) + throw uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("The procedure doesn't exist") ), uno::Reference< uno::XInterface >() ); + MacroName = aMacroInfo.msResolvedMacro; + } + uno::Reference< ui::XUIConfigurationManagerSupplier > xCfgSupplier(xModel, uno::UNO_QUERY_THROW); + uno::Reference< ui::XUIConfigurationManager > xCfgMgr = xCfgSupplier->getUIConfigurationManager(); + + uno::Reference< ui::XAcceleratorConfiguration > xAcc( xCfgMgr->getShortCutManager(), uno::UNO_QUERY_THROW ); + if ( MacroName.isEmpty() ) + // I believe this should really restore the [application] default. Since + // afaik we don't actually setup application default bindings on import + // we don't even know what the 'default' would be for this key + xAcc->removeKeyEvent( aKeyEvent ); + else + xAcc->setKeyEvent( aKeyEvent, ooo::vba::makeMacroURL( MacroName ) ); +} + uno::Any SAL_CALL VbaApplicationBase::CommandBars( const uno::Any& aIndex ) throw (uno::RuntimeException) { |