I have an Android NDK game (NDK 4.) Almost all of the code is in C++ (it's a port) so in the Java all I have is an Activity and a GLSurfaceView with an override for onTouchEvents. I'm trying to figure out how to receive key press events so that I can forward them on to the native code to be handled.
I tried having the View implement OnKeyListener but onKey() is never called. Also tried overriding the onKeyDown() and onKeyUp() in the View with no success. Am I missing something?
Update
The View as I'm currently using it:
public class FooView extends GLSurfaceView implements SurfaceHolder.Callback, OnKeyListener
{
private GameRenderer _renderer;
private GameListener _listener;
public FooView(Context context)
{
super(context);
this._renderer = new GameRenderer();
setRenderer(this._renderer);
this._listener = new GameListener(context);
BaseLib.setListener(this._listener);
}
#Override
public boolean onTouchEvent(final MotionEvent event)
{
// touch code...
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
Log.d("testing", "onKeyDown event from Java");
return super.onKeyDown(keyCode, event);
}
#Override
public boolean onKeyUp(int keyCode, KeyEvent event)
{
Log.d("testing", "onKeyUp event from Java");
return super.onKeyUp(keyCode, event);
}
#Override
public boolean onKey(View view, int keyCode, KeyEvent event)
{
Log.d("testing", "onKey event from Java");
return true;
}
}
Try this:
#Override
public boolean dispatchKeyEvent(KeyEvent event)
{
//
// SEND event.getAction() to your NDK code
//
if(<NDK CODE PROCESSED IT>) return true;
// default behavior for everything else
return super.dispatchKeyEvent(event);
}
(typing from memory, so the syntax may not be 100%, but... )as per my comment... are you doing this... ?
class myAct extends Activity implements View.onKeyListener
myButton.setOnKeyListener(this)
Related
I want to detect when the power button has been pressed (not long press) in my app.
I'm using the following code:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
Log.d("mytag", "keycode_power");
return true;
}
return super.onKeyDown(keyCode, event);
}
However, nothing prints to log. I've also tried:
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
Log.d("mytag", "power off");
}
return super.dispatchKeyEvent(event);
}
but that doesn't work either.
Any suggestions?
I'm No Expert, But I Don't Think That The Power Button Counts As A Keypress
As I described in the Title, my problem is that there is a view that is not focusable. So now I've no idea how to get KeyEvents from the View...
Edit:
If possible, event can be listened from service
I have used this code in a fragment to close a full screen pager view and it works
View v = inflater.inflate(R.layout.fragment_addetails, container1,
false);
v.setFocusableInTouchMode(true);
v.requestFocus();
v.setOnKeyListener(new OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK
&& pager.getVisibility() == View.VISIBLE) {
pager.setVisibility(View.GONE);
return true;
}
return false;
}
});
or this
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
//do code
return true
}
return false;
}
maybe this will help
if not please describe the full scenario for what your are trying to achieve
Ok I found out, that I can use the MediaButton to get the KeyEvent I wanted. I just needed to declare a BroadcastReceiver and register it. Thats it!
I have survey about this subject in a day.
What I mean is how to show toast when tapping the Videoview for a while.
Below is what I've found,
Android: Why can't I give an onClickListener to a VideoView?
detect double tap (Double click) or long click in a videoview
But these really can't solve my problem.I really don't know what has happend?
And is there any function can fire up long pressing event in the video view?
here's my code
these two event really can't work.
mVideoView.setOnLongClickListener(new OnLongClickListener() {
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
final int arg2, long arg3) {
Log.e("devon","onitemlongclick");
return true;
}
#Override
public boolean onLongClick(View v) {
Log.e("devon","onLongClick");
return true;
}
});
need help !!!thanks!
add OnLongClickListener in your setupViewComponent call
try using onTouch
try attaching the OnLongClickListener to the videoview's surface
try wrapping the videoview with a transparent imageview/something that grabs focus, and use that as your 'touching pad'
post logcat.
This is a sample example on how to create your own TouchListsners for managing Click and LongClick on VideoView. In this example I pass to the listeners the idex of the data clicked and the index of the view (in behind I have several VideoView in arrays maps to data list, like in an Adapter)
/**
* Simple OnTouchListenerIndexed with Indexes for VideoView ClickListeners
* You have to handle longClick and click by yourself
*/
private abstract class OnTouchListenerIndexed implements OnTouchListener {
private static final int LONG_CLICK_DURATION=600;//in millis
int dataIndex = INDEX_NOT_DEFINED;
int imageViewIndex = INDEX_NOT_DEFINED;
long timeActionDown;
AtomicBoolean stillNotConsumed=new AtomicBoolean(true);
AtomicBoolean actionDone=new AtomicBoolean(false);
public OnTouchListenerIndexed(int dataIndex, int imageViewIndex) {
this.dataIndex = dataIndex;
this.imageViewIndex = imageViewIndex;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
timeActionDown=System.currentTimeMillis();
stillNotConsumed.set(true);
actionDone.set(false);
//launch LongClick in 1s
v.postDelayed(new Runnable() {
#Override
public void run() {
if(stillNotConsumed.get()){
stillNotConsumed.set(false);
actionDone.set(true);
onLongTouch(dataIndex, imageViewIndex);
}
}
},LONG_CLICK_DURATION);
//consumed
return true;
}else if(event.getAction() == MotionEvent.ACTION_UP){
long timeActionUp=System.currentTimeMillis();
stillNotConsumed.set(false);
if(actionDone.get()){
//do nothing
return true;//you have consumed it
}else {
actionDone.set(true);
//Check Click or LongClick
if (timeActionUp - timeActionDown > LONG_CLICK_DURATION) {
//une seconde plus tard
return onLongTouch(dataIndex, imageViewIndex);
} else {
return onTouch(dataIndex, imageViewIndex);
}
}
}else{
//don't consume it
return false;
}
}
public abstract boolean onTouch(int dataIndex, int imageViewIndex);
public abstract boolean onLongTouch(int dataIndex, int imageViewIndex);
}
I'm having difficulty getting my main View's onKey event to trigger. I'm not sure what I'm doing wrong, I have correctly implemented the onClick event but cannot seem to figure out the onKey event.
Here's the relevant code:
public class MyActivity extends Activity {
private RelativeLayout main;
private ApplicationToolbar toolbar;
public void onCreate(Bundle savedInstanceState) {
...
this.main = (RelativeLayout) this.findViewById(R.id.main);
this.toolbar = new ApplicationToolbar(this);
// toolbar is added to main later on in the code...
this.main.setOnClickListener(mClickListener);
this.main.setOnKeyListener(mKeyListener);
}
private OnClickListener mClickListener = new OnClickListener() {
public void onClick(View v) {
toolbar.setVisibility(View.VISIBLE); // Works correctly.
}
};
private OnKeyListener mKeyListener = new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
toolbar.setBackgroundColor(0xFF0000FF); // Does not work.
return true;
}
};
}
In fact, no matter what code I put within mKeyListener it does not execute, which leads me to believe that the event itself is never being triggered, even when I pressed a bunch of keys on my physical keyboard (Motorola Droid, Android 2.1).
You can try overriding onKeyDown(int keyCode, KeyEvent event)
Check:
Back and other hard keys: three stories
is there a default back key(on device) listener in android?
I want to do a custom action when pressing on the Menu button on the phone.
Is it possible to set an onClickListener (or similar) on the button and if so, how?
onCreateOptionsMenu is only called the first time the button is pressed - I've already tried this.
Usually you shouldn't override MENU behavior as users expect menu to appear, however you can use something along these lines:
/* (non-Javadoc)
* #see android.app.Activity#onKeyDown(int, android.view.KeyEvent)
*/
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ( keyCode == KeyEvent.KEYCODE_MENU ) {
Log.d(TAG, "MENU pressed");
return true;
}
return super.onKeyDown(keyCode, event);
}
But onPrepareOptionsMenu(..) is called each time. :)
Updated for AppCompat v.22.+
As mentioned in this forum, KeyDown is not called for KEYCODE_MENU button pressed.
The solution is to override dispatchKeyEvent to this way:
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
int keyCode = event.getKeyCode();
int action = event.getAction();
boolean isDown = action == KeyEvent.ACTION_DOWN;
if (keyCode == KeyEvent.KEYCODE_MENU) {
return isDown ? this.onKeyDown(keyCode, event) : this.onKeyUp(keyCode, event);
}
return super.dispatchKeyEvent(event);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ( keyCode == KeyEvent.KEYCODE_MENU ) {
// do what you want to do here
return true;
}
return super.onKeyDown(keyCode, event);
}
It works until Google developers release a fix for this (or maybe it is not a bug and it works this way from now on).
You could probably hack something in using "OnMenuOpened" or some such, but I really wouldn't recommend it. The menu button is only supposed to be used to show menus, so there is consistency between applications.