psiemu 0.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- psiemu-0.0.0/LICENSE +21 -0
- psiemu-0.0.0/PKG-INFO +38 -0
- psiemu-0.0.0/README.md +29 -0
- psiemu-0.0.0/pyproject.toml +16 -0
- psiemu-0.0.0/setup.cfg +4 -0
- psiemu-0.0.0/src/__init__.py +23 -0
- psiemu-0.0.0/src/__main__.py +33 -0
- psiemu-0.0.0/src/psiemu.egg-info/PKG-INFO +38 -0
- psiemu-0.0.0/src/psiemu.egg-info/SOURCES.txt +11 -0
- psiemu-0.0.0/src/psiemu.egg-info/dependency_links.txt +1 -0
- psiemu-0.0.0/src/psiemu.egg-info/entry_points.txt +2 -0
- psiemu-0.0.0/src/psiemu.egg-info/top_level.txt +3 -0
- psiemu-0.0.0/src/psiemu.py +512 -0
psiemu-0.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Jason Morley
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
psiemu-0.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: psiemu
|
|
3
|
+
Version: 0.0.0
|
|
4
|
+
Author-email: Jason Morley <hello@jbmorley.co.uk>
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Dynamic: license-file
|
|
9
|
+
|
|
10
|
+
# PsiEmu
|
|
11
|
+
|
|
12
|
+
Lightweight TUI launcher for Psion MAME emulators.
|
|
13
|
+
|
|
14
|
+

|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
git clone ssh://git@codeberg.org/psion/psiemu.git
|
|
20
|
+
cd psiemu
|
|
21
|
+
|
|
22
|
+
export PSIEMU_ROM_PATH=~/path/to/roms
|
|
23
|
+
./psiemu
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Development
|
|
27
|
+
|
|
28
|
+
Print specific details of MAME systems using `-listroms` and `-listbios`. For exmaple,
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
$ mame psion3mx_fr -listbios Chii
|
|
32
|
+
BIOS options for system Series 3mx (French) (psion3mx_fr):
|
|
33
|
+
620f V6.20F/FRE
|
|
34
|
+
$ mame psion3mx_fr -listroms Chii
|
|
35
|
+
ROMs required for driver "psion3mx_fr".
|
|
36
|
+
Name Size Checksum
|
|
37
|
+
maple_v6.20f_fre.bin 2097152 CRC(b4fc57f4) SHA1(26588937d811adf08b973a0188927707d1f6a6e4)
|
|
38
|
+
```
|
psiemu-0.0.0/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# PsiEmu
|
|
2
|
+
|
|
3
|
+
Lightweight TUI launcher for Psion MAME emulators.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
git clone ssh://git@codeberg.org/psion/psiemu.git
|
|
11
|
+
cd psiemu
|
|
12
|
+
|
|
13
|
+
export PSIEMU_ROM_PATH=~/path/to/roms
|
|
14
|
+
./psiemu
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Development
|
|
18
|
+
|
|
19
|
+
Print specific details of MAME systems using `-listroms` and `-listbios`. For exmaple,
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
$ mame psion3mx_fr -listbios Chii
|
|
23
|
+
BIOS options for system Series 3mx (French) (psion3mx_fr):
|
|
24
|
+
620f V6.20F/FRE
|
|
25
|
+
$ mame psion3mx_fr -listroms Chii
|
|
26
|
+
ROMs required for driver "psion3mx_fr".
|
|
27
|
+
Name Size Checksum
|
|
28
|
+
maple_v6.20f_fre.bin 2097152 CRC(b4fc57f4) SHA1(26588937d811adf08b973a0188927707d1f6a6e4)
|
|
29
|
+
```
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta:__legacy__"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "psiemu"
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
license = "MIT"
|
|
9
|
+
authors = [
|
|
10
|
+
{name = "Jason Morley", email = "hello@jbmorley.co.uk"}
|
|
11
|
+
]
|
|
12
|
+
dependencies = []
|
|
13
|
+
dynamic = ["version"]
|
|
14
|
+
|
|
15
|
+
[project.scripts]
|
|
16
|
+
psiemu = "src.psiemu:main"
|
psiemu-0.0.0/setup.cfg
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2025 Jason Morley
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
# copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
# SOFTWARE.
|
|
22
|
+
|
|
23
|
+
from . import *
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Copyright (c) 2025 Jason Morley
|
|
2
|
+
#
|
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
# furnished to do so, subject to the following conditions:
|
|
9
|
+
#
|
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
# copies or substantial portions of the Software.
|
|
12
|
+
#
|
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
# SOFTWARE.
|
|
20
|
+
|
|
21
|
+
import os
|
|
22
|
+
import sys
|
|
23
|
+
|
|
24
|
+
if not __package__:
|
|
25
|
+
# Make CLI runnable from source tree with
|
|
26
|
+
# python src/package
|
|
27
|
+
package_source_path = os.path.dirname(os.path.dirname(__file__))
|
|
28
|
+
sys.path.insert(0, package_source_path)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
if __name__ == "__main__":
|
|
32
|
+
from src.psiemu import main
|
|
33
|
+
main()
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: psiemu
|
|
3
|
+
Version: 0.0.0
|
|
4
|
+
Author-email: Jason Morley <hello@jbmorley.co.uk>
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Dynamic: license-file
|
|
9
|
+
|
|
10
|
+
# PsiEmu
|
|
11
|
+
|
|
12
|
+
Lightweight TUI launcher for Psion MAME emulators.
|
|
13
|
+
|
|
14
|
+

