public bool Init(IEnumerable <String> extensionDirs) { if (_agentsCache == null) { _agentsCache = new AgentsCache(); _agentsCache.EvtAgentAdded += _agentsCache_EvtAgentAdded; _agentsCache.Init(extensionDirs); _genericAppAgent = _agentsCache.GetAgent(GenericAppAgentName); if (_genericAppAgent == null) { _agentsCache.AddAgentByType(typeof(UnsupportedAppAgent)); _genericAppAgent = _agentsCache.GetAgent(GenericAppAgentName); } _agentsCache.AddAgentByType(typeof(NullAgent)); _nullAgent = _agentsCache.GetAgent(NullAgentName); _dialogAgent = _agentsCache.GetAgent(DialogControlAgentName); _menuControlAgent = _agentsCache.GetAgent(MenuControlAgentName); _textControlAgent = _genericAppAgent.TextControlAgent; WindowActivityMonitor.EvtFocusChanged += WindowActivityMonitor_EvtFocusChanged; getKeyboardActuator(); WindowActivityMonitor.GetActiveWindow(); } return(true); }
/// <summary> /// Call this function to raise events to indicated that something changed /// in the text window either due to editing or due to cursor movement. Event /// raised is asynchronous /// </summary> /// <param name="textInterface">text agent</param> protected void triggerTextChangedAsync(ITextControlAgent textInterface) { if (EvtTextChanged != null) { EvtTextChanged.BeginInvoke(textInterface, new TextChangedEventArgs(textInterface), null, null); } }
/// <summary> /// Call this function to raise events to indicated that something changed /// in the text window either due to editing or due to cursor movement. Event /// raised is synchronous /// </summary> /// <param name="textInterface">text agent</param> protected void triggerTextChanged(ITextControlAgent textInterface) { if (EvtTextChanged != null) { EvtTextChanged(this, new TextChangedEventArgs(textInterface)); } }
/// <summary> /// Dispose resources /// </summary> /// <param name="disposing">Disposed yet?</param> private void dispose(bool disposing) { if (!_disposed) { _textControlAgent = null; } _disposed = true; }
/// <summary> /// Activates a functional agent. The caller should to an 'await' /// on this to wait for it to complete. This is because some /// functional agents return data and the caller has to wait /// for the functional agent to exit so it can get the data. Eg /// FileBrowser agent that returns a filename /// </summary> /// <param name="caller">The calling agent (can be null)</param> /// <param name="agent">Functional agent to activate</param> /// <returns>the task to wait on</returns> public async Task ActivateAgent(IApplicationAgent caller, IFunctionalAgent agent) { lock (_syncActivateAgent) { if (_currentAgent != null && _currentAgent != agent) { if (caller == null && !_currentAgent.QueryAgentSwitch(agent)) { return; } _currentAgent.OnFocusLost(); } if (caller != null) { agent.Parent = caller; caller.OnPause(); } _textControlAgent = agent.TextControlAgent; setAgent(agent); } Log.Debug("Calling activateAgent: " + agent.Name); await activateAgent(agent); CompletionCode exitCode = agent.ExitCode; Log.Debug("Returned from activateAgent: " + agent.Name); setAgent(null); if (agent.ExitCommand != null) { if (agent.ExitCommand.ContextSwitch) { Context.AppPanelManager.CloseCurrentPanel(); } RunCommandDispatcher.Dispatch(agent.ExitCommand.Command); } else if (exitCode == CompletionCode.ContextSwitch) { Context.AppPanelManager.CloseCurrentPanel(); EnumWindows.RestoreFocusToTopWindow(); WindowActivityMonitor.GetActiveWindow(); } else { PausePanelChangeRequests(); EnumWindows.RestoreFocusToTopWindow(); ResumePanelChangeRequests(false); } }
/// <summary> /// Sets the text control agent to the specifed one, null agent /// if NULL /// </summary> /// <param name="textInterface">Text interface to set</param> protected void setTextInterface(TextControlAgentBase textInterface = null) { if (_textInterface != null) { Log.Debug("Disposing " + _textInterface.GetType().Name); _textInterface.Dispose(); } Log.Debug("Setting textinterface to " + ((textInterface != null) ? textInterface.GetType().Name : "null")); _textInterface = textInterface ?? _nullTextInterface; AgentManager.Instance.TextControlAgent = _textInterface; }
/// <summary> /// Initializes a new instance of the class. /// </summary> /// <param name="textControlAgent">currently active text control agent object</param> internal AgentContext(ITextControlAgent textControlAgent) { _textControlAgent = textControlAgent; }
/// <summary> /// Initializes a new instance of the class. /// </summary> /// <param name="textAgent">The objet that triggered the event</param> public TextChangedEventArgs(ITextControlAgent textAgent) { TextInterface = textAgent; }
/// <summary> /// Call this function to raise events to indicated that something changed /// in the text window either due to editing or due to cursor movement. Event /// raised is asynchronous /// </summary> /// <param name="textInterface">text agent</param> protected void triggerTextChangedAsync(ITextControlAgent textInterface) { if (EvtTextChanged != null) { EvtTextChanged.BeginInvoke(this, new TextChangedEventArgs(textInterface), null, null); } }
/// <summary> /// Sets the current agent to the specified one and raises /// a text changed event. /// </summary> /// <param name="agent">agent to set as the current agent</param> private void updateCurrentAgentAndNotify(IApplicationAgent agent) { _textControlAgent = agent.TextControlAgent; setAgent(agent); notifyTextChanged(_textControlAgent); }
/// <summary> /// Notifies that something changed in the active text window - /// either the text changed or the caret moved. This is a tricky /// thing to handle The event can be raised while this function /// is still executing due to a previous event. We must guard /// against. Subsequent calls must be blocked until the function /// has exited. /// </summary> /// <param name="textInterface">The source of the event</param> /// <returns>true if successful</returns> private bool notifyTextChanged(ITextControlAgent textInterface) { uint threadId = GetCurrentThreadId(); Log.Debug("Entered notifyTextChanged: " + threadId); // Use the semaphore to see if this is blocked if (TextChangedNotifications.OnHold()) { Log.Debug("NotificationsOnHold. Exit ThreadID: " + threadId); return(false); } // try to acquire a lock if (!tryLock(_syncTextChangeNotifyObj)) { Log.Debug("_lock is true. returning on thread : " + threadId); return(false); } try { // this is required as _syncTextChangeNotifyObj lock will // only work if different threads are trying to enter. // The following statement is required to block against // the same thread trying to re-enter the function if (_notifyTextChangedLock) { Log.Debug("REENTRANCY DETECTED. RETURNING"); return(true); } if (textInterface != _textControlAgent) { Log.Debug("event source is not the current agent. returning..."); return(false); } _notifyTextChangedLock = true; try { if (EvtTextChanged != null) { Log.Debug("Calling EvtTextChanged"); EvtTextChanged(this, EventArgs.Empty); Log.Debug("Returned from EvtTextChanged"); } else { Log.Debug("EvtTextChanged is null"); } } catch (Exception ex) { Log.Debug(ex.ToString()); } _notifyTextChangedLock = false; Log.Debug("Exit End of function ThreadID: " + threadId); } catch (Exception ex) { Log.Debug(ex.ToString()); } finally { release(_syncTextChangeNotifyObj); } Log.Debug("Returning"); return(true); }
/// <summary> /// Activates an application agent depending on the context. /// The monitorInfo parameter has all the information to make /// this decision. Depending on the active foreground process, /// the appropriate agent is activated. if there is no dedicated /// agent for the process, the generic agent is used. /// If a dialog the foreground window, the dialog agent is activated. /// If a menu has been activated, the menu agent is activated /// </summary> /// <param name="monitorInfo">Foreground window/process info</param> private void activateAppAgent(WindowActivityMonitorInfo monitorInfo) { if (_inActivateAppAgent) { Log.Debug("Already inside. returning"); return; } Log.Debug("Before syncsetagent"); lock (_syncActivateAgent) { _inActivateAppAgent = true; Log.Debug("After syncsetagent"); try { bool handled = false; Log.Debug(monitorInfo.ToString()); // did a request for displaying the contextual // menu come in? If so handle it. bool getContextMenu = _getContextMenu; Log.Debug("getContextMenu: " + getContextMenu); _getContextMenu = false; String processName = monitorInfo.FgProcess.ProcessName; // first check if there is an ad-hoc agent, if so, // activate it Log.Debug("Looking for adhoc agent for " + monitorInfo.FgHwnd); IApplicationAgent agent = _agentsCache.GetAgent(monitorInfo.FgHwnd); if (agent == null) { // check if a dialog or menu is active Log.Debug("Adhoc agent not present for " + monitorInfo.FgHwnd); if (EnableContextualMenusForDialogs && (String.Compare(processName, _currentProcessName, true) != 0) && isDialog(monitorInfo)) { Log.Debug("Fg window is a dialog. Setting agent to dialog agent"); agent = _dialogAgent; } else if (EnableContextualMenusForMenus && isMenu(monitorInfo)) { Log.Debug("Fg window is a menu. Setting agent to menu agent"); agent = _menuControlAgent; } else if (Windows.IsMinimized(monitorInfo.FgHwnd)) { Log.Debug("Window is minimized. Use generic agent"); agent = _genericAppAgent; } else { // check if there is a dedicated agent for this process Log.Debug("Getting agent for " + processName); agent = _agentsCache.GetAgent(monitorInfo.FgProcess); } } else { Log.Debug("Adhoc agent IS present for " + monitorInfo.FgHwnd); } Log.Debug("Current agent: " + ((_currentAgent != null) ? _currentAgent.Name : "null") + ", agent: " + ((agent != null) ? agent.Name : "null")); // if there is an agent switch, query the current agent // if it is OK to switch. Some agents may not allow // the switch if (_currentAgent != null && _currentAgent != agent) { bool allowSwitch = _currentAgent.QueryAgentSwitch(agent); Log.Debug("CurrentAgent is " + _currentAgent.Name + ", queryAgentSwitch: " + allowSwitch); if (!allowSwitch) { _currentAgent.OnFocusChanged(monitorInfo, ref handled); _textControlAgent = _currentAgent.TextControlAgent; return; } _currentAgent.OnFocusLost(); } // if there was a request to display // contextual menu, do so if (getContextMenu) { if (agent == null) { agent = _genericAppAgent; } Log.Debug("agent : " + agent.Name); agent.OnContextMenuRequest(monitorInfo); return; } // Inform the new agent about the current // focused element so it can display the scanner that // is appropriated for the context. if (agent != null) { Log.Debug("Trying agent " + agent.Name); agent.OnFocusChanged(monitorInfo, ref handled); Log.Debug("Returned from agent.OnFOcus"); } // If we have reached here, it means there was no // agent. Just use the default generic agent. See // if it will handle it if (!handled) { Log.Debug("Did not find agent for " + processName + ". trying generic app agent"); Log.Debug("_genericAppAgent is " + ((_genericAppAgent != null) ? "not null" : "null")); agent = _genericAppAgent; try { agent.OnFocusChanged(monitorInfo, ref handled); } catch (Exception ex) { Log.Exception(ex); } } // even the generic agent refused. Use the null agent // as the last resort Log.Debug("handled " + handled); if (!handled) { Log.Debug("generic app agent refused. Using null agent"); agent = _nullAgent; agent.OnFocusChanged(monitorInfo, ref handled); } updateCurrentAgentAndNotify(agent); } catch (Exception ex) { Log.Debug(ex.ToString()); } finally { _inActivateAppAgent = false; } } Log.Debug("Return"); }
public bool Init(IEnumerable<String> extensionDirs) { if (_agentsCache == null) { _agentsCache = new AgentsCache(); _agentsCache.EvtAgentAdded += _agentsCache_EvtAgentAdded; _agentsCache.Init(extensionDirs); _genericAppAgent = _agentsCache.GetAgent(GenericAppAgentName); if (_genericAppAgent == null) { _agentsCache.AddAgentByType(typeof(UnsupportedAppAgent)); _genericAppAgent = _agentsCache.GetAgent(GenericAppAgentName); } _agentsCache.AddAgentByType(typeof(NullAgent)); _nullAgent = _agentsCache.GetAgent(NullAgentName); _dialogAgent = _agentsCache.GetAgent(DialogControlAgentName); _menuControlAgent = _agentsCache.GetAgent(MenuControlAgentName); _textControlAgent = _genericAppAgent.TextControlAgent; WindowActivityMonitor.EvtFocusChanged += WindowActivityMonitor_EvtFocusChanged; //WindowActivityMonitor.GetActiveWindow(); } return true; }
/// <summary> /// Activates a functional agent. The caller should to an 'await' /// on this to wait for it to complete. This is because some /// functional agents return data and the caller has to wait /// for the functional agent to exit so it can get the data. Eg /// FileBrowser agent that returns a filename /// </summary> /// <param name="caller">The calling agent (can be null)</param> /// <param name="agent">Functional agent to activate</param> /// <returns>the task to wait on</returns> public async Task ActivateAgent(IApplicationAgent caller, IFunctionalAgent agent) { lock (_syncActivateAgent) { if (_currentAgent != null && _currentAgent != agent) { if (caller == null && !_currentAgent.QueryAgentSwitch(agent)) { return; } _currentAgent.OnFocusLost(); } if (caller != null) { agent.Parent = caller; caller.OnPause(); } _textControlAgent = agent.TextControlAgent; setAgent(agent); } Log.Debug("Calling activateAgent: " + agent.Name); await activateAgent(agent); CompletionCode exitCode = agent.ExitCode; Log.Debug("Returned from activateAgent: " + agent.Name); setAgent(null); if (agent.ExitCommand != null) { if (agent.ExitCommand.ContextSwitch) { Context.AppPanelManager.CloseCurrentPanel(); } RunCommandDispatcher.Dispatch(agent.ExitCommand.Command); } else if (exitCode == CompletionCode.ContextSwitch) { //Context.AppPanelManager.CloseCurrentPanel(); Context.AppPanelManager.ClearStack(); EnumWindows.RestoreFocusToTopWindow(); WindowActivityMonitor.GetActiveWindow(); } else { PausePanelChangeRequests(); EnumWindows.RestoreFocusToTopWindow(); ResumePanelChangeRequests(false); } }
/// <summary> /// Activates an application agent depending on the context. /// The monitorInfo parameter has all the information to make /// this decision. Depending on the active foreground process, /// the appropriate agent is activated. if there is no dedicated /// agent for the process, the generic agent is used. /// If a dialog the foreground window, the dialog agent is activated. /// If a menu has been activated, the menu agent is activated /// </summary> /// <param name="monitorInfo">Foreground window/process info</param> private void activateAppAgent(WindowActivityMonitorInfo monitorInfo) { if (_inActivateAppAgent) { Log.Debug("Already inside. returning"); return; } Log.Debug("Before syncsetagent"); lock (_syncActivateAgent) { _inActivateAppAgent = true; Log.Debug("After syncsetagent"); try { bool handled = false; Log.Debug(monitorInfo.ToString()); // did a request for displaying the contextual // menu come in? If so handle it. bool getContextMenu = _getContextMenu; Log.Debug("getContextMenu: " + getContextMenu); _getContextMenu = false; String processName = monitorInfo.FgProcess.ProcessName; // first check if there is an ad-hoc agent, if so, // activate it Log.Debug("Looking for adhoc agent for " + monitorInfo.FgHwnd); IApplicationAgent agent = _agentsCache.GetAgent(monitorInfo.FgHwnd); if (agent == null) { // check if a dialog or menu is active Log.Debug("Adhoc agent not present for " + monitorInfo.FgHwnd); if (EnableContextualMenusForDialogs && (String.Compare(processName, _currentProcessName, true) != 0) && isDialog(monitorInfo)) { Log.Debug("Fg window is a dialog. Setting agent to dialog agent"); agent = _dialogAgent; } else if (EnableContextualMenusForMenus && isMenu(monitorInfo)) { Log.Debug("Fg window is a menu. Setting agent to menu agent"); agent = _menuControlAgent; } else { // check if there is a dedicated agent for // this process Log.Debug("Getting agent for " + processName); agent = _agentsCache.GetAgent(monitorInfo.FgProcess); } } else { Log.Debug("Adhoc agent IS present for " + monitorInfo.FgHwnd); } Log.Debug("Current agent: " + ((_currentAgent != null) ? _currentAgent.Name : "null") + ", agent: " + ((agent != null) ? agent.Name : "null")); // if there is an agent switch, query the current agent // if it is OK to switch. Some agents may not allow // the switch if (_currentAgent != null && _currentAgent != agent) { bool allowSwitch = _currentAgent.QueryAgentSwitch(agent); Log.Debug("CurrentAgent is " + _currentAgent.Name + ", queryAgentSwitch: " + allowSwitch); if (!allowSwitch) { _currentAgent.OnFocusChanged(monitorInfo, ref handled); _textControlAgent = _currentAgent.TextControlAgent; return; } _currentAgent.OnFocusLost(); } // if there was a request to display // contextual menu, do so if (getContextMenu) { if (agent == null) { agent = _genericAppAgent; } Log.Debug("agent : " + agent.Name); agent.OnContextMenuRequest(monitorInfo); return; } // Inform the new agent about the current // focused element so it can display the scanner that // is appropriated for the context. if (agent != null) { Log.Debug("Trying agent " + agent.Name); agent.OnFocusChanged(monitorInfo, ref handled); Log.Debug("Returned from agent.OnFOcus"); } // If we have reached here, it means there was no // agent. Just use the default generic agent. See // if it will handle it if (!handled) { Log.Debug("Did not find agent for " + processName + ". trying generic app agent"); Log.Debug("_genericAppAgent is " + ((_genericAppAgent != null) ? "not null" : "null")); agent = _genericAppAgent; try { agent.OnFocusChanged(monitorInfo, ref handled); } catch (Exception ex) { Log.Exception(ex); } } // even the generic agent refused. Use the null agent // as the last resort Log.Debug("handled " + handled); if (!handled) { Log.Debug("generic app agent refused. Using null agent"); agent = _nullAgent; agent.OnFocusChanged(monitorInfo, ref handled); } updateCurrentAgentAndNotify(agent); } catch (Exception ex) { Log.Debug(ex.ToString()); } finally { _inActivateAppAgent = false; } } Log.Debug("Return"); }
/// <summary> /// Notifies that something changed in the active text window - /// either the text changed or the caret moved. This is a tricky /// thing to handle The event can be raised while this function /// is still executing due to a previous event. We must guard /// against. Subsequent calls must be blocked until the function /// has exited. /// </summary> /// <param name="textInterface">The source of the event</param> /// <returns>true if successful</returns> private bool notifyTextChanged(ITextControlAgent textInterface) { uint threadId = GetCurrentThreadId(); Log.Debug("Entered notifyTextChanged: " + threadId); // Use the semaphore to see if this is blocked if (TextChangedNotifications.OnHold()) { Log.Debug("NotificationsOnHold. Exit ThreadID: " + threadId); return false; } // try to acquire a lock if (!tryLock(_syncTextChangeNotifyObj)) { Log.Debug("_lock is true. returning on thread : " + threadId); return false; } try { // this is required as _syncTextChangeNotifyObj lock will // only work if different threads are trying to enter. // The following statement is required to block against // the same thread trying to re-enter the function if (_notifyTextChangedLock) { Log.Debug("REENTRANCY DETECTED. RETURNING"); return true; } if (textInterface != _textControlAgent) { Log.Debug("event source is not the current agent. returning..."); return false; } _notifyTextChangedLock = true; try { if (EvtTextChanged != null) { Log.Debug("Calling EvtTextChanged"); EvtTextChanged(this, EventArgs.Empty); Log.Debug("Returned from EvtTextChanged"); } else { Log.Debug("EvtTextChanged is null"); } } catch (Exception ex) { Log.Debug(ex.ToString()); } _notifyTextChangedLock = false; Log.Debug("Exit End of function ThreadID: " + threadId); } catch (Exception ex) { Log.Debug(ex.ToString()); } finally { release(_syncTextChangeNotifyObj); } Log.Debug("Returning"); return true; }