mirror of
https://github.com/clangen/musikcube.git
synced 2025-02-06 12:39:54 +00:00
Added missing flacdecoder file, and also debounced KEY_RESIZE event
handling.
This commit is contained in:
parent
9815c3277c
commit
4f8294169d
373
src/contrib/flacdecoder/libflac/win_utf8_io.c
Executable file
373
src/contrib/flacdecoder/libflac/win_utf8_io.c
Executable file
@ -0,0 +1,373 @@
|
||||
/* libFLAC - Free Lossless Audio Codec library
|
||||
* Copyright (C) 2013-2014 Xiph.Org Foundation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of the Xiph.org Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/utime.h>
|
||||
#include <io.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h> /* for WideCharToMultiByte and MultiByteToWideChar */
|
||||
|
||||
#include <share/win_utf8_io.h>
|
||||
|
||||
#define UTF8_BUFFER_SIZE 32768
|
||||
|
||||
static
|
||||
int local_vsnprintf(char *str, size_t size, const char *fmt, va_list va)
|
||||
{
|
||||
int rc;
|
||||
|
||||
#if defined _MSC_VER
|
||||
if (size == 0)
|
||||
return 1024;
|
||||
rc = vsnprintf_s (str, size, _TRUNCATE, fmt, va);
|
||||
if (rc < 0)
|
||||
rc = size - 1;
|
||||
#elif defined __MINGW32__
|
||||
rc = __mingw_vsnprintf (str, size, fmt, va);
|
||||
#else
|
||||
rc = vsnprintf (str, size, fmt, va);
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static UINT win_utf8_io_codepage = CP_ACP;
|
||||
|
||||
/* convert WCHAR stored Unicode string to UTF-8. Caller is responsible for freeing memory */
|
||||
static
|
||||
char *utf8_from_wchar(const wchar_t *wstr)
|
||||
{
|
||||
char *utf8str;
|
||||
int len;
|
||||
|
||||
if (!wstr) return NULL;
|
||||
if ((len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL)) == 0) return NULL;
|
||||
if ((utf8str = (char *)malloc(++len)) == NULL) return NULL;
|
||||
if (WideCharToMultiByte(CP_UTF8, 0, wstr, -1, utf8str, len, NULL, NULL) == 0) {
|
||||
free(utf8str);
|
||||
utf8str = NULL;
|
||||
}
|
||||
|
||||
return utf8str;
|
||||
}
|
||||
|
||||
/* convert UTF-8 back to WCHAR. Caller is responsible for freeing memory */
|
||||
static
|
||||
wchar_t *wchar_from_utf8(const char *str)
|
||||
{
|
||||
wchar_t *widestr;
|
||||
int len;
|
||||
|
||||
if (!str) return NULL;
|
||||
len=(int)strlen(str)+1;
|
||||
if ((widestr = (wchar_t *)malloc(len*sizeof(wchar_t))) != NULL) {
|
||||
if (MultiByteToWideChar(win_utf8_io_codepage, 0, str, len, widestr, len) == 0) {
|
||||
if (MultiByteToWideChar(CP_ACP, 0, str, len, widestr, len) == 0) { /* try conversion from Ansi in case the initial UTF-8 conversion had failed */
|
||||
free(widestr);
|
||||
widestr = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return widestr;
|
||||
}
|
||||
|
||||
/* retrieve WCHAR commandline, expand wildcards and convert everything to UTF-8 */
|
||||
int get_utf8_argv(int *argc, char ***argv)
|
||||
{
|
||||
typedef int (__cdecl *wgetmainargs_t)(int*, wchar_t***, wchar_t***, int, int*);
|
||||
wgetmainargs_t wgetmainargs;
|
||||
HMODULE handle;
|
||||
int wargc;
|
||||
wchar_t **wargv;
|
||||
wchar_t **wenv;
|
||||
char **utf8argv;
|
||||
int ret, i;
|
||||
|
||||
if ((handle = LoadLibrary("msvcrt.dll")) == NULL) return 1;
|
||||
if ((wgetmainargs = (wgetmainargs_t)GetProcAddress(handle, "__wgetmainargs")) == NULL) return 1;
|
||||
i = 0;
|
||||
/* if __wgetmainargs expands wildcards then it also erroneously converts \\?\c:\path\to\file.flac to \\file.flac */
|
||||
if (wgetmainargs(&wargc, &wargv, &wenv, 1, &i) != 0) return 1;
|
||||
if ((utf8argv = (char **)calloc(wargc, sizeof(char*))) == NULL) return 1;
|
||||
ret = 0;
|
||||
|
||||
for (i=0; i<wargc; i++) {
|
||||
if ((utf8argv[i] = utf8_from_wchar(wargv[i])) == NULL) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FreeLibrary(handle);
|
||||
|
||||
if (ret == 0) {
|
||||
win_utf8_io_codepage = CP_UTF8;
|
||||
*argc = wargc;
|
||||
*argv = utf8argv;
|
||||
} else {
|
||||
for (i=0; i<wargc; i++)
|
||||
free(utf8argv[i]);
|
||||
free(utf8argv);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* return number of characters in the UTF-8 string */
|
||||
size_t strlen_utf8(const char *str)
|
||||
{
|
||||
size_t len;
|
||||
if ((len = MultiByteToWideChar(win_utf8_io_codepage, 0, str, -1, NULL, 0)) == 0)
|
||||
len = strlen(str);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* get the console width in characters */
|
||||
int win_get_console_width(void)
|
||||
{
|
||||
int width = 80;
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (GetConsoleScreenBufferInfo(hOut, &csbi) != 0) width = csbi.dwSize.X;
|
||||
return width;
|
||||
}
|
||||
|
||||
/* print functions */
|
||||
|
||||
int print_console(FILE *stream, const wchar_t *text, size_t len)
|
||||
{
|
||||
static HANDLE hOut;
|
||||
static HANDLE hErr;
|
||||
DWORD out;
|
||||
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
hErr = GetStdHandle(STD_ERROR_HANDLE);
|
||||
if (stream == stdout && hOut != INVALID_HANDLE_VALUE && GetFileType(hOut) == FILE_TYPE_CHAR) {
|
||||
if (WriteConsoleW(hOut, text, len, &out, NULL) == 0) return -1;
|
||||
return out;
|
||||
} else if (stream == stderr && hErr != INVALID_HANDLE_VALUE && GetFileType(hErr) == FILE_TYPE_CHAR) {
|
||||
if (WriteConsoleW(hErr, text, len, &out, NULL) == 0) return -1;
|
||||
return out;
|
||||
} else {
|
||||
int ret = fputws(text, stream);
|
||||
if (ret < 0) return ret;
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
int printf_utf8(const char *format, ...)
|
||||
{
|
||||
char *utmp = NULL;
|
||||
wchar_t *wout = NULL;
|
||||
int ret = -1;
|
||||
|
||||
while (1) {
|
||||
va_list argptr;
|
||||
if (!(utmp = (char *)malloc(UTF8_BUFFER_SIZE*sizeof(char)))) break;
|
||||
va_start(argptr, format);
|
||||
ret = local_vsnprintf(utmp, UTF8_BUFFER_SIZE, format, argptr);
|
||||
va_end(argptr);
|
||||
if (ret < 0) break;
|
||||
if (!(wout = wchar_from_utf8(utmp))) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
ret = print_console(stdout, wout, wcslen(wout));
|
||||
break;
|
||||
}
|
||||
if (utmp) free(utmp);
|
||||
if (wout) free(wout);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fprintf_utf8(FILE *stream, const char *format, ...)
|
||||
{
|
||||
char *utmp = NULL;
|
||||
wchar_t *wout = NULL;
|
||||
int ret = -1;
|
||||
|
||||
while (1) {
|
||||
va_list argptr;
|
||||
if (!(utmp = (char *)malloc(UTF8_BUFFER_SIZE*sizeof(char)))) break;
|
||||
va_start(argptr, format);
|
||||
ret = local_vsnprintf(utmp, UTF8_BUFFER_SIZE, format, argptr);
|
||||
va_end(argptr);
|
||||
if (ret < 0) break;
|
||||
if (!(wout = wchar_from_utf8(utmp))) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
ret = print_console(stream, wout, wcslen(wout));
|
||||
break;
|
||||
}
|
||||
if (utmp) free(utmp);
|
||||
if (wout) free(wout);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vfprintf_utf8(FILE *stream, const char *format, va_list argptr)
|
||||
{
|
||||
char *utmp = NULL;
|
||||
wchar_t *wout = NULL;
|
||||
int ret = -1;
|
||||
|
||||
while (1) {
|
||||
if (!(utmp = (char *)malloc(UTF8_BUFFER_SIZE*sizeof(char)))) break;
|
||||
if ((ret = local_vsnprintf(utmp, UTF8_BUFFER_SIZE, format, argptr)) < 0) break;
|
||||
if (!(wout = wchar_from_utf8(utmp))) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
ret = print_console(stream, wout, wcslen(wout));
|
||||
break;
|
||||
}
|
||||
if (utmp) free(utmp);
|
||||
if (wout) free(wout);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* file functions */
|
||||
|
||||
FILE *fopen_utf8(const char *filename, const char *mode)
|
||||
{
|
||||
wchar_t *wname = NULL;
|
||||
wchar_t *wmode = NULL;
|
||||
FILE *f = NULL;
|
||||
|
||||
while (1) {
|
||||
if (!(wname = wchar_from_utf8(filename))) break;
|
||||
if (!(wmode = wchar_from_utf8(mode))) break;
|
||||
f = _wfopen(wname, wmode);
|
||||
break;
|
||||
}
|
||||
if (wname) free(wname);
|
||||
if (wmode) free(wmode);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
int _stat64_utf8(const char *path, struct __stat64 *buffer)
|
||||
{
|
||||
wchar_t *wpath;
|
||||
int ret;
|
||||
|
||||
if (!(wpath = wchar_from_utf8(path))) return -1;
|
||||
ret = _wstat64(wpath, buffer);
|
||||
free(wpath);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int chmod_utf8(const char *filename, int pmode)
|
||||
{
|
||||
wchar_t *wname;
|
||||
int ret;
|
||||
|
||||
if (!(wname = wchar_from_utf8(filename))) return -1;
|
||||
ret = _wchmod(wname, pmode);
|
||||
free(wname);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int utime_utf8(const char *filename, struct utimbuf *times)
|
||||
{
|
||||
wchar_t *wname;
|
||||
struct __utimbuf64 ut;
|
||||
int ret;
|
||||
|
||||
if (sizeof(*times) == sizeof(ut)) {
|
||||
memcpy(&ut, times, sizeof(ut));
|
||||
} else {
|
||||
ut.actime = times->actime;
|
||||
ut.modtime = times->modtime;
|
||||
}
|
||||
|
||||
if (!(wname = wchar_from_utf8(filename))) return -1;
|
||||
ret = _wutime64(wname, &ut);
|
||||
free(wname);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int unlink_utf8(const char *filename)
|
||||
{
|
||||
wchar_t *wname;
|
||||
int ret;
|
||||
|
||||
if (!(wname = wchar_from_utf8(filename))) return -1;
|
||||
ret = _wunlink(wname);
|
||||
free(wname);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rename_utf8(const char *oldname, const char *newname)
|
||||
{
|
||||
wchar_t *wold = NULL;
|
||||
wchar_t *wnew = NULL;
|
||||
int ret = -1;
|
||||
|
||||
while (1) {
|
||||
if (!(wold = wchar_from_utf8(oldname))) break;
|
||||
if (!(wnew = wchar_from_utf8(newname))) break;
|
||||
ret = _wrename(wold, wnew);
|
||||
break;
|
||||
}
|
||||
if (wold) free(wold);
|
||||
if (wnew) free(wnew);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HANDLE WINAPI CreateFile_utf8(const char *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
|
||||
{
|
||||
wchar_t *wname;
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
if ((wname = wchar_from_utf8(lpFileName)) != NULL) {
|
||||
handle = CreateFileW(wname, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
|
||||
free(wname);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
@ -54,21 +54,25 @@
|
||||
#include <core/plugin/PluginFactory.h>
|
||||
#include <core/library/LibraryFactory.h>
|
||||
|
||||
#include <boost/chrono.hpp>
|
||||
|
||||
#ifdef WIN32
|
||||
#undef MOUSE_MOVED
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define IDLE_TIMEOUT_MS 0
|
||||
#define REDRAW_DEBOUNCE_MS 100
|
||||
#else
|
||||
#define IDLE_TIMEOUT_MS 100
|
||||
#define REDRAW_DEBOUNCE_MS 200
|
||||
#endif
|
||||
|
||||
|
||||
using namespace musik::core;
|
||||
using namespace musik::core::audio;
|
||||
using namespace musik::box;
|
||||
using namespace cursespp;
|
||||
using namespace boost::chrono;
|
||||
|
||||
struct WindowState {
|
||||
ILayoutPtr layout;
|
||||
@ -110,14 +114,6 @@ static void changeLayout(WindowState& current, ILayoutPtr newLayout) {
|
||||
current.layout->Show();
|
||||
updateFocusedWindow(current, current.layout->GetFocus());
|
||||
}
|
||||
|
||||
if (current.input) {
|
||||
curs_set(1);
|
||||
wtimeout(current.focused->GetContent(), IDLE_TIMEOUT_MS);
|
||||
}
|
||||
else {
|
||||
curs_set(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void focusNextInLayout(WindowState& current) {
|
||||
@ -139,6 +135,47 @@ static void focusNextInLayout(WindowState& current) {
|
||||
}
|
||||
}
|
||||
|
||||
static inline std::string readKeyPress(int64 ch) {
|
||||
std::string kn = keyname((int)ch);
|
||||
|
||||
/* convert +ESC to M- sequences */
|
||||
if (kn == "^[") {
|
||||
int64 next = getch();
|
||||
if (next != -1) {
|
||||
kn = std::string("M-") + std::string(keyname((int)next));
|
||||
}
|
||||
}
|
||||
/* multi-byte UTF8 character */
|
||||
else if (ch >= 194 && ch <= 223) {
|
||||
kn = "";
|
||||
kn += (char)ch;
|
||||
kn += (char)getch();
|
||||
}
|
||||
else if (ch >= 224 && ch <= 239) {
|
||||
kn = "";
|
||||
kn += (char)ch;
|
||||
kn += (char)getch();
|
||||
kn += (char)getch();
|
||||
}
|
||||
else if (ch >= 240 && ch <= 244) {
|
||||
kn = "";
|
||||
kn += (char)ch;
|
||||
kn += (char)getch();
|
||||
kn += (char)getch();
|
||||
kn += (char)getch();
|
||||
}
|
||||
|
||||
// std::cerr << "keyname: " << kn << std::endl;
|
||||
// std::cerr << "ch: " << ch << std::endl;
|
||||
|
||||
return kn;
|
||||
}
|
||||
|
||||
static inline int64 now() {
|
||||
return duration_cast<milliseconds>(
|
||||
system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
int _main(int argc, _TCHAR* argv[]);
|
||||
|
||||
@ -196,6 +233,7 @@ int main(int argc, char* argv[])
|
||||
int64 ch;
|
||||
timeout(IDLE_TIMEOUT_MS);
|
||||
bool quit = false;
|
||||
int64 resizeAt = 0;
|
||||
|
||||
WindowState state;
|
||||
state.input = NULL;
|
||||
@ -208,47 +246,18 @@ int main(int argc, char* argv[])
|
||||
so it can draw a pretty cursor if it wants */
|
||||
if (state.input) {
|
||||
WINDOW *c = state.focused->GetContent();
|
||||
wtimeout(state.focused->GetContent(), IDLE_TIMEOUT_MS);
|
||||
curs_set(1);
|
||||
keypad(c, TRUE);
|
||||
ch = wgetch(c);
|
||||
}
|
||||
else {
|
||||
ch = wgetch(stdscr);
|
||||
curs_set(0);
|
||||
}
|
||||
|
||||
if (ch != -1) { /* -1 = idle timeout */
|
||||
std::string kn = keyname((int) ch);
|
||||
|
||||
int64 next = -1; /* used in escape sequences */
|
||||
|
||||
/* convert +ESC to M- sequences */
|
||||
if (kn == "^[") {
|
||||
next = getch();
|
||||
if (next != -1) {
|
||||
kn = std::string("M-") + std::string(keyname((int) next));
|
||||
}
|
||||
}
|
||||
/* multi-byte UTF8 character */
|
||||
else if (ch >= 194 && ch <= 223) {
|
||||
kn = "";
|
||||
kn += (char) ch;
|
||||
kn += (char) getch();
|
||||
}
|
||||
else if (ch >= 224 && ch <= 239) {
|
||||
kn = "";
|
||||
kn += (char) ch;
|
||||
kn += (char) getch();
|
||||
kn += (char) getch();
|
||||
}
|
||||
else if (ch >= 240 && ch <= 244) {
|
||||
kn = "";
|
||||
kn += (char) ch;
|
||||
kn += (char) getch();
|
||||
kn += (char) getch();
|
||||
kn += (char) getch();
|
||||
}
|
||||
|
||||
// std::cerr << "keyname: " << kn << std::endl;
|
||||
// std::cerr << "ch: " << ch << std::endl;
|
||||
std::string kn = readKeyPress((int) ch);
|
||||
|
||||
if (ch == '\t') { /* tab */
|
||||
focusNextInLayout(state);
|
||||
@ -257,10 +266,7 @@ int main(int argc, char* argv[])
|
||||
quit = true;
|
||||
}
|
||||
else if (kn == "KEY_RESIZE") {
|
||||
resize_term(0, 0);
|
||||
libraryLayout->Layout();
|
||||
consoleLayout->Layout();
|
||||
state.layout->BringToTop();
|
||||
resizeAt = now() + REDRAW_DEBOUNCE_MS;
|
||||
}
|
||||
else if (ch == KEY_F(2)) {
|
||||
changeLayout(state, libraryLayout);
|
||||
@ -281,6 +287,17 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
}
|
||||
|
||||
/* this is a bit of a hack, and if we have any more of these we
|
||||
need to generalize. but KEY_RESIZE often gets called dozens of
|
||||
times, so we debounce the actual resize until its settled. */
|
||||
if (resizeAt && now() > resizeAt) {
|
||||
resize_term(0, 0);
|
||||
libraryLayout->Layout();
|
||||
consoleLayout->Layout();
|
||||
state.layout->BringToTop();
|
||||
resizeAt = 0;
|
||||
}
|
||||
|
||||
ensureFocusIsValid(state);
|
||||
Window::WriteToScreen(state.input);
|
||||
MessageQueue::Instance().Dispatch();
|
||||
|
@ -27,9 +27,6 @@
|
||||
<ClCompile Include="cursespp\Window.cpp">
|
||||
<Filter>cursespp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="cursespp\Colors.cpp">
|
||||
<Filter>cursespp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="cursespp\LayoutBase.cpp">
|
||||
<Filter>cursespp</Filter>
|
||||
</ClCompile>
|
||||
@ -93,6 +90,9 @@
|
||||
<ClCompile Include="cursespp\MessageQueue.cpp">
|
||||
<Filter>cursespp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="cursespp\Colors.cpp">
|
||||
<Filter>app</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user