zoukankan      html  css  js  c++  java
  • 在minimo中用方向键切换焦点

     

    minimo中用方向键切换焦点

     

    转载时请注明出处和作者联系方式

    作者联系方式:李先静 <xianjimli at hotmail dot com>

     

    XUL编写的minimo实在太慢了,起动过程足足要40秒钟,我对它已经完全失去信心了。前几天发现用GTK+编写的minimo则要快得多,第二次起动仅仅花了7秒钟时间,这要让我精神大振,可惜mozilla中所带的GTK+编写的minimo已经没有人维护了,代码很凌乱,很多功能也都不支持。

     

    最后我们决定用GTK+重新编写minimo,而界面完全模仿Windows Mobile5.0 中的IE。经过一周时间的努力,基本功能已经完成,只是还有少数功能需要完善。其中方向键切换焦点就是其中的问题之一,在firefox里,默认情况是不能用方向键在网页中切换焦点的,切换焦点只能用tab键,而普通手机根本没有tab键,我们希望能用方向键代替tab实现焦点切换。

     

    以前在阅读mozilla代码时,我记得有个扩展可以实现这个功能,不过忘了具体是哪个扩展了,今天在extension目录里找了一下,很快确认是spatialnavigation扩展,spatial取得真不怎么样,我还以为是什么3D相关的东西的呢,还好navigation给了一些提示。

     

    Spatialnavigation的实现原理很简单:

     

    NS_IMETHODIMP
    nsSpatialNavigation::Init(nsIDOMWindow *aWindow)
    {
      mTopWindow = aWindow;

      nsCOMPtr<nsIDOM3EventTarget> target;
      nsCOMPtr<nsIDOMEventGroup> systemGroup;
      nsresult rv = getEventTargetFromWindow(aWindow, getter_AddRefs(target), getter_AddRefs(systemGroup));
      if (NS_FAILED(rv))
        return rv;  
      
      target->AddGroupedEventListener(NS_LITERAL_STRING("keypress"),
                                      static_cast<nsIDOMKeyListener*>(this),
                                      PR_FALSE,
                                      systemGroup);
      
      return NS_OK;
    }

     

    这个函数向DOMWindow注册按键事件,当有按键发生时,nsSpatialNavigation相关虚函数就会被调用。

     

    NS_IMETHODIMP
    nsSpatialNavigation::KeyDown(nsIDOMEvent* aEvent)
    {
      nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
      PRBool enabled;
      prefBranch->GetBoolPref("snav.enabled", &enabled);
      if (!enabled) //  this doesn't work.  wtf? if (!mService->mEnabled)
        return NS_OK;
     

      nsCOMPtr<nsIDOMNSUIEvent> uiEvent(do_QueryInterface(aEvent));
      if (uiEvent)
      {
        // If a web page wants to use the keys mapped to our
        // move, they have to use evt.preventDefault() after
        // they get the key

        PRBool preventDefault;
        uiEvent->GetPreventDefault(&preventDefault);
        if (preventDefault)
          return NS_OK;
      }

      PRInt32 formControlType = -1;
      // check to see if we are in a text field.
      // based on nsTypeAheadFind.
        
      //nsEvent should be renamed.
      nsCOMPtr<nsIDOMNSEvent> nsEvent = do_QueryInterface(aEvent);
      if (!nsEvent)
        return NS_ERROR_FAILURE;
      
      nsCOMPtr<nsIDOMEventTarget> domEventTarget;
      nsEvent->GetOriginalTarget(getter_AddRefs(domEventTarget));
      
      nsCOMPtr<nsIContent> targetContent = do_QueryInterface(domEventTarget);

      if (targetContent->IsNodeOfType(nsINode::eXUL))
        return NS_OK;
      
      if (targetContent->IsNodeOfType(nsINode::eHTML_FORM_CONTROL))
      {
          nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(targetContent));
          formControlType = formControl->GetType();
          
          if (mService->mIgnoreTextFields)
          {
            if (formControlType == NS_FORM_TEXTAREA ||
                formControlType == NS_FORM_INPUT_TEXT ||
                formControlType == NS_FORM_INPUT_PASSWORD ||
                formControlType == NS_FORM_INPUT_FILE)
            {
              return NS_OK;
            }
          }
      }
      else if (mService->mIgnoreTextFields && targetContent->IsNodeOfType(nsINode::eHTML))
      {
        // Test for isindex, a deprecated kind of text field. We're using a string
        // compare because <isindex> is not considered a form control, so it does
        // not support nsIFormControl or eHTML_FORM_CONTROL, and it's not worth
        // having a table of atoms just for it.
        
          if (isContentOfType(targetContent, "isindex"))
            return NS_OK;
      }

        if (formControlType == NS_FORM_INPUT_TEXT ||
            formControlType == NS_FORM_INPUT_PASSWORD)
        {
          PRInt32 selectionStart, textLength;
          nsCOMPtr<nsIDOMNSHTMLInputElement> input = do_QueryInterface(targetContent);
          if (input) {
            input->GetSelectionStart (&selectionStart);
            input->GetTextLength (&textLength);
          } else {
            nsCOMPtr<nsIDOMNSHTMLTextAreaElement> textArea = do_QueryInterface(targetContent);
            if (textArea) {
              textArea->GetSelectionStart (&selectionStart);
              textArea->GetTextLength (&textLength);
            }
          }
              
          if (textLength != 0 && selectionStart != 0)
            return NS_OK;
        }

        // We're using this key, no one else should
        aEvent->StopPropagation();
            aEvent->PreventDefault();
            
        return Left();
      }
      
      if (keyCode == mService->mKeyCodeRight)
      {
        // ************************************************************************************
        // NS_FORM_TEXTAREA cases:

        // ************************************************************************************
        // NS_FORM_INPUT_TEXT | NS_FORM_INPUT_PASSWORD | NS_FORM_INPUT_FILE cases

        if (formControlType == NS_FORM_INPUT_TEXT ||
            formControlType == NS_FORM_INPUT_PASSWORD)
        {
          PRInt32 selectionEnd, textLength;
          nsCOMPtr<nsIDOMNSHTMLInputElement> input = do_QueryInterface(targetContent);
          if (input) {
            input->GetSelectionEnd (&selectionEnd);
            input->GetTextLength (&textLength);
          } else {
            nsCOMPtr<nsIDOMNSHTMLTextAreaElement> textArea = do_QueryInterface(targetContent);
            if (textArea) {
              textArea->GetSelectionEnd (&selectionEnd);
              textArea->GetTextLength (&textLength);
            }
          }
          
          // going down.

          if (textLength  != selectionEnd)
            return NS_OK;
        }
            
        aEvent->StopPropagation();
            aEvent->PreventDefault();
        return Right();
      }
      
      if (keyCode == mService->mKeyCodeUp)
      {

        // If we are going up or down, in a select, lets not
        // navigate.
        //
        // FIX: What we really want to do is determine if we are
        // at the start or the end fo the form element, and
        // based on the selected position we decide to nav. or
        // not.

        // ************************************************************************************
        // NS_FORM_SELECT cases:
        // * if it is a select form of 'size' attr != than '1' then we do as above.

        // * if it is a select form of 'size' attr == than '1', snav can take care of it.
        // if (formControlType == NS_FORM_SELECT)
        //   return NS_OK;

        aEvent->StopPropagation();
        aEvent->PreventDefault();
        return Up();
      }
      
      if (keyCode == mService->mKeyCodeDown)
      {
        // If we are going up or down, in a select, lets not
        // navigate.
        //
        // FIX: What we really want to do is determine if we are
        // at the start or the end fo the form element, and
        // based on the selected position we decide to nav. or
        // not.

        // ************************************************************************************
        // NS_FORM_SELECT cases:
        // * if it is a select form of 'size' attr != than '1' then we do as above.

        // * if it is a select form of 'size' attr == than '1', snav can take care of it.
        // if (formControlType == NS_FORM_SELECT)
        //   return NS_OK;

        aEvent->StopPropagation();  // We're using this key, no one else should
        aEvent->PreventDefault();
        return Down();
      }
      
      return NS_OK;
    }

     

    以上函数负责对按键事件的处理。我发现该函数被调用了,但是就是没有切换焦点,调试了好一会才发现,原来是两个设置没有设,后来加了一个函数,在初始时调用,一切正常了:

     

    gboolean mozilla_pref_init(void)
    {
        nsresult rv;
        nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);

        if(NS_SUCCEEDED(rv) && pref != nsnull)
        {
            pref->SetIntPref("snav.keyCode.modifier", 0);
            pref->SetBoolPref("snav.enabled", true);
        }

        return TRUE;
    }

     

    Spatialnavigation是一个非常典型的扩展,对于实现自己的扩展很有参考价值,特别是添加自己的快捷键处理。

     

    ~~end~~

     

  • 相关阅读:
    nginx命令
    linux 命令
    js导出excel页面数据
    Linux上使用shell脚本查看内存情况(超实用)
    Gson解析json繁杂数据
    纯js制作遮罩层对话框
    简易树形菜单(可伸缩)
    一句实现jquery导航栏
    沁园春-雪
    python day3 int,str,list类型补充
  • 原文地址:https://www.cnblogs.com/zhangyunlin/p/6167698.html
Copyright © 2011-2022 走看看