Skip to content

Commit

Permalink
(feat): Composition support for keyboard.imeSetComposition
Browse files Browse the repository at this point in the history
Fix bugs
  • Loading branch information
trueadm committed Oct 15, 2021
1 parent 8c581bc commit 41e0199
Show file tree
Hide file tree
Showing 12 changed files with 261 additions and 8 deletions.
65 changes: 65 additions & 0 deletions docs/src/api/class-keyboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,71 @@ Modifier keys DO influence `keyboard.down`. Holding down `Shift` will type the t

Name of the key to press or a character to generate, such as `ArrowLeft` or `a`.

## async method: Keyboard.imeSetComposition

If there is an active composition, it will update the composition. Otherwise it will start a new one. It will dispatch either
a `compositionstart` or a `compositionupdate`. In order to cancel a composition: `keyboard.insertText('')`, and in order to commit/end a composition:
`keyboard.insertText(<text to insert>)`.

### param: Keyboard.imeSetComposition.text
- `text` <[string]>

Sets the text in the active composition

### param: Keyboard.imeSetComposition.selectionStart
- `selectionStart` <[int]>

Sets the selection start of the focused element after the composition text is inserted. This is relatvie to the active composition,
so if the text in the focused element is `abcd` but only `d` is part of the active composition, a selection start of `1` will set the
selection start to be after `d`, which is absolute position `4`.

### param: Keyboard.imeSetComposition.selectionEnd
- `selectionEnd` <[int]>

Sets the selection end of the focused element after the composition text is inserted. This is relatvie to the active composition,
so if the text in the focused element is `abcd` but only `d` is part of the active composition, a selection end of `1` will set the
selection end to be after `d`, which is absolute position `4`.

### option: Keyboard.imeSetComposition.replacementStart
- `replacementStart` <[int]>

Sets the start position of the absolute range that is to be replaced with the composition text.


### option: Keyboard.imeSetComposition.replacementEnd
- `replacementEnd` <[int]>

Sets the end position of the absolute range that is to be replaced with the composition text.


```js
const page = await browser.newPage();
await page.goto('https://w3c.github.io/uievents/tools/key-event-viewer-ce.html');
await page.focus('#input');
await page.keyboard.imeSetComposition('', 1, 1);
await page.keyboard.imeSetComposition('', 1, 1);
await browser.close();
```


```python async
page = await browser.new_page()
await page.goto("https://w3c.github.io/uievents/tools/key-event-viewer-ce.html")
await page.focus("#input");
await page.keyboard.imeSetComposition("", 1, 1)
await page.keyboard.imeSetComposition("", 1, 1)
await browser.close()
```

```python sync
page = browser.new_page()
page.goto("https://w3c.github.io/uievents/tools/key-event-viewer-ce.html")
page.focus("#input");
page.keyboard.imeSetComposition("", 1, 1)
page.keyboard.imeSetComposition("", 1, 1)
browser.close()
```

## async method: Keyboard.insertText

Dispatches only `input` event, does not emit the `keydown`, `keyup` or `keypress` events.
Expand Down
7 changes: 7 additions & 0 deletions packages/playwright-core/src/client/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ export class Keyboard implements api.Keyboard {
});
}

async imeSetComposition(text: string, selectionStart: number, selectionEnd: number,
options: channels.PageKeyboardImeSetCompositionOptions) {
await this._page._wrapApiCall(async channel => {
await channel.keyboardImeSetComposition({ text, selectionStart, selectionEnd, ...options });
});
}

