soft keyboard and `textInputNotRequired'

9 posts / 0 new
Last post
hugh
Offline
Last seen: 4 months 1 week ago
Joined: 25 Apr 2010 - 20:04
soft keyboard and `textInputNotRequired'

i'm trying to implement the popup soft keyboard on android. this needs to be triggered from the ComponentPeer. so by implementing `textInputRequired' inside juce_android_Windowing.cpp i can get a keyboard to appear. but then i have no way to remove it. at first, i thought i could hook `dismissPendingTextInput' but this is not called when there is no "pending text input", for example if you don't make an edit to a box.

i put a bit of a hack into my version as follows;

i added virtual void ComponentPeer::textInputNotRequired(); and then implemented this in juce_android_Windowing.cpp

right now i'm triggering this from the Label

void Label::editorAboutToBeHidden (TextEditor*) 
{
    ComponentPeer* const peer = getPeer();
    if (peer)
        peer->textInputNotRequired();
}

probably not the ideal place, but it gets there.

here's also the code to do the soft keyboard,

juce_android_Windowing.cpp:

void textInputRequired (const Point<int>& position)
    {
        view.callVoidMethod (ComponentPeerView.showKeyboard, true);
    }

    void textInputNotRequired ()
    {
        view.callVoidMethod (ComponentPeerView.showKeyboard, false);
    }

   void dismissPendingTextInput()
    {
        view.callVoidMethod (ComponentPeerView.showKeyboard, false);
    }

Java activity,

import android.view.inputmethod.InputMethodManager;

     public void showKeyboard(boolean v)
        {
            InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
            if (v)
                imm.showSoftInput(this, InputMethodManager.SHOW_FORCED);
            else
                imm.hideSoftInputFromWindow(getWindowToken(), 0);
        }

There are probably many problems left with this. firstly, forcing the keyboard on and off is probably not the best way and secondly, i'm not yet checking for the existence of a real keyboard.

also, it's still wobbly. the keyboard can keep popping up and down if you've got a panel with several entry boxes. not ideal.

-- hugh.

bebopagogo
Offline
Last seen: 1 year 8 months ago
Joined: 15 Mar 2012 - 01:08
Re: soft keyboard and `textInputNotRequired'

Did you add your Java activity code as a method of the "JuceAppActivity" class? Or extend that class in some other way? (i.e. without modifying the "JuceAppActivity.java" file). I'm not a big Java jockey but the "final" keyword on JuceAppActivity may not let you extend it. I'm just looking at adding your ideas here to an app that needs keyboard popup / popdown and just trying to figure out how to proceed in a pragmatic way (given my newness to Android and Juce). For example, in IOS, I was able able add some C++/Objective C to inform the main window when the keyboard popped up/down and the keyboard size so the window could resize itself so the keyboard didn't hide it. I'm trying to figure out how to do the same for Android and your code here looks like a place to start (So thanks for posting this in the first place!)

bebopagogo

