// Create the command to show on the Integration settings page LPCWSTR CreateCommand(CEStr& rsReady) { rsReady = L""; for (INT_PTR i = 0; i < ourSwitches.size(); i++) { Switch* ps = ourSwitches[i]; _ASSERTE(ps && !ps->szSwitch.IsEmpty()); bool bOpt = !ps->szOpt.IsEmpty(); bool bQuot = (bOpt && IsQuotationNeeded(ps->szOpt)); lstrmerge(&rsReady.ms_Val, ps->szSwitch, bOpt ? L" " : NULL, bQuot ? L"\"" : NULL, bOpt ? ps->szOpt.c_str() : NULL, bQuot ? L"\" " : L" "); } if (!rsReady.IsEmpty() || bCmdList) { lstrmerge(&rsReady.ms_Val, bCmdList ? L"-runlist " : L"-run ", szCmd); } else { rsReady.Set(szCmd); } return rsReady.c_str(L""); };
// Concatenate strings from array and set resource item bool CLngRc::SetResource(MArray<LngRcItem>& arr, int idx, MJsonValue* pJson) { CEStr lsValue; MJsonValue jStr; // [ "Decrease window height ", "(check ‘Resize with arrows’)" ] size_t iCount = pJson->getLength(); for (size_t i = 0; i < iCount; i++) { if (!pJson->getItem(i, jStr) || (jStr.getType() != MJsonValue::json_String)) { _ASSERTE(FALSE && "String format failure"); return false; } lstrmerge(&lsValue.ms_Val, jStr.getString()); } if (lsValue.IsEmpty()) { _ASSERTE(FALSE && "Empty resource string (array)"); return false; } return SetResource(arr, idx, lsValue.ms_Val, true); }
LPCWSTR GetDirectory(CEStr& szDir) { DWORD nLen, nMax; nMax = GetCurrentDirectory(MAX_PATH, szDir.GetBuffer(MAX_PATH)); if (!nMax) { szDir.Empty(); goto wrap; } else if (nMax > MAX_PATH) { nLen = GetCurrentDirectory(nMax, szDir.GetBuffer(nMax)); if (!nLen || (nLen > nMax)) { szDir.Empty(); goto wrap; } } wrap: return szDir.IsEmpty() ? NULL : szDir.c_str(); }
LPCWSTR CRConFiles::GetFileFromConsole(LPCWSTR asSrc, CEStr& szFull) { CEStr szWinPath; LPCWSTR pszWinPath = MakeWinPath(asSrc, mp_RCon ? mp_RCon->GetMntPrefix() : NULL, szWinPath); if (!pszWinPath || !*pszWinPath) { _ASSERTE(pszWinPath && *pszWinPath); return NULL; } if (IsFilePath(pszWinPath, true)) { if (!FileExists(pszWinPath)) // otherwise it will cover directories too return NULL; szFull.Attach(szWinPath.Detach()); } else { CEStr szDir; LPCWSTR pszDir = mp_RCon->GetConsoleCurDir(szDir, true); // We may get empty dir here if we are in "~" subdir if (!pszDir || !*pszDir) { _ASSERTE(pszDir && *pszDir && wcschr(pszDir,L'/')==NULL); return NULL; } // Попытаться просканировать один-два уровеня подпапок bool bFound = FileExistSubDir(pszDir, pszWinPath, 1, szFull); if (!bFound) { // git diffs style, but with backslashes (they are converted already) // "a/src/ConEmu.cpp" and "b/src/ConEmu.cpp" if (pszWinPath[0] && (pszWinPath[1] == L'\\') && wcschr(L"abicwo", pszWinPath[0])) { LPCWSTR pszSlash = pszWinPath; while (!bFound && ((pszSlash = wcschr(pszSlash, L'\\')) != NULL)) { while (*pszSlash == L'\\') pszSlash++; if (!*pszSlash) break; bFound = FileExistSubDir(pszDir, pszSlash, 1, szFull); if (!bFound) { // Try to go to parent folder (useful while browsing git-diff-s) bFound = CheckParentFolders(pszDir, pszSlash, szFull); } } } else { // let's try to check some paths from #include // for example: #include "src/common/Common.h" LPCWSTR pszSlash = pszWinPath; while (*pszSlash == L'\\') pszSlash++; bFound = CheckParentFolders(pszDir, pszSlash, szFull); } } if (!bFound) { // If there is "src" subfolder in the current folder const wchar_t* predefined[] = {L"trunk", L"src", L"source", L"sources", NULL}; for (size_t i = 0; !bFound && predefined[i]; ++i) { CEStr szSrc(JoinPath(pszDir, predefined[i])); if (DirectoryExists(szSrc)) bFound = FileExistSubDir(szSrc, pszWinPath, 1, szFull); } } if (!bFound) { return NULL; } } if (!szFull.IsEmpty()) { // "src\conemu\realconsole.cpp" --> "src\ConEmu\RealConsole.cpp" MakePathProperCase(szFull); } return szFull; }
// Returns true on changes // bDeQuote: replace two "" with one " // bDeEscape: process special symbols: ^e^[^r^n^t^b bool DemangleArg(CEStr& rsDemangle, bool bDeQuote /*= true*/, bool bDeEscape /*= false*/) { if (rsDemangle.IsEmpty() || !(bDeQuote || bDeEscape)) { return false; // Nothing to do } LPCWSTR pszDemangles = (bDeQuote && bDeEscape) ? L"^\"" : bDeQuote ? L"\"" : L"^"; LPCWSTR pchCap = wcspbrk(rsDemangle, pszDemangles); if (pchCap == NULL) { return false; // Nothing to replace } wchar_t* pszDst = rsDemangle.ms_Val; const wchar_t* pszSrc = rsDemangle.ms_Val; const wchar_t* pszEnd = rsDemangle.ms_Val + rsDemangle.GetLen(); while (pszSrc < pszEnd) { if (bDeQuote && (*pszSrc == L'"')) { *(pszDst++) = *(pszSrc++); if (*pszSrc == L'"') // Expected, but may be missed by user? pszSrc++; } else if (bDeEscape && (*pszSrc == L'^')) { switch (*(++pszSrc)) { case L'^': // Demangle cap *pszDst = L'^'; break; case 0: // Leave single final cap *pszDst = L'^'; continue; case L'r': case L'R': // CR *pszDst = L'\r'; break; case L'n': case L'N': // LF *pszDst = L'\n'; break; case L't': case L'T': // TAB *pszDst = L'\t'; break; case L'a': case L'A': // BELL *pszDst = 7; break; case L'b': case L'B': // BACK *pszDst = L'\b'; break; case L'e': case L'E': case L'[': // ESC *pszDst = 27; break; default: // Unknown ctrl-sequence, bypass *(pszDst++) = *(pszSrc++); continue; } pszDst++; pszSrc++; } else { *(pszDst++) = *(pszSrc++); } } // Was processed? Zero terminate it. *pszDst = 0; return true; }
void CSetPgDebug::debugLogShell(DWORD nParentPID, CESERVER_REQ_ONCREATEPROCESS* pInfo) { CSetPgDebug* pDbgPg = (CSetPgDebug*)gpSetCls->GetPageObj(thi_Debug); if (!pDbgPg) return; if ((pDbgPg->GetActivityLoggingType() != glt_Processes) && (pDbgPg->GetActivityLoggingType() != glt_Shell)) return; LPCWSTR pszFile = pInfo->wsValue + pInfo->nActionLen; LPCWSTR pszParam = pInfo->wsValue + pInfo->nActionLen+pInfo->nFileLen; DebugLogShellActivity *shl = (DebugLogShellActivity*)calloc(sizeof(DebugLogShellActivity),1); shl->nParentPID = nParentPID; shl->nParentBits = pInfo->nSourceBits; wcscpy_c(shl->szFunction, pInfo->sFunction); shl->pszAction = lstrdup(pInfo->wsValue); shl->pszFile = lstrdup(pszFile); shl->pszParam = lstrdup(pszParam); shl->bDos = (pInfo->nImageBits == 16) && (pInfo->nImageSubsystem == IMAGE_SUBSYSTEM_DOS_EXECUTABLE); shl->nImageBits = pInfo->nImageBits; shl->nImageSubsystem = pInfo->nImageSubsystem; shl->nShellFlags = pInfo->nShellFlags; shl->nCreateFlags = pInfo->nCreateFlags; shl->nStartFlags = pInfo->nStartFlags; shl->nShowCmd = pInfo->nShowCmd; shl->hStdIn = (DWORD)pInfo->hStdIn; shl->hStdOut = (DWORD)pInfo->hStdOut; shl->hStdErr = (DWORD)pInfo->hStdErr; // Append directory and bat/tmp files contents to pszParam { LPCWSTR pszDir = (pInfo->wsValue+pInfo->nActionLen+pInfo->nFileLen+pInfo->nParamLen); LPCWSTR pszAppFile = NULL; wchar_t*& pszParamEx = shl->pszParam; if (pszDir && *pszDir) { CEStr lsDir((pszParamEx && *pszParamEx) ? L"\r\n\r\n" : NULL, L"CD: \"", pszDir, L"\""); lstrmerge(&pszParamEx, lsDir); } if (shl->pszFile) { LPCWSTR pszExt = PointToExt(shl->pszFile); if (pszExt && (!lstrcmpi(pszExt, L".bat") || !lstrcmpi(pszExt, L".cmd"))) debugLogShellText(pszParamEx, (pszAppFile = shl->pszFile)); } if (pszParam && *pszParam) { LPCWSTR pszNext = pszParam; CEStr szArg; while (0 == NextArg(&pszNext, szArg)) { if (!*szArg || (*szArg == L'-') || (*szArg == L'/')) continue; LPCWSTR pszExt = PointToExt(szArg); // Perhaps process *.tmp files too? (used with VC RC compilation?) if (pszExt && (!lstrcmpi(pszExt, L".bat") || !lstrcmpi(pszExt, L".cmd") /*|| !lstrcmpi(pszExt, L".tmp")*/) && (!pszAppFile || (lstrcmpi(szArg, pszAppFile) != 0))) { debugLogShellText(pszParamEx, szArg); } else if (szArg[0] == L'@') { CEStr lsPath; if (IsFilePath(szArg.Mid(1), true)) { // Full path to "arguments file" lsPath.Set(szArg.Mid(1)); } else if ((szArg[1] != L'\\' && szArg[1] != L'/') && (pszDir && *pszDir)) { // Relative path to "arguments file" lsPath = JoinPath(pszDir, szArg.Mid(1)); } if (!lsPath.IsEmpty()) { debugLogShellText(pszParamEx, lsPath); } } } } } // end of "Append directory and bat/tmp files contents to pszParam" PostMessage(pDbgPg->Dlg(), DBGMSG_LOG_ID, DBGMSG_LOG_SHELL_MAGIC, (LPARAM)shl); }
bool IsNeedCmd(BOOL bRootCmd, LPCWSTR asCmdLine, CEStr &szExe, LPCWSTR* rsArguments /*= NULL*/, BOOL* rpbNeedCutStartEndQuot /*= NULL*/, BOOL* rpbRootIsCmdExe /*= NULL*/, BOOL* rpbAlwaysConfirmExit /*= NULL*/, BOOL* rpbAutoDisableConfirmExit /*= NULL*/) { bool rbNeedCutStartEndQuot = false; bool rbRootIsCmdExe = true; bool rbAlwaysConfirmExit = false; bool rbAutoDisableConfirmExit = false; wchar_t *pwszEndSpace; if (rsArguments) *rsArguments = NULL; bool lbRc = false; BOOL lbFirstWasGot = FALSE; LPCWSTR pwszCopy; int nLastChar; #ifdef _DEBUG CmdArg szDbgFirst; #endif if (!asCmdLine || !*asCmdLine) { _ASSERTE(asCmdLine && *asCmdLine); goto wrap; } #ifdef _DEBUG // Это минимальные проверки, собственно к коду - не относятся bool bIsBatch = false; { NextArg(asCmdLine, szDbgFirst); LPCWSTR psz = PointToExt(szDbgFirst); if (lstrcmpi(psz, L".cmd")==0 || lstrcmpi(psz, L".bat")==0) bIsBatch = true; } #endif if (!szExe.GetBuffer(MAX_PATH)) { _ASSERTE(FALSE && "Failed to allocate MAX_PATH"); lbRc = true; goto wrap; } szExe.Empty(); if (!asCmdLine || *asCmdLine == 0) { _ASSERTE(asCmdLine && *asCmdLine); lbRc = true; goto wrap; } pwszCopy = asCmdLine; // cmd /c ""c:\program files\arc\7z.exe" -?" // да еще и внутри могут быть двойными... // cmd /c "dir c:\" nLastChar = lstrlenW(pwszCopy) - 1; if (pwszCopy[0] == L'"' && pwszCopy[nLastChar] == L'"') { //if (pwszCopy[1] == L'"' && pwszCopy[2]) //{ // pwszCopy ++; // Отбросить первую кавычку в командах типа: ""c:\program files\arc\7z.exe" -?" // if (rbNeedCutStartEndQuot) *rbNeedCutStartEndQuot = TRUE; //} //else // глючила на ""F:\VCProject\FarPlugin\#FAR180\far.exe -new_console"" //if (wcschr(pwszCopy+1, L'"') == (pwszCopy+nLastChar)) { // LPCWSTR pwszTemp = pwszCopy; // // Получим первую команду (исполняемый файл?) // if ((iRc = NextArg(&pwszTemp, szArg)) != 0) { // //Parsing command line failed // lbRc = true; goto wrap; // } // pwszCopy ++; // Отбросить первую кавычку в командах типа: "c:\arc\7z.exe -?" // lbFirstWasGot = TRUE; // if (rbNeedCutStartEndQuot) *rbNeedCutStartEndQuot = TRUE; //} else { // Will be dequoted in 'NextArg' function. Examples // "C:\GCC\msys\bin\make.EXE -f "makefile" COMMON="../../../plugins/common"" // ""F:\VCProject\FarPlugin\#FAR180\far.exe -new_console"" // ""cmd"" // cmd /c ""c:\program files\arc\7z.exe" -?" // да еще и внутри могут быть двойными... // cmd /c "dir c:\" // Получим первую команду (исполняемый файл?) CmdArg arg; if (!NextArg(pwszCopy, arg)) { //Parsing command line failed #ifdef WARN_NEED_CMD _ASSERTE(FALSE); #endif lbRc = true; goto wrap; } szExe.Set(arg); if (lstrcmpiW(szExe, L"start") == 0) { // Команду start обрабатывает только процессор #ifdef WARN_NEED_CMD _ASSERTE(FALSE); #endif lbRc = true; goto wrap; } LPCWSTR pwszQ = pwszCopy + 1 + lstrlen(szExe); wchar_t* pszExpand = NULL; if (*pwszQ != L'"' && IsExecutable(szExe, &pszExpand)) { pwszCopy ++; // отбрасываем lbFirstWasGot = TRUE; if (pszExpand) { szExe.Set(pszExpand); SafeFree(pszExpand); if (rsArguments) *rsArguments = pwszQ; } rbNeedCutStartEndQuot = true; } } } // Получим первую команду (исполняемый файл?) if (!lbFirstWasGot) { szExe.Empty(); // `start` command must be processed by processor itself if ((lstrcmpni(pwszCopy, L"start", 5) == 0) && (!pwszCopy[5] || isSpace(pwszCopy[5]))) { #ifdef WARN_NEED_CMD _ASSERTE(FALSE); #endif lbRc = true; goto wrap; } // 17.10.2010 - support executable file path without parameters, but with spaces in its path // 22.11.2015 - or some weirdness, like `C:\Program Files\CB/cb_console_runner.exe "C:\sources\app.exe"` LPCWSTR pchEnd = wcschr(pwszCopy, L' '); if (!pchEnd) pchEnd = pwszCopy + lstrlenW(pwszCopy); CEStr szTemp; DWORD nTempSize; while (pchEnd) { szTemp.Set(pwszCopy, (pchEnd - pwszCopy)); _ASSERTE(szTemp[(pchEnd - pwszCopy)] == 0); // Argument was quoted? if (!szTemp.IsEmpty()) { INT_PTR len = szTemp.GetLen(); if ((len > 2) && (szTemp[0] == L'"') && (szTemp[len-1] == L'"')) { memmove(szTemp.ms_Val, szTemp.ms_Val+1, (len-2)*sizeof(*szTemp.ms_Val)); szTemp.ms_Val[len-2] = 0; } } // If this is a full path without environment variables if (!szTemp.IsEmpty() && ((IsFilePath(szTemp, true) && !wcschr(szTemp, L'%')) // or file/dir may be found via env.var. substitution or searching in %PATH% || FileExistsSearch((LPCWSTR)szTemp, szTemp)) // Than check if it is a FILE (not a directory) && FileExists(szTemp, &nTempSize) && nTempSize) { // OK, it an our executable? if (rsArguments) *rsArguments = pchEnd; szExe.Set(szTemp); break; } _ASSERTE(*pchEnd == 0 || *pchEnd == L' '); if (!*pchEnd) break; // Find next space after nonspace while (*(pchEnd) == L' ') pchEnd++; // If quoted string starts from here - it's supposed to be an argument if (*pchEnd == L'"') { // And we must not get here, because the executable must be already processed above // _ASSERTE(*pchEnd != L'"'); break; } pchEnd = wcschr(pchEnd, L' '); if (!pchEnd) pchEnd = pwszCopy + lstrlenW(pwszCopy); } if (szExe.IsEmpty()) { CmdArg arg; if (!(pwszCopy = NextArg(pwszCopy, arg))) { //Parsing command line failed #ifdef WARN_NEED_CMD _ASSERTE(FALSE); #endif lbRc = true; goto wrap; } szExe.Set(arg); _ASSERTE(lstrcmpiW(szExe, L"start") != 0); // Обработка переменных окружения и поиск в PATH if (FileExistsSearch((LPCWSTR)szExe, szExe)) { if (rsArguments) *rsArguments = pwszCopy; } } } if (!*szExe) { _ASSERTE(szExe[0] != 0); } else { // Если юзеру нужен редирект - то он должен явно указать ком.процессор // Иначе нереально (или достаточно сложно) определить, является ли символ // редиректом, или это просто один из аргументов команды... // "Левые" символы в имени файла (а вот в "первом аргументе" все однозначно) if (wcspbrk(szExe, L"?*<>|")) { rbRootIsCmdExe = TRUE; // запуск через "процессор" lbRc = true; goto wrap; // добавить "cmd.exe" } // если "путь" не указан if (wcschr(szExe, L'\\') == NULL) { bool bHasExt = (wcschr(szExe, L'.') != NULL); // Проверим, может это команда процессора (типа "DIR")? if (!bHasExt) { bool bIsCommand = false; wchar_t* pszUppr = lstrdup(szExe); if (pszUppr) { // избежать линковки на user32.dll //CharUpperBuff(pszUppr, lstrlen(pszUppr)); for (wchar_t* p = pszUppr; *p; p++) { if (*p >= L'a' && *p <= 'z') *p -= 0x20; } const wchar_t* pszFind = gsInternalCommands; while (*pszFind) { if (lstrcmp(pszUppr, pszFind) == 0) { bIsCommand = true; break; } pszFind += lstrlen(pszFind)+1; } free(pszUppr); } if (bIsCommand) { #ifdef WARN_NEED_CMD _ASSERTE(FALSE); #endif rbRootIsCmdExe = TRUE; // запуск через "процессор" lbRc = true; goto wrap; // добавить "cmd.exe" } } // Try to find executable in %PATH% { #ifndef CONEMU_MINIMAL MWow64Disable wow; wow.Disable(); // Disable Wow64 file redirector #endif apiSearchPath(NULL, szExe, bHasExt ? NULL : L".exe", szExe); } } // end: if (wcschr(szExe, L'\\') == NULL) } // Если szExe не содержит путь к файлу - запускаем через cmd // "start "" C:\Utils\Files\Hiew32\hiew32.exe C:\00\Far.exe" if (!IsFilePath(szExe)) { #ifdef WARN_NEED_CMD _ASSERTE(FALSE); #endif rbRootIsCmdExe = TRUE; // запуск через "процессор" lbRc = true; goto wrap; // добавить "cmd.exe" } //pwszCopy = wcsrchr(szArg, L'\\'); if (!pwszCopy) pwszCopy = szArg; else pwszCopy ++; pwszCopy = PointToName(szExe); //2009-08-27 pwszEndSpace = szExe.ms_Val + lstrlenW(szExe) - 1; while ((*pwszEndSpace == L' ') && (pwszEndSpace > szExe)) { *(pwszEndSpace--) = 0; } #ifndef __GNUC__ #pragma warning( push ) #pragma warning(disable : 6400) #endif if (lstrcmpiW(pwszCopy, L"cmd")==0 || lstrcmpiW(pwszCopy, L"cmd.exe")==0 || lstrcmpiW(pwszCopy, L"tcc")==0 || lstrcmpiW(pwszCopy, L"tcc.exe")==0) { rbRootIsCmdExe = TRUE; // уже должен быть выставлен, но проверим rbAlwaysConfirmExit = TRUE; rbAutoDisableConfirmExit = FALSE; _ASSERTE(!bIsBatch); lbRc = false; goto wrap; // уже указан командный процессор, cmd.exe в начало добавлять не нужно } // Issue 1211: Decide not to do weird heuristic. // If user REALLY needs redirection (root command, huh?) // - he must call "cmd /c ..." directly // Если есть одна из команд перенаправления, или слияния - нужен CMD.EXE if (!bRootCmd) { if (wcschr(asCmdLine, L'&') || wcschr(asCmdLine, L'>') || wcschr(asCmdLine, L'<') || wcschr(asCmdLine, L'|') || wcschr(asCmdLine, L'^') // или экранирования ) { #ifdef WARN_NEED_CMD _ASSERTE(FALSE); #endif lbRc = true; goto wrap; } } //if (lstrcmpiW(pwszCopy, L"far")==0 || lstrcmpiW(pwszCopy, L"far.exe")==0) if (IsFarExe(pwszCopy)) { bool bFound = (wcschr(pwszCopy, L'.') != NULL); // Если указали при запуске просто "far" - это может быть батник, расположенный в %PATH% if (!bFound) { CEStr szSearch; if (apiSearchPath(NULL, pwszCopy, L".exe", szSearch)) { if (lstrcmpi(PointToExt(szSearch), L".exe") == 0) bFound = true; } } if (bFound) { rbAutoDisableConfirmExit = TRUE; rbRootIsCmdExe = FALSE; // FAR! _ASSERTE(!bIsBatch); lbRc = false; goto wrap; // уже указан исполняемый файл, cmd.exe в начало добавлять не нужно } } if (IsExecutable(szExe)) { rbRootIsCmdExe = FALSE; // Для других программ - буфер не включаем _ASSERTE(!bIsBatch); lbRc = false; goto wrap; // Запускается конкретная консольная программа. cmd.exe не требуется } //Можно еще Доделать поиски с: SearchPath, GetFullPathName, добавив расширения .exe & .com //хотя фар сам формирует полные пути к командам, так что можно не заморачиваться #ifdef WARN_NEED_CMD _ASSERTE(FALSE); #endif rbRootIsCmdExe = TRUE; #ifndef __GNUC__ #pragma warning( pop ) #endif lbRc = true; wrap: if (rpbNeedCutStartEndQuot) *rpbNeedCutStartEndQuot = rbNeedCutStartEndQuot; if (rpbRootIsCmdExe) *rpbRootIsCmdExe = rbRootIsCmdExe; if (rpbAlwaysConfirmExit) *rpbAlwaysConfirmExit = rbAlwaysConfirmExit; if (rpbAutoDisableConfirmExit) *rpbAutoDisableConfirmExit = rbAutoDisableConfirmExit; return lbRc; }
// May comes from Task or ConEmu's -run switch // or from Setting\Environment page where one line is a single command (bAlone == true) bool CProcessEnvCmd::AddCommands(LPCWSTR asCommands, LPCWSTR* ppszEnd/*= NULL*/, bool bAlone /*= false*/, INT_PTR anBefore /*= -1*/) { bool bNew = false; LPCWSTR lsCmdLine = asCommands; CEStr lsSet, lsAmp, lsCmd; if (ppszEnd) *ppszEnd = asCommands; // Example: "set PATH=C:\Program Files;%PATH%" & set abc=def & cmd while (NextArg(&lsCmdLine, lsSet) == 0) { bool bTokenOk = false; wchar_t* lsNameVal = NULL; // It may contains only "set" or "alias" if was not quoted if ((lstrcmpi(lsSet, L"set") == 0) || (lstrcmpi(lsSet, L"alias") == 0)) { lsCmd.Set(lsSet); _ASSERTE(*lsCmdLine != L' '); // Now we shell get in lsSet "abc=def" token // Or to simplify usage, the rest of line is supported too, // so user may type in our Settings\Environment: // set V1=From Settings // instead of // set "V1=From Settings" bool bProcessed = false; if ((*lsCmdLine != L'"') || bAlone) { LPCWSTR pszAmp = bAlone ? NULL : wcschr(lsCmdLine, L'&'); if (!pszAmp) // No ampersand or bAlone? Use var value as the rest of line pszAmp = lsCmdLine + lstrlen(lsCmdLine); // Set tail pointer LPCWSTR pszValEnd = pszAmp; // Trim trailing spaces (only \x20) while ((pszValEnd > lsCmdLine) && (*(pszValEnd-1) == L' ')) pszValEnd--; // Trim possible leading/trailing quotes if (bAlone && (*lsCmdLine == L'"')) { lsCmdLine++; if (((pszValEnd-1) > lsCmdLine) && (*(pszValEnd-1) == L'"')) { _ASSERTE(*pszValEnd == 0); pszValEnd--; } } // OK, return it lsSet.Empty(); // to avoid debug asserts lsSet.Set(lsCmdLine, pszValEnd - lsCmdLine); lsCmdLine = SkipNonPrintable(pszAmp); // Leave possible '&' at pointer bProcessed = true; } // OK, lets get token like "name=var value" if (!bProcessed) { bProcessed = (NextArg(&lsCmdLine, lsSet) == 0); } if (bProcessed && (wcschr(lsSet, L'=') > lsSet.ms_Val)) { lsNameVal = lsSet.ms_Val; } } // Or full "set PATH=C:\Program Files;%PATH%" command (without quotes ATM) else if (lstrcmpni(lsSet, L"set ", 4) == 0) { lsCmd = L"set"; LPCWSTR psz = SkipNonPrintable(lsSet.ms_Val+4); if (wcschr(psz, L'=') > psz) { lsNameVal = (wchar_t*)psz; } } // Support "alias token=value" too else if (lstrcmpni(lsSet, L"alias ", 6) == 0) { lsCmd = L"alias"; LPCWSTR psz = SkipNonPrintable(lsSet.ms_Val+6); if (wcschr(psz, L'=') > psz) { lsNameVal = (wchar_t*)psz; } } // Process "chcp <cp>" too else if (lstrcmpi(lsSet, L"chcp") == 0) { lsCmd = L"chcp"; if (NextArg(&lsCmdLine, lsSet) == 0) { UINT nCP = GetCpFromString(lsSet); if (nCP > 0 && nCP <= 0xFFFF) { bTokenOk = true; _ASSERTE(lsNameVal == NULL); if (mp_CmdChCp) { SafeFree(mp_CmdChCp->pszName); mp_CmdChCp->pszName = lstrdup(lsSet); } else { bNew |= (NULL != Add(lsCmd, lsSet, NULL, anBefore)); } } } } // Change title without need of cmd.exe else if (lstrcmpi(lsSet, L"title") == 0) { lsCmd = L"title"; if (NextArg(&lsCmdLine, lsSet) == 0) { bTokenOk = true; _ASSERTE(lsNameVal == NULL); if (mp_CmdTitle) { SafeFree(mp_CmdTitle->pszName); mp_CmdTitle->pszName = lstrdup(lsSet); } else { bNew |= (NULL != Add(lsCmd, lsSet, NULL, anBefore)); } } } // Echo the "text" before console starts // Type the "text file" before console starts else if ((lstrcmpi(lsSet, L"echo") == 0) || (lstrcmpi(lsSet, L"type") == 0)) { lsCmd.Set(lsSet); // echo [-r] [-n] [-x] [-b] "String to echo" // type [-b] [-CP] "Path to text file to echo" CEStr lsSwitches; while (*lsCmdLine == L'-') { if (NextArg(&lsCmdLine, lsSet) != 0) break; lstrmerge(&lsSwitches.ms_Val, lsSwitches.IsEmpty() ? NULL : L" ", lsSet.ms_Val); } // Rest arguments are expected to be processed text or file CEStr lsAdd; while (NextArg(&lsCmdLine, lsSet) == 0) { bTokenOk = true; lstrmerge(&lsAdd.ms_Val, lsAdd.IsEmpty() ? NULL : L" ", lsSet.mb_Quoted ? L"\"" : NULL, lsSet.ms_Val, lsSet.mb_Quoted ? L"\"" : NULL); lsCmdLine = SkipNonPrintable(lsCmdLine); if (!*lsCmdLine || (*lsCmdLine == L'&') || (*lsCmdLine == L'|')) break; } if (!lsAdd.IsEmpty()) { bNew |= (NULL != Add(lsCmd, lsSwitches, lsAdd, anBefore)); } } else { lsCmd.Empty(); } // Well, known command was detected. What is next? if (lsNameVal || bTokenOk) { lsAmp.GetPosFrom(lsSet); if (NextArg(&lsCmdLine, lsAmp) != 0) { // End of command? Use may call only "set" without following app? Run simple "cmd" in that case _ASSERTE(lsCmdLine!=NULL && *lsCmdLine==0); bTokenOk = true; // And process SetEnvironmentVariable } else { if (lstrcmp(lsAmp, L"&") == 0) { // Only simple conveyer is supported! bTokenOk = true; // And process SetEnvironmentVariable } // Update last pointer (debug and asserts purposes) lsSet.GetPosFrom(lsAmp); } } if (!bTokenOk) { break; // Stop processing command line } else if (lsNameVal) { // And split name/value _ASSERTE(lsNameVal!=NULL); wchar_t* pszEq = wcschr(lsNameVal, L'='); if (!pszEq) { _ASSERTE(pszEq!=NULL); break; } *(pszEq++) = 0; bNew |= (NULL != Add(lsCmd, lsNameVal, pszEq ? pszEq : L"", anBefore)); } // Remember processed position if (ppszEnd) { *ppszEnd = lsCmdLine; } } // end of "while (NextArg(&lsCmdLine, lsSet) == 0)" // Fin if (ppszEnd && (!*ppszEnd || !**ppszEnd)) { static wchar_t szSimple[] = L"cmd"; *ppszEnd = szSimple; } return bNew; }
bool TermX::GetSubstitute(const KEY_EVENT_RECORD& k, CEStr& lsSubst) { _ASSERTE(lsSubst.IsEmpty()); // Bypass AltGr+keys to console intact if ((k.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_ALT_PRESSED)) == (LEFT_CTRL_PRESSED|RIGHT_ALT_PRESSED)) { if (k.uChar.UnicodeChar) { wchar_t szData[3] = {k.uChar.UnicodeChar}; if (LastDeadCharVK == k.wVirtualKeyCode) szData[1] = k.uChar.UnicodeChar; lsSubst.Set(szData); LastDeadCharVK = 0; } else { LastDeadCharVK = k.wVirtualKeyCode; lsSubst.Clear(); } return true; } wchar_t szSubst[16] = L""; static UINT F1Codes[24] = { 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 23, 24, 25, 26, 28, 29, 31, 32, 33, 34, 42, 43, 44, 45 }; static wchar_t F1F4Codes[] = {L'P', L'Q', L'R', L'S'}; static wchar_t ArrowCodes[] = {L'F', L'H', L'D', L'A', L'C', L'B'}; typedef DWORD XTermCtrls; const XTermCtrls xtc_Shift = 1, xtc_Alt = 2, xtc_Ctrl = 4, xtc_None = 0; struct processor { XTermCtrls Mods; wchar_t szSubst[16]; void SetKey(CEStr& lsSubst, wchar_t c, wchar_t prefix=L'O') { if (!Mods) { //wcscpy_c(szSubst, L"\033O*A"); msprintf(szSubst, countof(szSubst), L"\033%c%c", prefix, c); } else { msprintf(szSubst, countof(szSubst), L"\033[1;%c%c", Mods+L'1', c); } lsSubst.Set(szSubst); } void SetFKey(CEStr& lsSubst, UINT fn) { if (!Mods) { msprintf(szSubst, countof(szSubst), L"\033[%u~", fn); } else { msprintf(szSubst, countof(szSubst), L"\033[%u;%c~", fn, Mods+L'1'); } lsSubst.Set(szSubst); } void SetTilde(CEStr& lsSubst, wchar_t c) { if (!Mods) { msprintf(szSubst, countof(szSubst), L"\033[%c~", c); } else { msprintf(szSubst, countof(szSubst), L"\033[%c;%c~", c, Mods+L'1'); } lsSubst.Set(szSubst); } } Processor = {xtc_None}; if (k.dwControlKeyState & (SHIFT_PRESSED)) Processor.Mods |= xtc_Shift; if (k.dwControlKeyState & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) Processor.Mods |= xtc_Alt; if (k.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)) Processor.Mods |= xtc_Ctrl; switch (k.wVirtualKeyCode) { case VK_END: case VK_HOME: case VK_LEFT: case VK_UP: case VK_RIGHT: case VK_DOWN: Processor.SetKey(lsSubst, ArrowCodes[(k.wVirtualKeyCode-VK_END)], AppCursorKeys ? L'O' : L'['); return true; case VK_F1: case VK_F2: case VK_F3: case VK_F4: Processor.SetKey(lsSubst, F1F4Codes[(k.wVirtualKeyCode-VK_F1)]); return true; case VK_F5: case VK_F6: case VK_F7: case VK_F8: case VK_F9: case VK_F10: case VK_F11: case VK_F12: case VK_F13: case VK_F14: case VK_F15: case VK_F16: case VK_F17: case VK_F18: case VK_F19: case VK_F20: case VK_F21: case VK_F22: case VK_F23: case VK_F24: // "\033[11;*~" .. L"\033[15;*~", and so on: F1Codes[] Processor.SetFKey(lsSubst, F1Codes[(k.wVirtualKeyCode-VK_F1)]); return true; case VK_INSERT: Processor.SetTilde(lsSubst, L'2'); return true; case VK_PRIOR: Processor.SetTilde(lsSubst, L'5'); return true; case VK_NEXT: Processor.SetTilde(lsSubst, L'6'); return true; case VK_DELETE: Processor.SetTilde(lsSubst, L'3'); return true; case VK_BACK: if ((Processor.Mods & xtc_Alt)) szSubst[0] = 0x1B; szSubst[(Processor.Mods == xtc_Alt) ? 1 : 0] = ((Processor.Mods & (xtc_Ctrl|xtc_Alt)) == (xtc_Ctrl|xtc_Alt)) ? 0x9F : (Processor.Mods & xtc_Ctrl) ? X_CTRL('_')/*0x1F*/ : X_CDEL/*0x7F*/; szSubst[(Processor.Mods == xtc_Alt) ? 2 : 1] = 0; lsSubst.Set(szSubst); return true; case VK_TAB: if (!(k.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED|LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED))) { wcscpy_c(szSubst, (k.dwControlKeyState & SHIFT_PRESSED) ? L"\033[Z" : L"\t"); } lsSubst.Set(szSubst); return true; /* NumPad with NumLock ON */ case VK_NUMPAD0: case VK_NUMPAD1: case VK_NUMPAD2: case VK_NUMPAD3: case VK_NUMPAD4: case VK_NUMPAD5: case VK_NUMPAD6: case VK_NUMPAD7: case VK_NUMPAD8: case VK_NUMPAD9: case VK_DECIMAL: // VK_OEM_PERIOD}, // Actually, this may be comma case VK_DIVIDE: case VK_MULTIPLY: case VK_SUBTRACT: case VK_ADD: if (k.uChar.UnicodeChar) { // Just a digits '0'..'9' and symbols +-/*. szSubst[0] = k.uChar.UnicodeChar; szSubst[1] = 0; } lsSubst.Set(szSubst); return true; } // Alt+Char if ((Processor.Mods & xtc_Alt) && k.uChar.UnicodeChar // connector/gh#4: AltGr+Char && (((k.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED|LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) != (LEFT_CTRL_PRESSED|RIGHT_ALT_PRESSED)) // or just a Alt+Char || !(Processor.Mods & xtc_Ctrl)) ) { szSubst[0] = L'\033'; szSubst[1] = k.uChar.UnicodeChar; szSubst[2] = 0; lsSubst.Set(szSubst); return true; } // Ctrl+Char: A-->1, ..., J-->10, ... if (Processor.Mods & (xtc_Alt | xtc_Ctrl)) { wchar_t key_char = k.uChar.UnicodeChar; if (!key_char) { switch (k.wVirtualKeyCode) { case VK_OEM_2: key_char = L'?'; break; // Ctrl+/ -> \x1F case VK_OEM_3: key_char = L'~'; break; case VK_OEM_4: key_char = L'['; break; case VK_OEM_5: key_char = L'\\'; break; case VK_OEM_6: key_char = L']'; break; case VK_OEM_COMMA: key_char = L','; break; case VK_OEM_PERIOD: key_char = L'.'; break; case VK_OEM_MINUS: key_char = L'-'; break; case VK_OEM_PLUS: key_char = L'='; break; default: if (k.wVirtualKeyCode >= L'0' && k.wVirtualKeyCode <= L'9') key_char = k.wVirtualKeyCode; else if (k.wVirtualKeyCode >= L'A' && k.wVirtualKeyCode <= L'Z') key_char = k.wVirtualKeyCode; } } if (key_char) { szSubst[0] = szSubst[1] = szSubst[2] = szSubst[3] = 0; if ((Processor.Mods == xtc_Ctrl) && (key_char == L'2' || key_char == L' ')) { // Must send '\x00' but it's not a valid ASCIIZ string, have to be processed in connector return false; } else if (key_char >= L'A' && key_char <= L'Z') { if (Processor.Mods == xtc_Ctrl) { // In vt220: If XOFF support is enabled, then CTRL-S is a "hold screen" local function and CTRL-Q is an "unhold screen" local function. szSubst[0] = (wchar_t)(1 + (key_char - L'A')); } else if ((Processor.Mods == (xtc_Ctrl|xtc_Alt)) || (Processor.Mods == (xtc_Ctrl|xtc_Alt|xtc_Shift))) { szSubst[0] = 0x1B; szSubst[1] = (wchar_t)(1 + (key_char - L'A')); } // doesn't work, "showkey -a" receives "<x1B><xC3><x82><x01>" //else if (Processor.Mods == (xtc_Ctrl|xtc_Alt|xtc_Shift)) //{ // szSubst[0] = 0x1B; szSubst[1] = 0xC2; // szSubst[2] = (wchar_t)(1 + (key_char - L'A')); //} } else if ((Processor.Mods == xtc_Ctrl) && (key_char == L'1' || key_char == L'9' || key_char == L'0')) { // Strangely Ctrl+1, Ctrl+9, Ctrl+0 generate only 1, 9 and 0. szSubst[0] = key_char; } else if ((Processor.Mods == xtc_Ctrl) && (key_char >= L'3' && key_char <= L'7')) { szSubst[0] = (wchar_t)(0x1B + (key_char - L'3')); } else switch (key_char) { case L',': szSubst[0] = 0x2C; break; // Processor.SetKey(lsSubst, L'l'); break; case L'.': szSubst[0] = 0x2E; break; // Processor.SetKey(lsSubst, L'n'); break; //case L'-': // Processor.SetKey(lsSubst, L'm'); break; //case L'0': // Processor.SetKey(lsSubst, L'p'); break; //case L'1': // Processor.SetKey(lsSubst, L'q'); break; // case L'2': // processed above //case L'3': // Processor.SetKey(lsSubst, L's'); break; //case L'4': // Processor.SetKey(lsSubst, L't'); break; //case L'5': // Processor.SetKey(lsSubst, L'u'); break; //case L'6': case L'~': szSubst[0] = 0x1E; break; //case L'7': // Processor.SetKey(lsSubst, L'w'); break; case L'8': szSubst[0] = 0x1B; if ((Processor.Mods == (xtc_Ctrl|xtc_Alt)) || (Processor.Mods == (xtc_Ctrl|xtc_Alt|xtc_Shift))) szSubst[1] = 0x7F; else szSubst[0] = 0x7F; break; //Processor.SetKey(lsSubst, L'x'); break; //case L'9': // Processor.SetKey(lsSubst, L'y'); break; //case L'=': // Processor.SetKey(lsSubst, L'X'); break; case L'[': case L'\\': case L']': { wchar_t c = (key_char == L'[') ? 0x1B : (key_char == L'\\') ? 0x1C : 0x1D; szSubst[0] = 0x1B; if (Processor.Mods == xtc_Alt) szSubst[1] = 0x40 + c; else if ((Processor.Mods == (xtc_Ctrl|xtc_Alt)) || (Processor.Mods == (xtc_Ctrl|xtc_Alt|xtc_Shift))) szSubst[1] = c; else szSubst[0] = c; break; } case L'?': if (!(Processor.Mods & xtc_Alt)) szSubst[0] = (Processor.Mods & xtc_Shift) ? 0x7F : 0x1F; else { szSubst[0] = 0x1B; szSubst[1] = (Processor.Mods & xtc_Shift) ? 0x3F : 0x2F; } break; } if (szSubst[0]) { lsSubst.Set(szSubst); return true; } } } return false; }
bool TermX::GetSubstitute(const MOUSE_EVENT_RECORD& m, TermMouseMode MouseMode, CEStr& lsSubst) { _ASSERTE(lsSubst.IsEmpty()); if (!MouseMode) { lsSubst.Clear(); return false; } wchar_t szSubst[16] = L""; // Deprecated. Mouse events mimic xterm behavior now. #if 0 // http://conemu.github.io/en/VimXterm.html#Vim-scrolling-using-mouse-Wheel // https://github.com/Maximus5/ConEmu/issues/1007 if ((m.dwEventFlags & MOUSE_WHEELED) && (MouseMode & tmm_VIM)) { // If the high word of the dwButtonState member contains // a positive value, the wheel was rotated forward, away from the user. // Otherwise, the wheel was rotated backward, toward the user. short dir = (short)HIWORD(m.dwButtonState); // Ctrl/Alt/Shift DWORD mods = (m.dwControlKeyState & (LEFT_ALT_PRESSED|LEFT_CTRL_PRESSED|RIGHT_ALT_PRESSED|RIGHT_CTRL_PRESSED|SHIFT_PRESSED)); if (mods == 0) { if (dir <= 0) wcscpy_c(szSubst, L"\033[62~"); // <MouseDown> else wcscpy_c(szSubst, L"\033[63~"); // <MouseUp> } else if (mods == SHIFT_PRESSED) { if (dir <= 0) wcscpy_c(szSubst, L"\033[64~"); // <S-MouseDown> else wcscpy_c(szSubst, L"\033[65~"); // <S-MouseUp> } else return false; lsSubst.Set(szSubst); return true; } #endif if ((m.dwEventFlags & MOUSE_WHEELED) && (MouseMode & tmm_SCROLL)) { KEY_EVENT_RECORD k = {TRUE, 1}; short dir = (short)HIWORD(m.dwButtonState); DWORD mods = (m.dwControlKeyState & (LEFT_ALT_PRESSED|LEFT_CTRL_PRESSED|RIGHT_ALT_PRESSED|RIGHT_CTRL_PRESSED|SHIFT_PRESSED)); UINT nCount = 1; if (mods == 0) { k.wVirtualKeyCode = (dir > 0) ? VK_UP : VK_DOWN; nCount = gpConEmu->mouse.GetWheelScrollLines(); } else if (mods == SHIFT_PRESSED) { k.wVirtualKeyCode = (dir > 0) ? VK_PRIOR : VK_NEXT; } else return false; CEStr lsPart; if (!GetSubstitute(k, lsPart) || lsPart.IsEmpty()) return false; if (nCount > 1) { INT_PTR l = lsPart.GetLen(); wchar_t* ptr = lsSubst.GetBuffer(l*nCount); for (UINT i = 1; i <= nCount; ++i, ptr += l) wcscpy_s(ptr, l+1, lsPart); } else { lsSubst.Attach(lsPart.Detach()); } return true; } if (!(MouseMode & ~(tmm_VIM|tmm_SCROLL))) return false; BYTE NewBtns = (m.dwButtonState & 0x1F); if ((NewBtns != MouseButtons) || ((m.dwEventFlags & MOUSE_WHEELED) && HIWORD(m.dwButtonState)) || ((LastMousePos != m.dwMousePosition) && ((MouseMode & tmm_ANY) || ((MouseMode & tmm_BTN) && NewBtns))) ) { // #XTERM_MOUSE Unfortunately, szSubst is too short to pass "missed" coordinates // Like we do for Far events, MouseMove with RBtn pressed in tmm_ANY|tmm_BTN // modes would send all intermediate coordinates between two events BYTE code; bool released = false; if (NewBtns & FROM_LEFT_1ST_BUTTON_PRESSED) code = 0; // MB1 pressed else if (NewBtns & FROM_LEFT_2ND_BUTTON_PRESSED) code = 1; // MB2 pressed else if (NewBtns & RIGHTMOST_BUTTON_PRESSED) code = 2; // MB3 pressed else if (NewBtns & FROM_LEFT_3RD_BUTTON_PRESSED) code = 64; // MB4 pressed else if (NewBtns & FROM_LEFT_4TH_BUTTON_PRESSED) code = 64 + 1; // MB5 pressed else if (m.dwEventFlags & MOUSE_WHEELED) { // #XTERM_MOUSE Post multiple events if dir contains multiple notches short dir = (short)HIWORD(m.dwButtonState); if (dir > 0) code = 64; // MB4 else if (dir < 0) code = 64 + 1; // MB5 } else { released = true; code = 3; } if (m.dwControlKeyState & SHIFT_PRESSED) code |= 4; if (m.dwControlKeyState & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) code |= 8; if (m.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)) code |= 16; if ((m.dwEventFlags & MOUSE_MOVED) && (MouseMode & (tmm_BTN|tmm_ANY))) code |= 32; // (1,1) is upper left character position SHORT coord[] = {std::max<SHORT>(0, m.dwMousePosition.X) + 1, std::max<SHORT>(0, m.dwMousePosition.Y) + 1}; if (MouseMode & tmm_XTERM) { msprintf(szSubst, countof(szSubst), L"\033[<%u;%u;%u%c", code, coord[0], coord[1], released ? 'm' : 'M'); } else if (MouseMode & tmm_URXVT) { msprintf(szSubst, countof(szSubst), L"\033[%u;%u;%uM", code + 0x20, coord[0], coord[1]); } else { wcscpy_c(szSubst, L"\033[M"); size_t i = wcslen(szSubst); szSubst[i++] = code + 32; // And coords. Must be in "screen" coordinate space for (size_t s = 0; s < 2; ++s) { // (1,1) is upper left character position if (!(MouseMode & tmm_UTF8)) szSubst[i++] = std::min<unsigned>(255, coord[s] + 32); else if (coord[s] < 0x80) szSubst[i++] = coord[s]; else if (coord[s] < 0x800) { // xterm #262: positions from 96 to 2015 are encoded as a two-byte UTF-8 sequence szSubst[i++] = 0xC0 + (coord[s] >> 6); szSubst[i++] = 0x80 + (coord[s] & 0x3F); } else { // #XTERM_MOUSE Xterm reports out-of-range positions as a NUL byte. szSubst[i++] = 1; // It's impossible to post NUL byte ATM } }
INT_PTR CRecreateDlg::OnInitDialog(HWND hDlg, UINT messg, WPARAM wParam, LPARAM lParam) { LRESULT lbRc = FALSE; gpConEmu->OnOurDialogOpened(); CDynDialog::LocalizeDialog(hDlg); // Visual SendMessage(hDlg, WM_SETICON, ICON_BIG, (LPARAM)hClassIcon); SendMessage(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)hClassIconSm); // Set password style (avoid "bars" on some OS) SendDlgItemMessage(hDlg, tRunAsPassword, WM_SETFONT, (LPARAM)(HFONT)GetStockObject(DEFAULT_GUI_FONT), 0); // Add menu items HMENU hSysMenu = GetSystemMenu(hDlg, FALSE); InsertMenu(hSysMenu, 0, MF_BYPOSITION | MF_SEPARATOR, 0, 0); InsertMenu(hSysMenu, 0, MF_BYPOSITION | MF_STRING | MF_ENABLED, ID_RESETCMDHISTORY, L"Clear history..."); InsertMenu(hSysMenu, 0, MF_BYPOSITION | MF_STRING | MF_ENABLED | (gpSet->isSaveCmdHistory ? MF_CHECKED : 0), ID_STORECMDHISTORY, L"Store history"); //#ifdef _DEBUG //SetWindowPos(ghOpWnd, HWND_NOTOPMOST, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE); //#endif RConStartArgsEx* pArgs = mp_Args; _ASSERTE(pArgs); // Fill command and task drop down SendMessage(hDlg, UM_FILL_CMDLIST, TRUE, 0); // Set text in command and folder fields { LPCWSTR pszSetCmd = mpsz_DefCmd ? mpsz_DefCmd : pArgs->pszSpecialCmd ? pArgs->pszSpecialCmd : L""; CEStr lsTempCmd, lsAppend; if (!mpsz_DefCmd && pArgs) { RConStartArgsEx tempArgs; tempArgs.AssignFrom(pArgs); tempArgs.CleanSecure(); tempArgs.RunAsSystem = pArgs->RunAsSystem; tempArgs.eSplit = RConStartArgsEx::eSplitNone; SafeFree(tempArgs.pszSpecialCmd); SafeFree(tempArgs.pszStartupDir); tempArgs.NewConsole = pArgs->NewConsole; lsAppend = tempArgs.CreateCommandLine(); if (!lsAppend.IsEmpty()) { lsTempCmd = lstrmerge(pszSetCmd, ((lsAppend[0] == L' ') ? NULL : L" "), lsAppend); pszSetCmd = lsTempCmd.ms_Val; } } SetDlgItemText(hDlg, IDC_RESTART_CMD, pszSetCmd); // TODO: gh-959: enable autocorrection of cbRunAsAdmin by IDC_RESTART_CMD task contents (first line) } // "%CD%" was specified as startup dir? In Task parameters for example... CEStr lsStartDir; if (pArgs->pszStartupDir && (lstrcmpi(pArgs->pszStartupDir, L"%CD%") == 0)) { lsStartDir.Set(ms_RConCurDir); } // Suggest default ConEmu working directory otherwise (unless it's a cra_RecreateTab) if (lsStartDir.IsEmpty()) { lsStartDir.Set(gpConEmu->WorkDir()); } // Current directory, startup directory, ConEmu startup directory, and may be startup directory history in the future AddDirectoryList(mpsz_DefDir ? mpsz_DefDir : lsStartDir.ms_Val); AddDirectoryList(ms_RConCurDir); AddDirectoryList(ms_RConStartDir); AddDirectoryList(gpConEmu->WorkDir()); LPCWSTR pszShowDir; if ((pArgs->aRecreate == cra_RecreateTab) && !ms_RConCurDir.IsEmpty()) pszShowDir = ms_RConCurDir; else pszShowDir = mpsz_DefDir ? mpsz_DefDir : lsStartDir.ms_Val; SetDlgItemText(hDlg, IDC_STARTUP_DIR, pszShowDir); // Split controls if (pArgs->aRecreate == cra_RecreateTab) { // Hide Split's ShowWindow(GetDlgItem(hDlg, gbRecreateSplit), SW_HIDE); ShowWindow(GetDlgItem(hDlg, rbRecreateSplitNone), SW_HIDE); ShowWindow(GetDlgItem(hDlg, rbRecreateSplit2Right), SW_HIDE); ShowWindow(GetDlgItem(hDlg, rbRecreateSplit2Bottom), SW_HIDE); ShowWindow(GetDlgItem(hDlg, stRecreateSplit), SW_HIDE); ShowWindow(GetDlgItem(hDlg, tRecreateSplit), SW_HIDE); } else { // Fill splits SetDlgItemInt(hDlg, tRecreateSplit, (1000-pArgs->nSplitValue)/10, FALSE); CheckRadioButton(hDlg, rbRecreateSplitNone, rbRecreateSplit2Bottom, rbRecreateSplitNone+pArgs->eSplit); EnableWindow(GetDlgItem(hDlg, tRecreateSplit), (pArgs->eSplit != pArgs->eSplitNone)); EnableWindow(GetDlgItem(hDlg, stRecreateSplit), (pArgs->eSplit != pArgs->eSplitNone)); } // Спрятать флажок "New window" bool bRunInNewWindow_Hidden = (pArgs->aRecreate == cra_EditTab || pArgs->aRecreate == cra_RecreateTab); ShowWindow(GetDlgItem(hDlg, cbRunInNewWindow), bRunInNewWindow_Hidden ? SW_HIDE : SW_SHOWNORMAL); const wchar_t *pszUser = pArgs->pszUserName; const wchar_t *pszDomain = pArgs->pszDomain; bool bResticted = (pArgs->RunAsRestricted == crb_On); int nChecked = rbCurrentUser; int nNetOnly = cbRunAsNetOnly; DWORD nUserNameLen = countof(ms_CurUser); if (!GetUserName(ms_CurUser, &nUserNameLen)) ms_CurUser[0] = 0; wchar_t szRbCaption[MAX_PATH*3]; lstrcpy(szRbCaption, L"Run as current &user: "******"UPN format" остается в pszUser lstrcpyn(szOtherUser, pszUser, MAX_PATH); wcscat_c(szOtherUser, L"@"); lstrcpyn(szOtherUser+_tcslen(szOtherUser), pszDomain, MAX_PATH); } else { // "Старая" нотация domain\user lstrcpyn(szOtherUser, pszDomain, MAX_PATH); wcscat_c(szOtherUser, L"\\"); lstrcpyn(szOtherUser+_tcslen(szOtherUser), pszUser, MAX_PATH); } } else { lstrcpyn(szOtherUser, pszUser, countof(szOtherUser)); } SetDlgItemText(hDlg, tRunAsPassword, pArgs->szUserPassword); EnableWindow(GetDlgItem(hDlg, cbRunAsNetOnly), TRUE); } } SetDlgItemText(hDlg, tRunAsUser, (nChecked == rbAnotherUser) ? szOtherUser : L""); CheckRadioButton(hDlg, rbCurrentUser, rbAnotherUser, nChecked); RecreateDlgProc(hDlg, UM_USER_CONTROLS, 0, 0); if (gOSVer.dwMajorVersion < 6) { // В XP и ниже это просто RunAs - с возможностью ввода имени пользователя и пароля //apiShowWindow(GetDlgItem(hDlg, cbRunAsAdmin), SW_HIDE); SetDlgItemTextA(hDlg, cbRunAsAdmin, "&Run as..."); //GCC hack. иначе не собирается // И уменьшить длину RECT rcBox; GetWindowRect(GetDlgItem(hDlg, cbRunAsAdmin), &rcBox); SetWindowPos(GetDlgItem(hDlg, cbRunAsAdmin), NULL, 0, 0, (rcBox.right-rcBox.left)/2, rcBox.bottom-rcBox.top, SWP_NOMOVE|SWP_NOZORDER); } else if (gpConEmu->mb_IsUacAdmin || (pArgs && (pArgs->RunAsAdministrator == crb_On))) { CheckDlgButton(hDlg, cbRunAsAdmin, BST_CHECKED); if (gpConEmu->mb_IsUacAdmin) // Только в Vista+ если GUI уже запущен под админом { EnableWindow(GetDlgItem(hDlg, cbRunAsAdmin), FALSE); } else //if (gOSVer.dwMajorVersion < 6) { RecreateDlgProc(hDlg, WM_COMMAND, cbRunAsAdmin, 0); } } //} SetClassLongPtr(hDlg, GCLP_HICON, (LONG_PTR)hClassIcon); if (pArgs->aRecreate == cra_RecreateTab) { SetWindowText(hDlg, CLngRc::getRsrc(lng_DlgRestartConsole/*"Restart console"*/)); SendDlgItemMessage(hDlg, IDC_RESTART_ICON, STM_SETICON, (WPARAM)LoadIcon(NULL,IDI_EXCLAMATION), 0); lbRc = TRUE; } else { SetWindowText(hDlg, CLngRc::getRsrc(lng_DlgCreateNewConsole/*"Create new console"*/)); // If we disallowed to create "Multiple consoles in one window" // - Check & Disable "New window" checkbox bool bForceNewWindow = (!gpSetCls->IsMulti() && gpConEmu->isVConExists(0)); CheckDlgButton(hDlg, cbRunInNewWindow, (pArgs->aRecreate == cra_CreateWindow || bForceNewWindow) ? BST_CHECKED : BST_UNCHECKED); EnableWindow(GetDlgItem(hDlg, cbRunInNewWindow), !bForceNewWindow); // SendDlgItemMessage(hDlg, IDC_RESTART_ICON, STM_SETICON, (WPARAM)LoadIcon(NULL,IDI_QUESTION), 0); POINT pt = {0,0}; MapWindowPoints(GetDlgItem(hDlg, IDC_TERMINATE), hDlg, &pt, 1); DestroyWindow(GetDlgItem(hDlg, IDC_TERMINATE)); SetWindowPos(GetDlgItem(hDlg, IDC_START), NULL, pt.x, pt.y, 0,0, SWP_NOSIZE|SWP_NOZORDER); SetDlgItemText(hDlg, IDC_START, (pArgs->aRecreate == cra_EditTab) ? L"&Save" : L"&Start"); DestroyWindow(GetDlgItem(hDlg, IDC_WARNING)); } // Align "New window" and "Run as administrator" checkboxes { RECT rcBox = {}; GetWindowRect(GetDlgItem(hDlg, cbRunAsAdmin), &rcBox); MapWindowPoints(NULL, hDlg, (LPPOINT)&rcBox, 2); const int chk_height = (rcBox.bottom - rcBox.top); POINT pt = {rcBox.left}; if (!bRunInNewWindow_Hidden) { RECT rcIcoBox = {}; GetWindowRect(GetDlgItem(hDlg, IDC_RESTART_ICON), &rcIcoBox); MapWindowPoints(NULL, hDlg, (LPPOINT)&rcIcoBox, 2); const int ico_height = (rcIcoBox.bottom - rcIcoBox.top); const int h2 = (chk_height * 5) / 2; pt.y = rcIcoBox.top + (ico_height - h2)/2; SetWindowPos(GetDlgItem(hDlg, cbRunInNewWindow), NULL, pt.x, pt.y, 0,0, SWP_NOSIZE|SWP_NOZORDER); pt.y += (h2 - chk_height); } else { RECT rcBtnBox = {}; GetWindowRect(GetDlgItem(hDlg, IDC_START), &rcBtnBox); MapWindowPoints(NULL, hDlg, (LPPOINT)&rcBtnBox, 2); const int btn_height = (rcBtnBox.bottom - rcBtnBox.top); pt.y = rcBtnBox.top + (btn_height - chk_height)/2; } SetWindowPos(GetDlgItem(hDlg, cbRunAsAdmin), NULL, pt.x, pt.y, 0,0, SWP_NOSIZE|SWP_NOZORDER); } // Dpi aware processing at the end of sequence // because we done some manual control reposition if (mp_DpiAware) { mp_DpiAware->Attach(hDlg, ghWnd, CDynDialog::GetDlgClass(hDlg)); } // Ensure, it will be "on screen" RECT rect; GetWindowRect(hDlg, &rect); RECT rcCenter = CenterInParent(rect, mh_Parent); MoveWindow(hDlg, rcCenter.left, rcCenter.top, rect.right - rect.left, rect.bottom - rect.top, false); // Была отключена обработка CConEmuMain::OnFocus (лишние телодвижения) PostMessage(hDlg, (WM_APP+1), 0,0); // Default focus control if (pArgs->aRecreate == cra_RecreateTab) SetFocus(GetDlgItem(hDlg, IDC_START)); // Win+~ (Recreate tab), Focus on "Restart" button" else if ((pArgs->pszUserName && *pArgs->pszUserName) && !*pArgs->szUserPassword) SetFocus(GetDlgItem(hDlg, tRunAsPassword)); // We need password, all other fields are ready else SetFocus(GetDlgItem(hDlg, IDC_RESTART_CMD)); // Set focus in command-line field return lbRc; }