8 Replies Latest reply on May 25, 2007 8:46 AM by JKohn99

    Giving focus to Flex app without mouse

    fabiomina
      Hi,

      I am trying to build a form-based Flex application that must be accessbile by using keyboard only and I am having serious problems with focus management.

      My simple objectives are:
      - when application is loaded, the focus is given to first form field
      - pressing the tab key, the focus cycles on form fields

      My environment is:
      - Flex Builder 2
      - Flash Player 9
      - Internet Explorer 6

      This is a basic app to demonstrate my problem:

      <?xml version="1.0" encoding="utf-8"?>
      <mx:Application
      xmlns:mx=" http://www.adobe.com/2006/mxml"
      creationComplete="input1.setFocus()"
      width="516" height="310">
      <mx:Canvas width="420" height="244">
      <mx:TextInput id="input1" x="130" y="50"/>
      <mx:TextInput id="input2" x="130" y="103"/>
      <mx:TextInput id="input3" x="130" y="156"/>
      </mx:Canvas>
      </mx:Application>


      In this simple app, I have 2 input fields and I explicitely give the focus to the first field on creationComplete.

      The strange behaviour that I see is:
      1 - loading the app (using Flex Builder-->Run as) the focus is actually in the first field and I can type in it
      2 - BUT, pressing the tab key once, the focus goes outside the Flash applet to the browser controls (e.g. address bar)
      3 - repeatedly pressing the tab key, the focus cycles through browser controls and the Flash applet (first field only)
      4 - if I take the mouse (which I am required not to use!) and click into the first field, it take the focus and then..
      5 - pressing the tab key twice, the focus shift to the second and then the third field
      6 - BUT, if I press the tab from the third field, it leaves the Flash applet again

      I found a workaround for the behaviour on step 6, so I am able to cycle through my field without leaving the applet.
      What I did is adding the follwowing attribute to the Application tag:

      keyFocusChange="event.preventDefault();focusManager.getNextFocusManagerComponent(event.sh iftKey).setFocus()"

      However, my real issue is on avoiding the use of the mouse on point 4.

      I also tried modifying the index.template.html in order to have the enclosing HTML page explicitely giving focus to the Flash applet, but the behaviour does not change:

      <body scroll="no" onLoad="window.document.myFlashApplet.focus()">

      It seems to me this should be a fairly known issue, but I was not able to find a solution so far.
      Can anybody help me?

      Thanks,
      Fabio
        • 1. Re: Giving focus to Flex app without mouse
          etapeta
          Hi,

          I effectively got the same problem.

          I found some solutions on the web, such as calling "${application}.focus();" from the html hosting application, in its onLoad javascript event (where ${application} is the id of the <embed> or <object> html element).
          But none worked.

          I don't get the same problem in Firefox, only in IE.

          I would appreciate a valid solution to this.
          • 2. Re: Giving focus to Flex app without mouse
            fabiomina Level 1
            Hi,

            It seems nobody is going to give a solution to this problem..

            As it is a real issue of the platform (and not a general question on how to do something), maybe an Adobe engineer should answer to this topic?
            • 3. Re: Giving focus to Flex app without mouse
              JKohn99 Level 1
              I may have a solution. I've been working the Adobe on something like this. (We actually have support). Once I am satisfied that the solution works i will post it here.
              • 4. Re: Giving focus to Flex app without mouse
                JKohn99 Level 1
                Below is a version of your sample application where the focus is working correctly.
                This may seem like alot of work since you're manually controlling the focus. However this is actually very handy if you have multiple components on a screen and only want to tab in the sub component. Our application has this requirement.
                I've implemented forward and backward (shift-tab) tabbing.

                To get the focus on startup (in IE) you need to add the following JavaScript to your
                index_template.html:
                window.onload = function()
                {
                var fxControl = document.${application} || window.${application};
                fxControl.focus();
                }


                Thanks to John Zhao from Adobe for providing the initial example.
                //--------------------------------------------- example ------------------------------------------
                <?xml version="1.0" encoding="utf-8"?>
                <mx:Application xmlns:mx=" http://www.adobe.com/2006/mxml" layout="absolute"
                creationComplete="setFocusControl()">
                <mx:Canvas id="box" x="10" y="10" width="100%" height="100%" >
                <mx:TextInput id="f1" text="f1" x="75" y="57"/>
                <mx:TextInput id="f2" text="f2" x="75" y="87"/>
                <mx:TextInput id="f3" text="f3 " x="75" y="117"/>
                <mx:Script>
                <![CDATA[

                import mx.core.UIComponent;
                private var len:Number;
                private var focus_index :Number=0;

                private var tiList:Array = new Array();

                protected function setFocusControl():void
                {
                // So it's easier to see where the focus is.
                StyleManager.getStyleDeclaration("global").setStyle("focusThickness", 4);
                StyleManager.getStyleDeclaration("global").setStyle("focusAlpha", 5);
                // Set focus to the first component and set the index to the
                // next one.
                f1.setFocus();
                focus_index = 0;
                addEventListener(FocusEvent.KEY_FOCUS_CHANGE, changeFocus);
                // build a list of the UIComponents we
                // want to focus on.
                var list:Array = box.getChildren();

                for each (var ui:UIComponent in list)
                {
                if(ui is TextInput)
                {
                tiList.push(ui);
                }

                }
                len = tiList.length;
                }

                protected function changeFocus(event:FocusEvent):void{
                event.stopImmediatePropagation();
                event.preventDefault();
                if(event.shiftKey == false)
                callLater(setCompFocus);
                else
                callLater(setCompFocusBackwards);



                }

                protected function setCompFocus():void
                {


                var l:int = tiList.length;
                var idx:int = focus_index;

                if(focus_index >= len-1)
                {
                focus_index = 0
                }
                else
                {
                focus_index++
                }
                var input:TextInput = tiList[focus_index] as TextInput;
                trace("Setting focus on : " + input.id + " with index: " + focus_index);
                input.setFocus();


                }
                protected function setCompFocusBackwards():void
                {


                var l:int = tiList.length;
                var idx:int = focus_index;

                var last:int = len -1;
                if(focus_index == 0)
                {
                focus_index = last;
                }
                else
                {
                focus_index--;
                }
                var input:TextInput = tiList[focus_index] as TextInput;
                trace("Setting focus on : " + input.id + " with index: " + focus_index);
                input.setFocus();

                }

                ]]>
                </mx:Script>
                <mx:Button x="75" y="157" label="Don't focus on this button"/>
                </mx:Canvas>
                </mx:Application>
                • 5. Giving focus to Flex app without mouse
                  fabiomina Level 1
                  Thank you for yor response, JKohn99 .

                  Unfortunately your example is not an answer to my problem.
                  As I wrote in the initial post, there are two issues:

                  1 - While I can give the initial focus to a field in the applet, the focus moves away when I press the tab key: I must click in a field with the mouse at least once to move the focus to the applet in a "sticky" way

                  2 - Even after using the mouse to give the "sticky" focus to the applet, if I press tab from the last input field, the focus leaves the applet

                  Your example is a solution for the second issue, which I already have a workaround for (I also use the keyFocusChange event, as described in my initial post).
                  What is really bothering me is the first issue, and it is not solved by the proposed code, where the focus do work correctly only AFTER I click in the first field with the mouse.

                  BTW, I verified that using Firefox instead of Internet Explorer, the focus is correctly managed.

                  • 6. Re: Giving focus to Flex app without mouse
                    JKohn99 Level 1
                    I guess I don't understand what you're trying to accomplish. In my example the focus starts in the first field, and pressing the tab key moves to the second field. This seems to me to be standard behavior when pressing a tab key.

                    With my example you can precisely control where the focus goes and it does not tab out to the address bar and you should never have to use the mouse.
                    • 7. Re: Giving focus to Flex app without mouse
                      fabiomina Level 1
                      If you see your example working correctly, I guess this is because you could also see MY example working correctly!

                      I just found out that the issue is related to the way used in my HTML page to load the Flash ActiveX.
                      To avoid the activation problem introduced by security changes in IE ( http://msdn.microsoft.com/ieupdate/), Adobe introduced a Javascript-based mechanism to instantiate the <object> tag ( http://www.adobe.com/devnet/activecontent/), and this is the default in Flex Builder 2.0 (i.e. when I launch my app, Flex Builder generates an enclosing HTML page which use Javascript to instantiate the applet).
                      It looks like in IE6, this mechanism fails to give focus to the applet in a sticky way without a mouse click (no problem with IE7 and Firefox).

                      In fact, if I change the template file used by the Builder to generate the enclosing HTML (index.template.html ), and I force a normal <object> tag in the page:
                      - I see the "Pres SPACEBAR or ENTER key to activate and use this control" message shown by IE....
                      - but, after pressing spacebar or enter, the focus is in the first field and I CAN move it to other fields with the tab key

                      So, now I have understood much better the issue, but I am still wondering if there is a solution better than the following ones:

                      - to force users to move from IE6 (not realistic, the have so many PCs..)
                      - to live with the annoying initial activation message
                      • 8. Re: Giving focus to Flex app without mouse
                        JKohn99 Level 1
                        I use the following javascript to give focus to the Flash activeX control
                        To get the focus on startup (in IE) you need to add the following JavaScript to your
                        index_template.html:
                        window.onload = function()
                        {
                        var fxControl = document.${application} || window.${application};
                        fxControl.focus();
                        }

                        This avoids having to use the mouse on startup.