1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** USBX Component */
16 /** */
17 /** HID Keyboard Client */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22
23 /* Include necessary system files. */
24
25 #define UX_SOURCE_CODE
26
27 #include "ux_api.h"
28 #include "ux_host_class_hid.h"
29 #include "ux_host_class_hid_keyboard.h"
30 #include "ux_host_stack.h"
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_host_class_hid_keyboard_callback PORTABLE C */
37 /* 6.1.10 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function is the callback mechanism for a report registration. */
45 /* */
46 /* INPUT */
47 /* */
48 /* callback Pointer to callback */
49 /* */
50 /* OUTPUT */
51 /* */
52 /* None */
53 /* */
54 /* CALLS */
55 /* */
56 /* _ux_utility_memory_copy Copy memory */
57 /* _ux_utility_memory_set Set memory */
58 /* */
59 /* CALLED BY */
60 /* */
61 /* HID Class when a report is generated */
62 /* */
63 /* RELEASE HISTORY */
64 /* */
65 /* DATE NAME DESCRIPTION */
66 /* */
67 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
68 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
69 /* verified memset and memcpy */
70 /* cases, */
71 /* resulting in version 6.1 */
72 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
73 /* added standalone support, */
74 /* resulting in version 6.1.10 */
75 /* */
76 /**************************************************************************/
_ux_host_class_hid_keyboard_callback(UX_HOST_CLASS_HID_REPORT_CALLBACK * callback)77 VOID _ux_host_class_hid_keyboard_callback(UX_HOST_CLASS_HID_REPORT_CALLBACK *callback)
78 {
79
80 /* This array contains the bit for each alternate key (modifier or lock key)
81 that we report to the application. For example, if you wanted to set the
82 bit for the CAPS_LOCK key, you would do:
83 keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state |= alternate_key_bits[0];
84 Index 0 is used since it corresponds to the CAPS_LOCK bit in the array. Note
85 that _alternate_key_state is what we report to the application. */
86 const ULONG alternate_key_bits[] = {
87 UX_HID_KEYBOARD_STATE_CAPS_LOCK,
88 UX_HID_KEYBOARD_STATE_NUM_LOCK,
89 UX_HID_KEYBOARD_STATE_SCROLL_LOCK,
90 UX_HID_KEYBOARD_STATE_LEFT_CTRL,
91 UX_HID_KEYBOARD_STATE_LEFT_SHIFT,
92 UX_HID_KEYBOARD_STATE_LEFT_ALT,
93 UX_HID_KEYBOARD_STATE_LEFT_GUI,
94 UX_HID_KEYBOARD_STATE_RIGHT_CTRL,
95 UX_HID_KEYBOARD_STATE_RIGHT_SHIFT,
96 UX_HID_KEYBOARD_STATE_RIGHT_ALT,
97 UX_HID_KEYBOARD_STATE_RIGHT_GUI,
98 };
99
100 /* Define the indices for each alternate key in the alternate key bits array. */
101
102 #define ALTERNATE_KEY_BITS_IDX_CAPS_LOCK ( 0)
103 #define ALTERNATE_KEY_BITS_IDX_NUM_LOCK ( 1)
104 #define ALTERNATE_KEY_BITS_IDX_SCROLL_LOCK ( 2)
105
106 #define ALTERNATE_KEY_BITS_IDX_LEFT_CTRL ( 3)
107 #define ALTERNATE_KEY_BITS_IDX_LEFT_SHIFT ( 4)
108 #define ALTERNATE_KEY_BITS_IDX_LEFT_ALT ( 5)
109 #define ALTERNATE_KEY_BITS_IDX_LEFT_GUI ( 6)
110 #define ALTERNATE_KEY_BITS_IDX_RIGHT_CTRL ( 7)
111 #define ALTERNATE_KEY_BITS_IDX_RIGHT_SHIFT ( 8)
112 #define ALTERNATE_KEY_BITS_IDX_RIGHT_ALT ( 9)
113 #define ALTERNATE_KEY_BITS_IDX_RIGHT_GUI (10)
114
115 /* Define a macro to get the index of a modifier key in the alternate key bits array. */
116 #define GET_ALTERNATE_KEY_BITS_IDX(usage) ((usage) - UX_HID_MODIFIER_KEY_LEFT_CONTROL + ALTERNATE_KEY_BITS_IDX_LEFT_CTRL)
117
118 /* Define key states. */
119 #define KEY_STATE_REGULAR (11)
120 #define KEY_STATE_NO_KEY (12)
121
122 #define KEY_UP ( 0)
123 #define KEY_KEEP ( 1)
124 #define KEY_DOWN ( 2)
125 #define KEY_DEL ( 3)
126
127
128 UX_HOST_CLASS_HID_CLIENT *hid_client;
129 UX_HOST_CLASS_HID_KEYBOARD *keyboard_instance;
130 UX_HOST_CLASS_HID_KEYBOARD_LAYOUT *keyboard_layout;
131 UCHAR *keypad_array;
132 ULONG *array_head;
133 ULONG *array_tail;
134 ULONG *array_end;
135 ULONG *array_start;
136 ULONG *report_buffer;
137 ULONG *report_buffer_end;
138 ULONG keyboard_char = 0;
139 ULONG shift_on;
140 ULONG capslock_on;
141 ULONG numlock_on;
142 ULONG key_usage;
143 ULONG key_value;
144
145 /* This variable either contains an index into the alternate key bit array,
146 or a value that describes the current key i.e. regular key or no key. */
147 UINT key_state;
148
149 #if !defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE)
150 UCHAR *previous_lock_key_states;
151 UCHAR *current_lock_key_states;
152 #else
153 UINT i, i_save, new_count;
154 UCHAR *state_usage;
155 UCHAR *state_value;
156 UCHAR *state_action;
157 #endif
158
159
160 /* Get the HID client instance that issued the callback. */
161 hid_client = callback -> ux_host_class_hid_report_callback_client;
162
163 /* Get the keyboard local instance. */
164 keyboard_instance = (UX_HOST_CLASS_HID_KEYBOARD *) hid_client -> ux_host_class_hid_client_local_instance;
165
166 /* Get the report buffer. */
167 report_buffer = (ULONG *)callback -> ux_host_class_hid_report_callback_buffer;
168
169 /* Get the end of report buffer. */
170 report_buffer_end = &report_buffer[callback -> ux_host_class_hid_report_callback_actual_length];
171
172 #if !defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE)
173
174 /* Get the previous states of the lock keys. */
175 previous_lock_key_states = &keyboard_instance -> ux_host_class_hid_keyboard_key_state[0];
176
177 /* Get the current states of the lock keys and immediately initialize them to zero;
178 if a lock key is not pressed in this report, it will remain zero (not pressed). */
179 current_lock_key_states = &keyboard_instance -> ux_host_class_hid_keyboard_key_state[3];
180 _ux_utility_memory_set(current_lock_key_states, 0, 3); /* Use case of memset is verified. */
181
182 /* Scan the report buffer and decode it. */
183 while(report_buffer < report_buffer_end)
184 {
185
186 /* Get usage and value from buffer. */
187 key_usage = *report_buffer ++;
188 key_value = *report_buffer ++;
189
190 /* Analyze the usage we have received. We eliminate the page from the usage. */
191 key_usage &= 0xFF;
192 #else
193
194 /* Initialize key states for report processing. */
195 state_usage = keyboard_instance -> ux_host_class_hid_keyboard_key_state;
196 state_value = state_usage + keyboard_instance -> ux_host_class_hid_keyboard_key_count * 2;
197 state_action = state_value + keyboard_instance -> ux_host_class_hid_keyboard_key_count * 2;
198
199 /* Reset state actions to DEL(not received). */
200 _ux_utility_memory_set(state_usage + keyboard_instance -> ux_host_class_hid_keyboard_key_count, 0, keyboard_instance -> ux_host_class_hid_keyboard_key_count); /* Use case of memset is verified. */
201 _ux_utility_memory_set(state_value + keyboard_instance -> ux_host_class_hid_keyboard_key_count, 0, keyboard_instance -> ux_host_class_hid_keyboard_key_count); /* Use case of memset is verified. */
202 _ux_utility_memory_set(state_action, KEY_DEL, keyboard_instance -> ux_host_class_hid_keyboard_key_count * 2); /* Use case of memset is verified. */
203
204 new_count = keyboard_instance -> ux_host_class_hid_keyboard_key_count;
205 while(report_buffer < report_buffer_end)
206 {
207
208 /* Get usage and value from buffer. */
209 key_usage = *report_buffer ++;
210 key_value = *report_buffer ++;
211
212 /* Analyze the usage we have received. We eliminate the page from the usage. */
213 key_usage &= 0xFF;
214 key_value &= 0xFF;
215
216 /* If there is no key or in phantom state (roll over), skip. */
217 if (key_usage <= UX_HID_KEYBOARD_PHANTOM_STATE)
218 continue;
219
220 /* Check if the key is previously reported. */
221 for (i = 0; i < keyboard_instance -> ux_host_class_hid_keyboard_key_count; i ++)
222 {
223
224 /* Check if it's modified. */
225 if (state_usage[i] == key_usage)
226 {
227
228 /* Replace action state. */
229 state_action[i] = (state_value[i] == key_value) ? KEY_KEEP : (key_value ? KEY_DOWN : KEY_UP);
230
231 /* Replace key value. */
232 state_value[i] = key_value;
233 break;
234 }
235 }
236
237 /* When there is new key, add to new key list. */
238 if (i == keyboard_instance -> ux_host_class_hid_keyboard_key_count)
239 {
240
241 /* Add key value. */
242 state_usage [new_count] = key_usage;
243 state_value [new_count] = key_value;
244
245 /* Add key action. */
246 state_action[new_count] = key_value ? KEY_DOWN : KEY_KEEP;
247
248 new_count ++;
249 }
250 } /* while(report_buffer < report_buffer_end) */
251
252 /* Process pending key states. */
253 i_save = 0;
254 for (i = 0; i < new_count; i ++)
255 {
256
257 /* Get state value from buffer. */
258 key_usage = state_usage[i];
259 key_value = state_value[i];
260 key_state = state_action[i];
261
262 /* If no key, just skip. */
263 if (key_usage == 0)
264 continue;
265
266 /* If key not reported, add up event if it's enabled. */
267 if (key_state == KEY_DEL)
268 {
269
270 /* Clear state, do not save. */
271 state_usage[i] = 0;
272 state_action[i] = KEY_UP;
273 }
274
275 /* Key reported, process it. */
276 else
277 {
278
279 /* We need to save key anyway. */
280 if (i_save < i)
281 {
282 state_usage[i_save] = key_usage;
283 state_value[i_save] = key_value;
284 }
285 i_save ++;
286 }
287
288 /* Skip keep keys. */
289 if (state_action[i] == KEY_KEEP)
290 continue;
291
292 /* Now handle key event. */
293 keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state &= ~(UX_HID_KEYBOARD_STATE_FUNCTION | UX_HID_KEYBOARD_STATE_KEY_UP);
294 #endif /* UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE */
295
296 /* Determine what key this is. */
297 switch(key_usage)
298 {
299
300 /* This is the usage of a modifier key. Set or clear the appropriate
301 bits in the alternate key state bitmap. */
302 case UX_HID_MODIFIER_KEY_LEFT_SHIFT :
303 case UX_HID_MODIFIER_KEY_RIGHT_SHIFT :
304 case UX_HID_MODIFIER_KEY_LEFT_ALT :
305 case UX_HID_MODIFIER_KEY_RIGHT_ALT :
306 case UX_HID_MODIFIER_KEY_RIGHT_CONTROL :
307 case UX_HID_MODIFIER_KEY_LEFT_CONTROL :
308 case UX_HID_MODIFIER_KEY_RIGHT_GUI :
309 case UX_HID_MODIFIER_KEY_LEFT_GUI :
310
311 key_state = GET_ALTERNATE_KEY_BITS_IDX(key_usage);
312
313 /* We have received a modifier Key. Remember the state. */
314 if (key_value > 0)
315 keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state |= alternate_key_bits[key_state];
316 else
317 keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state &= ~alternate_key_bits[key_state];
318
319 break;
320
321 /* This is the usage of a LOCK key. Just save the its index in the alternate
322 key bit array. */
323
324 case UX_HID_LED_KEY_CAPS_LOCK :
325 key_state = ALTERNATE_KEY_BITS_IDX_CAPS_LOCK;
326 break;
327
328 case UX_HID_LED_KEY_NUM_LOCK :
329 key_state = ALTERNATE_KEY_BITS_IDX_NUM_LOCK;
330 break;
331
332 case UX_HID_LED_KEY_SCROLL_LOCK :
333 key_state = ALTERNATE_KEY_BITS_IDX_SCROLL_LOCK;
334 break;
335
336 #if !defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE)
337
338 /* Usage no key. */
339 case UX_HID_KEYBOARD_NO_KEY :
340 case UX_HID_KEYBOARD_PHANTOM_STATE :
341 key_state = KEY_STATE_NO_KEY;
342 break;
343 #endif
344
345 /* This is the usage of a regular key. Here, we just get the decoded
346 value; we will add it to the queue later. */
347 default :
348
349 /* By default the key will be saved. */
350 key_state = KEY_STATE_REGULAR;
351
352 /* Skip decode if decode is disabled. */
353 if (keyboard_instance -> ux_host_class_hid_keyboard_keys_decode_disable == UX_TRUE)
354 {
355
356 /* Use raw data (scan code) as key code. */
357 keyboard_char = key_value;
358 break;
359 }
360
361 /* Get keyboard layout instance. */
362 keyboard_layout = keyboard_instance -> ux_host_class_hid_keyboard_layout;
363
364 /* Is this key outside the valid range? */
365 if (key_value > keyboard_layout -> ux_host_class_hid_keyboard_layout_keys_upper_range)
366 {
367
368 /* Set a flag to discard it. */
369 key_state = KEY_STATE_NO_KEY;
370 break;
371 }
372
373 /* We have received a regular key. Depending on the state of the shift or numlock status, the key should be mapped into
374 one of the translation tables. We verify if the key is within our mapping range. */
375
376 /* Get SHIFT, CAPS_LOCK and NUM_LOCK states. */
377 shift_on = (keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state & UX_HID_KEYBOARD_STATE_SHIFT) ? UX_TRUE : UX_FALSE;
378 capslock_on = (keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state & UX_HID_KEYBOARD_STATE_CAPS_LOCK) ? UX_TRUE : UX_FALSE;
379 numlock_on = (keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state & UX_HID_KEYBOARD_STATE_NUM_LOCK) ? UX_TRUE : UX_FALSE;
380
381 /* Check if we have letters ('a' to 'z'). */
382 if (key_value >= keyboard_layout -> ux_host_class_hid_keyboard_layout_letters_lower_range &&
383 key_value <= keyboard_layout -> ux_host_class_hid_keyboard_layout_letters_upper_range)
384 {
385
386 /* We have letters, check the Shift and CapsLock state. */
387 if (shift_on != capslock_on)
388
389 /* Shift and CapsLock in different state: upper case. */
390 keyboard_char = keyboard_layout -> ux_host_class_hid_keyboard_layout_shift_array[key_value];
391 else
392
393 /* Lower case. */
394 keyboard_char = keyboard_layout -> ux_host_class_hid_keyboard_layout_regular_array[key_value];
395
396 break; /* default: */
397 }
398
399 /* Check if we have received a keypad key. They may be multiplexed. */
400 if (key_value >= keyboard_layout -> ux_host_class_hid_keyboard_layout_keypad_lower_range &&
401 key_value <= keyboard_layout -> ux_host_class_hid_keyboard_layout_keypad_upper_range)
402 {
403
404 /* We have a keypad key. Check the NumLock state. */
405 if (numlock_on)
406
407 /* Numlock is on. */
408 keypad_array = keyboard_layout -> ux_host_class_hid_keyboard_layout_numlock_on_array;
409
410 else
411
412 /* Numlock is off. */
413 keypad_array = keyboard_layout -> ux_host_class_hid_keyboard_layout_numlock_off_array;
414
415 /* Decode the keypad key. */
416 keyboard_char = keypad_array[key_value -
417 keyboard_layout -> ux_host_class_hid_keyboard_layout_keypad_lower_range];
418
419 break; /* default: */
420 }
421
422 /* Check the state of the shift. */
423 if (shift_on)
424
425 /* We get the key from the shifted array. */
426 keyboard_char = keyboard_layout -> ux_host_class_hid_keyboard_layout_shift_array[key_value];
427
428 else
429
430 /* We get the key from the regular array. */
431 keyboard_char = keyboard_layout -> ux_host_class_hid_keyboard_layout_regular_array[key_value];
432
433 break; /* default: */
434
435 } /* switch(key_usage) */
436
437 #if defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE)
438
439 if (state_action[i] == KEY_UP)
440
441 #if defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_KEY_DOWN_ONLY)
442
443 /* Skip save. */
444 continue;
445 #else
446
447 /* Save key up state. */
448 keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state |= UX_HID_KEYBOARD_STATE_KEY_UP;
449 #endif
450 #endif
451
452 /* If there is no key, just try next. */
453 if (key_state == KEY_STATE_NO_KEY)
454 continue;
455
456 /* Is this a LOCK key (i.e. caps lock, scroll lock or num lock)? */
457 if (key_state <= ALTERNATE_KEY_BITS_IDX_SCROLL_LOCK)
458 {
459
460 /* Skip decode if decode is disabled. */
461 if (keyboard_instance -> ux_host_class_hid_keyboard_keys_decode_disable == UX_TRUE)
462 {
463
464 /* Use raw data (scan code) as key code. */
465 keyboard_char = key_value;
466 }
467 else
468 {
469
470 #if !defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE)
471
472 /* Reflect the press in the current lock key state. */
473 current_lock_key_states[key_state] = (UCHAR)key_value;
474
475 /* Take action only if key state changes from up to down (pressed).
476 Remember that the nothing happens when lock keys are released. */
477 if (previous_lock_key_states[key_state] == 0)
478 #elif !defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_KEY_DOWN_ONLY)
479
480 /* Take action only if key state changes from up to down (pressed). */
481 if (state_action[i] == KEY_DOWN)
482 #endif
483 {
484
485 /* Reflect the change in the keyboard state. The state should be inverted. */
486 if (keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state & alternate_key_bits[key_state])
487 keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state &= (ULONG)~alternate_key_bits[key_state];
488 else
489 keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state |= alternate_key_bits[key_state];
490
491 #if defined(UX_HOST_STANDALONE)
492
493 /* Let background task to set LED status. */
494 keyboard_instance -> ux_host_class_hid_keyboard_out_state = UX_STATE_WAIT;
495 #else
496
497 /* Wake up the keyboard thread semaphore. */
498 _ux_host_semaphore_put(&keyboard_instance -> ux_host_class_hid_keyboard_semaphore);
499 #endif
500 }
501
502 #if defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE) && defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_LOCK_KEYS)
503
504 /* Use usage and UX_HID_KEYBOARD_STATE_FUNCTION. */
505 keyboard_char = key_usage;
506 keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state |= UX_HID_KEYBOARD_STATE_FUNCTION;
507
508 #else
509
510 /* Check next usage & value. */
511 continue;
512 #endif
513 }
514 }
515
516 /* If it's modifier, check next usage & value. */
517 else if (key_state < KEY_STATE_REGULAR)
518 {
519 #if defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE) && defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE_REPORT_MODIFIER_KEYS)
520
521 /* Use usage and UX_HID_KEYBOARD_STATE_FUNCTION. */
522 keyboard_char = key_usage;
523 keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state |= UX_HID_KEYBOARD_STATE_FUNCTION;
524 #else
525
526 /* Check next usage & value. */
527 continue;
528 #endif
529 }
530
531 /* If we get here, then we have a regular key. Now it's time to save
532 raw/decoded key in the key queue. */
533
534 /* This key should now be inserted in the circular array for the application to retrieve it. */
535 array_start = keyboard_instance -> ux_host_class_hid_keyboard_usage_array;
536 array_end = array_start + UX_HOST_CLASS_HID_KEYBOARD_USAGE_ARRAY_LENGTH;
537 array_head = keyboard_instance -> ux_host_class_hid_keyboard_usage_array_head;
538 array_tail = keyboard_instance -> ux_host_class_hid_keyboard_usage_array_tail;
539
540 /* We have a single usage/value. We have to store it into the array. If the array overflows,
541 there is no mechanism for flow control here so we ignore the usage/value until the
542 applications makes more room in the array. */
543
544 /* Is the head at the end of the array and need to loop back? */
545 if ((array_head + 2) >= array_end)
546 array_head = array_start;
547 else
548 array_head += 2;
549
550 /* Do we have enough space to store the new usage? */
551 if (array_head != array_tail)
552 {
553
554 /* Yes, we have some space. */
555 *keyboard_instance -> ux_host_class_hid_keyboard_usage_array_head = keyboard_char;
556 *(keyboard_instance -> ux_host_class_hid_keyboard_usage_array_head + 1) = keyboard_instance -> ux_host_class_hid_keyboard_alternate_key_state;
557
558 /* Now update the array head. */
559 keyboard_instance -> ux_host_class_hid_keyboard_usage_array_head = array_head;
560 }
561 else
562
563 /* Error trap. */
564 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_BUFFER_OVERFLOW);
565
566 } /* while(report_buffer < report_buffer_end) */
567
568 #if !defined(UX_HOST_CLASS_HID_KEYBOARD_EVENTS_KEY_CHANGES_MODE)
569
570 /* Copy the current lock key states to the previous states. Note that if
571 a lock key wasn't down in this report, its current state would have
572 remained zero (not pressed). */
573 _ux_utility_memory_copy(previous_lock_key_states, current_lock_key_states, 3); /* Use case of memcpy is verified. */
574 #else
575
576 /* Clear redundant data after last saved key. */
577 _ux_utility_memory_set(state_usage + i_save, 0, keyboard_instance -> ux_host_class_hid_keyboard_key_count - i_save); /* Use case of memset is verified. */
578 #endif
579
580 /* Return to caller. */
581 return;
582 }
583
584