Propagate input even return values in more places. Handle repeats better.

This commit is contained in:
Henrik Rydgard 2014-06-15 13:04:10 +02:00
parent 6739fc5654
commit a3e23f0ac6
13 changed files with 105 additions and 77 deletions

View File

@ -412,11 +412,15 @@ extern "C" jboolean JNICALL Java_com_henrikrydgard_libnative_NativeApp_touch
return retval;
}
extern "C" jboolean Java_com_henrikrydgard_libnative_NativeApp_keyDown(JNIEnv *, jclass, jint deviceId, jint key) {
extern "C" jboolean Java_com_henrikrydgard_libnative_NativeApp_keyDown(JNIEnv *, jclass, jint deviceId, jint key, jboolean isRepeat) {
KeyInput keyInput;
keyInput.deviceId = deviceId;
keyInput.keyCode = key;
keyInput.flags = KEY_DOWN;
if (isRepeat) {
ILOG("Is repeat! %i", key);
keyInput.flags |= KEY_IS_REPEAT;
}
return NativeKey(keyInput);
}

View File

@ -14,12 +14,12 @@ public class InputDeviceState {
// DEVICE_ID_PAD_0 from the cpp code. TODO: allocate these sequentially if we get more controllers.
private static int deviceId = 10;
private InputDevice mDevice;
private int[] mAxes;
InputDevice getDevice() { return mDevice; }
@TargetApi(19)
void logAdvanced(InputDevice device) {
Log.i(TAG, "Vendor ID:" + device.getVendorId() + " productId: " + device.getProductId());
@ -68,17 +68,13 @@ public class InputDeviceState {
public boolean onKeyDown(KeyEvent event) {
int keyCode = event.getKeyCode();
if (event.getRepeatCount() == 0) {
NativeApp.keyDown(deviceId, keyCode);
return true;
}
return false;
boolean repeat = event.getRepeatCount() > 0;
return NativeApp.keyDown(deviceId, keyCode, repeat);
}
public boolean onKeyUp(KeyEvent event) {
int keyCode = event.getKeyCode();
NativeApp.keyUp(deviceId, keyCode);
return true;
int keyCode = event.getKeyCode();
return NativeApp.keyUp(deviceId, keyCode);
}
public boolean onJoystickMotion(MotionEvent event) {

View File

@ -532,9 +532,6 @@ public class NativeActivity extends Activity {
boolean passThrough = false;
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_MUTE:
case KeyEvent.KEYCODE_MENU:
passThrough = true;
break;
@ -608,25 +605,22 @@ public class NativeActivity extends Activity {
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Eat these keys, to avoid accidental exits / other screwups.
// Maybe there's even more we need to eat on tablets?
boolean repeat = event.getRepeatCount() > 0;
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
if (event.isAltPressed()) {
NativeApp.keyDown(0, 1004); // special custom keycode
NativeApp.keyDown(0, 1004, repeat); // special custom keycode
} else if (NativeApp.isAtTopLevel()) {
Log.i(TAG, "IsAtTopLevel returned true.");
return super.onKeyDown(keyCode, event);
} else {
NativeApp.keyDown(0, keyCode);
NativeApp.keyDown(0, keyCode, repeat);
}
return true;
case KeyEvent.KEYCODE_MENU:
case KeyEvent.KEYCODE_SEARCH:
NativeApp.keyDown(0, keyCode);
NativeApp.keyDown(0, keyCode, repeat);
return true;
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
// NativeApp should ignore these.
return super.onKeyDown(keyCode, event);
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_DPAD_DOWN:
@ -641,8 +635,7 @@ public class NativeActivity extends Activity {
// send the rest of the keys through.
// TODO: get rid of the three special cases above by adjusting the native side of the code.
// Log.d(TAG, "Key down: " + keyCode + ", KeyEvent: " + event);
NativeApp.keyDown(0, keyCode);
return true;
return NativeApp.keyDown(0, keyCode, repeat);
}
}
@ -665,9 +658,7 @@ public class NativeActivity extends Activity {
// Search probably should also be ignored. We send it to the app.
NativeApp.keyUp(0, keyCode);
return true;
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
return super.onKeyUp(keyCode, event);
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_DPAD_LEFT:
@ -681,8 +672,7 @@ public class NativeActivity extends Activity {
// send the rest of the keys through.
// TODO: get rid of the three special cases above by adjusting the native side of the code.
// Log.d(TAG, "Key down: " + keyCode + ", KeyEvent: " + event);
NativeApp.keyUp(0, keyCode);
return true;
return NativeApp.keyUp(0, keyCode);
}
}

View File

@ -22,7 +22,7 @@ public class NativeApp {
// There's not really any reason to ever call shutdown as we can recover from a killed activity.
public static native void shutdown();
public static native boolean keyDown(int deviceId, int key);
public static native boolean keyDown(int deviceId, int key, boolean isRepeat);
public static native boolean keyUp(int deviceId, int key);
public static native void beginJoystickEvent();

View File

@ -71,6 +71,8 @@ public class NativeGLView extends GLSurfaceView implements SensorEventListener,
public boolean onTouchEvent(final MotionEvent ev) {
boolean canReadToolType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
boolean retval = false;
for (int i = 0; i < ev.getPointerCount(); i++) {
int pid = ev.getPointerId(i);
int code = 0;
@ -101,11 +103,11 @@ public class NativeGLView extends GLSurfaceView implements SensorEventListener,
int tool = getToolType(ev, i);
code |= tool << 10; // We use the Android tool type codes
}
NativeApp.touch(ev.getX(i), ev.getY(i), code, pid);
retval = retval || NativeApp.touch(ev.getX(i), ev.getY(i), code, pid);
}
}
return true;
}
return retval;
}
// Sensor management
public void onAccuracyChanged(Sensor sensor, int arg1) {
@ -165,9 +167,10 @@ public class NativeGLView extends GLSurfaceView implements SensorEventListener,
}
}
boolean repeat = false; // Moga has no repeats?
switch (event.getAction()) {
case KeyEvent.ACTION_DOWN:
NativeApp.keyDown(NativeApp.DEVICE_ID_PAD_0, event.getKeyCode());
NativeApp.keyDown(NativeApp.DEVICE_ID_PAD_0, event.getKeyCode(), repeat);
break;
case KeyEvent.ACTION_UP:
NativeApp.keyUp(NativeApp.DEVICE_ID_PAD_0, event.getKeyCode());

View File

@ -65,4 +65,4 @@ public class NativeRenderer implements GLSurfaceView.Renderer {
}
});
}
}
}

