/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; namespace ooo { namespace vba { const OUString sUrlPart0( "vnd.sun.star.script:" ); const OUString sUrlPart1( "?language=Basic&location=document" ); OUString makeMacroURL( const OUString& sMacroName ) { return sUrlPart0 + sMacroName + sUrlPart1; } OUString extractMacroName( const OUString& rMacroUrl ) { if( rMacroUrl.startsWith( sUrlPart0 ) && rMacroUrl.endsWith( sUrlPart1 ) ) { return rMacroUrl.copy( sUrlPart0.getLength(), rMacroUrl.getLength() - sUrlPart0.getLength() - sUrlPart1.getLength() ); } return OUString(); } OUString trimMacroName( const OUString& rMacroName ) { // the name may contain whitespaces and may be enclosed in apostrophs OUString aMacroName = rMacroName.trim(); sal_Int32 nMacroLen = aMacroName.getLength(); if( (nMacroLen >= 2) && (aMacroName[ 0 ] == '\'') && (aMacroName[ nMacroLen - 1 ] == '\'') ) aMacroName = aMacroName.copy( 1, nMacroLen - 2 ).trim(); return aMacroName; } SfxObjectShell* findShellForUrl( const OUString& sMacroURLOrPath ) { SfxObjectShell* pFoundShell=nullptr; SfxObjectShell* pShell = SfxObjectShell::GetFirst(); INetURLObject aObj; aObj.SetURL( sMacroURLOrPath ); bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid; OUString aURL; if ( bIsURL ) aURL = sMacroURLOrPath; else { osl::FileBase::getFileURLFromSystemPath( sMacroURLOrPath, aURL ); aObj.SetURL( aURL ); } OSL_TRACE("Trying to find shell for url %s", OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 ).getStr() ); while ( pShell ) { uno::Reference< frame::XModel > xModel = pShell->GetModel(); // are we searching for a template? if so we have to cater for the // fact that in openoffice a document opened from a template is always // a new document :/ if ( xModel.is() ) { SAL_INFO( "filter.ms", "shell " << pShell << " has model with url " << xModel->getURL() << " and we look for " << aURL); OUString aName = xModel->getURL() ; if (aName.isEmpty()) { uno::Reference< frame::XFrame > xFrame( xModel->getCurrentController()->getFrame(), uno::UNO_QUERY_THROW ); uno::Reference< beans::XPropertySet > xProps( xFrame, uno::UNO_QUERY_THROW ); xProps->getPropertyValue("Title") >>= aName; sal_Int32 pos = 0; aName = aName.getToken(0,'-',pos); aName = aName.trim(); if( sMacroURLOrPath.lastIndexOf( aName ) >= 0 ) { pFoundShell = pShell; break; } } if ( sMacroURLOrPath.endsWithIgnoreAsciiCase( ".dot" ) ) { uno::Reference const xDocPropSupp(xModel, uno::UNO_QUERY); if (xDocPropSupp.is()) { uno::Reference< document::XDocumentProperties > const xDocProps(xDocPropSupp->getDocumentProperties(), uno::UNO_QUERY_THROW); OUString sCurrName = xDocProps->getTemplateName(); if( sMacroURLOrPath.lastIndexOf( sCurrName ) >= 0 ) { pFoundShell = pShell; break; } } } else { // sometimes just the name of the document ( without the path // is used bool bDocNameNoPathMatch = false; if ( !aURL.isEmpty() && aURL.indexOf( '/' ) == -1 ) { sal_Int32 lastSlashIndex = xModel->getURL().lastIndexOf( '/' ); if ( lastSlashIndex > -1 ) { bDocNameNoPathMatch = xModel->getURL().copy( lastSlashIndex + 1 ).equals( aURL ); if ( !bDocNameNoPathMatch ) { OUString aTmpName = "'" + xModel->getURL().copy( lastSlashIndex + 1 ) + "'"; bDocNameNoPathMatch = aTmpName.equals( aURL ); } } } if ( aURL.equals( xModel->getURL() ) || bDocNameNoPathMatch ) { pFoundShell = pShell; break; } } } pShell = SfxObjectShell::GetNext( *pShell ); } return pFoundShell; } // sMod can be empty ( but we really need the library to search in ) // if sMod is empty and a macro is found then sMod is updated // if sMod is empty, only standard modules will be searched (no class, document, form modules) bool hasMacro( SfxObjectShell* pShell, const OUString& sLibrary, OUString& sMod, const OUString& sMacro ) { bool bFound = false; #if !HAVE_FEATURE_SCRIPTING (void) pShell; (void) sLibrary; (void) sMod; (void) sMacro; #else if ( !sLibrary.isEmpty() && !sMacro.isEmpty() ) { OSL_TRACE("** Searching for %s.%s in library %s" ,OUStringToOString( sMod, RTL_TEXTENCODING_UTF8 ).getStr() ,OUStringToOString( sMacro, RTL_TEXTENCODING_UTF8 ).getStr() ,OUStringToOString( sLibrary, RTL_TEXTENCODING_UTF8 ).getStr() ); BasicManager* pBasicMgr = pShell-> GetBasicManager(); if ( pBasicMgr ) { StarBASIC* pBasic = pBasicMgr->GetLib( sLibrary ); if ( !pBasic ) { sal_uInt16 nId = pBasicMgr->GetLibId( sLibrary ); pBasicMgr->LoadLib( nId ); pBasic = pBasicMgr->GetLib( sLibrary ); } if ( pBasic ) { if ( !sMod.isEmpty() ) // we wish to find the macro is a specific module { SbModule* pModule = pBasic->FindModule( sMod ); if ( pModule && pModule->FindMethod( sMacro, SbxClassType::Method )) { bFound = true; } } else if( SbMethod* pMethod = dynamic_cast< SbMethod* >( pBasic->Find( sMacro, SbxClassType::Method ) ) ) { if( SbModule* pModule = pMethod->GetModule() ) { // when searching for a macro without module name, do not search in class/document/form modules if( pModule->GetModuleType() == script::ModuleType::NORMAL ) { sMod = pModule->GetName(); bFound = true; } } } } } } #endif return bFound; } OUString getDefaultProjectName( SfxObjectShell* pShell ) { OUString aPrjName; if( BasicManager* pBasicMgr = pShell ? pShell->GetBasicManager() : nullptr ) { aPrjName = pBasicMgr->GetName(); if( aPrjName.isEmpty() ) aPrjName = "Standard"; } return aPrjName; } void parseMacro( const OUString& sMacro, OUString& sContainer, OUString& sModule, OUString& sProcedure ) { sal_Int32 nMacroDot = sMacro.lastIndexOf( '.' ); if ( nMacroDot != -1 ) { sProcedure = sMacro.copy( nMacroDot + 1 ); sal_Int32 nContainerDot = sMacro.lastIndexOf( '.', nMacroDot - 1 ); if ( nContainerDot != -1 ) { sModule = sMacro.copy( nContainerDot + 1, nMacroDot - nContainerDot - 1 ); sContainer = sMacro.copy( 0, nContainerDot ); } else sModule = sMacro.copy( 0, nMacroDot ); } else sProcedure = sMacro; } OUString resolveVBAMacro( SfxObjectShell* pShell, const OUString& rLibName, const OUString& rModuleName, const OUString& rMacroName ) { #if !HAVE_FEATURE_SCRIPTING (void) pShell; (void) rLibName; (void) rModuleName; (void) rMacroName; #else if( pShell ) { OUString aLibName = rLibName.isEmpty() ? getDefaultProjectName( pShell ) : rLibName ; OUString aModuleName = rModuleName; if( hasMacro( pShell, aLibName, aModuleName, rMacroName ) ) return aLibName + "." + aModuleName + "." + rMacroName; } #endif return OUString(); } MacroResolvedInfo resolveVBAMacro( SfxObjectShell* pShell, const OUString& MacroName, bool bSearchGlobalTemplates ) { #if !HAVE_FEATURE_SCRIPTING (void) pShell; (void) MacroName; (void) bSearchGlobalTemplates; return MacroResolvedInfo(); #else if( !pShell ) return MacroResolvedInfo(); // the name may be enclosed in apostrophs OUString aMacroName = trimMacroName( MacroName ); // parse the macro name sal_Int32 nDocSepIndex = aMacroName.indexOf( '!' ); if( nDocSepIndex > 0 ) { // macro specified by document name // find document shell for document name and call ourselves // recursively // assume for now that the document name is *this* document OUString sDocUrlOrPath = aMacroName.copy( 0, nDocSepIndex ); aMacroName = aMacroName.copy( nDocSepIndex + 1 ); SAL_INFO("filter.ms", "doc search, current shell is " << pShell); SfxObjectShell* pFoundShell = nullptr; if( bSearchGlobalTemplates ) { SvtPathOptions aPathOpt; OUString aAddinPath = aPathOpt.GetAddinPath(); if( sDocUrlOrPath.startsWith( aAddinPath ) ) pFoundShell = pShell; } if( !pFoundShell ) pFoundShell = findShellForUrl( sDocUrlOrPath ); SAL_INFO( "filter.ms", "doc search, after find, found shell is " << pFoundShell); return resolveVBAMacro( pFoundShell, aMacroName ); } // macro is contained in 'this' document ( or code imported from a template // where that template is a global template or perhaps the template this // document is created from ) MacroResolvedInfo aRes( pShell ); // macro format = Container.Module.Procedure OUString sContainer, sModule, sProcedure; parseMacro( aMacroName, sContainer, sModule, sProcedure ); #if 0 // As long as service VBAProjectNameProvider isn't supported in the model, disable the createInstance call // (the ServiceNotRegisteredException is wrongly caught in ScModelObj::createInstance) uno::Reference< container::XNameContainer > xPrjNameCache; uno::Reference< lang::XMultiServiceFactory> xSF( pShell->GetModel(), uno::UNO_QUERY); if ( xSF.is() ) try { xPrjNameCache.set( xSF->createInstance( "ooo.vba.VBAProjectNameProvider" ), uno::UNO_QUERY ); } catch( const uno::Exception& ) // createInstance may throw { } #endif std::vector< OUString > sSearchList; if ( !sContainer.isEmpty() ) { // service VBAProjectNameProvider not implemented #if 0 // get the Project associated with the Container if ( xPrjNameCache.is() ) { if ( xPrjNameCache->hasByName( sContainer ) ) { OUString sProject; xPrjNameCache->getByName( sContainer ) >>= sProject; sContainer = sProject; } } #endif sSearchList.push_back( sContainer ); // First Lib to search } else { // Ok, if we have no Container specified then we need to search them in order, this document, template this document created from, global templates, // get the name of Project/Library for 'this' document OUString sThisProject( "Standard" ); try { uno::Reference< beans::XPropertySet > xProps( pShell->GetModel(), uno::UNO_QUERY_THROW ); uno::Reference< script::vba::XVBACompatibility > xVBAMode( xProps->getPropertyValue( "BasicLibraries" ), uno::UNO_QUERY_THROW ); sThisProject = xVBAMode->getProjectName(); } catch( const uno::Exception& /*e*/) {} sSearchList.push_back( sThisProject ); // First Lib to search // service VBAProjectNameProvider not implemented #if 0 if ( xPrjNameCache.is() ) { // is this document created from a template? uno::Reference< document::XDocumentPropertiesSupplier > const xDocPropSupp(pShell->GetModel(), uno::UNO_QUERY_THROW); uno::Reference< document::XDocumentProperties > xDocProps( xDocPropSupp->getDocumentProperties(), uno::UNO_QUERY_THROW ); OUString sCreatedFrom = xDocProps->getTemplateURL(); if ( !sCreatedFrom.isEmpty() ) { INetURLObject aObj; aObj.SetURL( sCreatedFrom ); bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid; OUString aURL; if ( bIsURL ) aURL = sCreatedFrom; else { osl::FileBase::getFileURLFromSystemPath( sCreatedFrom, aURL ); aObj.SetURL( aURL ); } sCreatedFrom = aObj.GetLastName(); } sal_Int32 nIndex = sCreatedFrom.lastIndexOf( '.' ); if ( nIndex != -1 ) sCreatedFrom = sCreatedFrom.copy( 0, nIndex ); OUString sPrj; if ( !sCreatedFrom.isEmpty() && xPrjNameCache->hasByName( sCreatedFrom ) ) { xPrjNameCache->getByName( sCreatedFrom ) >>= sPrj; // Make sure we don't double up with this project if ( !sPrj.equals( sThisProject ) ) sSearchList.push_back( sPrj ); } // get list of global template Names uno::Sequence< OUString > sTemplateNames = xPrjNameCache->getElementNames(); sal_Int32 nLen = sTemplateNames.getLength(); for ( sal_Int32 index = 0; ( bSearchGlobalTemplates && index < nLen ); ++index ) { if ( !sCreatedFrom.equals( sTemplateNames[ index ] ) ) { if ( xPrjNameCache->hasByName( sTemplateNames[ index ] ) ) { xPrjNameCache->getByName( sTemplateNames[ index ] ) >>= sPrj; // Make sure we don't double up with this project if ( !sPrj.equals( sThisProject ) ) sSearchList.push_back( sPrj ); } } } } #endif } std::vector< OUString >::iterator it_end = sSearchList.end(); for ( std::vector< OUString >::iterator it = sSearchList.begin(); !aRes.mbFound && (it != it_end); ++it ) { aRes.mbFound = hasMacro( pShell, *it, sModule, sProcedure ); if ( aRes.mbFound ) sContainer = *it; } //aRes.msResolvedMacro = sProcedure.Insert( '.', 0 ).Insert( sModule, 0).Insert( '.', 0 ).Insert( sContainer, 0 ); aRes.msResolvedMacro = sContainer + "." + sModule + "." + sProcedure; return aRes; #endif } // Treat the args as possible inputs (conversion at bottom of method) bool executeMacro( SfxObjectShell* pShell, const OUString& sMacroName, uno::Sequence< uno::Any >& aArgs, uno::Any& aRet, const uno::Any& /*aCaller*/) { #if !HAVE_FEATURE_SCRIPTING (void) pShell; (void) sMacroName; (void) aArgs; (void) aRet; return false; #else bool bRes = false; if ( !pShell ) return bRes; OUString sUrl = makeMacroURL( sMacroName ); uno::Sequence< sal_Int16 > aOutArgsIndex; uno::Sequence< uno::Any > aOutArgs; try { ErrCode nErr( ERRCODE_BASIC_INTERNAL_ERROR ); if ( pShell ) { nErr = pShell->CallXScript( sUrl, aArgs, aRet, aOutArgsIndex, aOutArgs, false ); sal_Int32 nLen = aOutArgs.getLength(); // convert any out params to seem like they were inputs if ( nLen ) { for ( sal_Int32 index=0; index < nLen; ++index ) { sal_Int32 nOutIndex = aOutArgsIndex[ index ]; aArgs[ nOutIndex ] = aOutArgs[ index ]; } } } bRes = ( nErr == ERRCODE_NONE ); } catch ( const uno::Exception& ) { bRes = false; } return bRes; #endif } uno::Sequence< OUString > VBAMacroResolver_getSupportedServiceNames() { uno::Sequence aServiceNames { "com.sun.star.script.vba.VBAMacroResolver" }; return aServiceNames; } OUString VBAMacroResolver_getImplementationName() { return OUString( "com.sun.star.comp.vba.VBAMacroResolver" ); } uno::Reference< uno::XInterface > SAL_CALL VBAMacroResolver_createInstance( const uno::Reference< uno::XComponentContext >& ) throw (uno::Exception) { return static_cast< ::cppu::OWeakObject* >( new VBAMacroResolver ); } VBAMacroResolver::VBAMacroResolver() : mpObjShell( nullptr ) { } VBAMacroResolver::~VBAMacroResolver() { } // com.sun.star.lang.XServiceInfo interface ----------------------------------- OUString SAL_CALL VBAMacroResolver::getImplementationName() throw (uno::RuntimeException, std::exception) { return VBAMacroResolver_getImplementationName(); } sal_Bool SAL_CALL VBAMacroResolver::supportsService( const OUString& rService ) throw (uno::RuntimeException, std::exception) { return cppu::supportsService(this, rService); } uno::Sequence< OUString > SAL_CALL VBAMacroResolver::getSupportedServiceNames() throw (uno::RuntimeException, std::exception) { return VBAMacroResolver_getSupportedServiceNames(); } // com.sun.star.lang.XInitialization interface -------------------------------- void SAL_CALL VBAMacroResolver::initialize( const uno::Sequence< uno::Any >& rArgs ) throw (uno::Exception, uno::RuntimeException, std::exception) { OSL_ENSURE( rArgs.getLength() < 2, "VBAMacroResolver::initialize - missing arguments" ); if( rArgs.getLength() < 2 ) throw uno::RuntimeException(); // first argument: document model mxModel.set( rArgs[ 0 ], uno::UNO_QUERY_THROW ); uno::Reference< lang::XUnoTunnel > xUnoTunnel( mxModel, uno::UNO_QUERY_THROW ); mpObjShell = reinterpret_cast< SfxObjectShell* >( xUnoTunnel->getSomething( SfxObjectShell::getUnoTunnelId() ) ); if( !mpObjShell ) throw uno::RuntimeException(); // second argument: VBA project name if( !(rArgs[ 1 ] >>= maProjectName) || (maProjectName.isEmpty()) ) throw uno::RuntimeException(); } // com.sun.star.script.vba.XVBAMacroResolver interface ------------------------ OUString SAL_CALL VBAMacroResolver::resolveVBAMacroToScriptURL( const OUString& rVBAMacroName ) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) { if( !mpObjShell ) throw uno::RuntimeException(); // the name may be enclosed in apostrophs OUString aMacroName = trimMacroName( rVBAMacroName ); if( aMacroName.isEmpty() ) throw lang::IllegalArgumentException(); // external references not supported here (syntax is "url!macroname" or "[url]!macroname" or "[url]macroname") if( (aMacroName[ 0 ] == '[') || (aMacroName.indexOf( '!' ) >= 0) ) throw lang::IllegalArgumentException(); // check if macro name starts with project name, replace with "Standard" // TODO: adjust this when custom VBA project name is supported sal_Int32 nDotPos = aMacroName.indexOf( '.' ); if( (nDotPos == 0) || (nDotPos + 1 == aMacroName.getLength()) ) throw lang::IllegalArgumentException(); if( (nDotPos > 0) && aMacroName.matchIgnoreAsciiCase( maProjectName ) ) aMacroName = aMacroName.copy( nDotPos + 1 ); // try to find the macro MacroResolvedInfo aInfo = resolveVBAMacro( mpObjShell, aMacroName ); if( !aInfo.mbFound ) throw lang::IllegalArgumentException(); // build and return the script URL return makeMacroURL( aInfo.msResolvedMacro ); } OUString SAL_CALL VBAMacroResolver::resolveScriptURLtoVBAMacro( const OUString& /*rScriptURL*/ ) throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception) { OSL_ENSURE( false, "VBAMacroResolver::resolveScriptURLtoVBAMacro - not implemented" ); throw uno::RuntimeException(); } bool getModifier( char c, sal_uInt16& mod ) { if ( c == '+' ) { mod |= KEY_SHIFT; return true; } else if ( c == '^' ) { mod |= KEY_MOD1; return true; } else if ( c == '%' ) { mod |= KEY_MOD2; return true; } return false; } 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 |= ( rtl::toAsciiUpperCase( c ) - 'A' ) + KEY_A; if ( rtl::isAsciiUpperCase( c ) ) nVclKey |= KEY_SHIFT; } else if ( isdigit( c ) ) nVclKey |= ( c - '0' ) + KEY_0; else if ( c == '~' ) // special case nVclKey = KEY_RETURN; else if ( c == ' ' ) // special case nVclKey = KEY_SPACE; 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 }, { "SCROLLLOCK", KEY_SCROLLLOCK }, { "NUMLOCK", KEY_NUMLOCK }, { "TAB", KEY_TAB }, { "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 OUString& Key ) throw ( uno::RuntimeException ) { static std::map< OUString, sal_uInt16 > s_KeyCodes; if ( s_KeyCodes.empty() ) { for (KeyCodeEntry & i : aMSKeyCodesData) { s_KeyCodes[ OUString::createFromAscii( i.sName ) ] = i.nCode; } } OUString sKeyCode; sal_uInt16 nVclKey = 0; // parse the modifier if any for ( int i=0; isecond; } } awt::KeyEvent aKeyEvent = svt::AcceleratorExecute::st_VCLKey2AWTKey( vcl::KeyCode( nVclKey ) ); return aKeyEvent; } void applyShortCutKeyBinding ( const uno::Reference< frame::XModel >& rxModel, const awt::KeyEvent& rKeyEvent, const OUString& rMacroName ) throw (uno::RuntimeException, std::exception) { OUString MacroName( rMacroName ); if ( !MacroName.isEmpty() ) { OUString aMacroName = MacroName.trim(); if( aMacroName.startsWith("!") ) MacroName = aMacroName.copy(1).trim(); SfxObjectShell* pShell = nullptr; if ( rxModel.is() ) { uno::Reference< lang::XUnoTunnel > xObjShellTunnel( rxModel, uno::UNO_QUERY_THROW ); pShell = reinterpret_cast( xObjShellTunnel->getSomething(SfxObjectShell::getUnoTunnelId())); if ( !pShell ) throw uno::RuntimeException(); } MacroResolvedInfo aMacroInfo = resolveVBAMacro( pShell, aMacroName ); if( !aMacroInfo.mbFound ) throw uno::RuntimeException( "The procedure doesn't exist" ); MacroName = aMacroInfo.msResolvedMacro; } uno::Reference< ui::XUIConfigurationManagerSupplier > xCfgSupplier(rxModel, 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( rKeyEvent ); else xAcc->setKeyEvent( rKeyEvent, ooo::vba::makeMacroURL( MacroName ) ); } } // namespace vba } // namespace ooo /* vim:set shiftwidth=4 softtabstop=4 expandtab: */