playwright
playwright copied to clipboard
[Feature] Russian Keyboard Layout
Note from maintainers
In most cases you should use locator.pressSequentially()
method instead of locator.type()
. This will work with any keyboard layout. You only need to type character by character if there is some special keyboard handling on the page.
const input = await page.locator('#kinput');
await input.fill('hello');
await input.fill('привiт');
Context:
- Playwright Version: [1.12.2]
- Operating System: [Linux & Mac]
- Node.js version: [14.17.0]
- Browser: [Chromium]
- Extra: [any specific details about your environment]
## System:
- OS: Linux 5.8 Ubuntu 20.04.2 LTS (Focal Fossa)
- Memory: 15.31 GB / 31.30 GB
- Container: Yes
## Binaries:
- Node: 14.17.0 - /usr/bin/node
- npm: 7.5.2 - /usr/local/bin/npm
## Languages:
- Bash: 5.0.17 - /usr/bin/bash
## npmPackages:
- playwright: 1.12.2 => 1.12.2
## System:
- OS: macOS 11.4
- Memory: 670.91 MB / 32.00 GB
## Binaries:
- Node: 15.3.0 - ~/.asdf/installs/nodejs/15.3.0/bin/node
- Yarn: 1.22.10 - /usr/local/bin/yarn
- npm: 7.0.14 - ~/.asdf/installs/nodejs/15.3.0/bin/npm
## Languages:
- Bash: 3.2.57 - /bin/bash
## npmPackages:
- playwright: 1.12.2 => 1.12.2
Code Snippet
Help us help you! Put down a short code snippet that illustrates your bug and that we can run and debug locally. For example:
const {chromium, webkit, firefox} = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://learn.javascript.ru/article/keyboard-events/keyboard-dump/');
const checkbox = await page.$('input[name="keyupStop"]');
await checkbox.click();
const input = await page.$('#kinput');
await input.type(' working ', { delay: 500, noWaitAfter: false, timeout: 15000 });
await input.type(' не работает ', { delay: 500, noWaitAfter: false, timeout: 15000 });
})();
Describe the bug
When I try to type russian characters keyup/down events are not triggered
We currently hard code in a US keyboard layout. We can add in more layouts, but its a lot of work for each one so we've been waiting for a flood of user requests to prioritize it.
[GOOD FIRST ISSUE]
I want to work on this issue.
@JoelEinbinder hi, could you please suggest how to nicely implement this feature? Is it ok to:
- create the second file with the Russian layout
- create a common file and merge EN/RU layouts there
- use this common file in
packages/playwright-core/src/server/input.ts
instead of the English one?
I guess if somebody will want to add a new layout then more or less 2 lines should be changed. Of course besides the layout itself.
Might want to consider different keyboard layouts; like Standard(ЙЦУКЕН) and Phonetic(ЯШЕРТЫ)
We currently hard code in a US keyboard layout. We can add in more layouts, but its a lot of work for each one so we've been waiting for a flood of user requests to prioritize it.
can we add the same file but with a Russian keyboard Chars?
I did a small PoC to support other keyboard layouts using a generator, to simplify the process. You can find it here:
https://github.com/microsoft/playwright/pull/24249
I noticed that keyCodes found in usKeyboardLayout.ts
don't match some keyCode
s from my generator. For instance, Period
currently has a keyCode
of 190
for US, but my generator sets it to 46
.
Looking at the code, it apparently uses Virtual-Key Codes in those cases.
I'll change my generator to use these values.
For primary input layouts, the following list is available:
https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/default-input-locales-for-windows-language-packs?view=windows-11
So, if we decide to select the keyboard layout by locale, we can use this table (115 keyboard layouts):
KLID | Layout Name | Locales |
---|---|---|
00000409 | US keyboard | af-ZA, en-US, en-AU, en-BZ, en-CA, en-029, en-HK, en-JM, en-MY, en-PH, en-SG, en-ZA, en-TT, en-ZW, fil-PH, id-ID, jv, rw-RW, sw-KE, ms-MY, ms-BN, moh-CA, om-ET, pap-029, st-ZA, so-SO, uz-Latn-UZ, ts-ZA, xh-ZA, zu-ZA |
0000041C | Albanian keyboard | sq-AL |
0000040C | French keyboard | gsw-FR, br-FR, fr-FR, co-FR, en-GB, fr-CM, fr-CI, fr-HT, fr-ML, fr-MC, fr-MA, fr-RE, fr-SN, fr-CD, mg, oc-FR |
00000401 | Arabic (101) keyboard | ar-SA, ar-BH, ar-EG, ar-IQ, ar-JO, ar-KW, ar-LB, ar-LY, ar-OM, ar-QA, ar-SY, ar-AE, ar-YE |
00020401 | Arabic (102) AZERTY keyboard | ar-DZ, ar-MA, ar-TN |
0002042B | Armenian Phonetic keyboard | hy-AM |
0000044D | Assamese - INSCRIPT keyboard | as-IN |
0000040A | Spanish keyboard | es-ES_tradnl, eu-ES, ca-ES, gl-ES, es-ES, ca-ES-valencia |
0000042C | Azerbaijani Latin keyboard | az-Latn-AZ |
0000082C | Azerbaijani Cyrillic keyboard | az-Cyrl-AZ |
00000445 | Bangla keyboard | bn-BD |
0000046D | Bashkir keyboard | ba-RU |
00000423 | Belarusian keyboard | be-BY |
00020445 | Bangla - INSCRIPT keyboard | bn-IN |
00000439 | Devanagari - INSCRIPT keyboard | hi-IN, kok-IN, sa-IN |
0000041A | Standard keyboard | bs-Latn-BA, hr-HR, hr-BA |
0000201A | Bosnian (Cyrillic) keyboard | bs-Cyrl-BA |
00030402 | Bulgarian keyboard | bg-BG |
00130C00 | Myanmar (Visual order) keyboard | my-MM |
00000410 | Italian keyboard | it-IT |
0000085F | Central Atlas Tamazight keyboard | tzm-Latn-DZ |
0000105F | Tifinagh (Basic) keyboard | tzm-Tfng-MA, zgh |
00000492 | Central Kurdish keyboard | ku-Arab-IQ |
00000419 | Russian keyboard | ru-RU |
0000045C | Cherokee Nation keyboard | chr-Cher-US |
00000407 | German keyboard | de-DE, en-GB, de-AT, de-LU |
00000809 | United Kingdom keyboard | en-GB |
00000405 | Czech keyboard | cs-CZ |
00000406 | Danish keyboard | da-DK, en-US, fo-FO, kl-GL |
00000465 | Divehi Phonetic keyboard | dv-MV |
00020409 | United States-International keyboard | nl-NL, en-US, en-GB, fy-NL |
00000813 | Belgian (Period) keyboard | nl-BE |
00000C51 | Dzongkha keyboard | dz-BT |
0000080C | Belgian French keyboard | fr-BE |
0000040B | Finnish keyboard | en-GB, fi-FI |
00004009 | English (India) keyboard | en-IN |
00001809 | Irish keyboard | en-IE, ga-IE |
00001409 | NZ Aotearoa keyboard | en-NZ |
00000424 | Slovenian keyboard | en-GB, sl-SI |
0000041D | Swedish keyboard | en-GB, sv-SE, sv-FI |
00000425 | Estonian keyboard | et-EE |
00001009 | Canadian French keyboard | fr-CA |
0000100C | Swiss French keyboard | fr-LU, fr-CH, it-CH |
00000488 | Wolof keyboard | ff-Latn-SN, wo-SN |
00010437 | Georgian (QWERTY) keyboard | ka-GE |
00000807 | Swiss German keyboard | de-LI, de-CH, rm-CH |
00000408 | Greek keyboard | el-GR |
00000474 | Guarani keyboard | gn-PY |
00000447 | Gujarati keyboard | gu-IN |
00000468 | Hausa keyboard | ha-Latn-NG |
00000475 | Hawaiian keyboard | haw-US |
0002040D | Hebrew (Standard) keyboard | he-IL |
00010439 | Hindi Traditional keyboard | hi-IN |
0000040E | Hungarian keyboard | hu-HU |
0000040F | Icelandic keyboard | is-IS |
00000470 | Igbo keyboard | ig-NG |
0000085D | Inuktitut - Latin keyboard | iu-Latn-CA |
0001045D | Inuktitut - Naqittaut keyboard | iu-Cans-CA |
00110C00 | Javanese keyboard | jv-Java |
0000044B | Kannada keyboard | kn-IN |
00000420 | Urdu keyboard | ur-PK, pa-Arab-PK, sd-Arab-PK, ur-IN |
0000043F | Kazakh keyboard | kk-KZ |
00000453 | Khmer keyboard | km-KH |
00000440 | Kyrgyz Cyrillic keyboard | ky-KG |
0000080A | Latin American keyboard | quc-Latn-GT, arn-CL, quz-BO, quz-EC, quz-PE, es-AR, es-BO, es-CL, es-CO, es-CR, es-MX, es-DO, es-EC, es-SV, es-GT, es-HN, es-419, es-NI, es-PA, es-PY, es-PE, es-PR, es-US, es-UY, es-VE |
00000454 | Lao keyboard | lo-LA |
00020426 | Latvian (Standard) keyboard | lv-LV |
00010427 | Lithuanian keyboard | lt-LT |
0002042E | Sorbian Standard keyboard | dsb-DE, hsb-DE |
0000046E | Luxembourgish keyboard | lb-LU |
0001042F | Macedonian - Standard keyboard | mk-MK |
0000044C | Malayalam keyboard | ml-IN |
0000043A | Maltese 47-Key keyboard | mt-MT |
00000481 | Maori keyboard | mi-NZ |
0000044E | Marathi keyboard | mr-IN |
00000429 | Persian keyboard | fa-IR |
00000450 | Mongolian Cyrillic keyboard | mn-MN |
00010850 | Traditional Mongolian (Standard) keyboard | mn-Mong-CN, mn-Mong-MN |
00090C00 | N’Ko keyboard | nqo |
00000461 | Nepali keyboard | ne-NP, ne-IN |
0000043B | Norwegian with Sami keyboard | se-NO, smj-NO, sma-NO |
00000414 | Norwegian keyboard | nb-NO, nn-NO |
00000448 | Odia keyboard | or-IN |
00000463 | Pashto (Afghanistan) keyboard | ps-AF |
00050429 | Persian (Standard) keyboard | fa-AF |
00000415 | Polish (Programmers) keyboard | pl-PL |
00000416 | Portuguese (Brazil ABNT) keyboard | pt-BR |
00000816 | Portuguese keyboard | pt-PT |
00000446 | Punjabi keyboard | pa-IN |
00010418 | Romanian (Standard) keyboard | ro-RO, ro-MD |
00000485 | Sakha keyboard | sah-RU |
0001083B | Finnish with Sami keyboard | smn-FI, sms-FI, se-FI |
0000083B | Swedish with Sami keyboard | smj-SE, sma-SE, se-SE |
00011809 | Scottish Gaelic keyboard | gd-GB |
0000081A | Serbian (Latin) keyboard | sr-Latn-RS, sr-Latn-BA, sr-Latn-ME |
00000C1A | Serbian (Cyrillic) keyboard | sr-Cyrl-RS, sr-Cyrl-BA, sr-Cyrl-ME |
0000046C | Sesotho sa Leboa keyboard | nso-ZA |
00000432 | Setswana keyboard | tn-ZA, tn-BW |
0000045B | Sinhala keyboard | si-LK |
0000041B | Slovak keyboard | sk-SK |
0000045A | Syriac keyboard | syr-SY |
00000428 | Tajik keyboard | tg-Cyrl-TJ |
00020449 | Tamil 99 keyboard | ta-IN, ta-LK |
00010444 | Tatar keyboard | tt-RU |
0000044A | Telugu keyboard | te-IN |
0000041E | Thai Kedmanee keyboard | th-TH |
00010451 | Tibetan (PRC) - Updated keyboard | bo-CN |
00000451 | Tibetan (PRC) keyboard | bo-CN |
0000041F | Turkish Q keyboard | tr-TR |
00000442 | Turkmen keyboard | tk-TM |
00020422 | Ukrainian (Enhanced) keyboard | uk-UA |
00010480 | Uyghur keyboard | ug-CN |
00000843 | Uzbek Cyrillic keyboard | uz-Cyrl-UZ |
00000452 | United Kingdom Extended keyboard | cy-GB |
0000046A | Yoruba keyboard | yo-NG |
There's some ambiguity yet for en-US
, en-GB
, hi-IN
and bo-CN
but I think we can assume the following default values:
Default | Locale | KLID | Layout Name |
---|---|---|---|
✔️ | hi-IN | 00010439 | Hindi Traditional keyboard |
hi-IN | 00000439 | Devanagari - INSCRIPT keyboard | |
✔️ | bo-CN | 00010451 | Tibetan (PRC) - Updated keyboard |
bo-CN | 00000451 | Tibetan (PRC) keyboard | |
✔️ | en-US | 00000409 | US keyboard |
en-US | 00000406 | Danish keyboard | |
en-US | 00020409 | United States-International keyboard | |
en-GB | 0000040C | French keyboard | |
en-GB | 00000407 | German keyboard | |
✔️ | en-GB | 00000809 | United Kingdom keyboard |
en-GB | 00020409 | United States-International keyboard | |
en-GB | 0000040B | Finnish keyboard | |
en-GB | 00000424 | Slovenian keyboard | |
en-GB | 0000041D | Swedish keyboard |
We have updated our docs and this issue to emphasize that in most circumstances you do not need to call type()
or pressSequentially()
, but instead should just call fill()
. This method works regardless of the keyboard layout.
If you have tried using pressSequentially()
and it does not work for you, and you still need keyboard layouts support in type()
/pressSequentially()
, please comment here with your usecase. Ideally, share a repro so that we can figure out why fill()
does not work for you. This will greatly help us prioritize this feature relative to other issues. Thank you!
If you have tried using
pressSequentially()
and it does not work for you, and you still need keyboard layouts support intype()
/pressSequentially()
, please comment here with your usecase.
The app that I am testing had a bug where each keystroke resulted in a re-render of the contentEditable
HTML element that the user was typing in. This was not noticeable for normal typing, but it prevented the usage of dead keys: When pressing a dead key, the element would re-render and thus resetting the keyboard mapping to default again, instead of changing the mapping temporarily for the next keystroke.
Dead keys are only present on some keyboard layouts, e.g. "US-International - PC". As I want to simulate the press of a dead key plus a follow-up keystroke for a test, I'd need support for specific layouts.
Example: Pressing Option+u
and then u
should result in ü
(on macOS with layout "US-International - PC").
I did implement other keyboard layouts in !24249 with deadkeys support but there were too many corner cases, so at the end that was not merged.
On chrome, you can use CDPSession to send all required events. For instance, you can check which events need to be sent in W3C Keyboard Event Viewer, and send the corresponding events with Input.dispatchKeyEvent.
Thanks for the tip. I have tried to reproduce the behavior with CDPSession
but I guess I'd need the missing Input.imeCommitComposition
command to exactly reproduce it, as you also have pointed out in https://github.com/microsoft/playwright/issues/5777#issuecomment-1651735889
Actually, for committing you can use the Input.insertText
command: https://github.com/microsoft/playwright/issues/5777#issuecomment-1651784399
It is true that Input.insertText
triggers the compositionend
event but it does not help me with my test, because Input.insertText
does not care if there was a composition session in progress or not. The provided text is correctly inserted anyway.
For my Playwright test, I want to assert that a composition session was not erroneously aborted by the browser re-rendering the input element. If the fix is applied, the resulting text in the form is ü
, without the fix, it is ¨u
. Using Input.insertText
in the test commits the composition session but it would result in the correct result (ü
) anyway, no matter if it commits a composition or not. So that test always succeeds, with or without bugfix.
would it be possible to utilise something like .charCodeAt(0)
to reduce all complexity?
However, I don't doubt there is a very good reason why we are not using it (and I'd love to hear it) 🙂