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~~

     

  • 相关阅读:
    Verilog非阻塞赋值的仿真/综合问题 (Nonblocking Assignments in Verilog Synthesis)上
    异步FIFO结构及FPGA设计 跨时钟域设计
    FPGA管脚分配需要考虑的因素
    An Introduction to Delta Sigma Converters (DeltaSigma转换器 上篇)
    An Introduction to Delta Sigma Converters (DeltaSigma转换器 下篇)
    中国通信简史 (下)
    谈谈德国大学的电子专业
    中国通信简史 (上)
    Verilog学习笔记
    Verilog非阻塞赋值的仿真/综合问题(Nonblocking Assignments in Verilog Synthesis) 下
  • 原文地址:https://www.cnblogs.com/zhangyunlin/p/6167698.html
Copyright © 2011-2022 走看看