|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
git clone ssh://git@codeberg.org/psion/psiemu.git
|
|
20
|
+
cd psiemu
|
|
21
|
+
|
|
22
|
+
export PSIEMU_ROM_PATH=~/path/to/roms
|
|
23
|
+
./psiemu
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Development
|
|
27
|
+
|
|
28
|
+
Print specific details of MAME systems using `-listroms` and `-listbios`. For exmaple,
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
$ mame psion3mx_fr -listbios Chii
|
|
32
|
+
BIOS options for system Series 3mx (French) (psion3mx_fr):
|
|
33
|
+
620f V6.20F/FRE
|
|
34
|
+
$ mame psion3mx_fr -listroms Chii
|
|
35
|
+
ROMs required for driver "psion3mx_fr".
|
|
36
|
+
Name Size Checksum
|
|
37
|
+
maple_v6.20f_fre.bin 2097152 CRC(b4fc57f4) SHA1(26588937d811adf08b973a0188927707d1f6a6e4)
|
|
38
|
+
```
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/__init__.py
|
|
5
|
+
src/__main__.py
|
|
6
|
+
src/psiemu.py
|
|
7
|
+
src/psiemu.egg-info/PKG-INFO
|
|
8
|
+
src/psiemu.egg-info/SOURCES.txt
|
|
9
|
+
src/psiemu.egg-info/dependency_links.txt
|
|
10
|
+
src/psiemu.egg-info/entry_points.txt
|
|
11
|
+
src/psiemu.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2025 Jason Morley
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
# copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
# SOFTWARE.
|
|
22
|
+
|
|
23
|
+
import argparse
|
|
24
|
+
import curses
|
|
25
|
+
import os
|
|
26
|
+
import subprocess
|
|
27
|
+
|
|
28
|
+
from dataclasses import dataclass
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
PROFILES = [
|
|
32
|
+
|
|
33
|
+
{
|
|
34
|
+
"name": "Psion",
|
|
35
|
+
"devices": [
|
|
36
|
+
|
|
37
|
+
{
|
|
38
|
+
"id": "psion3",
|
|
39
|
+
"title": "Series 3",
|
|
40
|
+
"resolution": (240, 80),
|
|
41
|
+
"scale": 2,
|
|
42
|
+
"variants": [
|
|
43
|
+
{
|
|
44
|
+
"name": "V1.91F",
|
|
45
|
+
"bios": "191f",
|
|
46
|
+
"languages": [
|
|
47
|
+
"en-GB",
|
|
48
|
+
"fr-FR",
|
|
49
|
+
"de-DE",
|
|
50
|
+
"es-ES",
|
|
51
|
+
"it-IT",
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "V1.80F",
|
|
56
|
+
"bios": "180f",
|
|
57
|
+
"languages": [
|
|
58
|
+
"en-GB",
|
|
59
|
+
"fr-FR",
|
|
60
|
+
"de-DE",
|
|
61
|
+
"it-IT",
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
{
|
|
68
|
+
"id": "psion3s",
|
|
69
|
+
"title": "Series 3s",
|
|
70
|
+
"description": "Series 3 variant with built-in Sheet program",
|
|
71
|
+
"resolution": (240, 80),
|
|
72
|
+
"scale": 2,
|
|
73
|
+
"variants": [
|
|
74
|
+
{
|
|
75
|
+
"name": "V1.91F",
|
|
76
|
+
"bios": "191f",
|
|
77
|
+
"languages": [
|
|
78
|
+
"en-GB",
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
{
|
|
85
|
+
"id": "psion3a",
|
|
86
|
+
"title": "Series 3a (1 MB ROM)",
|
|
87
|
+
"description": "1MB ROM variant of the Series 3a",
|
|
88
|
+
"resolution": (480, 160),
|
|
89
|
+
"variants": [
|
|
90
|
+
{
|
|
91
|
+
"name": "V3.22F",
|
|
92
|
+
"bios": "322f",
|
|
93
|
+
"languages": [
|
|
94
|
+
"en-GB",
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
{
|
|
101
|
+
"id": "psion3a",
|
|
102
|
+
"title": "Series 3a (2 MB ROM)",
|
|
103
|
+
"description": "2MB ROM variant of the Series 3a with built-in Spell and Patience programs",
|
|
104
|
+
"resolution": (480, 160),
|
|
105
|
+
"variants": [
|
|
106
|
+
{
|
|
107
|
+
"name": "V3.40F",
|
|
108
|
+
"id": "psion3a2",
|
|
109
|
+
"bios": "340f",
|
|
110
|
+
"languages": [
|
|
111
|
+
"en-GB",
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"name": "V3.40F",
|
|
116
|
+
"id": "psion3a2_it",
|
|
117
|
+
"bios": "340f",
|
|
118
|
+
"languages": [
|
|
119
|
+
"it-IT",
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"name": "V3.40F",
|
|
124
|
+
"id": "psion3a2_us",
|
|
125
|
+
"bios": "340f",
|
|
126
|
+
"languages": [
|
|
127
|
+
"en-US",
|
|
128
|
+
],
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"name": "V3.41F",
|
|
132
|
+
"id": "psion3a2_de",
|
|
133
|
+
"bios": "341f",
|
|
134
|
+
"languages": [
|
|
135
|
+
"de-DE",
|
|
136
|
+
],
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"name": "V3.43F",
|
|
140
|
+
"id": "psion3a2_ru",
|
|
141
|
+
"bios": "343f",
|
|
142
|
+
"languages": [
|
|
143
|
+
"ru-RU",
|
|
144
|
+
],
|
|
145
|
+
},
|
|
146
|
+
],
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
{
|
|
150
|
+
"id": "psion3c",
|
|
151
|
+
"title": "Series 3c",
|
|
152
|
+
"resolution": (480, 160),
|
|
153
|
+
"variants": [
|
|
154
|
+
{
|
|
155
|
+
"name": "V5.20F",
|
|
156
|
+
"bios": "520f",
|
|
157
|
+
"languages": [
|
|
158
|
+
"en-GB",
|
|
159
|
+
],
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
{
|
|
165
|
+
"title": "Series 3mx",
|
|
166
|
+
"resolution": (480, 160),
|
|
167
|
+
"variants": [
|
|
168
|
+
{
|
|
169
|
+
"name": "V6.16F",
|
|
170
|
+
"id": "psion3mx",
|
|
171
|
+
"bios": "616f",
|
|
172
|
+
"languages": [
|
|
173
|
+
"en-GB",
|
|
174
|
+
],
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"name": "V6.17F",
|
|
178
|
+
"id": "psion3mx_nl",
|
|
179
|
+
"bios": "617f",
|
|
180
|
+
"languages": [
|
|
181
|
+
"nl-NL",
|
|
182
|
+
],
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"name": "V6.20F",
|
|
186
|
+
"id": "psion3mx_fr",
|
|
187
|
+
"bios": "620f",
|
|
188
|
+
"languages": [
|
|
189
|
+
"fr-FR",
|
|
190
|
+
],
|
|
191
|
+
},
|
|
192
|
+
]
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
{
|
|
196
|
+
"title": "Siena",
|
|
197
|
+
"resolution": (240, 160),
|
|
198
|
+
"variants": [
|
|
199
|
+
{
|
|
200
|
+
"name": "V4.20F",
|
|
201
|
+
"id": "siena",
|
|
202
|
+
"bios": "420f",
|
|
203
|
+
"languages": [
|
|
204
|
+
"en-GB",
|
|
205
|
+
],
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"name": "V4.21F",
|
|
209
|
+
"id": "siena_fr",
|
|
210
|
+
"bios": "421f",
|
|
211
|
+
"languages": [
|
|
212
|
+
"fr-FR",
|
|
213
|
+
],
|
|
214
|
+
},
|
|
215
|
+
]
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
{
|
|
219
|
+
"id": "psionwa",
|
|
220
|
+
"title": "Workabout",
|
|
221
|
+
"resolution": (240, 100),
|
|
222
|
+
"variants": [
|
|
223
|
+
{
|
|
224
|
+
"name": "V2.40F",
|
|
225
|
+
"bios": "240f",
|
|
226
|
+
"languages": [
|
|
227
|
+
"en-GB",
|
|
228
|
+
],
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"name": "V1.00F",
|
|
232
|
+
"bios": "100f",
|
|
233
|
+
"languages": [
|
|
234
|
+
"en-GB",
|
|
235
|
+
],
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
"name": "V0.24B",
|
|
239
|
+
"bios": "024b",
|
|
240
|
+
"languages": [
|
|
241
|
+
"en-GB",
|
|
242
|
+
],
|
|
243
|
+
},
|
|
244
|
+
],
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
{
|
|
248
|
+
"id": "psionwamx",
|
|
249
|
+
"title": "Workabout MX",
|
|
250
|
+
"resolution": (240, 100),
|
|
251
|
+
"variants": [
|
|
252
|
+
{
|
|
253
|
+
"name": "V7.20F",
|
|
254
|
+
"bios": "720f",
|
|
255
|
+
"languages": [
|
|
256
|
+
"en-GB",
|
|
257
|
+
],
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
},
|
|
261
|
+
],
|
|
262
|
+
},
|
|
263
|
+
|
|
264
|
+
{
|
|
265
|
+
"name": "Acorn",
|
|
266
|
+
"devices": [
|
|
267
|
+
|
|
268
|
+
{
|
|
269
|
+
"id": "pocketbk",
|
|
270
|
+
"title": "Acorn Pocket Book",
|
|
271
|
+
"resolution": (240, 80),
|
|
272
|
+
"scale": 2,
|
|
273
|
+
"variants": [
|
|
274
|
+
{
|
|
275
|
+
"name": "V1.91F",
|
|
276
|
+
"bios": "191f",
|
|
277
|
+
"languages": [
|
|
278
|
+
"en-GB",
|
|
279
|
+
],
|
|
280
|
+
}
|
|
281
|
+
]
|
|
282
|
+
},
|
|
283
|
+
|
|
284
|
+
{
|
|
285
|
+
"id": "pocketbk2",
|
|
286
|
+
"title": "Acorn Pocket Book II",
|
|
287
|
+
"resolution": (480, 160),
|
|
288
|
+
"variants": [
|
|
289
|
+
{
|
|
290
|
+
"name": "V1.30F",
|
|
291
|
+
"bios": "130f",
|
|
292
|
+
"languages": [
|
|
293
|
+
"en-GB",
|
|
294
|
+
],
|
|
295
|
+
}
|
|
296
|
+
]
|
|
297
|
+
},
|
|
298
|
+
|
|
299
|
+
],
|
|
300
|
+
},
|
|
301
|
+
|
|
302
|
+
]
|
|
303
|
+
|
|
304
|
+
LANGUAGES = {
|
|
305
|
+
"de-DE": {"name": "German", "symbol": "de"},
|
|
306
|
+
"en-GB": {"name": "British English", "symbol": "en"},
|
|
307
|
+
"en-US": {"name": "American English", "symbol": "us"},
|
|
308
|
+
"es-ES": {"name": "Spanish", "symbol": "es"},
|
|
309
|
+
"fr-FR": {"name": "French", "symbol": "fr"},
|
|
310
|
+
"it-IT": {"name": "Italian", "symbol": "it"},
|
|
311
|
+
"nl-NL": {"name": "Dutch", "symbol": "nl"},
|
|
312
|
+
"ru-RU": {"name": "Russian", "symbol": "ru"},
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
NOTES = """Special keys:
|
|
316
|
+
|
|
317
|
+
- Menu -> F11 (Shift + F11 on macOS)
|
|
318
|
+
- Psion -> Alt
|
|
319
|
+
- Help -> F10
|
|
320
|
+
|
|
321
|
+
Silkscreen buttons:
|
|
322
|
+
|
|
323
|
+
- System -> F1
|
|
324
|
+
- Data -> F2
|
|
325
|
+
- Word -> F3
|
|
326
|
+
- Agenda -> F4
|
|
327
|
+
- Time -> F5
|
|
328
|
+
- World -> F6
|
|
329
|
+
- Calc -> F7
|
|
330
|
+
- Sheet -> F8
|
|
331
|
+
|
|
332
|
+
"""
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
@dataclass
|
|
336
|
+
class Selection:
|
|
337
|
+
|
|
338
|
+
vendor: int
|
|
339
|
+
device: int
|
|
340
|
+
variant: int
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def mame_command(profile):
|
|
344
|
+
|
|
345
|
+
command = [
|
|
346
|
+
"mame",
|
|
347
|
+
"-window",
|
|
348
|
+
"-nomaximize",
|
|
349
|
+
"-skip_gameinfo",
|
|
350
|
+
"-rompath", os.environ["PSIEMU_ROM_PATH"],
|
|
351
|
+
profile["id"],
|
|
352
|
+
]
|
|
353
|
+
|
|
354
|
+
if "resolution" in profile:
|
|
355
|
+
device_scale = profile["scale"] if "scale" in profile else 1
|
|
356
|
+
scale = 2 * device_scale # TODO: Detect display scale.
|
|
357
|
+
(width, height) = profile['resolution']
|
|
358
|
+
command.extend([
|
|
359
|
+
"-prescale", "%s" % (scale, ),
|
|
360
|
+
"-resolution", "%dx%d" % (width * scale, height * scale),
|
|
361
|
+
])
|
|
362
|
+
|
|
363
|
+
if "bios" in profile:
|
|
364
|
+
command.extend([
|
|
365
|
+
"-bios", profile["bios"],
|
|
366
|
+
])
|
|
367
|
+
|
|
368
|
+
return command
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def run_mame(profile):
|
|
372
|
+
subprocess.Popen(mame_command(profile),
|
|
373
|
+
start_new_session=True,
|
|
374
|
+
stdout=subprocess.DEVNULL,
|
|
375
|
+
stderr=subprocess.DEVNULL)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def language_symbol(variant):
|
|
379
|
+
languages = variant["languages"]
|
|
380
|
+
if len(languages) > 1:
|
|
381
|
+
return "+ "
|
|
382
|
+
elif len(languages) == 1:
|
|
383
|
+
return LANGUAGES[languages[0]]["symbol"]
|
|
384
|
+
else:
|
|
385
|
+
return " "
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def language_description(variant):
|
|
389
|
+
return ", " .join([LANGUAGES[language]["name"] for language in variant["languages"]])
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
def device_picker(stdscr):
|
|
393
|
+
|
|
394
|
+
def render_device_section(devices, is_section_active, y_pos, selection):
|
|
395
|
+
|
|
396
|
+
for device_index, profile in enumerate(devices):
|
|
397
|
+
title = profile["title"].ljust(22)
|
|
398
|
+
variants = profile["variants"]
|
|
399
|
+
|
|
400
|
+
for variant_index, variant in enumerate(variants):
|
|
401
|
+
name = variant["name"]
|
|
402
|
+
languages = language_symbol(variant)
|
|
403
|
+
# languages = "".join([LANGUAGES[language] for language in variant["languages"]])
|
|
404
|
+
if is_section_active and device_index == selection.device and variant_index == selection.variant:
|
|
405
|
+
name = "-> " + name
|
|
406
|
+
else:
|
|
407
|
+
name = " " + name
|
|
408
|
+
# While it might seem like a good idea to use `ljust` here to ensure these are consistent lengths
|
|
409
|
+
# we're instead relying on `name` being of equal length to avoid bumping into Python's terrible
|
|
410
|
+
# handling of multi-codepoint emoji.
|
|
411
|
+
# In the future, we might want to use 'grapheme' which provides suport for this.
|
|
412
|
+
title += f"{name} {languages} "
|
|
413
|
+
|
|
414
|
+
stdscr.addstr(y_pos + device_index, 0, " " + title)
|
|
415
|
+
|
|
416
|
+
return y_pos + len(devices)
|
|
417
|
+
|
|
418
|
+
curses.use_default_colors()
|
|
419
|
+
curses.curs_set(0)
|
|
420
|
+
|
|
421
|
+
selection = Selection(0, 0, 0)
|
|
422
|
+
|
|
423
|
+
while True:
|
|
424
|
+
|
|
425
|
+
(height, width) = stdscr.getmaxyx()
|
|
426
|
+
stdscr.clear()
|
|
427
|
+
|
|
428
|
+
offset = 0
|
|
429
|
+
for vendor_index, vendor in enumerate(PROFILES):
|
|
430
|
+
stdscr.addstr(offset, 0, vendor["name"])
|
|
431
|
+
offset += render_device_section(devices=vendor["devices"],
|
|
432
|
+
is_section_active=vendor_index == selection.vendor,
|
|
433
|
+
y_pos=offset + 2,
|
|
434
|
+
selection=selection)
|
|
435
|
+
offset += 1
|
|
436
|
+
|
|
437
|
+
# Current selection.
|
|
438
|
+
vendor = PROFILES[selection.vendor]
|
|
439
|
+
devices = vendor["devices"]
|
|
440
|
+
profile = vendor["devices"][selection.device]
|
|
441
|
+
variant = profile["variants"][selection.variant]
|
|
442
|
+
|
|
443
|
+
# Fixup the profile.
|
|
444
|
+
profile["bios"] = variant["bios"]
|
|
445
|
+
if "id" in variant:
|
|
446
|
+
profile["id"] = variant["id"]
|
|
447
|
+
|
|
448
|
+
# Get the command.
|
|
449
|
+
command = mame_command(profile)
|
|
450
|
+
|
|
451
|
+
# Display the description for the current selection.
|
|
452
|
+
stdscr.hline(height - 5, 0, curses.ACS_HLINE, width)
|
|
453
|
+
if "description" in profile:
|
|
454
|
+
stdscr.addstr(height-4, 0, profile["description"])
|
|
455
|
+
stdscr.addstr(height-3, 0, language_description(variant))
|
|
456
|
+
stdscr.addstr(height-2, 0, " ".join(command))
|
|
457
|
+
|
|
458
|
+
# Get and handle input.
|
|
459
|
+
key = stdscr.getch()
|
|
460
|
+
if key == curses.KEY_UP:
|
|
461
|
+
|
|
462
|
+
if selection.device > 0:
|
|
463
|
+
selection.device -= 1
|
|
464
|
+
selection.variant = 0
|
|
465
|
+
elif selection.vendor > 0:
|
|
466
|
+
selection.vendor -= 1
|
|
467
|
+
selection.device = len(PROFILES[selection.vendor]["devices"]) - 1
|
|
468
|
+
selection.variant = 0
|
|
469
|
+
|
|
470
|
+
elif key == curses.KEY_DOWN:
|
|
471
|
+
|
|
472
|
+
if selection.device < len(devices) - 1:
|
|
473
|
+
selection.device += 1
|
|
474
|
+
selection.variant = 0
|
|
475
|
+
elif selection.vendor < len(PROFILES) - 1:
|
|
476
|
+
selection.vendor += 1
|
|
477
|
+
selection.device = 0
|
|
478
|
+
selection.variant = 0
|
|
479
|
+
|
|
480
|
+
elif key == curses.KEY_LEFT:
|
|
481
|
+
|
|
482
|
+
if selection.variant > 0:
|
|
483
|
+
selection.variant -= 1
|
|
484
|
+
|
|
485
|
+
elif key == curses.KEY_RIGHT:
|
|
486
|
+
|
|
487
|
+
variants = profile["variants"]
|
|
488
|
+
if selection.variant < len(variants) - 1:
|
|
489
|
+
selection.variant += 1
|
|
490
|
+
|
|
491
|
+
elif key == ord('\n'):
|
|
492
|
+
|
|
493
|
+
profile["bios"] = variant["bios"]
|
|
494
|
+
if "id" in variant:
|
|
495
|
+
profile["id"] = variant["id"]
|
|
496
|
+
run_mame(profile)
|
|
497
|
+
|
|
498
|
+
elif key == 27 or key == ord('q'):
|
|
499
|
+
|
|
500
|
+
return None
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
def main():
|
|
504
|
+
parser = argparse.ArgumentParser()
|
|
505
|
+
options = parser.parse_args()
|
|
506
|
+
|
|
507
|
+
os.environ.setdefault('ESCDELAY', '25')
|
|
508
|
+
curses.wrapper(lambda stdscr: device_picker(stdscr))
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
if __name__ == "__main__":
|
|
512
|
+
main()
|