Omnipressent. Too many devices?

How many devices do you own? Personally I find it frustrating that each device is it's only silo of files, resources and settings. This is an idea I've been playing with for a while the get my devices to act like one device.

I developed a C# application to test the idea, combining services like VNC, HID sharing and scripts to try to produce a seamless experience across various computers.




 
 How many devices do you own? Personally I find it frustrating that each device is it's only silo of files, resources and settings. This is an idea I've been playing with for a while the get my devices to act like one device.

Back when I was young, before decent internet connections when computers were new and novel I spent hours getting my computer just right, customizing, tweaking, I knew where every file was. And at some people we started collecting more and more devices. At the moment I have a laptop and a desktop at home, a work laptop and a phone and I find it a little frustrating that how neglected and underutilized my desktop is or that I have music on my phone and decent music on my phone but it's just not about files it would be nice to have a consistent experience across them all.

Some people say that's what services like dropbox are for and I've tried that. I kept a set of scripts in a folder in dropbox but it wasn't the same. Before Tony Stark gets in his car he doesn't need to copy his music files and his themes into dropbox and then open it up in his cars computer. He just always has a consistent experience which everything he needs where ever he goes. Omnipressent was an (overly) ambitious project to do that.



The idea was you would install an app that would run in your taskbar and set up VPN tunnels to all your other computers. And from there you can access the screen, speakers, keyboard, mouse or files on any of your other devices. But also kind of merge your devices so you could use a tablet as a screen or pipe your audio to another device. individually none of these functions are new but combining them in a user friendly way is.

Omnipressent with developer concept shown


 Frankly this project has always been too big for me to do on my own but I couldn't let it go. After trying to hack something together using scripts run out of dropbox I eventually started to develop my own software if only to figure out the problems a little more.

After eventually coding a project to the point where it was too complex for one person to manage I had to scarp the first version. With what I learned I coded a new simplified version (seen above).
The new design was to keep the hub of the program very simple and to wrap each service so it could pass messages in a simplified way. I wrote a standard structure that each service would use so that I could plug in services written by others. That gave the application the ability to sync the clipboard, send commands, send keyboard and mouse input and allow you to connect to the other computers screen using VNC. The main idea was the make this services as seamless as possible when you move to the edge of the screen VNC would seamlessly slide in sliding your computers screen out give an effect similar to virtual desktops in linux making it seem like both screens are part of your computer. Here's a low quality video explaining the concept.
On one hand I was surprised that how much I got done but on the other hand I could not complete the project fully on my own. I did complete a proof of concept but in order to make this a tidy reliable product I would require experts to write drivers and a security team to ensure trust.

Still I'm quite proud of how simple the coded ended up. Here is The Hub, there all the services are connected and controlled.

