7#include <QtCore/QLoggingCategory>
8#include <QtCore/QThread>
9#include <QtCore/QTimer>
21 m_stateUpdateTimer =
new QTimer(
this);
31 for (
auto slot : std::as_const(m_slots))
32 slot->invalidateInsertedCard();
33 SCardReleaseContext(m_context);
40void QPcscManager::processSlotUpdates()
42 for (
auto &
state : m_slotStates) {
46 if ((
state.dwEventState & SCARD_STATE_UNKNOWN) != 0)
49 if (
state.dwEventState ==
state.dwCurrentState)
56 slot->processStateChange(
state.dwEventState, m_targetDetectionRunning);
63void QPcscManager::removeSlots()
65 for (
auto &
state : m_slotStates) {
71 if ((
state.dwEventState & SCARD_STATE_UNKNOWN) != 0
72 || !(m_targetDetectionRunning || slot->hasCard())) {
73 qCDebug(QT_NFC_PCSC) <<
"Removing slot:" << slot;
74 state.dwEventState = SCARD_STATE_UNKNOWN;
75 slot->invalidateInsertedCard();
76 m_slots.
remove(slot->name());
78 state.pvUserData =
nullptr;
84 [](
const auto &
state) {
return (
state.dwEventState & SCARD_STATE_UNKNOWN) != 0; });
91void QPcscManager::updateSlotList()
95#ifndef SCARD_AUTOALLOCATE
98#define LIST_READER_BUFFER_EXTRA 1024
101 buf.resize(listSize);
104 auto ret = SCardListReaders(m_context,
nullptr,
list, &listSize);
107 DWORD listSize = SCARD_AUTOALLOCATE;
112 if (
ret == LONG(SCARD_E_NO_READERS_AVAILABLE)) {
114 ret = SCARD_S_SUCCESS;
116#ifndef SCARD_AUTOALLOCATE
117 else if (
ret == LONG(SCARD_E_INSUFFICIENT_BUFFER)) {
122 buf.resize(listSize);
125 ret = SCardListReaders(m_context,
nullptr,
list, &listSize);
126 if (
ret == LONG(SCARD_E_NO_READERS_AVAILABLE)) {
128 ret = SCARD_S_SUCCESS;
131#undef LIST_READER_BUFFER_EXTRA
134 if (
ret != SCARD_S_SUCCESS) {
139#ifdef SCARD_AUTOALLOCATE
143 SCardFreeMemory(m_context,
list);
150 if (
list !=
nullptr) {
157 for (
auto &
state : m_slotStates) {
161 if (presentSlots.contains(slot->name()))
162 presentSlots.remove(slot->name());
164 state.dwEventState = SCARD_STATE_UNKNOWN;
167 if (!m_targetDetectionRunning)
171 for (
auto &&slotName :
std::as_const(presentSlots)) {
173 qCDebug(QT_NFC_PCSC) <<
"New slot:" << slot;
175 m_slots[slotName] = slot;
177 SCARD_READERSTATE
state {};
178 state.pvUserData = slot;
180 state.dwCurrentState = SCARD_STATE_UNAWARE;
186bool QPcscManager::establishContext()
192 LONG
ret = SCardEstablishContext(SCARD_SCOPE_USER,
nullptr,
nullptr, &m_context);
193 if (
ret != SCARD_S_SUCCESS) {
202void QPcscManager::onStateUpdate()
205 if (!m_targetDetectionRunning) {
206 m_stateUpdateTimer->
stop();
210 if (!establishContext())
218 if (!m_targetDetectionRunning) {
220 SCardReleaseContext(m_context);
221 m_hasContext =
false;
223 m_stateUpdateTimer->
stop();
238 LONG
ret = SCardGetStatusChange(m_context, 0, m_slotStates.
data(), m_slotStates.
size());
240 if (
ret == SCARD_S_SUCCESS ||
ret == LONG(SCARD_E_UNKNOWN_READER)) {
241 processSlotUpdates();
243 }
else if (
ret == LONG(SCARD_E_CANCELLED) ||
ret == LONG(SCARD_E_UNKNOWN_READER)
244 ||
ret == LONG(SCARD_E_TIMEOUT)) {
253 m_hasContext =
false;
254 for (
auto slot :
std::as_const(m_slots)) {
258 SCardReleaseContext(m_context);
260 m_slotStates.
clear();
268 m_requestedMethod = accessMethod;
270 if (m_targetDetectionRunning)
273 m_targetDetectionRunning =
true;
274 m_stateUpdateTimer->
start();
280 m_targetDetectionRunning =
false;
289 SCARDHANDLE cardHandle;
290 DWORD activeProtocol;
292 LONG
ret = SCardConnect(m_context, slot->
name().
ptr(), SCARD_SHARE_SHARED,
293 SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &cardHandle, &activeProtocol);
294 if (
ret != SCARD_S_SUCCESS) {
296 retryCardDetection(slot);
300 auto card =
new QPcscCard(cardHandle, activeProtocol,
this);
301 auto uid = card->readUid();
302 auto maxInputLength = card->readMaxInputLength();
305 if (card->supportsNdef())
309 && (accessMethods & m_requestedMethod) == 0) {
310 qCDebug(QT_NFC_PCSC) <<
"Dropping card without required access support";
315 if (!card->isValid()) {
316 qCDebug(QT_NFC_PCSC) <<
"Card became invalid";
319 retryCardDetection(slot);
335void QPcscManager::retryCardDetection(
const QPcscSlot *slot)
339 for (
auto &
state : m_slotStates) {
340 if (
state.pvUserData == slot) {
341 state.dwCurrentState = SCARD_STATE_UNAWARE;
qsizetype size() const noexcept
bool isEmpty() const noexcept
qsizetype removeIf(Predicate pred)
void append(parameter_type t)
size_type remove(const Key &key)
AccessMethod
This enum describes the access methods a near field target supports.
QThread * thread() const
Returns the thread in which the object lives.
void deleteLater()
\threadsafe
void onStartTargetDetectionRequest(QNearFieldTarget::AccessMethod accessMethod)
void onStopTargetDetectionRequest()
void cardInserted(QPcscCard *card, const QByteArray &uid, QNearFieldTarget::AccessMethods accessMethods, int maxInputLength)
QPcscCard * connectToCard(QPcscSlot *slot)
CPtr ptr() const noexcept
static qsizetype nameSize(CPtr p)
void invalidateInsertedCard()
const QPcscSlotName & name() const
iterator insert(const T &value)
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
void stop()
Stops the timer.
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
QString errorMessage(LONG error)
Combined button and popup list for selecting options.
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
GLenum GLuint GLenum GLsizei const GLchar * buf
#define LIST_READER_BUFFER_EXTRA
static QT_BEGIN_NAMESPACE constexpr int StateUpdateIntervalMs
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent