Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timob 10232: Android: Capturing onKeyPress from the hardware keyboard #3095

Merged
merged 7 commits into from
Oct 10, 2012
9 changes: 9 additions & 0 deletions android/titanium/src/java/org/appcelerator/titanium/TiC.java
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ public class TiC
*/
public static final String EVENT_FOCUSED = "focused";

/**
* @module.api
*/
public static final String EVENT_KEY_PRESSED = "keypressed";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be "keyPressed" instead? "keypressed" doesn't follow the standard capitalization format.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The event name should be all lower case. This is part of the new event system (http://jira.appcelerator.org/browse/TIMOB-10291).

/**
* @module.api
*/
Expand Down Expand Up @@ -248,6 +252,11 @@ public class TiC
*/
public static final String EVENT_PROPERTY_IS_USER_GESTURE = "isUserGesture";

/**
* @module.api
*/
public static final String EVENT_PROPERTY_KEYCODE = "keyCode";

/**
* @module.api
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ protected TiUIView handleGetView()
}
realizeViews(view);
view.registerForTouch();
view.registerForKeyPress();
}
return view;
}
Expand Down
101 changes: 83 additions & 18 deletions android/titanium/src/java/org/appcelerator/titanium/view/TiUIView.java
Original file line number Diff line number Diff line change
Expand Up @@ -517,13 +517,9 @@ public void propertyChanged(String key, Object oldValue, Object newValue, KrollP
setzIndexChanged(true);
}
} else if (key.equals(TiC.PROPERTY_FOCUSABLE)) {
boolean focusable = TiConvert.toBoolean(proxy.getProperty(TiC.PROPERTY_FOCUSABLE));
nativeView.setFocusable(focusable);
if (focusable) {
registerForKeyClick(nativeView);
} else {
//nativeView.setOnClickListener(null); // ? mistake? I assume OnKeyListener was meant
nativeView.setOnKeyListener(null);
if (newValue != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This 'if' statement can be merged with the 'else if' statement from above.

boolean focusable = TiConvert.toBoolean(newValue);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably don't need to create a new variable focusable when you're only using it once.

registerForKeyPress(nativeView, focusable);
}
} else if (key.equals(TiC.PROPERTY_TOUCH_ENABLED)) {
doSetClickable(TiConvert.toBoolean(newValue));
Expand Down Expand Up @@ -696,17 +692,6 @@ public void processProperties(KrollDict d)
nativeView.setEnabled(TiConvert.toBoolean(d, TiC.PROPERTY_ENABLED));
}

if (d.containsKey(TiC.PROPERTY_FOCUSABLE) && !nativeViewNull) {
boolean focusable = TiConvert.toBoolean(d, TiC.PROPERTY_FOCUSABLE);
nativeView.setFocusable(focusable);
if (focusable) {
registerForKeyClick(nativeView);
} else {
//nativeView.setOnClickListener(null); // ? mistake? I assume OnKeyListener was meant
nativeView.setOnKeyListener(null);
}
}

initializeBorder(d, bgColor);

if (d.containsKey(TiC.PROPERTY_OPACITY) && !nativeViewNull) {
Expand Down Expand Up @@ -1041,6 +1026,11 @@ protected boolean allowRegisterForTouch()
return true;
}

protected boolean allowRegisterForKeyPress()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this was for module developers to extend and use this functionality, then we need add a description, and a module.api annotation

{
return true;
}

public View getOuterView()
{
if (borderView == null) {
Expand Down Expand Up @@ -1218,6 +1208,7 @@ public boolean onTouch(View view, MotionEvent event)
});

}

protected void registerForTouch(final View touchable)
{
if (touchable == null) {
Expand All @@ -1238,6 +1229,80 @@ protected void registerForTouch(final View touchable)
doSetClickable(touchable);
}


public void registerForKeyPress()
{
if (allowRegisterForKeyPress()) {
registerForKeyPress(getNativeView());
}
}

protected void registerForKeyPress(final View v)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this need to be 'final'?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it makes sure the view is not changed in the method.

{
if (v == null) {
return;
}

boolean focusable = false;
Object prop = proxy.getProperty(TiC.PROPERTY_FOCUSABLE);
if (prop != null) {
focusable = TiConvert.toBoolean(prop);
}
registerForKeyPress(v, focusable);
}

protected void registerForKeyPress(final View v, boolean focusable)
{
if (v == null) {
return;
}

v.setFocusable(focusable);

// The listener for the "keypressed" event is only triggered when the view has focus. So we only register the
// "keypressed" event when the view is focusable.
if (focusable) {
registerForKeyPressEvents(v);
} else {
v.setOnKeyListener(null);
}
}

/**
* Registers a callback to be invoked when a hardware key is pressed in this view.
*
* @param v The view to have the key listener to attach to.
*/
protected void registerForKeyPressEvents(final View v)
{
if (v == null) {
return;
}

v.setOnKeyListener(new OnKeyListener()
{
public boolean onKey(View view, int keyCode, KeyEvent event)
{
if (event.getAction() == KeyEvent.ACTION_UP) {
KrollDict data = new KrollDict();
data.put(TiC.EVENT_PROPERTY_KEYCODE, keyCode);
proxy.fireEvent(TiC.EVENT_KEY_PRESSED, data);

switch (keyCode) {
case KeyEvent.KEYCODE_ENTER:
case KeyEvent.KEYCODE_DPAD_CENTER:
if (proxy.hasListeners(TiC.EVENT_CLICK)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this documented? i.e click event is fired when enter key is pressed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's an existed behavior and already documented http://docs.appcelerator.com/titanium/2.1/#!/api/Titanium.UI.View-event-click

proxy.fireEvent(TiC.EVENT_CLICK, null);
}
}
return true;
}
return false;
}
});
}


/**
* Sets the nativeView's opacity.
* @param opacity the opacity to set.
Expand Down
12 changes: 12 additions & 0 deletions apidoc/Titanium/UI/View.yml
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,18 @@ events:
summary: Y coordinate of the event from the `source` view's coordinate system.
type: Number

- name: keypressed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

summary: Fired when a hardware key is pressed in the view.
description: |
A keypressed event is generated by pressing a hardware key. On Android, this event can only be
fired when the property [focusable](Titanium.UI.View.focusable) is set to true.
platforms: [android]
since: {android: 3.0.0}
properties:
- name: keyCode
type: Number
summary: The code for the physical key that was pressed. For more details see [KeyEvent](http://developer.android.com/reference/android/view/KeyEvent.html).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing comma, should be "For more details, see"


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For an immediate customer need this may work, but if this is eventually going to be cross-platform, we can't send Android key codes back to the app--we'd need to provide some kind of Titanium class to map keycodes.

I think if we need to include this for this release, we should make a note that this API is experimental and subject to change. Or words to that effect.

- name: longclick
summary: Fired when the device detects a long click.
description: |
Expand Down