티스토리 뷰
이번 글에서는 실제로 사용자가 하나씩 입력하는 문자를 버퍼에 저장하였다가, 사용자가 엔터키를 누르게 되었을 때 저장해 둔 문자열을 리턴해 주는 코드를 만드는 방법에 대해서 설명하도록 하겠다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | #define CTRL_B 2 #define CTRL_C 3 #define CTRL_F 6 #define EOL '\0' #define ENTER '\r' #define BS '\b' #define ESC 0x1B #define ESC2 '[' #define DELIMIT '~' #define DELETE 0x7F #define UP_ARROW 'A' #define DN_ARROW 'B' #define RI_ARROW 'C' #define LE_ARROW 'D' static char command_buf[BD_CMD_BUF_SZ]; void *wait_command( void ) { char *cp = command_buf; char ch; int len, i; *cp = EOL; while (1) { ch = getc (); switch (ch) { case ENTER: putc ( '\n' ); return command_buf; case BS: // back space if (cp > command_buf) { puts ( "\b\x1B[K" ); if (*cp) { len = strlen (--cp); for (i=0; i<len; i++) cp[i] = cp[i+1]; puts (cp); printf ( "\x1B[%uD" , len-1); } else { *(--cp) = EOL; } } break ; case DELETE: // Delete if (*cp) { len = strlen (cp); for (i=0; i<len; i++) cp[i] = cp[i+1]; cp[i+1] = EOL; puts ( "\x1B[K" ); puts (cp); printf ( "\x1B[%uD" , len-1); } break ; case CTRL_B: // Ctrl+B i = 0; if (cp > command_buf) { --cp; i++; while (cp > command_buf && *cp == ' ' ) { --cp; i++; } while (cp >= command_buf && *cp != ' ' ) { --cp; i++; } ++cp; --i; printf ( "\x1B[%uD" , i); } break ; case CTRL_C: // Ctrl+C command_buf[0] = EOL; putc ( '\n' ); return command_buf; case CTRL_F: // Ctrl+F i = 0; char *end_cp = command_buf + strlen (command_buf); if (cp < end_cp) { while (cp < end_cp && *cp != ' ' ) { ++cp; i++; } while (cp < end_cp && *cp == ' ' ) { ++cp; i++; } if (i) printf ( "\x1B[%uC" , i); } break ; case ESC: // Special Keys if ( getc () != ESC2) break ; switch ( getc ()) { case UP_ARROW: break ; case DN_ARROW: break ; case RI_ARROW: if (cp < (command_buf + strlen (command_buf))) { ++cp; puts ( "\x1B[C" ); } break ; case LE_ARROW: if (cp > command_buf) { --cp; puts ( "\x1B[D" ); } break ; case '1' : ch = getc (); if (ch == DELIMIT) // KEY_HOME { len = cp - command_buf; if (len) { printf ( "\x1B[%uD" , len); cp = command_buf; } break ; } if ( getc () != DELIMIT) break ; switch (ch) { case '1' : // KEY_F1; break ; case '2' : // KEY_F2; break ; case '3' : // KEY_F3; break ; case '4' : // KEY_F4; break ; case '5' : // KEY_F5; break ; case '7' : // KEY_F6; break ; case '8' : // KEY_F7; break ; case '9' : // KEY_F8; break ; } break ; case '2' : ch = getc (); if (ch == DELIMIT) // KEY_INS; { break ; } if ( getc () != DELIMIT) break ; switch (ch) { case '0' : // KEY_F9; break ; case '1' : // KEY_F10; break ; case '3' : // KEY_F11; break ; case '4' : // KEY_F12; break ; } break ; case '4' : // KEY_END; if ( getc () == DELIMIT) { len = strlen (cp); if (len) { printf ( "\x1B[%uC" , len); cp += len; } } break ; case '5' : // KEY_PGUP; if ( getc () == DELIMIT) { } break ; case '6' : // KEY_PGDN; if ( getc () == DELIMIT) { } break ; } break ; default : if ( strlen (command_buf) < (BD_CMD_BUF_SZ - 1)) { if (*cp) { len = strlen (cp); for (i=len+1; i; i--) cp[i] = cp[i-1]; *cp = ch; puts ( "\x1B[K" ); puts (cp); printf ( "\x1B[%uD" , len); ++cp; } else { *cp++ = ch; *cp = EOL; putc (ch); } } break ; } // switch } // while return command_buf; } |
코드가 꽤 길지만 앞에서 설명한 글을 참고하면 특정 키가 눌러졌을때에 해당하는 코드는 그렇게 길지 않으므로 조금만 분석하면 쉽게 이해할 수 있을 것이다.
주요 기능들에 대해서 간단히 설명하면 다음과 같다.
엔터키를 누르면 입력이 끝났음을 알려주는 것이므로 문자열 버퍼의 시작 주소를 리턴해 주도록 하고 있다.
백스페이스와 delete 키는 입력 중인 문자열을 수정하기 위하여 사용된다. 백스페이스키는 현재 커서가 위치하고 있는 바로 앞의 글자를 지우고 커서 뒤에 있는 문자열을 한글자씩 앞으로 당기는 기능을 수행한다. 이에 반해 delete 키는 현재 커서 위치에 있는 글자를 하나 지우고 커서 뒤에 있는 글자들을 한칸씩 앞으로 당기게 된다.
왼쪽 화살표와 오른쪽 화살표는 각각 커서를 한칸만 왼쪽 혹은 오른쪽으로 이동 시킨다.
Home 키는 입력중인 문자열의 시작 부분으로 커서를 옮기게 하고, End 키는 입력중인 문자열의 마지막 위치로 커서를 옮겨주는 기능을 수행한다.
Ctrl+B와 Ctrl+F 키는 커서를 한 단어씩 옮기도록 한다.
Ctrl+C는 입력 중인 동작을 취소할 때 사용한다.
사용자가 문자를 입력한 후 엔터키를 눌렀을 때 해당 문자열이 그대로 출력되는 것을 볼 수 있다.
코드에서 구현된 다양한 특수 키들을 눌러 보면서 입력 중인 문자들을 수정하거나 커서를 옮겨 보면서 제대로 동작되는지 확인해서 코드에 문제가 없는지 검증해 보도록 한다.
'심화' 카테고리의 다른 글
User Interface - 메뉴 방식 (0) | 2017.07.08 |
---|---|
User Interface - argc, argv (0) | 2017.07.07 |
User Interface - UART 특수키 처리 (0) | 2017.06.24 |
megaOS - 13. Mailbox (1) | 2016.11.13 |
megaOS - 12. Flag (0) | 2016.11.08 |