diff options
| author | Pascal Getreuer <50221757+getreuer@users.noreply.github.com> | 2022-05-13 23:00:32 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-05-14 16:00:32 +1000 |
| commit | 68b16bba68d79c63bbd649a5be58756e937c96da (patch) | |
| tree | be0d3d672c13c080f4da58687b5b1a261f465911 /quantum | |
| parent | 90eef4cd153cdc1b00d973e6abb029828f656294 (diff) | |
[Core] Add Caps Word feature to core (#16588)
Co-authored-by: precondition <57645186+precondition@users.noreply.github.com>
Co-authored-by: Drashna Jaelre <drashna@live.com>
Diffstat (limited to 'quantum')
| -rw-r--r-- | quantum/caps_word.c | 80 | ||||
| -rw-r--r-- | quantum/caps_word.h | 43 | ||||
| -rw-r--r-- | quantum/keyboard.c | 7 | ||||
| -rw-r--r-- | quantum/process_keycode/process_caps_word.c | 160 | ||||
| -rw-r--r-- | quantum/process_keycode/process_caps_word.h | 37 | ||||
| -rw-r--r-- | quantum/quantum.c | 3 | ||||
| -rw-r--r-- | quantum/quantum.h | 5 | ||||
| -rw-r--r-- | quantum/quantum_keycodes.h | 3 |
8 files changed, 338 insertions, 0 deletions
diff --git a/quantum/caps_word.c b/quantum/caps_word.c new file mode 100644 index 0000000000..5b83659f28 --- /dev/null +++ b/quantum/caps_word.c | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | // Copyright 2021-2022 Google LLC | ||
| 2 | // | ||
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | // you may not use this file except in compliance with the License. | ||
| 5 | // You may obtain a copy of the License at | ||
| 6 | // | ||
| 7 | // https://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | // | ||
| 9 | // Unless required by applicable law or agreed to in writing, software | ||
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | // See the License for the specific language governing permissions and | ||
| 13 | // limitations under the License. | ||
| 14 | |||
| 15 | #include "caps_word.h" | ||
| 16 | |||
| 17 | /** @brief True when Caps Word is active. */ | ||
| 18 | static bool caps_word_active = false; | ||
| 19 | |||
| 20 | #if CAPS_WORD_IDLE_TIMEOUT > 0 | ||
| 21 | // Constrain timeout to a sensible range. With 16-bit timers, the longest | ||
| 22 | // timeout possible is 32768 ms, rounded here to 30000 ms = half a minute. | ||
| 23 | # if CAPS_WORD_IDLE_TIMEOUT < 100 || CAPS_WORD_IDLE_TIMEOUT > 30000 | ||
| 24 | # error "CAPS_WORD_IDLE_TIMEOUT must be between 100 and 30000 ms" | ||
| 25 | # endif | ||
| 26 | |||
| 27 | /** @brief Deadline for idle timeout. */ | ||
| 28 | static uint16_t idle_timer = 0; | ||
| 29 | |||
| 30 | void caps_word_task(void) { | ||
| 31 | if (caps_word_active && timer_expired(timer_read(), idle_timer)) { | ||
| 32 | caps_word_off(); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | void caps_word_reset_idle_timer(void) { | ||
| 37 | idle_timer = timer_read() + CAPS_WORD_IDLE_TIMEOUT; | ||
| 38 | } | ||
| 39 | #endif // CAPS_WORD_IDLE_TIMEOUT > 0 | ||
| 40 | |||
| 41 | void caps_word_on(void) { | ||
| 42 | if (caps_word_active) { | ||
| 43 | return; | ||
| 44 | } | ||
| 45 | |||
| 46 | clear_mods(); | ||
| 47 | #ifndef NO_ACTION_ONESHOT | ||
| 48 | clear_oneshot_mods(); | ||
| 49 | #endif // NO_ACTION_ONESHOT | ||
| 50 | #if CAPS_WORD_IDLE_TIMEOUT > 0 | ||
| 51 | caps_word_reset_idle_timer(); | ||
| 52 | #endif // CAPS_WORD_IDLE_TIMEOUT > 0 | ||
| 53 | |||
| 54 | caps_word_active = true; | ||
| 55 | caps_word_set_user(true); | ||
| 56 | } | ||
| 57 | |||
| 58 | void caps_word_off(void) { | ||
| 59 | if (!caps_word_active) { | ||
| 60 | return; | ||
| 61 | } | ||
| 62 | |||
| 63 | unregister_weak_mods(MOD_MASK_SHIFT); // Make sure weak shift is off. | ||
| 64 | caps_word_active = false; | ||
| 65 | caps_word_set_user(false); | ||
| 66 | } | ||
| 67 | |||
| 68 | void caps_word_toggle(void) { | ||
| 69 | if (caps_word_active) { | ||
| 70 | caps_word_off(); | ||
| 71 | } else { | ||
| 72 | caps_word_on(); | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | bool is_caps_word_on(void) { | ||
| 77 | return caps_word_active; | ||
| 78 | } | ||
| 79 | |||
| 80 | __attribute__((weak)) void caps_word_set_user(bool active) {} | ||
diff --git a/quantum/caps_word.h b/quantum/caps_word.h new file mode 100644 index 0000000000..b83f73371e --- /dev/null +++ b/quantum/caps_word.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | // Copyright 2021-2022 Google LLC | ||
| 2 | // | ||
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | // you may not use this file except in compliance with the License. | ||
| 5 | // You may obtain a copy of the License at | ||
| 6 | // | ||
| 7 | // https://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | // | ||
| 9 | // Unless required by applicable law or agreed to in writing, software | ||
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | // See the License for the specific language governing permissions and | ||
| 13 | // limitations under the License. | ||
| 14 | |||
| 15 | #pragma once | ||
| 16 | |||
| 17 | #include "quantum.h" | ||
| 18 | |||
| 19 | #ifndef CAPS_WORD_IDLE_TIMEOUT | ||
| 20 | # define CAPS_WORD_IDLE_TIMEOUT 5000 // Default timeout of 5 seconds. | ||
| 21 | #endif // CAPS_WORD_IDLE_TIMEOUT | ||
| 22 | |||
| 23 | #if CAPS_WORD_IDLE_TIMEOUT > 0 | ||
| 24 | /** @brief Matrix scan task for Caps Word feature */ | ||
| 25 | void caps_word_task(void); | ||
| 26 | |||
| 27 | /** @brief Resets timer for Caps Word idle timeout. */ | ||
| 28 | void caps_word_reset_idle_timer(void); | ||
| 29 | #else | ||
| 30 | static inline void caps_word_task(void) {} | ||
| 31 | #endif // CAPS_WORD_IDLE_TIMEOUT > 0 | ||
| 32 | |||
| 33 | void caps_word_on(void); /**< Activates Caps Word. */ | ||
| 34 | void caps_word_off(void); /**< Deactivates Caps Word. */ | ||
| 35 | void caps_word_toggle(void); /**< Toggles Caps Word. */ | ||
| 36 | bool is_caps_word_on(void); /**< Gets whether currently active. */ | ||
| 37 | |||
| 38 | /** | ||
| 39 | * @brief Caps Word set callback. | ||
| 40 | * | ||
| 41 | * @param active True if Caps Word is active, false otherwise | ||
| 42 | */ | ||
| 43 | void caps_word_set_user(bool active); | ||
diff --git a/quantum/keyboard.c b/quantum/keyboard.c index 1dccd48e2f..a65f9d6d18 100644 --- a/quantum/keyboard.c +++ b/quantum/keyboard.c | |||
| @@ -108,6 +108,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 108 | #ifdef BLUETOOTH_ENABLE | 108 | #ifdef BLUETOOTH_ENABLE |
| 109 | # include "outputselect.h" | 109 | # include "outputselect.h" |
| 110 | #endif | 110 | #endif |
| 111 | #ifdef CAPS_WORD_ENABLE | ||
| 112 | # include "caps_word.h" | ||
| 113 | #endif | ||
| 111 | 114 | ||
| 112 | static uint32_t last_input_modification_time = 0; | 115 | static uint32_t last_input_modification_time = 0; |
| 113 | uint32_t last_input_activity_time(void) { | 116 | uint32_t last_input_activity_time(void) { |
| @@ -549,6 +552,10 @@ void quantum_task(void) { | |||
| 549 | autoshift_matrix_scan(); | 552 | autoshift_matrix_scan(); |
| 550 | #endif | 553 | #endif |
| 551 | 554 | ||
| 555 | #ifdef CAPS_WORD_ENABLE | ||
| 556 | caps_word_task(); | ||
| 557 | #endif | ||
| 558 | |||
| 552 | #ifdef SECURE_ENABLE | 559 | #ifdef SECURE_ENABLE |
| 553 | secure_task(); | 560 | secure_task(); |
| 554 | #endif | 561 | #endif |
diff --git a/quantum/process_keycode/process_caps_word.c b/quantum/process_keycode/process_caps_word.c new file mode 100644 index 0000000000..15238f04a1 --- /dev/null +++ b/quantum/process_keycode/process_caps_word.c | |||
| @@ -0,0 +1,160 @@ | |||
| 1 | // Copyright 2021-2022 Google LLC | ||
| 2 | // | ||
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | // you may not use this file except in compliance with the License. | ||
| 5 | // You may obtain a copy of the License at | ||
| 6 | // | ||
| 7 | // https://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | // | ||
| 9 | // Unless required by applicable law or agreed to in writing, software | ||
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | // See the License for the specific language governing permissions and | ||
| 13 | // limitations under the License. | ||
| 14 | |||
| 15 | #include "process_caps_word.h" | ||
| 16 | |||
| 17 | bool process_caps_word(uint16_t keycode, keyrecord_t* record) { | ||
| 18 | if (keycode == CAPSWRD) { // Pressing CAPSWRD toggles Caps Word. | ||
| 19 | if (record->event.pressed) { | ||
| 20 | caps_word_toggle(); | ||
| 21 | } | ||
| 22 | return false; | ||
| 23 | } | ||
| 24 | |||
| 25 | #ifndef NO_ACTION_ONESHOT | ||
| 26 | const uint8_t mods = get_mods() | get_oneshot_mods(); | ||
| 27 | #else | ||
| 28 | const uint8_t mods = get_mods(); | ||
| 29 | #endif // NO_ACTION_ONESHOT | ||
| 30 | |||
| 31 | if (!is_caps_word_on()) { | ||
| 32 | // The following optionally turns on Caps Word by holding left and | ||
| 33 | // right shifts or by double tapping left shift. This way Caps Word | ||
| 34 | // may be used without needing a dedicated key and also without | ||
| 35 | // needing combos or tap dance. | ||
| 36 | |||
| 37 | #ifdef BOTH_SHIFTS_TURNS_ON_CAPS_WORD | ||
| 38 | // Many keyboards enable the Command feature by default, which also | ||
| 39 | // uses left+right shift. It can be configured to use a different | ||
| 40 | // key combination by defining IS_COMMAND(). We make a non-fatal | ||
| 41 | // warning if Command is enabled but IS_COMMAND() is *not* defined. | ||
| 42 | # if defined(COMMAND_ENABLE) && !defined(IS_COMMAND) | ||
| 43 | # pragma message "BOTH_SHIFTS_TURNS_ON_CAPS_WORD and Command should not be enabled at the same time, since both use the Left Shift + Right Shift key combination. Please disable Command, or ensure that `IS_COMMAND` is not set to (get_mods() == MOD_MASK_SHIFT)." | ||
| 44 | # else | ||
| 45 | if (mods == MOD_MASK_SHIFT | ||
| 46 | # ifdef COMMAND_ENABLE | ||
| 47 | // Don't activate Caps Word at the same time as Command. | ||
| 48 | && !(IS_COMMAND()) | ||
| 49 | # endif // COMMAND_ENABLE | ||
| 50 | ) { | ||
| 51 | caps_word_on(); | ||
| 52 | } | ||
| 53 | # endif // defined(COMMAND_ENABLE) && !defined(IS_COMMAND) | ||
| 54 | #endif // BOTH_SHIFTS_TURNS_ON_CAPS_WORD | ||
| 55 | |||
| 56 | #ifdef DOUBLE_TAP_SHIFT_TURNS_ON_CAPS_WORD | ||
| 57 | // Double tapping left shift turns on Caps Word. | ||
| 58 | // | ||
| 59 | // NOTE: This works with KC_LSFT and one-shot left shift. It | ||
| 60 | // wouldn't make sense with mod-tap or Space Cadet shift since | ||
| 61 | // double tapping would of course trigger the tapping action. | ||
| 62 | if (record->event.pressed) { | ||
| 63 | static bool tapped = false; | ||
| 64 | static uint16_t timer = 0; | ||
| 65 | if (keycode == KC_LSFT || keycode == OSM(MOD_LSFT)) { | ||
| 66 | if (tapped && !timer_expired(record->event.time, timer)) { | ||
| 67 | // Left shift was double tapped, activate Caps Word. | ||
| 68 | caps_word_on(); | ||
| 69 | } | ||
| 70 | tapped = true; | ||
| 71 | timer = record->event.time + GET_TAPPING_TERM(keycode, record); | ||
| 72 | } else { | ||
| 73 | tapped = false; // Reset when any other key is pressed. | ||
| 74 | } | ||
| 75 | } | ||
| 76 | #endif // DOUBLE_TAP_SHIFT_TURNS_ON_CAPS_WORD | ||
| 77 | |||
| 78 | return true; | ||
| 79 | } | ||
| 80 | |||
| 81 | #if CAPS_WORD_IDLE_TIMEOUT > 0 | ||
| 82 | caps_word_reset_idle_timer(); | ||
| 83 | #endif // CAPS_WORD_IDLE_TIMEOUT > 0 | ||
| 84 | |||
| 85 | // From here on, we only take action on press events. | ||
| 86 | if (!record->event.pressed) { | ||
| 87 | return true; | ||
| 88 | } | ||
| 89 | |||
| 90 | if (!(mods & ~MOD_MASK_SHIFT)) { | ||
| 91 | switch (keycode) { | ||
| 92 | // Ignore MO, TO, TG, TT, and OSL layer switch keys. | ||
| 93 | case QK_MOMENTARY ... QK_MOMENTARY_MAX: | ||
| 94 | case QK_TO ... QK_TO_MAX: | ||
| 95 | case QK_TOGGLE_LAYER ... QK_TOGGLE_LAYER_MAX: | ||
| 96 | case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX: | ||
| 97 | case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX: | ||
| 98 | return true; | ||
| 99 | |||
| 100 | #ifndef NO_ACTION_TAPPING | ||
| 101 | case QK_MOD_TAP ... QK_MOD_TAP_MAX: | ||
| 102 | if (record->tap.count == 0) { | ||
| 103 | // Deactivate if a mod becomes active through holding | ||
| 104 | // a mod-tap key. | ||
| 105 | caps_word_off(); | ||
| 106 | return true; | ||
| 107 | } | ||
| 108 | keycode &= 0xff; | ||
| 109 | break; | ||
| 110 | |||
| 111 | # ifndef NO_ACTION_LAYER | ||
| 112 | case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: | ||
| 113 | # endif // NO_ACTION_LAYER | ||
| 114 | if (record->tap.count == 0) { | ||
| 115 | return true; | ||
| 116 | } | ||
| 117 | keycode &= 0xff; | ||
| 118 | break; | ||
| 119 | #endif // NO_ACTION_TAPPING | ||
| 120 | |||
| 121 | #ifdef SWAP_HANDS_ENABLE | ||
| 122 | case QK_SWAP_HANDS ... QK_SWAP_HANDS_MAX: | ||
| 123 | if (keycode > 0x56F0 || record->tap.count == 0) { | ||
| 124 | return true; | ||
| 125 | } | ||
| 126 | keycode &= 0xff; | ||
| 127 | break; | ||
| 128 | #endif // SWAP_HANDS_ENABLE | ||
| 129 | } | ||
| 130 | |||
| 131 | clear_weak_mods(); | ||
| 132 | if (caps_word_press_user(keycode)) { | ||
| 133 | send_keyboard_report(); | ||
| 134 | return true; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | caps_word_off(); | ||
| 139 | return true; | ||
| 140 | } | ||
| 141 | |||
| 142 | __attribute__((weak)) bool caps_word_press_user(uint16_t keycode) { | ||
| 143 | switch (keycode) { | ||
| 144 | // Keycodes that continue Caps Word, with shift applied. | ||
| 145 | case KC_A ... KC_Z: | ||
| 146 | case KC_MINS: | ||
| 147 | add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to next key. | ||
| 148 | return true; | ||
| 149 | |||
| 150 | // Keycodes that continue Caps Word, without shifting. | ||
| 151 | case KC_1 ... KC_0: | ||
| 152 | case KC_BSPC: | ||
| 153 | case KC_DEL: | ||
| 154 | case KC_UNDS: | ||
| 155 | return true; | ||
| 156 | |||
| 157 | default: | ||
| 158 | return false; // Deactivate Caps Word. | ||
| 159 | } | ||
| 160 | } | ||
diff --git a/quantum/process_keycode/process_caps_word.h b/quantum/process_keycode/process_caps_word.h new file mode 100644 index 0000000000..f215bbc3a3 --- /dev/null +++ b/quantum/process_keycode/process_caps_word.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | // Copyright 2021-2022 Google LLC | ||
| 2 | // | ||
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | // you may not use this file except in compliance with the License. | ||
| 5 | // You may obtain a copy of the License at | ||
| 6 | // | ||
| 7 | // https://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | // | ||
| 9 | // Unless required by applicable law or agreed to in writing, software | ||
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | // See the License for the specific language governing permissions and | ||
| 13 | // limitations under the License. | ||
| 14 | |||
| 15 | #pragma once | ||
| 16 | |||
| 17 | #include "quantum.h" | ||
| 18 | #include "caps_word.h" | ||
| 19 | |||
| 20 | /** | ||
| 21 | * @brief Process handler for Caps Word feature. | ||
| 22 | * | ||
| 23 | * @param keycode Keycode registered by matrix press, per keymap | ||
| 24 | * @param record keyrecord_t structure | ||
| 25 | * @return true Continue processing keycodes, and send to host | ||
| 26 | * @return false Stop processing keycodes, and don't send to host | ||
| 27 | */ | ||
| 28 | bool process_caps_word(uint16_t keycode, keyrecord_t* record); | ||
| 29 | |||
| 30 | /** | ||
| 31 | * @brief Weak function for user-level Caps Word press modification. | ||
| 32 | * | ||
| 33 | * @param keycode Keycode registered by matrix press, per keymap | ||
| 34 | * @return true Continue Caps Word | ||
| 35 | * @return false Stop Caps Word | ||
| 36 | */ | ||
| 37 | bool caps_word_press_user(uint16_t keycode); | ||
diff --git a/quantum/quantum.c b/quantum/quantum.c index c0e801a4bb..b54b46760c 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c | |||
| @@ -307,6 +307,9 @@ bool process_record_quantum(keyrecord_t *record) { | |||
| 307 | #ifdef TERMINAL_ENABLE | 307 | #ifdef TERMINAL_ENABLE |
| 308 | process_terminal(keycode, record) && | 308 | process_terminal(keycode, record) && |
| 309 | #endif | 309 | #endif |
| 310 | #ifdef CAPS_WORD_ENABLE | ||
| 311 | process_caps_word(keycode, record) && | ||
| 312 | #endif | ||
| 310 | #ifdef SPACE_CADET_ENABLE | 313 | #ifdef SPACE_CADET_ENABLE |
| 311 | process_space_cadet(keycode, record) && | 314 | process_space_cadet(keycode, record) && |
| 312 | #endif | 315 | #endif |
diff --git a/quantum/quantum.h b/quantum/quantum.h index 7829ec7e0c..92e1af1c40 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h | |||
| @@ -233,6 +233,11 @@ extern layer_state_t layer_state; | |||
| 233 | # include "pointing_device.h" | 233 | # include "pointing_device.h" |
| 234 | #endif | 234 | #endif |
| 235 | 235 | ||
| 236 | #ifdef CAPS_WORD_ENABLE | ||
| 237 | # include "caps_word.h" | ||
| 238 | # include "process_caps_word.h" | ||
| 239 | #endif | ||
| 240 | |||
| 236 | // For tri-layer | 241 | // For tri-layer |
| 237 | void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3); | 242 | void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3); |
| 238 | layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_t layer2, uint8_t layer3); | 243 | layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_t layer2, uint8_t layer3); |
diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h index 5d5c4ed8c4..2f8ee2322e 100644 --- a/quantum/quantum_keycodes.h +++ b/quantum/quantum_keycodes.h | |||
| @@ -602,6 +602,8 @@ enum quantum_keycodes { | |||
| 602 | SECURE_UNLOCK, | 602 | SECURE_UNLOCK, |
| 603 | SECURE_TOGGLE, | 603 | SECURE_TOGGLE, |
| 604 | 604 | ||
| 605 | CAPS_WORD, | ||
| 606 | |||
| 605 | // Start of custom keycode range for keyboards and keymaps - always leave at the end | 607 | // Start of custom keycode range for keyboards and keymaps - always leave at the end |
| 606 | SAFE_RANGE | 608 | SAFE_RANGE |
| 607 | }; | 609 | }; |
| @@ -964,5 +966,6 @@ enum quantum_keycodes { | |||
| 964 | #define PB_32 PROGRAMMABLE_BUTTON_32 | 966 | #define PB_32 PROGRAMMABLE_BUTTON_32 |
| 965 | #define PROGRAMMABLE_BUTTON_MIN PROGRAMMABLE_BUTTON_1 | 967 | #define PROGRAMMABLE_BUTTON_MIN PROGRAMMABLE_BUTTON_1 |
| 966 | #define PROGRAMMABLE_BUTTON_MAX PROGRAMMABLE_BUTTON_32 | 968 | #define PROGRAMMABLE_BUTTON_MAX PROGRAMMABLE_BUTTON_32 |
| 969 | #define CAPSWRD CAPS_WORD | ||
| 967 | 970 | ||
| 968 | #include "quantum_keycodes_legacy.h" | 971 | #include "quantum_keycodes_legacy.h" |