hugh
Offline
Last seen: 4 months 1 week ago
Joined: 25 Apr 2010 - 20:04
Re: soft keyboard and `textInputNotRequired'

Hello, i've been using this juce hack for a while now and it's mostly ok.

Yes, there are some other boring changes to make it work, i skipped over. let me see....

juce_ComponentPeer.h

 // any OS keyboard not required
    virtual void textInputNotRequired () {}

juce_android_windowing.cpp. note the hacks to the key codes. i've only fixed a few of them so that the basics work.

*** 91,102 ****
--- 94,106 ----
   METHOD (requestFocus,  "requestFocus",     "()Z") \
   METHOD (setVisible,    "setVisible",       "(Z)V") \
   METHOD (isVisible,     "isVisible",        "()Z") \
   METHOD (hasFocus,      "hasFocus",         "()Z") \
   METHOD (invalidate,    "invalidate",       "(IIII)V") \
   METHOD (containsPoint, "containsPoint",    "(II)Z") \
+  METHOD (showKeyboard, "showKeyboard",      "(Z)V") \
   METHOD (createGLView,  "createGLView",     "()L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$OpenGLView;") \
  
  DECLARE_JNI_CLASS (ComponentPeerView, JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView");
  #undef JNI_CLASS_MEMBERS
  
  
***************
*** 353,364 ****
--- 357,379 ----
      {
          lastMousePos.setXY ((int) x, (int) y);
          currentModifiers = currentModifiers.withoutMouseButtons();
          handleMouseEvent (0, lastMousePos, currentModifiers, time);
      }
  
+     void handleKeyDownCallback (int k, int kc)
+     {
+         handleKeyPress(k, kc);
+     }
+ 
+     void handleKeyUpCallback (int k, int kc)
+     {
+         //handleKeyUpOrDown(false);
+     }
+ 
+ 
      //==============================================================================
      bool isFocused() const
      {
          return view.callBooleanMethod (ComponentPeerView.hasFocus);
      }
  
***************
*** 374,386 ****
          else
              handleFocusLoss();
      }
  
      void textInputRequired (const Point<int>& position)
      {
!         // TODO
      }
  
      //==============================================================================
      void handlePaintCallback (JNIEnv* env, jobject canvas)
      {
          jobject rect = env->CallObjectMethod (canvas, CanvasMinimal.getClipBounds);
--- 389,411 ----
          else
              handleFocusLoss();
      }
  
      void textInputRequired (const Point<int>& position)
      {
!         view.callVoidMethod (ComponentPeerView.showKeyboard, true);
!     }
! 
!     void textInputNotRequired ()
!     {
!         view.callVoidMethod (ComponentPeerView.showKeyboard, false);
!     }
! 
!     void dismissPendingTextInput()
!     {
!         view.callVoidMethod (ComponentPeerView.showKeyboard, false);
      }
  
      //==============================================================================
      void handlePaintCallback (JNIEnv* env, jobject canvas)
      {
          jobject rect = env->CallObjectMethod (canvas, CanvasMinimal.getClipBounds);
***************
*** 557,568 ****
--- 582,597 ----
  JUCE_VIEW_CALLBACK (void, handleMouseDown,  (JNIEnv* env, jobject view, jfloat x, jfloat y, jlong time),    handleMouseDownCallback ((float) x, (float) y, (int64) time))
  JUCE_VIEW_CALLBACK (void, handleMouseDrag,  (JNIEnv* env, jobject view, jfloat x, jfloat y, jlong time),    handleMouseDragCallback ((float) x, (float) y, (int64) time))
  JUCE_VIEW_CALLBACK (void, handleMouseUp,    (JNIEnv* env, jobject view, jfloat x, jfloat y, jlong time),    handleMouseUpCallback ((float) x, (float) y, (int64) time))
  JUCE_VIEW_CALLBACK (void, viewSizeChanged,  (JNIEnv* env, jobject view),                                    handleMovedOrResized())
  JUCE_VIEW_CALLBACK (void, focusChanged,     (JNIEnv* env, jobject view, jboolean hasFocus),                 handleFocusChangeCallback (hasFocus))
  
+ JUCE_VIEW_CALLBACK (void, handleKeyDown,  (JNIEnv* env, jobject view, jint k, jint kc),  handleKeyDownCallback ((int) k, (int)kc))
+ 
+ JUCE_VIEW_CALLBACK (void, handleKeyUp,  (JNIEnv* env, jobject view, jint k, jint kc),  handleKeyUpCallback ((int) k, (int)kc))
+ 
  //==============================================================================
  ComponentPeer* Component::createNewPeer (int styleFlags, void*)
  {
      return new AndroidComponentPeer (*this, styleFlags);
  }
  
***************
*** 621,637 ****
  
  //==============================================================================
  bool Process::isForegroundProcess()
  {
      return true;      // TODO
  }
- 
  void Process::makeForegroundProcess()
  {
  }
- 
  //==============================================================================
  void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType iconType,
                                                            const String& title, const String& message,
                                                            Component* associatedComponent)
  {
      android.activity.callVoidMethod (JuceAppActivity.showMessageBox, javaString (title).get(), javaString (message).get(), (jlong) 0);
--- 650,664 ----
***************
*** 752,778 ****
      return juceString (text);
  }
  
  //==============================================================================
  const int extendedKeyModifier       = 0x10000;
  
  const int KeyPress::spaceKey        = ' ';
! const int KeyPress::returnKey       = 0x0d;
! const int KeyPress::escapeKey       = 0x1b;
! const int KeyPress::backspaceKey    = 0x7f;
  const int KeyPress::leftKey         = extendedKeyModifier + 1;
  const int KeyPress::rightKey        = extendedKeyModifier + 2;
  const int KeyPress::upKey           = extendedKeyModifier + 3;
  const int KeyPress::downKey         = extendedKeyModifier + 4;
  const int KeyPress::pageUpKey       = extendedKeyModifier + 5;
  const int KeyPress::pageDownKey     = extendedKeyModifier + 6;
  const int KeyPress::endKey          = extendedKeyModifier + 7;
  const int KeyPress::homeKey         = extendedKeyModifier + 8;
  const int KeyPress::deleteKey       = extendedKeyModifier + 9;
  const int KeyPress::insertKey       = -1;
! const int KeyPress::tabKey          = 9;
  const int KeyPress::F1Key           = extendedKeyModifier + 10;
  const int KeyPress::F2Key           = extendedKeyModifier + 11;
  const int KeyPress::F3Key           = extendedKeyModifier + 12;
  const int KeyPress::F4Key           = extendedKeyModifier + 13;
  const int KeyPress::F5Key           = extendedKeyModifier + 14;
  const int KeyPress::F6Key           = extendedKeyModifier + 16;
--- 779,810 ----
      return juceString (text);
  }
  
  //==============================================================================
  const int extendedKeyModifier       = 0x10000;
  
+     const int KeyPress::returnKey       = 66;
+     const int KeyPress::escapeKey       = 4;
+     const int KeyPress::backspaceKey    = 67;
+     const int KeyPress::tabKey          = 61;
+ 
  const int KeyPress::spaceKey        = ' ';
!     //const int KeyPress::returnKey       = 0x0d;
!     //const int KeyPress::escapeKey       = 0x1b;
!     //const int KeyPress::backspaceKey    = 0x7f;
  const int KeyPress::leftKey         = extendedKeyModifier + 1;
  const int KeyPress::rightKey        = extendedKeyModifier + 2;
  const int KeyPress::upKey           = extendedKeyModifier + 3;
  const int KeyPress::downKey         = extendedKeyModifier + 4;
  const int KeyPress::pageUpKey       = extendedKeyModifier + 5;
  const int KeyPress::pageDownKey     = extendedKeyModifier + 6;
  const int KeyPress::endKey          = extendedKeyModifier + 7;
  const int KeyPress::homeKey         = extendedKeyModifier + 8;
  const int KeyPress::deleteKey       = extendedKeyModifier + 9;
  const int KeyPress::insertKey       = -1;
!     //const int KeyPress::tabKey          = 9;
  const int KeyPress::F1Key           = extendedKeyModifier + 10;
  const int KeyPress::F2Key           = extendedKeyModifier + 11;
  const int KeyPress::F3Key           = extendedKeyModifier + 12;
  const int KeyPress::F4Key           = extendedKeyModifier + 13;
  const int KeyPress::F5Key           = extendedKeyModifier + 14;
  const int KeyPress::F6Key           = extendedKeyModifier + 16;

There are some changes you have to make also to your generated java activity class:

import android.view.inputmethod.InputMethodManager;
...
      private native void handleKeyDown (int keycode, int textchar);
        private native void handleKeyUp (int keycode, int textchar);


        @Override
        public boolean onKeyDown(int keyCode, KeyEvent event)
        {
         
            handleKeyDown(keyCode, event.getUnicodeChar());
            return true;
        }    

        @Override
        public boolean onKeyUp(int keyCode, KeyEvent event)
        {
            handleKeyUp(keyCode, event.getUnicodeChar());
            return true;
        }    

        public void showKeyboard(boolean v)
        {
            InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
            if (v)
                imm.showSoftInput(this, InputMethodManager.SHOW_FORCED);
            else
                imm.hideSoftInputFromWindow(getWindowToken(), 0);
        }

i think that might be it,

-- hugh.

spaky
Offline
Last seen: 1 month 4 weeks ago
Joined: 22 Jun 2007 - 09:56
Re: soft keyboard and `textInputNotRequired'

