or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

atr-card-types.mdcard-connections.mdgui-components.mdindex.mdmonitoring.mdpcsc-interface.mdreader-management.mdsession-api.mdstatus-word-handling.mdutilities.md

gui-components.mddocs/

0

# GUI Components

1

2

wxPython-based graphical user interface components for building smart card applications with visual elements. These components provide ready-to-use GUI building blocks for smart card applications.

3

4

## Capabilities

5

6

### Core GUI Utilities

7

8

Basic utilities and constants for smart card GUI applications.

9

10

```python { .api }

11

def main_is_frozen():

12

"""

13

Detect if the application is running from a frozen executable (py2exe, PyInstaller, etc.).

14

15

Returns:

16

bool: True if running from frozen executable, False otherwise

17

"""

18

19

# Icon constants

20

ICO_SMARTCARD: str # Path to smartcard icon resource

21

ICO_READER: str # Path to reader icon resource

22

```

23

24

### Application Framework

25

26

Base classes for creating smart card applications with wxPython.

27

28

```python { .api }

29

class SimpleSCardApp:

30

"""

31

Base class for simple smart card applications.

32

Provides basic application framework with card monitoring.

33

"""

34

35

class SimpleSCardAppFrame:

36

"""

37

Main application frame for smart card applications.

38

Provides standard menu bar and status bar.

39

"""

40

41

class SimpleSCardAppEventObserver:

42

"""

43

Event observer for smart card application events.

44

Handles card insertion/removal events in GUI context.

45

"""

46

```

47

48

### Visual Components

49

50

Ready-to-use wxPython panels and controls for smart card applications.

51

52

```python { .api }

53

class APDUTracerPanel:

54

"""

55

Panel for displaying APDU command and response traces.

56

Provides formatted display of smart card communication.

57

58

Features:

59

- Command/response logging

60

- Hex and ASCII display modes

61

- Export functionality

62

- Search and filtering

63

"""

64

65

class CardAndReaderTreePanel:

66

"""

67

Tree control panel showing readers and inserted cards.

68

Provides hierarchical view of smart card system.

69

70

Features:

71

- Reader enumeration

72

- Card detection display

73

- ATR information

74

- Context menus

75

"""

76

77

class ReaderToolbar:

78

"""

79

Toolbar with common reader operations.

80

Provides quick access to reader functions.

81

82

Features:

83

- Reader selection

84

- Connect/disconnect buttons

85

- Status indicators

86

"""

87

```

88

89

### Input Validation

90

91

Specialized validators for smart card data input.

92

93

```python { .api }

94

class APDUHexValidator:

95

"""

96

wxPython validator for APDU hexadecimal input.

97

Ensures only valid hex characters and proper APDU format.

98

99

Features:

100

- Hex character validation

101

- Automatic spacing

102

- Length checking

103

- Invalid character filtering

104

"""

105

```

106

107

## Usage Examples

108

109

### Basic Smart Card Application

110

111

```python

112

import wx

113

from smartcard.wx import SimpleSCardAppFrame, main_is_frozen

114

from smartcard.CardMonitoring import CardMonitor, CardObserver

115

from smartcard.util import toHexString

116

117

class MyCardObserver(CardObserver):

118

def __init__(self, frame):

119

self.frame = frame

120

121

def update(self, observable, actions):

122

"""Handle card insertion/removal events in GUI."""

123

(addedcards, removedcards) = actions

124

125

# Update GUI in main thread

126

wx.CallAfter(self.update_gui, addedcards, removedcards)

127

128

def update_gui(self, addedcards, removedcards):

129

for card in addedcards:

130

self.frame.log_message(f"Card inserted: {toHexString(card.atr)}")

131

for card in removedcards:

132

self.frame.log_message(f"Card removed: {toHexString(card.atr)}")

133

134

class SmartCardApp(wx.App):

135

def OnInit(self):

136

# Create main frame

137

frame = SimpleSCardAppFrame(None, "Smart Card Application")

138

139

# Set up card monitoring

140

self.monitor = CardMonitor()

141

self.observer = MyCardObserver(frame)

142

self.monitor.addObserver(self.observer)

143

144

frame.Show()

145

return True

146

147

def OnExit(self):

148

# Clean up monitoring

149

if hasattr(self, 'monitor'):

150

self.monitor.deleteObserver(self.observer)

151

152

# Application entry point

153

if __name__ == '__main__':

154

app = SmartCardApp()

155

app.MainLoop()

156

```

