Added support for intercepting key events
This commit overrides the dispatchKeyEvent() method of the MainActivity class, allowing Android applications to intercept key events.
The main need for this change is to allow applications to intercept events from hardware buttons, either in the device itself or connected peripherals, e.g. a Bluetooth headset.
Fixes #100
PR Checklist:
- [x] All new features have been tested
- [ ] All new features have been documented
- [x] I have read the CONTRIBUTING.md file
- [x] I will abide by the code of conduct
Thanks for the contribution, but I'm not sure it's a good idea for the official template to implement Activity methods which aren't being used by Toga or any other higher-level library. They would have no test coverage, and there are dozens of such methods which could be useful for some app.
However, there is a way for you to use a custom MainActivity: use the Briefcase template / template_branch settings to point at your modified copy of this repository. Please give that a try and let me know how you get on.
I'll check the template functionality, in fact I did look for something like that, but I wasn't able to find it.
I'm not sure it's a good idea for the official template to implement Activity methods which aren't being used by Toga or any other higher-level library.
Assuming that access to hardware buttons in toga-android would be a desirable feature, how to go about integrating it then? Because it wouldn't be possible to implement it there without also (first?) adding support for it here.
Can you give more details of exactly what you're trying to achieve? What buttons do you want to detect, and for what purpose in your app?
To add this to Toga, first we'd need to discuss what the public API would look like. There is already an enumeration for keys, but it's currently only being used for menu shortcuts.
I can see a couple of design questions which would need to be answered in a consistent cross-platform way:
- How would this API interact with normal keyboard interaction, such as typing into a text box, pressing Enter to activate a button, or navigating between and within widgets with Tab and arrow keys?
- How can we represent buttons on connected peripherals?
Given the complexity of this area, it might be better for you to keep this as an Android-only feature for now.
Given the complexity of this area, it might be better for you to keep this as an Android-only feature for now.
Yes, that's exactly what I have in mind: an Android-specific feature for intercepting hardware button events.
In its barest version, integrating the changes in this commit would allow client code to intercept hardware key press events as below:
from android.view import KeyEvent
# ...
class MyApp(toga.App):
def __callbackKeyEvent(self, key_event):
key_code = key_event.getKeyCode()
if key_code in {KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_UP}:
if key_event.getAction() == KeyEvent.ACTION_DOWN:
print(f'Key code: {key_code}')
return True
return False
# ...
def startup(self):
self._impl._listener.dispatchKeyEvent = self.__callbackKeyEvent
# ...
Alternatively, the following method could be added to toga_android.TogaApp:
def dispatchKeyEvent(self, key_event):
key_code = key_event.getKeyCode()
if key_code not in {KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_UP}:
return False
app = self._impl
if not hasattr(app, 'on_hardware_key'):
return False
callback = app.on_hardware_key
if callback is None:
return False
return callback(key_event)
This would allow applications to register an event handler as below:
class MyApp(toga.App):
def __init__(self):
r'''Create a new application instance.
'''
super().__init__()
self._impl.on_hardware_key = self.__callbackKeyEvent
# ...
We prefer not to add platform-specific features to Toga, especially if they've only been requested by one person. So unless you're willing to put in the time to design an API which would at least in principle work across multiple platforms, I think using a custom template of your own is the best way forward.