----------------------------------------------------------------------------------------------------------------------------------------------------------------

    class Hub
    {
        bool running = true;
        string startupScriptPath = "startup.os";
        OmniService[] services; //Array containing all services.
        ArrayList messagesWaiting;
        GUI theGUI;

        public Hub()
        {
            int noOfMessageTypes = 0;
            messagesWaiting = new ArrayList();
            

            //This counts the number of message types to set the size of the services array.
            foreach (messageTypeEnum messageType in (messageTypeEnum[])Enum.GetValues(typeof(messageTypeEnum)))
                noOfMessageTypes++;  //There has to be a better way


            services = new OmniService[noOfMessageTypes];

            /*I have to say, I'm pretty proud of this. Almost everything is a service.
             *Enumerators matching the service names are used for routing messages (see sexy mainloop code).
             *The same enumerators are used for indexes here. Because I abscrated nicely you can be fairly agnostic when
             *Dealing this services and as such this control is fairly simple. Collects, routes and gives messages */

            services[messageTypeEnum.ServiceInfo.GetHashCode()] = new ServiceInfo();
            services[messageTypeEnum.ServiceController.GetHashCode()] = new ServiceController();
            services[messageTypeEnum.ServiceScriptGetter.GetHashCode()] = new ServiceScriptGetter();
            services[messageTypeEnum.ServiceScriptSetter.GetHashCode()] = new ServiceScriptSetter();
            services[messageTypeEnum.ServiceVNCClient.GetHashCode()] = new ServiceVNCClient();
            services[messageTypeEnum.ServiceVNCServer.GetHashCode()] = new ServiceVNCServer();
            services[messageTypeEnum.ServiceClipboardSetter.GetHashCode()] = new ServiceClipboardSetter();
            services[messageTypeEnum.ServiceClipboardGetter.GetHashCode()] = new ServiceClipboardGetter();
            services[messageTypeEnum.ServiceHIDGetter.GetHashCode()] = new ServiceHIDGetter();
            services[messageTypeEnum.ServiceHIDSetter.GetHashCode()] = new ServiceHIDSetter();
            services[messageTypeEnum.ServiceScreenSlide.GetHashCode()] = new ServiceScreenSlide();
            services[messageTypeEnum.ServiceScreenBlocker.GetHashCode()] = new ServiceScreenBlocker();
            services[messageTypeEnum.ServiceGUI.GetHashCode()] = new ServiceGUI();
            services[messageTypeEnum.ServiceCommandClient.GetHashCode()] = new ServiceCommandClient();
            RunStartupScript();
            while(running)
                mainLoop();
        }

        private void RunStartupScript()
        {
            messagesWaiting.Add(
                new Message(0,messageTypeEnum.ServiceScriptGetter,messageEnum.SetPath,startupScriptPath)
                );
            messagesWaiting.Add(
                new Message("0, ServiceScriptGetter, ReadScript, 0")
                );
        }

        public void setGUI(GUI g)
        {
            theGUI = g;
        }

        public void mainLoop()
        {
            //Called from a timer in the GUI form. I feel dirty but I just can't get a form to work from here. I think this should run the form no the other way arround but I can't make it work. 

            dbgLog("Main Loop Started ************************************************************");
               
            foreach (OmniService s in services)
            {   //Get messages from each service
                    while (true)
                    {
                        dbgLog(s.GetType().Name.ToString());
                        Message m = s.getMessage();
                        if (m == null)
                            break; //This feels a little wrong but it works well
                        messageIn(m);
                    }
            }
            foreach (Message msg in messagesWaiting)
            {   //Deliver messages
                    //msg.targetHost == -2 goes nowhere intentionaly. This is like /dev/null
                    if(msg.targetHost == -2)
                    {
                        //System.Windows.Forms.MessageBox.Show("targetHost set to -2. Service running without being configured. Message : " + msg.ToString());
                    }
                    if (msg.targetHost == -1) //To Log / Script
                        //this.messagesWaiting.Add( //Apparently you can't add to this in the foreach

                        services[messageTypeEnum.ServiceScriptSetter.GetHashCode()].giveMessage(
                        new Message(0, messageTypeEnum.ServiceScriptSetter, messageEnum.SaveToFile, msg.ToString())
                        );
                       // );
                    /* The above line might be a little confusing. 
                     * If hostID == -1, that means print to file, 
                     * this is used mainly for logging out HID info so it can be read back in.
                     * What I'm doing is nesting a Sting of a message in a message destied for Serviceoutput.
                     * The message I'm saving is the argument in anouther message telling ServiceOutput to Save To File
                     */

                    if(msg.targetHost == 0) //Internal / Local
                    services[msg.messageType.GetHashCode()].giveMessage(msg);

                    if (msg.targetHost > 0 | msg.targetHost == -3) //>0 to other host routed though webservice. -3 of webservice itself;
                        services[messageTypeEnum.ServiceCommandClient.GetHashCode()].giveMessage(msg); 
            }
 //Asume all delivered or undelivable. Drop all messages
            ((ServiceController)services[messageTypeEnum.ServiceController.GetHashCode()]).Tick();
            messagesWaiting.Clear();
            addStandingOrders();
            dbgLog("MainLoop finished-----------------------------------------------------------------------");
            omniWait();
        }
        public void addStandingOrders()
        {
            //This is for adding messages that are run each loop
            //messagesWaiting.Add(new Message(0, messageTypeEnum.ServiceInfo, messageEnum.UpdateInfo, ""));
            //messagesWaiting.Add(new Message("0,ServiceCommandClient,GetMessages,,"));
        }
        public void omniWait()
        {
            //This will eventualy become more complex, hence moving it out onto it's own method
            System.Threading.Thread.Sleep(5000);
        }
        public string info()
        {
            return "Super alpha V0.0 turbo edition.";
        }
 public void messageIn(Message msg)
        {
            /***************************
             * Takes a message in message object form.
             * This is internal and already processed
             * ready for routing
             ***************************/
            messagesWaiting.Add(msg);
        }
        public void messageIn(String msg)
        {
            messageIn(new Message(msg));
        }
        public void debugLog(string s)
        {
            messagesWaiting.Add(new Message(0, messageTypeEnum.ServiceGUI, messageEnum.PrintDebug, s));
        }
        public void dbgLog(String s)
        {
            Debug.WriteLine("S:" + System.DateTime.Now.Second.ToString() + "." + System.DateTime.Now.Millisecond.ToString() + " > " + s);
        }
    }