summaryrefslogtreecommitdiff
path: root/src/ui_readline.c
diff options
context:
space:
mode:
authorMichał Cichoń <michcic@gmail.com>2015-08-25 06:47:41 +0200
committerMichał Cichoń <michcic@gmail.com>2015-08-25 06:47:41 +0200
commit4f43140468cefba39573d1efbded5258fcc56c93 (patch)
tree7aa850b6252c1773ba33e9efa985f712709ea5af /src/ui_readline.c
parenta3bae55d41f5159df3a0125f02a8fa322e81bbe3 (diff)
downloadpianobar-windows-4f43140468cefba39573d1efbded5258fcc56c93.tar.gz
pianobar-windows-4f43140468cefba39573d1efbded5258fcc56c93.tar.bz2
pianobar-windows-4f43140468cefba39573d1efbded5258fcc56c93.zip
Port pianobar to Windows:
- use newly introduced console.h instead of terminal.h which emulate some behavior of VT terminals - replace ffmpeg/libov player with more abstract one with DirectShow implementation
Diffstat (limited to 'src/ui_readline.c')
-rw-r--r--src/ui_readline.c396
1 files changed, 256 insertions, 140 deletions
diff --git a/src/ui_readline.c b/src/ui_readline.c
index eeb5c12..12f4ac8 100644
--- a/src/ui_readline.c
+++ b/src/ui_readline.c
@@ -21,13 +21,75 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
-#include <stdlib.h>
+//#include <stdlib.h>
+//#include <stdio.h>
+//#include <string.h>
+//#include <unistd.h>
+//#include <assert.h>
+
+#include "ui_readline.h"
+#include "console.h"
#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
#include <assert.h>
-#include "ui_readline.h"
+static inline char* BarReadlineNextUtf8 (char* ptr) {
+ if ((*ptr & 0x80) == 0)
+ return ptr + 1;
+ else if ((*ptr & 0xE0) == 0xC0)
+ return ptr + 2;
+ else if ((*ptr & 0xF0) == 0xE0)
+ return ptr + 3;
+ else if ((*ptr & 0xF8) == 0xF0)
+ return ptr + 4;
+ else
+ return ptr;
+}
+
+static inline char* BarReadlinePriorUtf8 (char* ptr) {
+ while ((*(--ptr) & 0xC0) == 0x80)
+ /*continue*/;
+
+ return ptr;
+}
+
+static inline int BarReadlineEncodeUtf8 (int codePoint, char* utf8) {
+ if (codePoint < 0x80) {
+ utf8[0] = (char)codePoint;
+ return 1;
+ }
+ else if (codePoint < 0x0800) {
+ utf8[0] = (char)(0xC0 | ((codePoint >> 6) & 0x1F));
+ utf8[1] = (char)(0x80 | ((codePoint >> 0) & 0x3F));
+ return 2;
+ }
+ else if (codePoint < 0x10000) {
+ utf8[0] = (char)(0xE0 | ((codePoint >> 12) & 0x0F));
+ utf8[1] = (char)(0x80 | ((codePoint >> 6) & 0x3F));
+ utf8[2] = (char)(0x80 | ((codePoint >> 0) & 0x3F));
+ return 3;
+ }
+ else if (codePoint < 0x110000) {
+ utf8[0] = (char)(0xF0 | ((codePoint >> 18) & 0x07));
+ utf8[1] = (char)(0x80 | ((codePoint >> 12) & 0x3F));
+ utf8[2] = (char)(0x80 | ((codePoint >> 6) & 0x3F));
+ utf8[2] = (char)(0x80 | ((codePoint >> 0) & 0x3F));
+ return 4;
+ }
+ else
+ return 0;
+}
+
+struct _BarReadline_t {
+ DWORD DefaultAttr;
+};
+
+void BarReadlineInit(BarReadline_t* rl) {
+ static struct _BarReadline_t instance;
+ *rl = &instance;
+}
+
+void BarReadlineDestroy(BarReadline_t rl) {
+}
/* return size of previous UTF-8 character
*/
@@ -46,152 +108,206 @@ static size_t BarReadlinePrevUtf8 (char *ptr) {
* @param buffer
* @param buffer size
* @param accept these characters
- * @param input fds
+ * @param readline
* @param flags
* @param timeout (seconds) or -1 (no timeout)
* @return number of bytes read from stdin
*/
size_t BarReadline (char *buf, const size_t bufSize, const char *mask,
- BarReadlineFds_t *input, const BarReadlineFlags_t flags, int timeout) {
- size_t bufLen = 0;
- unsigned char escapeState = 0;
- fd_set set;
- const bool echo = !(flags & BAR_RL_NOECHO);
-
- assert (buf != NULL);
- assert (bufSize > 0);
- assert (input != NULL);
-
- memset (buf, 0, bufSize);
-
- /* if fd is a fifo fgetc will always return EOF if nobody writes to
- * it, stdin will block */
- while (1) {
- int curFd = -1;
- unsigned char chr;
- struct timeval timeoutstruct;
-
- /* select modifies set and timeout */
- memcpy (&set, &input->set, sizeof (set));
- timeoutstruct.tv_sec = timeout;
- timeoutstruct.tv_usec = 0;
-
- if (select (input->maxfd, &set, NULL, NULL,
- (timeout == -1) ? NULL : &timeoutstruct) <= 0) {
- /* fail or timeout */
- break;
- }
+ BarReadline_t input, const BarReadlineFlags_t flags, int timeout) {
+ HANDLE handle = BarConsoleGetStdIn();
+ DWORD timeStamp, waitResult;
+ int bufPos = 0, bufLen = 0;
+ char* bufOut = buf;
- assert (sizeof (input->fds) / sizeof (*input->fds) == 2);
- if (FD_ISSET(input->fds[0], &set)) {
- curFd = input->fds[0];
- } else if (input->fds[1] != -1 && FD_ISSET(input->fds[1], &set)) {
- curFd = input->fds[1];
- }
- if (read (curFd, &chr, sizeof (chr)) <= 0) {
- /* select() is going wild if fdset contains EOFed stdin, only check
- * for stdin, fifo is "reopened" as soon as another writer is
- * available
- * FIXME: ugly */
- if (curFd == STDIN_FILENO) {
- FD_CLR (curFd, &input->set);
+ const bool overflow = flags & BAR_RL_FULLRETURN;
+ const bool echo = !(flags & BAR_RL_NOECHO);
+
+ assert(buf != NULL);
+ assert(bufSize > 0);
+ assert(input != NULL);
+
+ memset(buf, 0, bufSize);
+
+ if (timeout != INFINITE) {
+ // convert timeout to ms
+ timeout *= 1000;
+
+ // get time stamp, required for simulating non-locking input timeouts
+ timeStamp = GetTickCount();
+ }
+ else
+ timeStamp = 0;
+
+ while (true) {
+ if (timeout != INFINITE) {
+ DWORD now = GetTickCount();
+ if ((int)(now - timeStamp) < timeout) {
+ timeout -= (int)(now - timeStamp);
+ timeStamp = now;
}
- continue;
+ else
+ timeout = 0;
}
- switch (chr) {
- /* EOT */
- case 4:
- /* return */
- case 10:
- if (echo) {
- fputs ("\n", stdout);
- }
- buf[bufLen] = '\0';
- return bufLen;
- break;
-
- /* clear line */
- case 21:
- if (echo) {
- while (bufLen > 0) {
- const size_t moveSize = BarReadlinePrevUtf8 (&buf[bufLen]);
- assert (bufLen >= moveSize);
-
- /* move caret and delete character */
- fputs ("\033[D\033[K", stdout);
- bufLen -= moveSize;
- }
- fflush (stdout);
- }
- bufLen = 0;
- break;
-
- /* escape */
- case 27:
- escapeState = 1;
- break;
-
- /* del */
- case 126:
- break;
-
- /* backspace */
- case 8: /* ASCII BS */
- case 127: /* ASCII DEL */
- if (bufLen > 0) {
- size_t moveSize = BarReadlinePrevUtf8 (&buf[bufLen]);
- assert (bufLen >= moveSize);
- memmove (&buf[bufLen-moveSize], &buf[bufLen], moveSize);
-
- bufLen -= moveSize;
-
- /* move caret back and delete last character */
- if (echo) {
- fputs ("\033[D\033[K", stdout);
- fflush (stdout);
- }
- }
- break;
- default:
- /* ignore control/escape characters */
- if (chr <= 0x1F) {
- break;
- }
- if (escapeState == 2) {
- escapeState = 0;
- break;
- }
- if (escapeState == 1 && chr == '[') {
- escapeState = 2;
- break;
- }
- /* don't accept chars not in mask */
- if (mask != NULL && !strchr (mask, chr)) {
- break;
- }
- /* don't write beyond buffer's limits */
- if (bufLen < bufSize-1) {
- buf[bufLen] = chr;
- ++bufLen;
- if (echo) {
- putchar (chr);
- fflush (stdout);
- }
- /* buffer full => return if requested */
- if (bufLen >= bufSize-1 && (flags & BAR_RL_FULLRETURN)) {
+ waitResult = WaitForSingleObject(handle, timeout);
+
+ if (WAIT_OBJECT_0 == waitResult) {
+ INPUT_RECORD inputRecords[8];
+ INPUT_RECORD* record;
+ DWORD recordsRead, i;
+
+ ReadConsoleInput(handle, inputRecords, sizeof(inputRecords) / sizeof(*inputRecords), &recordsRead);
+
+ for (i = 0, record = inputRecords; i < recordsRead; ++i, ++record)
+ {
+ int codePoint, keyCode;
+
+ if ((record->EventType != KEY_EVENT) || !record->Event.KeyEvent.bKeyDown)
+ continue;
+
+ keyCode = record->Event.KeyEvent.wVirtualKeyCode;
+ codePoint = record->Event.KeyEvent.uChar.UnicodeChar;
+
+ switch (keyCode) {
+ case VK_LEFT:
+ if (bufPos > 0)
+ {
+ if (echo) {
+ BarConsoleMoveCursor(-1);
+ }
+ bufOut = BarReadlinePriorUtf8(bufOut);
+ --bufPos;
+ }
+ break;
+
+ case VK_RIGHT:
+ if (bufPos < bufLen)
+ {
+ if (echo) {
+ BarConsoleMoveCursor(1);
+ }
+ bufOut = BarReadlineNextUtf8(bufOut);
+ ++bufPos;
+ }
+ break;
+
+ case VK_HOME:
if (echo) {
- fputs ("\n", stdout);
+ BarConsoleMoveCursor(-bufPos);
+ }
+ bufPos = 0;
+ bufOut = buf;
+ break;
+
+ case VK_END:
+ if (echo) {
+ BarConsoleMoveCursor(bufLen - bufPos);
+ }
+ bufPos = bufLen;
+ bufOut = buf + strlen(buf);
+ break;
+
+ case VK_BACK:
+ if (bufPos > 0) {
+ int moveSize;
+
+ char* oldBufOut = bufOut;
+ bufOut = BarReadlinePriorUtf8(bufOut);
+ moveSize = strlen(bufOut) - (oldBufOut - bufOut);
+ memmove(bufOut, oldBufOut, moveSize);
+ bufOut[moveSize] = '\0';
+
+ if (echo) {
+ BarConsoleMoveCursor(-1);
+ BarConsoleEraseCharacter();
+ }
+
+ --bufPos;
+ --bufLen;
+ }
+ break;
+
+ case VK_DELETE:
+ if (bufPos < bufLen) {
+ int moveSize;
+
+ if (echo) {
+ BarConsoleEraseCharacter();
+ }
+
+ char* nextCharOut = BarReadlineNextUtf8(bufOut);
+ moveSize = strlen(bufOut) - (bufOut - nextCharOut);
+ memmove(bufOut, nextCharOut, moveSize);
+ bufOut[moveSize] = '\0';
+
+ --bufLen;
}
- buf[bufLen] = '\0';
+ break;
+
+ case VK_RETURN:
+ if (echo)
+ fputc('\n', stdout);
return bufLen;
- }
+
+ default: {
+ char encodedCodePoint[5];
+ int encodedCodePointLength;
+
+ /*
+ if (keyCode == VK_MEDIA_PLAY_PAUSE) {
+ codePoint = 'p';
+ PlaySoundA("SystemNotification", NULL, SND_ASYNC);
+ }
+ else if (keyCode == VK_MEDIA_NEXT_TRACK) {
+ codePoint = 'n';
+ PlaySoundA("SystemNotification", NULL, SND_ASYNC);
+ }
+ */
+
+ if (codePoint <= 0x1F)
+ break;
+
+ /* don't accept chars not in mask */
+ if (mask != NULL && (codePoint > 255 || !strchr(mask, (char)codePoint)))
+ break;
+
+ encodedCodePointLength = BarReadlineEncodeUtf8(codePoint, encodedCodePoint);
+ encodedCodePoint[encodedCodePointLength] = '\0';
+
+ if (bufLen + encodedCodePointLength < (int)bufSize)
+ {
+ strncpy(bufOut, encodedCodePoint, encodedCodePointLength);
+
+ if (echo) {
+ fputs(encodedCodePoint, stdout);
+ fflush(stdout);
+ }
+
+ bufOut += encodedCodePointLength;
+ ++bufPos;
+ ++bufLen;
+
+ if ((bufLen >= (int)(bufSize - 1)) && overflow)
+ {
+ if (echo)
+ fputc('\n', stdout);
+ return bufLen;
+ }
+ }
+ }
+ break;
}
- break;
- } /* end switch */
- } /* end while */
- buf[0] = '\0';
- return 0;
+ }
+ }
+ else if (WAIT_TIMEOUT == waitResult)
+ break;
+ else
+ /* TODO: Handle errors. */
+ break;
+ }
+
+ return bufLen;
}
/* Read string from stdin
@@ -200,7 +316,7 @@ size_t BarReadline (char *buf, const size_t bufSize, const char *mask,
* @return number of bytes read from stdin
*/
size_t BarReadlineStr (char *buf, const size_t bufSize,
- BarReadlineFds_t *input, const BarReadlineFlags_t flags) {
+ BarReadline_t input, const BarReadlineFlags_t flags) {
return BarReadline (buf, bufSize, NULL, input, flags, -1);
}
@@ -208,7 +324,7 @@ size_t BarReadlineStr (char *buf, const size_t bufSize,
* @param write result into this variable
* @return number of bytes read from stdin
*/
-size_t BarReadlineInt (int *ret, BarReadlineFds_t *input) {
+size_t BarReadlineInt (int *ret, BarReadline_t input) {
int rlRet = 0;
char buf[16];
@@ -222,7 +338,7 @@ size_t BarReadlineInt (int *ret, BarReadlineFds_t *input) {
/* Yes/No?
* @param default (user presses enter)
*/
-bool BarReadlineYesNo (bool def, BarReadlineFds_t *input) {
+bool BarReadlineYesNo (bool def, BarReadline_t input) {
char buf[2];
BarReadline (buf, sizeof (buf), "yYnN", input, BAR_RL_FULLRETURN, -1);
if (*buf == 'y' || *buf == 'Y' || (def == true && *buf == '\0')) {