157

158

### APDU Tracer Application

159

160

```python

161

import wx

162

from smartcard.wx import APDUTracerPanel

163

from smartcard import Session

164

from smartcard.util import toHexString

165

166

class APDUTracerFrame(wx.Frame):

167

def __init__(self):

168

super().__init__(None, title="APDU Tracer", size=(800, 600))

169

170

# Create main panel

171

self.panel = wx.Panel(self)

172

173

# Create APDU tracer panel

174

self.tracer = APDUTracerPanel(self.panel)

175

176

# Create input panel

177

input_panel = wx.Panel(self.panel)

178

input_sizer = wx.BoxSizer(wx.HORIZONTAL)

179

180

wx.StaticText(input_panel, label="APDU:")

181

self.apdu_input = wx.TextCtrl(input_panel, value="00 A4 00 00")

182

send_btn = wx.Button(input_panel, label="Send")

183

send_btn.Bind(wx.EVT_BUTTON, self.on_send_apdu)

184

185

input_sizer.Add(wx.StaticText(input_panel, label="APDU:"), 0, wx.ALL|wx.CENTER, 5)

186

input_sizer.Add(self.apdu_input, 1, wx.ALL|wx.EXPAND, 5)

187

input_sizer.Add(send_btn, 0, wx.ALL, 5)

188

input_panel.SetSizer(input_sizer)

189

190

# Layout

191

main_sizer = wx.BoxSizer(wx.VERTICAL)

192

main_sizer.Add(self.tracer, 1, wx.ALL|wx.EXPAND, 5)

193

main_sizer.Add(input_panel, 0, wx.ALL|wx.EXPAND, 5)

194

self.panel.SetSizer(main_sizer)

195

196

# Initialize session

197

try:

198

self.session = Session()

199

self.tracer.add_trace("Session", "Connected to first reader")

200

except Exception as e:

201

self.tracer.add_trace("Error", f"Failed to connect: {e}")

202

self.session = None

203

204

def on_send_apdu(self, event):

205

"""Send APDU command and display in tracer."""

206

if not self.session:

207

self.tracer.add_trace("Error", "No session available")

208

return

209

210

try:

211

# Parse hex input

212

apdu_text = self.apdu_input.GetValue()

213

apdu_bytes = [int(x, 16) for x in apdu_text.split()]

214

215

# Send command

216

self.tracer.add_trace("Command", toHexString(apdu_bytes))

217

response, sw1, sw2 = self.session.sendCommandAPDU(apdu_bytes)

218

219

# Display response

220

if response:

221

self.tracer.add_trace("Response", f"{toHexString(response)} {sw1:02X} {sw2:02X}")

222

else:

223

self.tracer.add_trace("Response", f"{sw1:02X} {sw2:02X}")

224

225

except ValueError:

226

self.tracer.add_trace("Error", "Invalid hex input")

227

except Exception as e:

228

self.tracer.add_trace("Error", f"Command failed: {e}")

229

230

def __del__(self):

231

if hasattr(self, 'session') and self.session:

232

self.session.close()

233

234

class APDUTracerApp(wx.App):

235

def OnInit(self):

236

frame = APDUTracerFrame()

237

frame.Show()

238

return True

239

240

if __name__ == '__main__':

241

app = APDUTracerApp()

242

app.MainLoop()

243

```

244

245

### Reader and Card Tree View

246

247

