All pastes #415575 Raw Edit

Unnamed

public text v1 · immutable
#415575 ·published 2007-03-29 18:50 UTC
rendered paste body
/**************************************************************
 * Program: Lorei
 * Class:
 * Description:
 *  This class handles all of the logic required for lorei to
 *  opperate.  The class is currently designed around a 
 *  Dictonary that is used to store and look up created
 *  processes based on a file path to the launched exe.
 *  This may or maynot be the best solution but it works well.
 *     drawbacks: 1) Can only have one instance of a program 
 *                open at a time. But since i havent created a 
 *                way to identify more then one program instance
 *                at a time this is a mute point.
 *  The class primarily focuses on the creation and handleing of 
 *  the grammer classes used to control diffrent programs.  The
 *  grammer classes are what alow the speech api to understand 
 *  english. This class also hosts the LUA scripting engine 
 *  used to read and setup the grammers required for a 
 *  specific program this provides a large ammout of flexability 
 *  and change to programs without the need to recompile lorei. 
 *  This class acts as a interface providing LUA with the 
 *  functions that can be used in the script files. 
 *  
 * 
 **************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Speech.Recognition;
using System.Speech.Synthesis;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using LuaInterface;

namespace Lorei
{
    class LoreiLanguageProcesser
    {
        /************ Constructors ************/
        public LoreiLanguageProcesser()
        {
            // Setup LUA functions
            SetupLuaFunctions();

            // Setup Variables
            SetupSpeechSynthesizer();

            // Setup Engine
            SetupSpeechRecognitionEngine();

            // Start Lorei
            LoreiStartListening();
        }

        /************ Destructors ************/
        
        /************ Methods ************/
        public void LoreiStartListening()
        {
            m_speechRecognizer.Enabled = true;
            if (StateChanged != null) StateChanged(this, m_speechRecognizer.Enabled);
        }
        public void LoreiStopListening()
        {
            m_speechRecognizer.Enabled = false;
            if( StateChanged != null ) StateChanged(this, m_speechRecognizer.Enabled);
        }

        // Event Handlers
        private void m_speechRecognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            // Interaction Message
            m_speechSynthesizer.SpeakAsync("Speech Recognized");
            
            // Parse Speech
            ParseSpeech(e);
        }
        private void m_speechRecognizer_SpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e)
        {
            m_speechSynthesizer.SpeakAsync("No");
        }

        /************ Helper Methods ************/
        // Helper Methods For Lua Engine
        private void SetupLuaFunctions()
        {
            // Start up the lua engine
            m_luaEngine = new Lua();
   
            // Setup global functions
            m_luaEngine.RegisterFunction("SendMessage", this, this.GetType().GetMethod("DispatchMessageToWindow"));
            m_luaEngine.RegisterFunction("LaunchProgram", this, this.GetType().GetMethod("LaunchProgram"));
            RegisterFunctionTemplate("ExitProgram");
            //m_luaEngine.RegisterFunction("RegisterLoreiName", this, this.GetType().GetMethod("RegisterLoreiName"));
            RegisterFunctionTemplate("RegisterLoreiName");
            RegisterFunctionTemplate("RegisterLoreiFunction");
            RegisterFunctionTemplate("RegisterProgramWithScript");
            RegisterFunctionTemplate("RegisterLoreiProgramName");
            RegisterFunctionTemplate("RegisterLoreiProgramCommand");
        }
        private void RegisterFunctionTemplate(string functionName)
        {
            m_luaEngine.RegisterFunction(functionName, this, this.GetType().GetMethod(functionName));
        }

        // Helper Methods For Speech Recognition Engine
        private void SetupSpeechRecognitionEngine()
        {
            // Setup Speech Engine
            m_speechRecognizer = new SpeechRecognizer();

            if (m_speechRecognizer == null)
            {
                m_speechSynthesizer.SpeakAsync("Speech Recognizer Creation Failed is Null");
            }
            else m_speechSynthesizer.SpeakAsync("Speech Recognizer Created");

            // Call Lua Junk
            m_luaEngine.DoFile("setup.lua");

            // Setup Grammars
            LoadSpeechInformation();
            
            // Setup Event Handlers
            SetupEventHandlers();
        }
        private void LoadSpeechInformation()
        {
            // Data
            Choices keywords;
            Choices functions;
            Choices programs;
            Choices actions;
            Choices programActions;

            // Setup Grammars
            m_FunctionExecution  = new GrammarBuilder();
            m_ProgramControl     = new GrammarBuilder();

            // Setup Keywords
            keywords = new Choices(m_Keywords.ToArray());
            // Setup Function List
            functions = new Choices(m_Functions.ToArray());
            // Setup List of Programs;
            programs = new Choices(m_Programs.ToArray()); 
            // Program Functions
            programActions = new Choices(m_ProgramActions.ToArray());

            // Setup Grammar
            m_FunctionExecution.Append(keywords);
            m_FunctionExecution.Append(functions);
            m_FunctionExecution.Append(programs);
            m_ProgramControl.Append(keywords);
            m_ProgramControl.Append(programs);
            m_ProgramControl.Append(programActions);
            
            // Setup Engine
            m_FunctionGrammar = new Grammar(m_FunctionExecution);
            m_ProgramGrammar  = new Grammar(m_ProgramControl);
            m_FunctionGrammar.Name = "m_FunctionGrammar";
            m_ProgramGrammar.Name  = "m_ProgramGrammar";

            m_speechRecognizer.LoadGrammar(m_FunctionGrammar);
            m_speechRecognizer.LoadGrammar(m_ProgramGrammar);
        }
        private void SetupEventHandlers()
        {
            m_speechRecognizer.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(m_speechRecognizer_SpeechRecognized);
            m_speechRecognizer.SpeechRecognitionRejected += new EventHandler<SpeechRecognitionRejectedEventArgs>(m_speechRecognizer_SpeechRecognitionRejected);
        }

        // Helper Methods For Speech Synthesis Engine
        private void SetupSpeechSynthesizer()
        {
            m_speechSynthesizer = new SpeechSynthesizer();
        }

        // Helper Methods For Parsing Speech
        private void ParseSpeech(SpeechRecognizedEventArgs e)
        {
            // Check if disabled by voice
            // HACK::::::HACK::::::HACK
            if (m_disabledByVoice == true)
            {
                if (e.Result.Words[1].Text != "Enable") return;
                if (e.Result.Words[2].Text != "Speech") return;
                m_disabledByVoice = false;
                return;
            }
            // ENDHACK:::::ENDHACK::::ENDHACK

            //m_luaEngine.DoString("winamp:ToLaunch()");
            // This function calles the approprate function in the lua file so that 
            // programs can be controled from the lua script and lorei needs to know
            // nothing about the code that is ran there.
            // This creates a nice clean operational seperation between dispatch and
            // operation. Lorei is the dispatcher and LUA is the axual thing doing
            // all of the work. Most of the time the scripts just call back to lorei
            // functions to do all of the axual "Work" but it still prevents a lot of
            // boiler plate code.  This replaces alot of stupid code. Look below to see
            // what i replaced.  Every program would have had to be hard coded into lorei
            // and this system works much much better.
            switch (e.Result.Grammar.Name)
            {
                case "m_FunctionGrammar":
                    string s = e.Result.Words[2].Text.ToLower() + ".To" + e.Result.Words[1].Text + "()";
                    //m_luaEngine.DoString("winamp.ToLaunch()");
                    m_luaEngine.DoString(s);
                    break;
                case "m_ProgramGrammar":
                    //m_luaEngine["event"] = e;
                    //m_luaEngine.DoString(e.Result.Words[1].Text + ".OnSpeechReceved()");
                    m_luaEngine.GetFunction(e.Result.Words[1].Text + ".OnSpeechReceved").Call(e.Result.Words[2].Text);
                    break;
                default:
                    break;
            }

            // If i catch anyone doing something like this now that i have the LUA system
            // working i will hunt you down and break your little fingers. 
            //                                               Love Greg
            // PS: i left this in so you know what not to do
            // Not disabled so do the work
            /*switch (e.Result.Grammar.Name)
	        {
                case "m_FunctionGrammar":
                    switch (e.Result.Words[1].Text)
                    {
                        case "Launch":
                            switch (e.Result.Words[2].Text)
                            {
                                case "Ventrilo":
                                    LaunchProgram("C:\\Program Files\\Ventrilo\\Ventrilo.exe");
                                    break;

                                case "Command":
                                    LaunchProgram("C:\\Windows\\system32\\cmd.exe");
                                    break;

                                case "Winamp":
                                    LaunchProgram("C:\\Program Files\\Winamp\\winamp.exe");
                                    break;

                                case "Windows":
                                    LaunchProgram("C:\\WINDOWS\\explorer.exe");
                                    break;

                                default:
                                    break;
                            }
                            break;
                        case "Close":
                            switch (e.Result.Words[2].Text)
                            {
                                case "Ventrilo":
                                    ExitProgram("C:\\Program Files\\Ventrilo\\Ventrilo.exe");
                                    break;

                                case "Command":
                                    ExitProgram("C:\\Windows\\system32\\cmd.exe");
                                    break;

                                case "Winamp":
                                    ExitProgram("C:\\Program Files\\Winamp\\winamp.exe");
                                    break;

                                case "Windows":
                                    ExitProgram("C:\\WINDOWS\\explorer.exe");
                                    break;

                                default:
                                    break;
                            }
                            break;

                        case "Disable":
                            if (e.Result.Words[2].Text == "Speech") m_disabledByVoice = true ;
                            break;

                        default:
                            break;
                    }
                    break;

                case "m_ProgramGrammar":
                    switch (e.Result.Words[1].Text)
                    {
                        case "Winamp":
                            switch (e.Result.Words[2].Text)
                            {
                                case "Previous":
                                    DispatchMessageToWindow("C:\\Program Files\\Winamp\\winamp.exe", WM_COMMAND, WINAMP_BUTTON1, 0);
                                    break;
                                case "Play":
                                    DispatchMessageToWindow("C:\\Program Files\\Winamp\\winamp.exe", WM_COMMAND, WINAMP_BUTTON2, 0);
                                    break;
                                case "Pause":
                                    DispatchMessageToWindow("C:\\Program Files\\Winamp\\winamp.exe", WM_COMMAND, WINAMP_BUTTON3, 0);
                                    break;
                                case "Next":
                                    DispatchMessageToWindow("C:\\Program Files\\Winamp\\winamp.exe", WM_COMMAND, WINAMP_BUTTON5, 0);
                                    break;
                                case "Stop":
                                    DispatchMessageToWindow("C:\\Program Files\\Winamp\\winamp.exe", WM_COMMAND, WINAMP_BUTTON4, 0);
                                    break;
                            }
                            break;

                        default:
                            break;
                    }
                    break;

		        default:
                    break;
	        }*/
                

        }
        public void LaunchProgram(String p_program)
        {
            // If Key exists
            if (m_runningPrograms.ContainsKey(p_program))
            {
                // and If the key in the collection is null then we remake the process
                if (m_runningPrograms[p_program] == null)
                {
                    m_runningPrograms[p_program] = Process.Start(p_program);
                    return;
                }
                
                // Else we quit because we are allready manageing one
                m_speechSynthesizer.SpeakAsync("Unable to launch program");
                return;
            }
            // Add the program to the dictonary and continue as normal
            m_runningPrograms.Add(p_program, Process.Start(p_program));
        }
        public void ExitProgram(String p_program)
        {
            // Check and see if the process exists
            Process procToKill;
            if ( m_runningPrograms.TryGetValue(p_program, out procToKill) )
            {
                // Close the main window so the program exits
                procToKill.CloseMainWindow();
                // Then remove the process from the process map so we can
                // launch the program again later.
                m_runningPrograms.Remove(p_program);
            }
            // work done go home 
        }
        public void DispatchMessageToWindow(String p_program, int p_myMessage, int p_myWParam, int p_myLParam)
        {
            // This is cool
            Process myProcess;
            int     myMessage = p_myMessage;
            int     myWParam  = p_myWParam;
            int     myLParam  = p_myLParam;

            // Check and make shure the program exists because trying with a bad handle would be bad.....
            if (m_runningPrograms.TryGetValue(p_program, out myProcess))
            {
               // With out this call to refresh the process never updates the information 
               // about windows handles so when a program creates its main window it never changes
               // the information in this class.  Evil Evil Evil thing....
                myProcess.Refresh();  // This command took me days to find gota love msdn docs
                    
               // Import the win32 send message function so we can drop messages into the program
               LoreiLanguageProcesser.SendMessage(myProcess.MainWindowHandle, myMessage, myWParam, myLParam);
            }
            return;
        }
        
        // Lua General Script Methods
        private void SayMessage(string p_Message)
        {
            // This makes the speach engine for the program say things
            // this function is made accessable to lua so scripts can say stuff
            m_speechSynthesizer.SpeakAsync(p_Message);
        }

        // Lua Helper Methods for Registration
        public void RegisterProgramWithScript(string p_ProgramName) 
        {
            if (m_RegistrationComplete) return;

            m_luaEngine.DoFile(p_ProgramName + ".lua");
        }
        private void RegisterTemplate(string p_String, List<string> p_list)
        {
            // This function is a template to create other functions because
            // im lazy and copy paste is a bad idea so i make metafunctions...
            if (m_RegistrationComplete) return;

            // Check each element in list to see if new item exists already
            foreach (string x in p_list)
            {
                if (x == p_String) return;
            }

            p_list.Add(p_String);
        }
        public void RegisterLoreiName(string p_NameForLorei) 
        {
            // Do the work.... shame to need a function for this
            RegisterTemplate(p_NameForLorei, m_Keywords);
        }
        public void RegisterLoreiFunction(string p_NameOfFunction) 
        {
            RegisterTemplate(p_NameOfFunction, m_Functions);
        }
        public void RegisterLoreiProgramName(string p_NameOfProgram) 
        {
            RegisterTemplate(p_NameOfProgram, m_Programs);
        }
        public void RegisterLoreiProgramCommand(string p_NameOfProgramCommand) 
        {
            RegisterTemplate(p_NameOfProgramCommand, m_ProgramActions);
        }
        public void RegistrationDone() 
        {
            // Check to see if i should be called
            if (m_RegistrationComplete) return;

            // Set flag so we disable all register functions
            m_RegistrationComplete = true;
        }

        // Imported Stuff
        [DllImport("user32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto)]
        private static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);

        // Constants
        private const int WM_USER        = 0x0400;
        private const int WM_COMMAND     = 0x0111;
        private const int WM_QUIT        = 0x0012;
        private const int IPC_STARTPLAY  = 0x0102;
        private const int IPC_ISPLAYING  = 0x0104;
        private const int WINAMP_BUTTON1 = 40044;  // Winamp Previous
        private const int WINAMP_BUTTON2 = 40045;  // Winamp Play
        private const int WINAMP_BUTTON3 = 40046;  // Winamp Pause
        private const int WINAMP_BUTTON4 = 40047;  // Winamp Stop
        private const int WINAMP_BUTTON5 = 40048;  // Winamp Next
        private const int WINAMP_PLAYBOX = 40029;

        /************ Events ************/
        public event ParseSpeech TextReceived;
        public event ProcesserSwitchChanged StateChanged;

        /************ Accessers ************/
        public bool Active 
        {
            set
            {
                if (value == true) LoreiStartListening();
                else LoreiStopListening();
            }
            get
            {
                return m_speechRecognizer.Enabled;
            }
        }

        /************ Data ************/
        private List<String> m_Keywords       = new List<string>();
        private List<String> m_Functions      = new List<string>();
        private List<String> m_Programs       = new List<string>();
        private List<String> m_Aliases        = new List<string>();
        private List<String> m_ProgramActions = new List<string>();
        
        // Speech Components
        private SpeechRecognizer  m_speechRecognizer;
        private SpeechSynthesizer m_speechSynthesizer;
        private GrammarBuilder    m_FunctionExecution;
        private GrammarBuilder    m_ProgramControl;
        private Grammar m_FunctionGrammar;
        private Grammar m_ProgramGrammar;

        // Program Control Data
        private Dictionary<String, Process> m_runningPrograms = new Dictionary<string,Process>();
        private bool m_disabledByVoice = false;
        
        // Lua Engine Data
        Lua m_luaEngine;
        bool m_RegistrationComplete = false;
    }

    enum WinampCommands 
    {
        WINAMP_PREVIOUS = 40044,
        WINAMP_PLAY     = 40045,
        WINAMP_PAUSE    = 40046,
        WINAMP_STOP     = 40047,
        WINAMP_NEXT     = 40048
    }
}