forked from qt-creator/qt-creator
Terminal: Show key when input is hidden
Change-Id: I5fca6a8c4f43ea2b95bad4df247b5df0abad521c Reviewed-by: Alessandro Portale <alessandro.portale@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
7
src/libs/3rdparty/libptyqt/iptyprocess.h
vendored
7
src/libs/3rdparty/libptyqt/iptyprocess.h
vendored
@@ -11,6 +11,8 @@ class IPtyProcess
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum PtyType { UnixPty = 0, WinPty = 1, ConPty = 2, AutoPty = 3 };
|
enum PtyType { UnixPty = 0, WinPty = 1, ConPty = 2, AutoPty = 3 };
|
||||||
|
enum PtyInputFlag { None = 0x0, InputModeHidden = 0x1, };
|
||||||
|
Q_DECLARE_FLAGS(PtyInputFlags, PtyInputFlag)
|
||||||
|
|
||||||
IPtyProcess() = default;
|
IPtyProcess() = default;
|
||||||
IPtyProcess(const IPtyProcess &) = delete;
|
IPtyProcess(const IPtyProcess &) = delete;
|
||||||
@@ -43,6 +45,8 @@ public:
|
|||||||
return m_trace;
|
return m_trace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PtyInputFlags inputFlags() { return m_inputFlags; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QString m_shellPath;
|
QString m_shellPath;
|
||||||
QString m_lastError;
|
QString m_lastError;
|
||||||
@@ -50,6 +54,9 @@ protected:
|
|||||||
int m_exitCode{0};
|
int m_exitCode{0};
|
||||||
QPair<qint16, qint16> m_size; //cols / rows
|
QPair<qint16, qint16> m_size; //cols / rows
|
||||||
bool m_trace{false};
|
bool m_trace{false};
|
||||||
|
PtyInputFlags m_inputFlags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS(IPtyProcess::PtyInputFlags)
|
||||||
|
|
||||||
#endif // IPTYPROCESS_H
|
#endif // IPTYPROCESS_H
|
||||||
|
|||||||
@@ -172,6 +172,12 @@ bool UnixPtyProcess::startProcess(const QString &shellPath,
|
|||||||
static std::array<char, maxRead> buffer;
|
static std::array<char, maxRead> buffer;
|
||||||
|
|
||||||
int len = ::read(m_shellProcess.m_handleMaster, buffer.data(), buffer.size());
|
int len = ::read(m_shellProcess.m_handleMaster, buffer.data(), buffer.size());
|
||||||
|
|
||||||
|
struct termios termAttributes;
|
||||||
|
tcgetattr(m_shellProcess.m_handleMaster, &termAttributes);
|
||||||
|
const bool isPasswordEntry = !(termAttributes.c_lflag & ECHO) && (termAttributes.c_lflag & ICANON);
|
||||||
|
m_inputFlags.setFlag(PtyInputFlag::InputModeHidden, isPasswordEntry);
|
||||||
|
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
m_shellReadBuffer.append(buffer.data(), len);
|
m_shellReadBuffer.append(buffer.data(), len);
|
||||||
m_shellProcess.emitReadyRead();
|
m_shellProcess.emitReadyRead();
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ add_qtc_library(TerminalLib
|
|||||||
scrollback.cpp scrollback.h
|
scrollback.cpp scrollback.h
|
||||||
surfaceintegration.h
|
surfaceintegration.h
|
||||||
terminal_global.h
|
terminal_global.h
|
||||||
|
terminal.qrc
|
||||||
terminalsurface.cpp terminalsurface.h
|
terminalsurface.cpp terminalsurface.h
|
||||||
terminalview.cpp terminalview.h
|
terminalview.cpp terminalview.h
|
||||||
)
|
)
|
||||||
|
|||||||
BIN
src/libs/solutions/terminal/images/passwordlock.png
Normal file
BIN
src/libs/solutions/terminal/images/passwordlock.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 840 B |
5
src/libs/solutions/terminal/terminal.qrc
Normal file
5
src/libs/solutions/terminal/terminal.qrc
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/terminal">
|
||||||
|
<file>images/passwordlock.png</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
||||||
@@ -85,6 +85,7 @@ public:
|
|||||||
bool m_cursorBlinkState{true};
|
bool m_cursorBlinkState{true};
|
||||||
bool m_allowBlinkingCursor{true};
|
bool m_allowBlinkingCursor{true};
|
||||||
bool m_allowMouseTracking{true};
|
bool m_allowMouseTracking{true};
|
||||||
|
bool m_passwordModeActive{false};
|
||||||
|
|
||||||
SurfaceIntegration *m_surfaceIntegration{nullptr};
|
SurfaceIntegration *m_surfaceIntegration{nullptr};
|
||||||
};
|
};
|
||||||
@@ -258,6 +259,14 @@ void TerminalView::setColors(const std::array<QColor, 20> &newColors)
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TerminalView::setPasswordMode(bool passwordMode)
|
||||||
|
{
|
||||||
|
if (passwordMode != d->m_passwordModeActive) {
|
||||||
|
d->m_passwordModeActive = passwordMode;
|
||||||
|
updateViewport();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TerminalView::setFont(const QFont &font)
|
void TerminalView::setFont(const QFont &font)
|
||||||
{
|
{
|
||||||
QAbstractScrollArea::setFont(font);
|
QAbstractScrollArea::setFont(font);
|
||||||
@@ -731,16 +740,37 @@ void TerminalView::paintCursor(QPainter &p) const
|
|||||||
{
|
{
|
||||||
auto cursor = d->m_surface->cursor();
|
auto cursor = d->m_surface->cursor();
|
||||||
|
|
||||||
if (!d->m_preEditString.isEmpty())
|
const int cursorCellWidth = d->m_surface->cellWidthAt(cursor.position.x(), cursor.position.y());
|
||||||
cursor.shape = Cursor::Shape::Underline;
|
|
||||||
|
|
||||||
|
if (!d->m_preEditString.isEmpty()) {
|
||||||
|
cursor.shape = Cursor::Shape::Underline;
|
||||||
|
} else if (d->m_passwordModeActive) {
|
||||||
|
QRectF cursorRect = QRectF(gridToGlobal(cursor.position),
|
||||||
|
gridToGlobal({cursor.position.x() + cursorCellWidth,
|
||||||
|
cursor.position.y()},
|
||||||
|
true))
|
||||||
|
.toAlignedRect();
|
||||||
|
|
||||||
|
const qreal dpr = p.device()->devicePixelRatioF();
|
||||||
|
const QString key = QString("terminalpasswordlock-")
|
||||||
|
% QString::number(cursorRect.size().height())
|
||||||
|
% "@" % QString::number(dpr);
|
||||||
|
QPixmap px;
|
||||||
|
if (!QPixmapCache::find(key, &px)) {
|
||||||
|
const QPixmap lock(":/terminal/images/passwordlock.png");
|
||||||
|
px = lock.scaledToHeight(cursorRect.size().height() * dpr, Qt::SmoothTransformation);
|
||||||
|
px.setDevicePixelRatio(dpr);
|
||||||
|
QPixmapCache::insert(key, px);
|
||||||
|
}
|
||||||
|
|
||||||
|
p.drawPixmap(cursorRect.topLeft(), px);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
const bool blinkState = !cursor.blink || d->m_cursorBlinkState || !d->m_allowBlinkingCursor
|
const bool blinkState = !cursor.blink || d->m_cursorBlinkState || !d->m_allowBlinkingCursor
|
||||||
|| !d->m_cursorBlinkTimer.isActive();
|
|| !d->m_cursorBlinkTimer.isActive();
|
||||||
|
|
||||||
if (cursor.visible && blinkState) {
|
if (cursor.visible && blinkState) {
|
||||||
const int cursorCellWidth = d->m_surface->cellWidthAt(cursor.position.x(),
|
|
||||||
cursor.position.y());
|
|
||||||
|
|
||||||
QRectF cursorRect = QRectF(gridToGlobal(cursor.position),
|
QRectF cursorRect = QRectF(gridToGlobal(cursor.position),
|
||||||
gridToGlobal({cursor.position.x() + cursorCellWidth,
|
gridToGlobal({cursor.position.x() + cursorCellWidth,
|
||||||
cursor.position.y()},
|
cursor.position.y()},
|
||||||
@@ -984,7 +1014,10 @@ void TerminalView::updateViewport()
|
|||||||
|
|
||||||
void TerminalView::updateViewportRect(const QRect &rect)
|
void TerminalView::updateViewportRect(const QRect &rect)
|
||||||
{
|
{
|
||||||
viewport()->update(rect);
|
if (d->m_passwordModeActive)
|
||||||
|
viewport()->update();
|
||||||
|
else
|
||||||
|
viewport()->update(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalView::focusInEvent(QFocusEvent *)
|
void TerminalView::focusInEvent(QFocusEvent *)
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ public:
|
|||||||
void setSurfaceIntegration(SurfaceIntegration *surfaceIntegration);
|
void setSurfaceIntegration(SurfaceIntegration *surfaceIntegration);
|
||||||
void setColors(const std::array<QColor, 20> &colors);
|
void setColors(const std::array<QColor, 20> &colors);
|
||||||
|
|
||||||
|
void setPasswordMode(bool passwordMode);
|
||||||
|
|
||||||
struct Link
|
struct Link
|
||||||
{
|
{
|
||||||
QString text;
|
QString text;
|
||||||
|
|||||||
@@ -410,6 +410,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
connect(m_ptyProcess->notifier(), &QIODevice::readyRead, this, [this] {
|
connect(m_ptyProcess->notifier(), &QIODevice::readyRead, this, [this] {
|
||||||
|
if (m_setup.m_ptyData->ptyInputFlagsChangedHandler()
|
||||||
|
&& m_inputFlags != m_ptyProcess->inputFlags()) {
|
||||||
|
m_inputFlags = m_ptyProcess->inputFlags();
|
||||||
|
m_setup.m_ptyData->ptyInputFlagsChangedHandler()(
|
||||||
|
static_cast<Pty::PtyInputFlag>(m_inputFlags.toInt()));
|
||||||
|
}
|
||||||
|
|
||||||
emit readyRead(m_ptyProcess->readAll(), {});
|
emit readyRead(m_ptyProcess->readAll(), {});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -430,6 +437,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<IPtyProcess> m_ptyProcess;
|
std::unique_ptr<IPtyProcess> m_ptyProcess;
|
||||||
|
IPtyProcess::PtyInputFlags m_inputFlags;
|
||||||
};
|
};
|
||||||
|
|
||||||
class QProcessImpl final : public DefaultImpl
|
class QProcessImpl final : public DefaultImpl
|
||||||
|
|||||||
@@ -18,12 +18,19 @@ namespace Internal { class ProcessPrivate; }
|
|||||||
|
|
||||||
namespace Pty {
|
namespace Pty {
|
||||||
|
|
||||||
|
enum PtyInputFlag {
|
||||||
|
None = 0x0,
|
||||||
|
InputModeHidden = 0x1,
|
||||||
|
};
|
||||||
|
|
||||||
using ResizeHandler = std::function<void(const QSize &)>;
|
using ResizeHandler = std::function<void(const QSize &)>;
|
||||||
|
using PtyInputFlagsChangeHandler = std::function<void(PtyInputFlag)>;
|
||||||
|
|
||||||
class QTCREATOR_UTILS_EXPORT SharedData
|
class QTCREATOR_UTILS_EXPORT SharedData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ResizeHandler m_handler;
|
ResizeHandler m_handler;
|
||||||
|
PtyInputFlagsChangeHandler m_inputFlagsChangedHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
class QTCREATOR_UTILS_EXPORT Data
|
class QTCREATOR_UTILS_EXPORT Data
|
||||||
@@ -32,6 +39,15 @@ public:
|
|||||||
Data() : m_data(new SharedData) {}
|
Data() : m_data(new SharedData) {}
|
||||||
|
|
||||||
void setResizeHandler(const ResizeHandler &handler) { m_data->m_handler = handler; }
|
void setResizeHandler(const ResizeHandler &handler) { m_data->m_handler = handler; }
|
||||||
|
void setPtyInputFlagsChangedHandler(const PtyInputFlagsChangeHandler &handler)
|
||||||
|
{
|
||||||
|
m_data->m_inputFlagsChangedHandler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
PtyInputFlagsChangeHandler ptyInputFlagsChangedHandler() const
|
||||||
|
{
|
||||||
|
return m_data->m_inputFlagsChangedHandler;
|
||||||
|
}
|
||||||
|
|
||||||
QSize size() const { return m_size; }
|
QSize size() const { return m_size; }
|
||||||
void resize(const QSize &size);
|
void resize(const QSize &size);
|
||||||
|
|||||||
@@ -126,7 +126,12 @@ void TerminalWidget::setupPty()
|
|||||||
env.unset("CLINK_NOAUTORUN");
|
env.unset("CLINK_NOAUTORUN");
|
||||||
|
|
||||||
m_process->setProcessMode(ProcessMode::Writer);
|
m_process->setProcessMode(ProcessMode::Writer);
|
||||||
m_process->setPtyData(Utils::Pty::Data());
|
Utils::Pty::Data data;
|
||||||
|
data.setPtyInputFlagsChangedHandler([this](Pty::PtyInputFlag flags) {
|
||||||
|
const bool password = (flags & Pty::InputModeHidden);
|
||||||
|
setPasswordMode(password);
|
||||||
|
});
|
||||||
|
m_process->setPtyData(data);
|
||||||
m_process->setCommand(shellCommand);
|
m_process->setCommand(shellCommand);
|
||||||
if (m_openParameters.workingDirectory.has_value())
|
if (m_openParameters.workingDirectory.has_value())
|
||||||
m_process->setWorkingDirectory(*m_openParameters.workingDirectory);
|
m_process->setWorkingDirectory(*m_openParameters.workingDirectory);
|
||||||
|
|||||||
@@ -3716,6 +3716,31 @@
|
|||||||
id="use6090"
|
id="use6090"
|
||||||
transform="rotate(180,2008,576)" />
|
transform="rotate(180,2008,576)" />
|
||||||
</g>
|
</g>
|
||||||
|
<g
|
||||||
|
id="src/libs/solutions/terminal/images/passwordlock"
|
||||||
|
transform="translate(-5,4)">
|
||||||
|
<use
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
xlink:href="#transparentBackgroundRect"
|
||||||
|
id="use1"
|
||||||
|
transform="matrix(2.5,0,0,4,586,-1405)" />
|
||||||
|
<path
|
||||||
|
style="opacity:0.75;fill:#ffffff"
|
||||||
|
d="m 582,423 v -5 c 0,-4 -4,-15 -16,-15 -12,-0.0312 -16,11 -16,15 0,4 0,5 0,5 h -4 v 36 h 40 v -36 z"
|
||||||
|
id="path167"
|
||||||
|
sodipodi:nodetypes="czzzcccccc" />
|
||||||
|
<path
|
||||||
|
style="display:inline;fill:#000000;fill-opacity:1;stroke-width:4"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
d="m 566,407 c -6.624,0 -12,5.372 -12,12 v 12 h 4 v -12 c 0,-4.412 3.584,-8 8,-8 4.412,0 8,3.588 8,8 v 12 h 4 v -12 c 0,-6.628 -5.372,-12 -12,-12 z"
|
||||||
|
id="lockbow-1" />
|
||||||
|
<path
|
||||||
|
style="display:inline;fill:#000000;fill-opacity:1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
d="m 550,427 v 28 h 32 v -28 z m 18,15.388 V 447 h -4 v -4.612 c -1.172,-0.7 -2,-1.92 -2,-3.388 0,-2.212 1.792,-4 4,-4 2.208,0 4,1.788 4,4 0,1.464 -0.828,2.688 -2,3.388 z"
|
||||||
|
id="lockbody-1" />
|
||||||
|
</g>
|
||||||
</g>
|
</g>
|
||||||
<g
|
<g
|
||||||
inkscape:groupmode="layer"
|
inkscape:groupmode="layer"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 365 KiB After Width: | Height: | Size: 366 KiB |
Reference in New Issue
Block a user