```python

248

import wx

249

from smartcard.wx import CardAndReaderTreePanel

250

from smartcard.System import readers

251

from smartcard.CardMonitoring import CardMonitor, CardObserver

252

253

class ReaderCardFrame(wx.Frame):

254

def __init__(self):

255

super().__init__(None, title="Readers and Cards", size=(400, 500))

256

257

# Create tree panel

258

self.tree_panel = CardAndReaderTreePanel(self)

259

260

# Create context menu

261

self.create_context_menu()

262

263

# Set up card monitoring

264

self.monitor = CardMonitor()

265

self.observer = TreeCardObserver(self.tree_panel)

266

self.monitor.addObserver(self.observer)

267

268

# Initial population

269

self.refresh_tree()

270

271

# Layout

272

sizer = wx.BoxSizer(wx.VERTICAL)

273

sizer.Add(self.tree_panel, 1, wx.EXPAND)

274

self.SetSizer(sizer)

275

276

def create_context_menu(self):

277

"""Create context menu for tree items."""

278

menu = wx.Menu()

279

menu.Append(wx.ID_REFRESH, "Refresh")

280

menu.Append(wx.ID_PROPERTIES, "Properties")

281

282

self.Bind(wx.EVT_MENU, self.on_refresh, id=wx.ID_REFRESH)

283

self.Bind(wx.EVT_MENU, self.on_properties, id=wx.ID_PROPERTIES)

284

285

self.tree_panel.Bind(wx.EVT_CONTEXT_MENU,

286

lambda evt: self.PopupMenu(menu))

287

288

def refresh_tree(self):

289

"""Refresh the reader/card tree."""

290

self.tree_panel.clear()

291

292

# Add readers

293

for reader in readers():

294

self.tree_panel.add_reader(reader)

295

296

# Try to detect cards

297

try:

298

connection = reader.createConnection()

299

connection.connect()

300

atr = connection.getATR()

301

self.tree_panel.add_card_to_reader(reader, atr)

302

connection.disconnect()

303

except:

304

pass # No card present

305

306

def on_refresh(self, event):

307

self.refresh_tree()

308

309

def on_properties(self, event):

310

selected_item = self.tree_panel.get_selected_item()

311

if selected_item:

312

# Show properties dialog

313

dlg = wx.MessageDialog(self, f"Properties: {selected_item}",

314

"Item Properties", wx.OK)

315

dlg.ShowModal()

316

dlg.Destroy()

317

318

def __del__(self):

319

if hasattr(self, 'monitor'):

320

self.monitor.deleteObserver(self.observer)

321

322

class TreeCardObserver(CardObserver):

323

def __init__(self, tree_panel):

324

self.tree_panel = tree_panel

325

326

def update(self, observable, actions):

327

(addedcards, removedcards) = actions

328

329

# Update tree in main thread

330

wx.CallAfter(self.update_tree, addedcards, removedcards)

331

332

def update_tree(self, addedcards, removedcards):

333

for card in addedcards:

334

self.tree_panel.add_card_to_reader(card.reader, card.atr)

335

for card in removedcards:

336

self.tree_panel.remove_card_from_reader(card.reader)

337

338

class ReaderCardApp(wx.App):

339

def OnInit(self):

340

frame = ReaderCardFrame()

341

frame.Show()

342

return True

343

344

if __name__ == '__main__':

345

app = ReaderCardApp()

346

app.MainLoop()

347

```

348

349

### APDU Input Validation

350

351