async type(text: string, options: channels.PageKeyboardTypeOptions = {}) {
await this._page._wrapApiCall(async channel => {
await channel.keyboardType({ text, ...options });
Expand Down
4 changes: 4 additions & 0 deletions packages/playwright-core/src/dispatchers/pageDispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ export class PageDispatcher extends Dispatcher<Page, channels.PageInitializer, c
await this._page.keyboard.up(params.key);
}

async keyboardImeSetComposition(params: channels.PageKeyboardImeSetCompositionParams, metadata: CallMetadata): Promise<void> {
await this._page.keyboard.imeSetComposition(params.text, params.selectionStart, params.selectionEnd, params);
}

async keyboardInsertText(params: channels.PageKeyboardInsertTextParams, metadata: CallMetadata): Promise<void> {
await this._page.keyboard.insertText(params.text);
}
Expand Down
13 changes: 13 additions & 0 deletions packages/playwright-core/src/protocol/channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,7 @@ export interface PageChannel extends EventTargetChannel {
keyboardUp(params: PageKeyboardUpParams, metadata?: Metadata): Promise<PageKeyboardUpResult>;
keyboardInsertText(params: PageKeyboardInsertTextParams, metadata?: Metadata): Promise<PageKeyboardInsertTextResult>;
keyboardType(params: PageKeyboardTypeParams, metadata?: Metadata): Promise<PageKeyboardTypeResult>;
keyboardImeSetComposition(params: PageKeyboardImeSetCompositionParams, metadata?: Metadata): Promise<PageKeyboardImeSetCompositionResult>;
keyboardPress(params: PageKeyboardPressParams, metadata?: Metadata): Promise<PageKeyboardPressResult>;
mouseMove(params: PageMouseMoveParams, metadata?: Metadata): Promise<PageMouseMoveResult>;
mouseDown(params: PageMouseDownParams, metadata?: Metadata): Promise<PageMouseDownResult>;
Expand Down Expand Up @@ -1411,6 +1412,18 @@ export type PageKeyboardTypeOptions = {
delay?: number,
};
export type PageKeyboardTypeResult = void;
export type PageKeyboardImeSetCompositionParams = {
text: string,
selectionStart: number,
selectionEnd: number,
replacementStart?: number,
replacementEnd?: number,
};
export type PageKeyboardImeSetCompositionOptions = {
replacementStart?: number,
replacementEnd?: number,
};
export type PageKeyboardImeSetCompositionResult = void;
export type PageKeyboardPressParams = {
key: string,
delay?: number,
Expand Down
8 changes: 8 additions & 0 deletions packages/playwright-core/src/protocol/protocol.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1050,6 +1050,14 @@ Page:
tracing:
snapshot: true

keyboardImeSetComposition:
parameters:
text: string
selectionStart: number
selectionEnd: number
replacementStart: number?
replacementEnd: number?

keyboardPress:
parameters:
key: string
Expand Down
7 changes: 7 additions & 0 deletions packages/playwright-core/src/protocol/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,13 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
text: tString,
delay: tOptional(tNumber),
});
scheme.PageKeyboardImeSetCompositionParams = tObject({
text: tString,
selectionStart: tNumber,
selectionEnd: tNumber,
replacementStart: tOptional(tNumber),
replacementEnd: tOptional(tNumber),
});
scheme.PageKeyboardPressParams = tObject({
key: tString,
delay: tOptional(tNumber),
Expand Down
7 changes: 7 additions & 0 deletions packages/playwright-core/src/server/chromium/crInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ export class RawKeyboardImpl implements input.RawKeyboard {
async sendText(text: string): Promise<void> {
await this._client.send('Input.insertText', { text });
}

async imeSetComposition(text: string, selectionStart: number, selectionEnd: number, replacementStart: number | -1, replacementEnd: number | -1): Promise<void> {
if (replacementStart === -1 && replacementEnd === -1)
await this._client.send('Input.imeSetComposition', { text, selectionStart, selectionEnd });
else
await this._client.send('Input.imeSetComposition', { text, selectionStart, selectionEnd, replacementStart, replacementEnd });
}
}

export class RawMouseImpl implements input.RawMouse {
Expand Down
4 changes: 4 additions & 0 deletions packages/playwright-core/src/server/firefox/ffInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ export class RawKeyboardImpl implements input.RawKeyboard {
async sendText(text: string): Promise<void> {
await this._client.send('Page.insertText', { text });
}

async imeSetComposition(text: string, selectionStart: number, selectionEnd: number, replacementStart: number | -1, replacementEnd: number | -1): Promise<void> {
throw new Error('unimplemented');
}
}

export class RawMouseImpl implements input.RawMouse {
Expand Down
12 changes: 12 additions & 0 deletions packages/playwright-core/src/server/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export interface RawKeyboard {
keydown(modifiers: Set<types.KeyboardModifier>, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number, autoRepeat: boolean, text: string | undefined): Promise<void>;
keyup(modifiers: Set<types.KeyboardModifier>, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number): Promise<void>;
sendText(text: string): Promise<void>;
imeSetComposition(text: string, selectionStart: number, selectionEnd: number, replacementStart: number | -1, replacementEnd: number | -1): Promise<void>;
}

export class Keyboard {
Expand Down Expand Up @@ -87,6 +88,17 @@ export class Keyboard {
await this._page._doSlowMo();
}

async imeSetComposition(text: string, selectionStart: number, selectionEnd: number, options?: { replacementStart?: number, replacementEnd?: number}) {
let replacementStart = -1;
let replacementEnd = -1;
if (options && options.replacementStart !== undefined)
replacementStart = options.replacementStart;
if (options && options.replacementEnd !== undefined)
replacementEnd = options.replacementEnd;
await this._raw.imeSetComposition(text, selectionStart, selectionEnd, replacementStart, replacementEnd);
await this._page._doSlowMo();
}

async type(text: string, options?: { delay?: number }) {
const delay = (options && options.delay) || undefined;
for (const char of text) {
Expand Down
4 changes: 4 additions & 0 deletions packages/playwright-core/src/server/webkit/wkInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ export class RawKeyboardImpl implements input.RawKeyboard {
async sendText(text: string): Promise<void> {
await this._session!.send('Page.insertText', { text });
}

async imeSetComposition(text: string, selectionStart: number, selectionEnd: number, replacementStart: number | -1, replacementEnd: number | -1): Promise<void> {
throw new Error('unimplemented');
}
}

export class RawMouseImpl implements input.RawMouse {
Expand Down
33 changes: 33 additions & 0 deletions packages/playwright-core/types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13447,6 +13447,39 @@ export interface Keyboard {
*/
down(key: string): Promise<void>;

/**
* If there is an active composition, it will update the composition. Otherwise it will start a new one. It will dispatch
* either a `compositionstart` or a `compositionupdate`. In order to cancel a composition: `keyboard.insertText('')`, and
* in order to commit/end a composition: `keyboard.insertText(<text to insert>)`.
* @param text Sets the text in the active composition
* @param selectionStart Sets the selection start of the focused element after the composition text is inserted. This is relatvie to the active composition, so if the text in the focused element is `abcd` but only `d` is part of the active composition, a selection
* start of `1` will set the selection start to be after `d`, which is absolute position `4`.
* @param selectionEnd Sets the selection end of the focused element after the composition text is inserted. This is relatvie to the active composition, so if the text in the focused element is `abcd` but only `d` is part of the active composition, a selection
* end of `1` will set the selection end to be after `d`, which is absolute position `4`.
* @param options
*/
imeSetComposition(text: string, selectionStart: number, selectionEnd: number, options?: {
/**
* Sets the end position of the absolute range that is to be replaced with the composition text.
*
* ```js
* const page = await browser.newPage();
* await page.goto('https://w3c.github.io/uievents/tools/key-event-viewer-ce.html');
* await page.focus('#input');
* await page.keyboard.imeSetComposition('s', 1, 1);
* await page.keyboard.imeSetComposition('す', 1, 1);
* await browser.close();
* ```
*
*/
replacementEnd?: number;

/**
* Sets the start position of the absolute range that is to be replaced with the composition text.
*/
replacementStart?: number;
}): Promise<void>;

/**
* Dispatches only `input` event, does not emit the `keydown`, `keyup` or `keypress` events.
*
Expand Down
Loading

0 comments on commit 41e0199

Please sign in to comment.