Hey,

i also tried to get the soft keyboard working on Samsung Galaxy Tab2 10.1 with Android 4.03.

Following things I needed to add in addition to yours:

import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager

        @Override
        public InputConnection onCreateInputConnection(EditorInfo outAttrs)
        {
            outAttrs.actionLabel = "";
            outAttrs.hintText = "";
            outAttrs.initialCapsMode = 0;
            outAttrs.initialSelEnd = outAttrs.initialSelStart = -1;
            outAttrs.label = "";
            outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_EXTRACT_UI;        
            outAttrs.inputType = InputType.TYPE_NULL;        

            return  new BaseInputConnection(this, false);       
        } 
hugh
Offline
Last seen: 4 months 1 week ago
Joined: 25 Apr 2010 - 20:04
Re: soft keyboard and `textInputNotRequired'

Hi,

Thanks for the additions. i've not tried in on the samsung tab (nor other samsungs). i've tried the nexus7 (4.2) and a no-name gingerbread 2.3.3 phone.

jules
Online
Last seen: 6 min 56 sec ago
Joined: 29 Apr 2013 - 18:37
Re: soft keyboard and `textInputNotRequired'

I should add this stuff.. Hugh, could you perhaps mail me a copy of whatever your latest files are so I can have a shufty at the changes? Ta!

hugh
Offline
Last seen: 4 months 1 week ago
Joined: 25 Apr 2010 - 20:04
Re: soft keyboard and `textInputNotRequired'

will do. i'll send you a changelist against the latest juce tip.

-- hugh.

Nogoth
Offline
Last seen: 1 year 2 months ago
Joined: 30 Apr 2013 - 17:01
Re: soft keyboard and `textInputNotRequired'

I'm asking here to not open new topic. I am writing app and I need software keyboard. In landscape view everything is ok (I'm testing ok Galaxy Mini II), but in portrait it looks like something is covering keyboard. Do You know how to fix it?

Nogoth
Offline
Last seen: 1 year 2 months ago
Joined: 30 Apr 2013 - 17:01
Re: soft keyboard and `textInputNotRequired'

I found solution for keyboard problem on my Samsung Galaxy mini II (GT-S6500) with Android 2.3.6. I had to change outAttrs.inputType = InputType.TYPE_NULL;
to
outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
Without that my android couldn't find key pattern. After that keyboard was working ok, but it was opening with app, so i had to add to android manifest:
android:windowSoftInputMode="stateHidden"