1# Keyboard and Mouse Event 2 3 4Keyboard and mouse events refer to the input events of the peripheral keyboard and mouse. 5 6 7## Mouse Event 8 9The supported mouse events include the events triggered by the peripheral mouse and touchpad. 10 11Mouse events can trigger the following callbacks. 12 13| Name | Description | 14| ---------------------------------------- | ---------------------------------------- | 15| onHover(event: (isHover: boolean) => void) | Triggered when the mouse pointer enters or leaves the component.<br>**isHover**: whether the mouse pointer hovers over the component. The value **true** means that the mouse pointer enters the component, and the value **false** means that the mouse pointer leaves the component.| 16| onMouse(event: (event?: MouseEvent) => void) | Triggered when the component is clicked by a mouse button or the mouse pointer moves on the component. The **event** parameter indicates the timestamp, mouse button, action, coordinates of the clicked point on the entire screen, and coordinates of the clicked point relative to the component when the event is triggered.| 17 18When the component is bound to the **onHover** callback, you can use the [hoverEffect](../reference/arkui-ts/ts-universal-attributes-hover-effect.md) attribute to set the hover effect of the component in hover state. 19 20 21 **Figure 1** Mouse event data flow 22 23 24 25 26 27When ArkUI receives the mouse event, it checks whether the mouse event concerns pressing, lifting, or moving of the left mouse button, and then responds accordingly. 28 29 30- Yes: The mouse event is first converted into a touch event in the same position, and a collision test, gesture judgment, and callback response of the touch event are performed. The collision test and callback response of the mouse event are then performed. 31 32- No: Only the collision test and callback response of the mouse event are performed. 33 34 35>**NOTE** 36> 37>All touch events and gesture events that can be responded to by a single finger may be triggered and responded to by using the left mouse button. For example, to implement page redirection invoked by clicking a button with support for finger touches and left-clicks, you just need to bind one click event (**onClick**). If you want to implement different effects for the finger touch and the left-click, you can use the **source** parameter in the **onClick** callback to determine whether the current event is triggered by a finger or a mouse. 38 39 40### onHover 41 42 43```ts 44onHover(event: (isHover?: boolean) => void) 45``` 46 47 48Triggered when the mouse pointer enters or leaves the component. The **isHover** parameter indicates whether the mouse pointer hovers over the component. This event does not support custom bubbling settings. By default, event bubbling occurs between parent and child components. 49 50 51If this API is bound to a component, it is triggered when the mouse pointer enters the component from outside and the value of **isHover** is **true**, or when the mouse pointer leaves the component and the value of **isHover** is **false**. 52 53 54>**NOTE** 55> 56>Event bubbling is an event propagation in the document object model (DOM) when an event is first handled by an element and then bubbles up to its parent element. 57 58 59 60 61```ts 62// xxx.ets 63@Entry 64@Component 65struct MouseExample { 66 @State isHovered: boolean = false; 67 68 build() { 69 Column() { 70 Button(this.isHovered ? 'Hovered!' : 'Not Hover') 71 .width(200).height(100) 72 .backgroundColor(this.isHovered ? Color.Green : Color.Gray) 73 .onHover((isHover?: boolean) => { // Use the onHover API to listen for whether the mouse pointer is hovered over the button. 74 if(isHover){ 75 this.isHovered = isHover; 76 } 77 }) 78 }.width('100%').height('100%').justifyContent(FlexAlign.Center) 79 } 80} 81``` 82 83 84In this example, a **\<Button component>** is created, with the initial background color of gray and the content of **Not Hover**. The component is bound to the **onHover** callback. In the callback, **this.isHovered** is set to the callback parameter **isHover**. 85 86 87When the mouse pointer moves from outside the button to inside the button, the callback is invoked, the value of **isHover** changes to **true**, the value of **isHovered** changes to **true**, the background color of the component changes to **Color.Green**, and the content changes to **Hovered!**. 88 89 90When the mouse pointer moves from inside the button to outside the button, the callback is invoked, the value of **isHover** changes to **false**, and the component restores to its initial style. 91 92 93 94 95 96### onMouse 97 98 99```ts 100onMouse(event: (event?: MouseEvent) => void) 101``` 102 103 104Triggered when a mouse event occurs. It is triggered each time an action by the mouse pointer (**MouseAction**) is detected in the component. The parameter is a [MouseEvent](../reference/arkui-ts/ts-universal-mouse-key.md) object, which indicates the mouse event that triggers the callback. This event supports custom bubbling settings. By default, event bubbling occurs between parent and child components. It is commonly used for customized mouse behavior logic processing. 105 106 107You can use the **MouseEvent** object in the callback to obtain information about the triggered event, including the coordinates (**displayX**/**displayY**/**windowX**/**windowY**/**x**/**y**), button ([MouseButton](../reference/arkui-ts/ts-appendix-enums.md#mousebutton)), action ([MouseAction](../reference/arkui-ts/ts-appendix-enums.md#mouseaction)), timestamp (**timestamp**), display area of the object that triggers the event ([EventTarget](../reference/arkui-ts/ts-universal-events-click.md)), and event source ([SourceType](../reference/arkui-ts/ts-gesture-settings.md)). The **stopPropagation** callback of **MouseEvent** is used to set whether the current event blocks bubbling. 108 109 110>**NOTE** 111> 112>**MouseButton** indicates the physical mouse button being pressed or released that triggers the mouse event. The values are **Left**, **Right**, **Middle**, **Back**, **Forward**, and **None**. **None** indicates that no button is pressed or released, which means that the event is triggered by the mouse pointer moving on the component. 113 114 115 116```ts 117// xxx.ets 118@Entry 119@Component 120struct MouseExample { 121 @State isHovered: boolean = false; 122 @State buttonText: string = ''; 123 @State columnText: string = ''; 124 125 build() { 126 Column() { 127 Button(this.isHovered ? 'Hovered!' : 'Not Hover') 128 .width(200) 129 .height(100) 130 .backgroundColor(this.isHovered ? Color.Green : Color.Gray) 131 .onHover((isHover?: boolean) => { 132 if(isHover){ 133 this.isHovered = isHover 134 } 135 }) 136 .onMouse((event?: MouseEvent) => { // Set the onMouse callback for the button. 137 if(event){ 138 this.buttonText = 'Button onMouse:\n' + '' + 139 'button = ' + event.button + '\n' + 140 'action = ' + event.action + '\n' + 141 'x,y = (' + event.x + ',' + event.y + ')' + '\n' + 142 'windowXY=(' + event.windowX + ',' + event.windowY + ')'; 143 } 144 }) 145 Divider() 146 Text(this.buttonText).fontColor(Color.Green) 147 Divider() 148 Text(this.columnText).fontColor(Color.Red) 149 } 150 .width('100%') 151 .height('100%') 152 .justifyContent(FlexAlign.Center) 153 .borderWidth(2) 154 .borderColor(Color.Red) 155 .onMouse((event?: MouseEvent) => { // Set the onMouse callback for the column. 156 if(event){ 157 this.columnText = 'Column onMouse:\n' + '' + 158 'button = ' + event.button + '\n' + 159 'action = ' + event.action + '\n' + 160 'x,y = (' + event.x + ',' + event.y + ')' + '\n' + 161 'windowXY=(' + event.windowX + ',' + event.windowY + ')'; 162 } 163 }) 164 } 165} 166``` 167 168 169Bind the **onMouse** API to the button based on the **onHover** example. In the callback, the values of the callback parameters, such as **button** and **action**, are displayed. The same settings are performed on the outer **\<Column>** container. The entire process can be divided into the following two actions: 170 171 1721. Moving the mouse pointer: When the mouse pointer is moved from outside the button to inside the button, only the **onMouse** callback of the **\<Column>** is triggered. When the mouse pointer is moved to the button, as the **onMouse** event bubbles up by default, both the **onMouse** callbacks of the **\<Column>** and **\<Button>** components are invoked. In this process, the mouse pointer moves, but no mouse button is clicked. Therefore, in the displayed information, the value of **button** is 0 (enumerated value of **MouseButton.None**) and the value of **action** is **3** (enumerated value of **MouseAction.Move**). 173 1742. Clicking the mouse button: After the mouse pointer enters the **\<Button>** component, the **\<Button>** component is clicked twice, namely, left-click and right-click. 175 Left-clicked: button = 1 (enumerated value of **MouseButton.Left**); action = 1 (enumerated value of **MouseAction.Press**); action = 2 (enumerated value of **MouseAction.Release**). 176 177 Right-click: button = 2 (enumerated value of **MouseButton.Right**); action = 1 (enumerated value of **MouseAction.Press**); action = 2 (enumerated value of **MouseAction.Release**) 178 179 180 181 182 183To prevent the mouse event from bubbling, call the **stopPropagation()** API. 184 185 186 187```ts 188class ish{ 189 isHovered:boolean = false 190 set(val:boolean){ 191 this.isHovered = val; 192 } 193} 194class butf{ 195 buttonText:string = '' 196 set(val:string){ 197 this.buttonText = val 198 } 199} 200@Entry 201@Component 202struct MouseExample { 203 @State isHovered:ish = new ish() 204 build(){ 205 Column(){ 206 Button(this.isHovered ? 'Hovered!' : 'Not Hover') 207 .width(200) 208 .height(100) 209 .backgroundColor(this.isHovered ? Color.Green : Color.Gray) 210 .onHover((isHover?: boolean) => { 211 if(isHover) { 212 let ishset = new ish() 213 ishset.set(isHover) 214 } 215 }) 216 .onMouse((event?: MouseEvent) => { 217 if (event) { 218 if (event.stopPropagation) { 219 event.stopPropagation(); // Prevent the onMouse event from bubbling. 220 } 221 let butset = new butf() 222 butset.set('Button onMouse:\n' + '' + 223 'button = ' + event.button + '\n' + 224 'action = ' + event.action + '\n' + 225 'x,y = (' + event.x + ',' + event.y + ')' + '\n' + 226 'windowXY=(' + event.windowX + ',' + event.windowY + ')'); 227 } 228 }) 229 } 230 } 231} 232``` 233 234 235To prevent the mouse event of the child component (**\<Button>**) from bubbling up to its parent component (**\<Column>**), use the **event** parameter in the **onMouse** callback of **\<Button>** to call the **stopPropagation** API. 236 237 238 239```ts 240event.stopPropagation() 241``` 242 243 244With bubbling prevented, the mouse event on the **\<Button>** component will trigger the **onMouse** callback of the **\<Button>** component, but not the **onMouse** callback of the **\<Column>** component. 245 246 247### hoverEffect 248 249 250```ts 251hoverEffect(value: HoverEffect) 252``` 253 254 255Sets the hover effect of the component in hover state. The parameter value type is **HoverEffect**. The **Auto**, **Scale**, and **Highlight** effects are preset and do not support customization. 256 257 258 **Table 1** HoverEffect 259 260| Enum| Description | 261| -------------- | ---------------------------------------- | 262| Auto | Default hover effect, which varies by component. | 263| Scale | Scale effect. When the mouse pointer is placed over the component, the component is scaled up from 100% to 105%. When the mouse pointer is moved away, the component is scaled down from 105% to 100%.| 264| Highlight | Background fade-in and fade-out effect. When the mouse pointer is placed over the component, a white layer with 5% opacity is applied to the background color of the component, resulting in a dimmed background. When the mouse pointer is moved away, the background color of the component is restored to the original style.| 265| None | No effect. | 266 267 268 269```ts 270// xxx.ets 271@Entry 272@Component 273struct HoverExample { 274 build() { 275 Column({ space: 10 }) { 276 Button('Auto') 277 .width(170).height(70) 278 Button('Scale') 279 .width(170).height(70) 280 .hoverEffect(HoverEffect.Scale) 281 Button('Highlight') 282 .width(170).height(70) 283 .hoverEffect(HoverEffect.Highlight) 284 Button('None') 285 .width(170).height(70) 286 .hoverEffect(HoverEffect.None) 287 }.width('100%').height('100%').justifyContent(FlexAlign.Center) 288 } 289} 290``` 291 292 293 294 295 296For the **\<Button>** component, **Auto** creates the same effect as **Scale**. 297 298 299## Key Event 300 301 **Figure 2** Key event data flow 302 303 304 305 306The key event is triggered by a device such as a peripheral keyboard, and is sent to the currently focused window after being converted by the driver and multi-mode processing. After obtaining the event, the window distributes the event to the input method (which consumes the key as the input). If the input method does not consume the key event, the window sends the event to the ArkUI framework. Therefore, when an input box component has focus and an input method is enabled, most key events are consumed by the input method. For example, a letter key is used by the input method to enter a letter in the input box, and an arrow key is used by the input method to switch to the desired candidate word. 307 308 309After the key event is sent to the ArkUI framework, it first identifies the complete focus chain, and then sends the key event one by one from the leaf node to the root node. 310 311 312### onKeyEvent 313 314 315```ts 316onKeyEvent(event: (event?: KeyEvent) => void) 317``` 318 319 320Triggered when the bound component has [focus](arkts-common-events-focus-event.md) and a key event occurs on the component. The callback parameter [KeyEvent](../reference/arkui-ts/ts-universal-events-key.md) can be used to obtain the information about the key event, including [KeyType](../reference/arkui-ts/ts-appendix-enums.md#keytype), [keyCode](../reference/apis/js-apis-keycode.md), keyText, [KeySource](../reference/arkui-ts/ts-appendix-enums.md#keysource), **deviceId**, **metaKey**, **timestamp**, and **stopPropagation**. 321 322 323 324```ts 325// xxx.ets 326@Entry 327@Component 328struct KeyEventExample { 329 @State buttonText: string = ''; 330 @State buttonType: string = ''; 331 @State columnText: string = ''; 332 @State columnType: string = ''; 333 334 build() { 335 Column() { 336 Button('onKeyEvent') 337 .width(140).height(70) 338 .onKeyEvent((event?: KeyEvent) => { // Set the onKeyEvent event for the button. 339 if(event){ 340 if (event.type === KeyType.Down) { 341 this.buttonType = 'Down'; 342 } 343 if (event.type === KeyType.Up) { 344 this.buttonType = 'Up'; 345 } 346 this.buttonText = 'Button: \n' + 347 'KeyType:' + this.buttonType + '\n' + 348 'KeyCode:' + event.keyCode + '\n' + 349 'KeyText:' + event.keyText; 350 } 351 }) 352 353 Divider() 354 Text(this.buttonText).fontColor(Color.Green) 355 356 Divider() 357 Text(this.columnText).fontColor(Color.Red) 358 }.width('100%').height('100%').justifyContent(FlexAlign.Center) 359 .onKeyEvent((event?: KeyEvent) => { // Set the onKeyEvent event for the parent container <Column>. 360 if(event){ 361 if (event.type === KeyType.Down) { 362 this.columnType = 'Down'; 363 } 364 if (event.type === KeyType.Up) { 365 this.columnType = 'Up'; 366 } 367 this.columnText = 'Column: \n' + 368 'KeyType:' + this.buttonType + '\n' + 369 'KeyCode:' + event.keyCode + '\n' + 370 'KeyText:' + event.keyText; 371 } 372 }) 373 } 374} 375``` 376 377 378In the preceding example, **onKeyEvent** is bound to the **\<Button>** component and its parent container **\<Column>**. After the application opens and loads a page, the first focusable non-container component in the component tree automatically obtains focus. As the application has only one **\<Button>** component, the component automatically obtains focus. Because the **\<Button>** component is a child node of the **\<Column>** component, the **\<Column>** component also obtains focus. For details about the focus obtaining mechanism, see [Focus Event](arkts-common-events-focus-event.md). 379 380 381 382 383 384After the application is opened, press the following keys in sequence: Space, Enter, Left Ctrl, Left Shift, Letter A, and Letter Z. 385 386 3871. Because the **onKeyEvent** event bubbles by default, the **onKeyEvent** callbacks of both **\<Button>** and **\<Column>** are invoked. 388 3892. Each key has two callbacks, which correspond to **KeyType.Down** and **KeyType.Up** respectively, indicating that the key is pressed and then lifted. 390 391 392To prevent the key event of the **\<Button>** component from bubbling up to its parent container **\<Column>**, add the **event.stopPropagation()** API to the **onKeyEvent** callback of **\<Button>**. 393 394 395 396```ts 397class butypef{ 398 buttonType:string = '' 399 set(val:string){ 400 this.buttonType = val 401 } 402 get(){ 403 return this.buttonType 404 } 405} 406@Entry 407@Component 408struct MouseExample { 409 build() { 410 Column() { 411 Button('onKeyEvent') 412 .width(140).height(70) 413 .onKeyEvent((event?: KeyEvent) => { 414 // Use stopPropagation to prevent the key event from bubbling up. 415 if(event){ 416 if(event.stopPropagation) { 417 event.stopPropagation(); 418 } 419 if (event.type === KeyType.Down) { 420 let butset = new butypef() 421 butset.set('Down') 422 } 423 if (event.type === KeyType.Up) { 424 let butset = new butypef() 425 butset.set('Up') 426 } 427 let butfset = new butypef() 428 let butset = new butypef() 429 butfset.set('Button: \n' + 430 'KeyType:' + butset.get() + '\n' + 431 'KeyCode:' + event.keyCode + '\n' + 432 'KeyText:' + event.keyText) 433 } 434 }) 435 } 436 } 437} 438``` 439 440 441 442