View File

@ -159,6 +159,7 @@ enum {
KEY_DOWN = 1 << 0,
KEY_UP = 1 << 1,
KEY_HASWHEELDELTA = 1 << 2,
KEY_IS_REPEAT = 1 << 3,
};
struct KeyInput {

View File

@ -64,19 +64,28 @@ void ScreenManager::switchToNext() {
UI::SetFocusedView(0);
}
void ScreenManager::touch(const TouchInput &touch) {
if (!stack_.empty())
stack_.back().screen->touch(touch);
bool ScreenManager::touch(const TouchInput &touch) {
if (!stack_.empty()) {
return stack_.back().screen->touch(touch);
} else {
return false;
}
}
void ScreenManager::key(const KeyInput &key) {
if (!stack_.empty())
stack_.back().screen->key(key);
bool ScreenManager::key(const KeyInput &key) {
if (!stack_.empty()) {
return stack_.back().screen->key(key);
} else {
return false;
}
}
void ScreenManager::axis(const AxisInput &axis) {
if (!stack_.empty())
stack_.back().screen->axis(axis);
bool ScreenManager::axis(const AxisInput &axis) {
if (!stack_.empty()) {
return stack_.back().screen->axis(axis);
} else {
return false;
}
}
void ScreenManager::resized() {

View File

@ -49,9 +49,9 @@ public:
virtual void deviceLost() {}
virtual void resized() {}
virtual void dialogFinished(const Screen *dialog, DialogResult result) {}
virtual void touch(const TouchInput &touch) {}
virtual void key(const KeyInput &key) {}
virtual void axis(const AxisInput &touch) {}
virtual bool touch(const TouchInput &touch) { return false; }
virtual bool key(const KeyInput &key) { return false; }
virtual bool axis(const AxisInput &touch) { return false; }
virtual void sendMessage(const char *msg, const char *value) {}
virtual void RecreateViews() {}
@ -109,9 +109,9 @@ public:
void finishDialog(Screen *dialog, DialogResult result = DR_OK);
// Instant touch, separate from the update() mechanism.
void touch(const TouchInput &touch);
void key(const KeyInput &key);
void axis(const AxisInput &touch);
bool touch(const TouchInput &touch);
bool key(const KeyInput &key);
bool axis(const AxisInput &touch);
// Generic facility for gross hacks :P
void sendMessage(const char *msg, const char *value);

View File

@ -48,19 +48,22 @@ void UIScreen::render() {
}
}
void UIScreen::touch(const TouchInput &touch) {
bool UIScreen::touch(const TouchInput &touch) {
if (root_) {
UI::TouchEvent(touch, root_);
return true;
}
return false;
}
void UIScreen::key(const KeyInput &key) {
bool UIScreen::key(const KeyInput &key) {
if (root_) {
UI::KeyEvent(key, root_);
return UI::KeyEvent(key, root_);
}
return false;
}
void UIDialogScreen::key(const KeyInput &key) {
bool UIDialogScreen::key(const KeyInput &key) {
if ((key.flags & KEY_DOWN) && UI::IsEscapeKeyCode(key.keyCode)) {
if (finished_) {
ELOG("Screen already finished");
@ -68,12 +71,13 @@ void UIDialogScreen::key(const KeyInput &key) {
finished_ = true;
screenManager()->finishDialog(this, DR_BACK);
}
return true;
} else {
UIScreen::key(key);
return UIScreen::key(key);
}
}
void UIScreen::axis(const AxisInput &axis) {
bool UIScreen::axis(const AxisInput &axis) {
// Simple translation of hat to keys for Shield and other modern pads.
// TODO: Use some variant of keymap?
int flags = 0;
@ -104,7 +108,9 @@ void UIScreen::axis(const AxisInput &axis) {
hatDown_ = flags;
if (root_) {
UI::AxisEvent(axis, root_);
return true;
}
return (pressed & (PAD_BUTTON_LEFT | PAD_BUTTON_RIGHT | PAD_BUTTON_UP | PAD_BUTTON_DOWN)) != 0;
}
UI::EventReturn UIScreen::OnBack(UI::EventParams &e) {
@ -131,16 +137,15 @@ PopupScreen::PopupScreen(std::string title, std::string button1, std::string but
button2_ = d->T(button2.c_str());
}
void PopupScreen::touch(const TouchInput &touch) {
bool PopupScreen::touch(const TouchInput &touch) {
if (!box_ || (touch.flags & TOUCH_DOWN) == 0 || touch.id != 0) {
UIDialogScreen::touch(touch);
return;
return UIDialogScreen::touch(touch);
}
if (!box_->GetBounds().Contains(touch.x, touch.y))
screenManager()->finishDialog(this, DR_BACK);
UIDialogScreen::touch(touch);
return UIDialogScreen::touch(touch);
}
void PopupScreen::CreateViews() {

View File

@ -10,11 +10,12 @@ public:
UIScreen();
~UIScreen();
virtual void update(InputState &input);
virtual void render();
virtual void touch(const TouchInput &touch);
virtual void key(const KeyInput &touch);
virtual void axis(const AxisInput &touch);
virtual void update(InputState &input) override;
virtual void render() override;
virtual bool touch(const TouchInput &touch) override;
virtual bool key(const KeyInput &touch) override;
virtual bool axis(const AxisInput &touch) override;
// Some useful default event handlers
UI::EventReturn OnOK(UI::EventParams &e);
@ -39,7 +40,7 @@ private:
class UIDialogScreen : public UIScreen {
public:
UIDialogScreen() : UIScreen(), finished_(false) {}
virtual void key(const KeyInput &key);
virtual bool key(const KeyInput &key) override;
private:
bool finished_;
@ -51,9 +52,9 @@ public:
PopupScreen(std::string title, std::string button1 = "", std::string button2 = "");
virtual void CreatePopupContents(UI::ViewGroup *parent) = 0;
virtual void CreateViews();
virtual bool isTransparent() const { return true; }
virtual void touch(const TouchInput &touch);
virtual void CreateViews() override;
virtual bool isTransparent() const override { return true; }
virtual bool touch(const TouchInput &touch) override;
protected:
virtual bool FillVertical() const { return false; }

View File

@ -1122,8 +1122,10 @@ static std::set<HeldKey> heldKeys;
static const int repeatDelay = 15; // 250ms
static const int repeatInterval = 5; // 66ms
void KeyEvent(const KeyInput &key, ViewGroup *root) {
if (key.flags & KEY_DOWN) {
bool KeyEvent(const KeyInput &key, ViewGroup *root) {
bool retval = false;
// Ignore repeats for focus moves.
if ((key.flags & (KEY_DOWN | KEY_IS_REPEAT)) == KEY_DOWN) {
// We ignore the device ID here. Anything with a DPAD is OK.
if (key.keyCode >= NKCODE_DPAD_UP && key.keyCode <= NKCODE_DPAD_RIGHT) {
// Let's only repeat DPAD initially.
@ -1135,12 +1137,13 @@ void KeyEvent(const KeyInput &key, ViewGroup *root) {
// Check if the key is already held. If it is, ignore it. This is to avoid
// multiple key repeat mechanisms colliding.
if (heldKeys.find(hk) != heldKeys.end()) {
return;
return false;
}
heldKeys.insert(hk);
lock_guard lock(focusLock);
focusMoves.push_back(key.keyCode);
retval = true;
}
}
if (key.flags & KEY_UP) {
@ -1151,9 +1154,23 @@ void KeyEvent(const KeyInput &key, ViewGroup *root) {
hk.deviceId = key.deviceId;
hk.startFrame = 0; // irrelevant
heldKeys.erase(hk);
retval = true;
}
}
root->Key(key);
retval = true;
// Ignore volume keys and stuff here. Not elegant but need to propagate bools through the view hierarchy as well...
switch (key.keyCode) {
case NKCODE_VOLUME_DOWN:
case NKCODE_VOLUME_UP:
case NKCODE_VOLUME_MUTE:
retval = false;
break;
}
return retval;
}
static void ProcessHeldKeys(ViewGroup *root) {
@ -1174,14 +1191,16 @@ static void ProcessHeldKeys(ViewGroup *root) {
}
}
void TouchEvent(const TouchInput &touch, ViewGroup *root) {
bool TouchEvent(const TouchInput &touch, ViewGroup *root) {
EnableFocusMovement(false);
root->Touch(touch);
return true;
}
void AxisEvent(const AxisInput &axis, ViewGroup *root) {
bool AxisEvent(const AxisInput &axis, ViewGroup *root) {
root->Axis(axis);
return true;
}
void UpdateViewHierarchy(const InputState &input_state, ViewGroup *root) {

View File

@ -377,9 +377,9 @@ private:
void LayoutViewHierarchy(const UIContext &dc, ViewGroup *root);
void UpdateViewHierarchy(const InputState &input_state, ViewGroup *root);
// Hooks arrow keys for navigation
void KeyEvent(const KeyInput &key, ViewGroup *root);
void TouchEvent(const TouchInput &touch, ViewGroup *root);
void AxisEvent(const AxisInput &axis, ViewGroup *root);
bool KeyEvent(const KeyInput &key, ViewGroup *root);
bool TouchEvent(const TouchInput &touch, ViewGroup *root);
bool AxisEvent(const AxisInput &axis, ViewGroup *root);
void CaptureDrag(int id);
void ReleaseDrag(int id);