```python

352

import wx

353

from smartcard.wx import APDUHexValidator

354

355

class APDUInputFrame(wx.Frame):

356

def __init__(self):

357

super().__init__(None, title="APDU Input Validation", size=(500, 300))

358

359

panel = wx.Panel(self)

360

361

# Create validated text controls

362

wx.StaticText(panel, label="APDU Command (Hex):")

363

self.apdu_ctrl = wx.TextCtrl(panel, size=(300, -1))

364

self.apdu_ctrl.SetValidator(APDUHexValidator())

365

366

wx.StaticText(panel, label="Expected Response Length:")

367

self.len_ctrl = wx.TextCtrl(panel)

368

369

# Buttons

370

validate_btn = wx.Button(panel, label="Validate")

371

clear_btn = wx.Button(panel, label="Clear")

372

373

validate_btn.Bind(wx.EVT_BUTTON, self.on_validate)

374

clear_btn.Bind(wx.EVT_BUTTON, self.on_clear)

375

376

# Status

377

self.status = wx.StaticText(panel, label="Enter APDU command...")

378

379

# Layout

380

sizer = wx.BoxSizer(wx.VERTICAL)

381

sizer.Add(wx.StaticText(panel, label="APDU Command (Hex):"), 0, wx.ALL, 5)

382

sizer.Add(self.apdu_ctrl, 0, wx.ALL|wx.EXPAND, 5)

383

sizer.Add(wx.StaticText(panel, label="Expected Response Length:"), 0, wx.ALL, 5)

384

sizer.Add(self.len_ctrl, 0, wx.ALL, 5)

385

386

btn_sizer = wx.BoxSizer(wx.HORIZONTAL)

387

btn_sizer.Add(validate_btn, 0, wx.ALL, 5)

388

btn_sizer.Add(clear_btn, 0, wx.ALL, 5)

389

sizer.Add(btn_sizer, 0, wx.ALL, 5)

390

391

sizer.Add(self.status, 0, wx.ALL, 5)

392

393

panel.SetSizer(sizer)

394

395

def on_validate(self, event):

396

"""Validate APDU input."""

397

try:

398

apdu_text = self.apdu_ctrl.GetValue()

399

if not apdu_text.strip():

400

self.status.SetLabel("❌ Empty APDU")

401

return

402

403

# Parse hex bytes

404

bytes_list = [int(x, 16) for x in apdu_text.split()]

405

406

# Basic APDU validation

407

if len(bytes_list) < 4:

408

self.status.SetLabel("❌ APDU too short (minimum 4 bytes)")

409

return

410

411

if len(bytes_list) > 255:

412

self.status.SetLabel("❌ APDU too long (maximum 255 bytes)")

413

return

414

415

cla, ins, p1, p2 = bytes_list[:4]

416

417

# Validate structure

418

if len(bytes_list) == 4:

419

apdu_type = "Case 1 (no data, no response)"

420

elif len(bytes_list) == 5:

421

le = bytes_list[4]

422

apdu_type = f"Case 2 (no data, Le={le})"

423

elif len(bytes_list) > 5:

424

lc = bytes_list[4]

425

if len(bytes_list) == 5 + lc:

426

apdu_type = f"Case 3 (Lc={lc}, no response)"

427

elif len(bytes_list) == 6 + lc:

428

le = bytes_list[-1]

429

apdu_type = f"Case 4 (Lc={lc}, Le={le})"

430

else:

431

self.status.SetLabel("❌ Invalid APDU structure")

432

return

433

434

self.status.SetLabel(f"✅ Valid APDU: {apdu_type}")

435

436

except ValueError:

437

self.status.SetLabel("❌ Invalid hex characters")

438

except Exception as e:

439

self.status.SetLabel(f"❌ Validation error: {e}")

440

441

def on_clear(self, event):

442

"""Clear all inputs."""

443

self.apdu_ctrl.Clear()

444

self.len_ctrl.Clear()

445

self.status.SetLabel("Enter APDU command...")

446

447

class APDUInputApp(wx.App):

448

def OnInit(self):

449

frame = APDUInputFrame()

450

frame.Show()

451

return True

452

453

if __name__ == '__main__':

454

app = APDUInputApp()

455

app.MainLoop()

456

```

457

458

## Installation Note

459

460

The GUI components require wxPython to be installed:

461

462

```bash

463

pip install pyscard[Gui]

464

# or

465

pip install wxPython

466

```

467

468

## Related Types

469

470

```python { .api }

471

# wxPython-based types (require wxPython installation)

472

wx.Panel # Base panel class

473

wx.Frame # Base frame class

474

wx.App # Application class

475

wx.Validator # Input validator base class

476

477

# GUI event types

478

wx.Event # Base event class

479

wx.CommandEvent # Command event class

480

481

# Icon resource types

482

IconResource = str # Path to icon file

483

```