From ff4aa7db79bb5db8c8db8fbca9921a7f87d4cd10 Mon Sep 17 00:00:00 2001 From: Dor Blayzer <59066376+Dor-bl@users.noreply.github.com> Date: Fri, 27 Mar 2026 22:53:52 +0000 Subject: [PATCH 1/5] feat(android): add AndroidKeyMetastate class for keyboard metastate constants --- .../webdriver/extensions/android/nativekey.py | 43 +++++++++++++++++++ test/unit/webdriver/device/keyboard_test.py | 13 +++++- test/unit/webdriver/nativekey_test.py | 10 ++++- 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/appium/webdriver/extensions/android/nativekey.py b/appium/webdriver/extensions/android/nativekey.py index 05b558790..638116894 100644 --- a/appium/webdriver/extensions/android/nativekey.py +++ b/appium/webdriver/extensions/android/nativekey.py @@ -13,6 +13,49 @@ # limitations under the License. +class AndroidKeyMetastate: + """Keyboard metastate constants for Android key events. + + These constants can be combined with bitwise OR and passed to + Keyboard.press_keycode or Keyboard.long_press_keycode as metastate. + Values are based on android.view.KeyEvent. + """ + + # No modifiers. + NONE = 0 + + # This mask is used to check whether one of the SHIFT meta keys is pressed. + META_SHIFT_ON = 0x01 + META_SHIFT_LEFT_ON = 0x40 + META_SHIFT_RIGHT_ON = 0x80 + + # This mask is used to check whether one of the ALT meta keys is pressed. + META_ALT_ON = 0x02 + META_ALT_LEFT_ON = 0x10 + META_ALT_RIGHT_ON = 0x20 + + # This mask is used to check whether one of the SYM meta keys is pressed. + META_SYM_ON = 0x04 + + # This mask is used to check whether the FUNCTION meta key is pressed. + META_FUNCTION_ON = 0x08 + + # This mask is used to check whether one of the CTRL meta keys is pressed. + META_CTRL_ON = 0x1000 + META_CTRL_LEFT_ON = 0x2000 + META_CTRL_RIGHT_ON = 0x4000 + + # This mask is used to check whether one of the META meta keys is pressed. + META_META_ON = 0x10000 + META_META_LEFT_ON = 0x20000 + META_META_RIGHT_ON = 0x40000 + + # Lock key states. + META_CAPS_LOCK_ON = 0x100000 + META_NUM_LOCK_ON = 0x200000 + META_SCROLL_LOCK_ON = 0x400000 + + class AndroidKey: # Key code constant: Unknown key code. UNKNOWN = 0 diff --git a/test/unit/webdriver/device/keyboard_test.py b/test/unit/webdriver/device/keyboard_test.py index 526f1826f..573b492af 100644 --- a/test/unit/webdriver/device/keyboard_test.py +++ b/test/unit/webdriver/device/keyboard_test.py @@ -14,6 +14,7 @@ import httpretty +from appium.webdriver.extensions.android.nativekey import AndroidKeyMetastate from appium.webdriver.webdriver import WebDriver from test.unit.helper.test_helper import android_w3c_driver, appium_command, get_httpretty_request_body, ios_w3c_driver @@ -71,7 +72,11 @@ def test_press_keycode_with_flags(self): # metastate is META_SHIFT_ON and META_NUM_LOCK_ON # flags is CANCELFLAG_CANCELEDED, FLAG_KEEP_TOUCH_MODE, FLAG_FROM_SYSTEM assert isinstance( - driver.press_keycode(86, metastate=0x00000001 | 0x00200000, flags=0x20 | 0x00000004 | 0x00000008), + driver.press_keycode( + 86, + metastate=AndroidKeyMetastate.META_SHIFT_ON | AndroidKeyMetastate.META_NUM_LOCK_ON, + flags=0x20 | 0x00000004 | 0x00000008, + ), WebDriver, ) @@ -87,7 +92,11 @@ def test_long_press_keycode_with_flags(self): # metastate is META_SHIFT_ON and META_NUM_LOCK_ON # flags is CANCELFLAG_CANCELEDED, FLAG_KEEP_TOUCH_MODE, FLAG_FROM_SYSTEM assert isinstance( - driver.long_press_keycode(86, metastate=0x00000001 | 0x00200000, flags=0x20 | 0x00000004 | 0x00000008), + driver.long_press_keycode( + 86, + metastate=AndroidKeyMetastate.META_SHIFT_ON | AndroidKeyMetastate.META_NUM_LOCK_ON, + flags=0x20 | 0x00000004 | 0x00000008, + ), WebDriver, ) diff --git a/test/unit/webdriver/nativekey_test.py b/test/unit/webdriver/nativekey_test.py index 733f6159b..c7a178114 100644 --- a/test/unit/webdriver/nativekey_test.py +++ b/test/unit/webdriver/nativekey_test.py @@ -13,7 +13,7 @@ # limitations under the License. -from appium.webdriver.extensions.android.nativekey import AndroidKey +from appium.webdriver.extensions.android.nativekey import AndroidKey, AndroidKeyMetastate class TestAndroidKey: @@ -23,6 +23,14 @@ def test_has_some_codes(self): assert AndroidKey.CAMERA == 27 assert AndroidKey.SPACE == 62 + def test_has_some_metastates(self): + assert AndroidKeyMetastate.NONE == 0 + assert AndroidKeyMetastate.META_SHIFT_ON == 0x00000001 + assert AndroidKeyMetastate.META_NUM_LOCK_ON == 0x00200000 + assert ( + AndroidKeyMetastate.META_SHIFT_ON | AndroidKeyMetastate.META_NUM_LOCK_ON + ) == 0x00000001 | 0x00200000 + def test_is_gamepad_key(self): assert AndroidKey.is_gamepad_button(AndroidKey.BUTTON_8) assert not AndroidKey.is_gamepad_button(250) From 56e01c3c0e70892f7bddf9448ba311215774116f Mon Sep 17 00:00:00 2001 From: Dor Blayzer <59066376+Dor-bl@users.noreply.github.com> Date: Sat, 28 Mar 2026 00:03:42 +0100 Subject: [PATCH 2/5] Reformat import statement for AndroidKey and Metastate --- test/unit/webdriver/nativekey_test.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/unit/webdriver/nativekey_test.py b/test/unit/webdriver/nativekey_test.py index c7a178114..2ae299f67 100644 --- a/test/unit/webdriver/nativekey_test.py +++ b/test/unit/webdriver/nativekey_test.py @@ -13,8 +13,10 @@ # limitations under the License. -from appium.webdriver.extensions.android.nativekey import AndroidKey, AndroidKeyMetastate - +from appium.webdriver.extensions.android.nativekey import ( + AndroidKey, + AndroidKeyMetastate, +) class TestAndroidKey: def test_has_some_codes(self): From bc167fb3f3d8845e4da8cfb837c34a6f7cbf9371 Mon Sep 17 00:00:00 2001 From: Dor Blayzer <59066376+Dor-bl@users.noreply.github.com> Date: Sat, 28 Mar 2026 00:08:57 +0100 Subject: [PATCH 3/5] add space --- test/unit/webdriver/nativekey_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/unit/webdriver/nativekey_test.py b/test/unit/webdriver/nativekey_test.py index 2ae299f67..9fece1d94 100644 --- a/test/unit/webdriver/nativekey_test.py +++ b/test/unit/webdriver/nativekey_test.py @@ -18,6 +18,7 @@ AndroidKeyMetastate, ) + class TestAndroidKey: def test_has_some_codes(self): assert AndroidKey.ENTER == 66 From 1ec3fc0ef3efc3540040c9867fa30e899ec2c8d3 Mon Sep 17 00:00:00 2001 From: Dor Blayzer <59066376+Dor-bl@users.noreply.github.com> Date: Fri, 27 Mar 2026 23:20:27 +0000 Subject: [PATCH 4/5] fix(test): simplify assertion for AndroidKeyMetastate in test_has_some_metastates --- test/unit/webdriver/nativekey_test.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/unit/webdriver/nativekey_test.py b/test/unit/webdriver/nativekey_test.py index 9fece1d94..ba38abe98 100644 --- a/test/unit/webdriver/nativekey_test.py +++ b/test/unit/webdriver/nativekey_test.py @@ -30,9 +30,7 @@ def test_has_some_metastates(self): assert AndroidKeyMetastate.NONE == 0 assert AndroidKeyMetastate.META_SHIFT_ON == 0x00000001 assert AndroidKeyMetastate.META_NUM_LOCK_ON == 0x00200000 - assert ( - AndroidKeyMetastate.META_SHIFT_ON | AndroidKeyMetastate.META_NUM_LOCK_ON - ) == 0x00000001 | 0x00200000 + assert (AndroidKeyMetastate.META_SHIFT_ON | AndroidKeyMetastate.META_NUM_LOCK_ON) == 0x00000001 | 0x00200000 def test_is_gamepad_key(self): assert AndroidKey.is_gamepad_button(AndroidKey.BUTTON_8) From 64e3600da3779104b6066182660b598594a88289 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Fri, 27 Mar 2026 23:20:12 -0700 Subject: [PATCH 5/5] Update appium/webdriver/extensions/android/nativekey.py --- appium/webdriver/extensions/android/nativekey.py | 1 + 1 file changed, 1 insertion(+) diff --git a/appium/webdriver/extensions/android/nativekey.py b/appium/webdriver/extensions/android/nativekey.py index 638116894..59362681d 100644 --- a/appium/webdriver/extensions/android/nativekey.py +++ b/appium/webdriver/extensions/android/nativekey.py @@ -19,6 +19,7 @@ class AndroidKeyMetastate: These constants can be combined with bitwise OR and passed to Keyboard.press_keycode or Keyboard.long_press_keycode as metastate. Values are based on android.view.KeyEvent. + https://developer.android.com/reference/android/view/KeyEvent """ # No modifiers.