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