Compare commits
1292 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90164dfee7 | ||
|
|
73f641cb66 | ||
|
|
3d51835b9b | ||
|
|
f358d76409 | ||
|
|
ce486e9244 | ||
|
|
691b7215a0 | ||
|
|
5be45d0ff2 | ||
|
|
8a4b326127 | ||
|
|
051374cd55 | ||
|
|
71cd92da29 | ||
|
|
c2d3a0c8b4 | ||
|
|
fe8b151666 | ||
|
|
9e2d67f7a1 | ||
|
|
23ea3745ca | ||
|
|
d8d5a8fada | ||
|
|
21ce0e90bf | ||
|
|
ec420b8012 | ||
|
|
bd67899943 | ||
|
|
4b7600f3a5 | ||
|
|
5eabd69659 | ||
|
|
e83be21756 | ||
|
|
13c58536be | ||
|
|
512dccdbfa | ||
|
|
bb3a8453e0 | ||
|
|
e337fcaadc | ||
|
|
890a149a5d | ||
|
|
5b3ac259ce | ||
|
|
ce50043048 | ||
|
|
ebfbf6082f | ||
|
|
b44bec2207 | ||
|
|
576ce21fc8 | ||
|
|
2ba015d0be | ||
|
|
98ae2ac96a | ||
|
|
1c25ed7666 | ||
|
|
fd4c7a4ed2 | ||
|
|
32d275c138 | ||
|
|
f8924286ce | ||
|
|
6e77345263 | ||
|
|
1438c64b9e | ||
|
|
2ff1256aef | ||
|
|
5d169854c4 | ||
|
|
e61d328cb0 | ||
|
|
0c196888fb | ||
|
|
85efed8308 | ||
|
|
857c88a951 | ||
|
|
74b0a7f6f8 | ||
|
|
5da5d00aec | ||
|
|
eb59fae9b0 | ||
|
|
b6b38d6f44 | ||
|
|
4f4d9e0ae3 | ||
|
|
43c1776594 | ||
|
|
397638998b | ||
|
|
6ddbda00df | ||
|
|
df0bf74bfe | ||
|
|
5ee0651f56 | ||
|
|
9ec1c28b35 | ||
|
|
bfdbf06731 | ||
|
|
ca58b30c47 | ||
|
|
0fb2f383ac | ||
|
|
5d0eb1d330 | ||
|
|
ee77144e2b | ||
|
|
9d3a2cc219 | ||
|
|
e964ac86d5 | ||
|
|
bb26b3d549 | ||
|
|
71c8d82c33 | ||
|
|
9fffe0d710 | ||
|
|
51f8b22dfa | ||
|
|
63a36a1054 | ||
|
|
057084a708 | ||
|
|
79b130ed23 | ||
|
|
75e8b16ea3 | ||
|
|
1b35708d89 | ||
|
|
ebff343a55 | ||
|
|
c7b91e5f19 | ||
|
|
b9d52dfaf7 | ||
|
|
2c8f66586f | ||
|
|
219bf564f7 | ||
|
|
291be6f5a6 | ||
|
|
1da2344aa3 | ||
|
|
750cf7ad20 | ||
|
|
962acd1537 | ||
|
|
7a44765860 | ||
|
|
007be8e52c | ||
|
|
5e4c98eae6 | ||
|
|
858a6dc27e | ||
|
|
ad5d14c672 | ||
|
|
199685a25b | ||
|
|
d99e243f57 | ||
|
|
64f1211cf8 | ||
|
|
9432f86e43 | ||
|
|
fc99d4d757 | ||
|
|
7fb2b21a22 | ||
|
|
260b300da9 | ||
|
|
f26d5b02cb | ||
|
|
c9ff061feb | ||
|
|
86ad318e6c | ||
|
|
df05339d2a | ||
|
|
ec1303a232 | ||
|
|
c1049734e6 | ||
|
|
99fa79caaf | ||
|
|
761062a6d7 | ||
|
|
11227b3ee1 | ||
|
|
8d63d50aea | ||
|
|
3360aa6c33 | ||
|
|
bfffd98fd4 | ||
|
|
9a86184a45 | ||
|
|
00828cb804 | ||
|
|
ec31a36fd9 | ||
|
|
9003c76261 | ||
|
|
7148f262c0 | ||
|
|
3ab417e291 | ||
|
|
4ced7b7657 | ||
|
|
ad69143573 | ||
|
|
4a71afaf96 | ||
|
|
a1b87f445b | ||
|
|
33e63f000a | ||
|
|
1c8b7955eb | ||
|
|
0bade29c25 | ||
|
|
4cff3e51cb | ||
|
|
d264c3d91e | ||
|
|
099fed07e9 | ||
|
|
091fec0867 | ||
|
|
a670268a6b | ||
|
|
caa44b3d4a | ||
|
|
f3977da8f3 | ||
|
|
7dc3184f31 | ||
|
|
d09c20aa01 | ||
|
|
81411e6b54 | ||
|
|
a8d1c73fec | ||
|
|
1b3742efbb | ||
|
|
e01bb09e8c | ||
|
|
2c9c0751a4 | ||
|
|
e10a7579e8 | ||
|
|
c52a04c7d3 | ||
|
|
79dd98b20e | ||
|
|
2e71429b03 | ||
|
|
4ab299d0af | ||
|
|
c60a941d1b | ||
|
|
e2197c586b | ||
|
|
93e9d3cb5f | ||
|
|
2e7b68bf74 | ||
|
|
6ffb198e9c | ||
|
|
604458810e | ||
|
|
af5ed093b8 | ||
|
|
8f491e7dbb | ||
|
|
c1324da3fc | ||
|
|
0bbc4462fd | ||
|
|
e0261e925e | ||
|
|
46b3f71b8f | ||
|
|
3e598a17cf | ||
|
|
c1b13f2db2 | ||
|
|
a059e49579 | ||
|
|
6d7df1c5e8 | ||
|
|
dd5715ce79 | ||
|
|
43acf3c5b1 | ||
|
|
f7db9e3527 | ||
|
|
1621a67f36 | ||
|
|
248631a1a8 | ||
|
|
b4cb6e10ca | ||
|
|
5fa73e4413 | ||
|
|
49c4b20113 | ||
|
|
43ece23b89 | ||
|
|
f976851442 | ||
|
|
5470dd74bd | ||
|
|
ddd178fa82 | ||
|
|
8d411cac5f | ||
|
|
bfbb85399e | ||
|
|
9f8a120664 | ||
|
|
e1cd6b6037 | ||
|
|
2fd4487922 | ||
|
|
27a459b0dd | ||
|
|
6c344d4ae2 | ||
|
|
d7aa9952d8 | ||
|
|
09093c8f3e | ||
|
|
222bf09df4 | ||
|
|
3041ff8d25 | ||
|
|
bfe1952705 | ||
|
|
97181a39da | ||
|
|
39b3d3de0f | ||
|
|
056d16017f | ||
|
|
5cef0aef92 | ||
|
|
f794de5b9b | ||
|
|
4a67af9b90 | ||
|
|
f178dff4e0 | ||
|
|
ba821cb02f | ||
|
|
b169831810 | ||
|
|
06b3c71304 | ||
|
|
fe94f4cbb4 | ||
|
|
a4daa49f70 | ||
|
|
3b1d534f6d | ||
|
|
c1777b1098 | ||
|
|
c827a29a7b | ||
|
|
253b219d67 | ||
|
|
b702f3daf1 | ||
|
|
76c9f46438 | ||
|
|
c6c203da43 | ||
|
|
00302b74d1 | ||
|
|
32f6f18527 | ||
|
|
4fd0446538 | ||
|
|
082ad61d14 | ||
|
|
0ca4faa25b | ||
|
|
46a0566e2e | ||
|
|
97440d45d6 | ||
|
|
c5afe4e745 | ||
|
|
bc6e819396 | ||
|
|
d650a97dda | ||
|
|
cf88eb9d60 | ||
|
|
0a742ea8d0 | ||
|
|
cb8935746f | ||
|
|
608ac953e5 | ||
|
|
4d0d0b205d | ||
|
|
07b643e24c | ||
|
|
02fb020dfd | ||
|
|
bac6ebdf95 | ||
|
|
b7072d4097 | ||
|
|
d7c7bb00b8 | ||
|
|
0485f0c7ed | ||
|
|
2ade6c0739 | ||
|
|
5eeb19871b | ||
|
|
083a0ae5fc | ||
|
|
ccc370e1c4 | ||
|
|
23b8cafc41 | ||
|
|
d7ab96856c | ||
|
|
3c77229f61 | ||
|
|
fcd206891f | ||
|
|
3bf9130b0a | ||
|
|
4125ac013f | ||
|
|
e089e9c121 | ||
|
|
81af379bbc | ||
|
|
9b07aa6894 | ||
|
|
a75140c6d7 | ||
|
|
f3364cfdc0 | ||
|
|
f64b4e0e56 | ||
|
|
a1356d3bcf | ||
|
|
4c5a1ceefa | ||
|
|
e4b4a35375 | ||
|
|
cc2afef390 | ||
|
|
7c5706ead9 | ||
|
|
bcb739fcd2 | ||
|
|
85ef3724f1 | ||
|
|
cb21422836 | ||
|
|
1c9674cec9 | ||
|
|
6dcc09a96f | ||
|
|
0260c9d3fb | ||
|
|
80c03f28f8 | ||
|
|
eeaf67079a | ||
|
|
c50863c0d5 | ||
|
|
f4ab6542fa | ||
|
|
dfbe1bd234 | ||
|
|
1e89cdc055 | ||
|
|
7a40959f13 | ||
|
|
2b4d55804c | ||
|
|
858dac5601 | ||
|
|
e944945b7a | ||
|
|
920151a460 | ||
|
|
ac2a01fb09 | ||
|
|
a7933018cb | ||
|
|
5ee889eadd | ||
|
|
e811f03011 | ||
|
|
417c81de60 | ||
|
|
212c653165 | ||
|
|
e36f11385f | ||
|
|
abb05f4883 | ||
|
|
2973f33959 | ||
|
|
053c2ed2b9 | ||
|
|
1865570390 | ||
|
|
ba1ee7e6cc | ||
|
|
f6b0fcbc0f | ||
|
|
a802058886 | ||
|
|
bbc1f68966 | ||
|
|
ca0b42c3bd | ||
|
|
9536a475ff | ||
|
|
cfd731c376 | ||
|
|
de1015f6ac | ||
|
|
6c0730fef4 | ||
|
|
c73132610e | ||
|
|
77abaaf8b8 | ||
|
|
2787e86fd7 | ||
|
|
355808b0f6 | ||
|
|
80c13fa75b | ||
|
|
9a6c2aa1ea | ||
|
|
63d76ee837 | ||
|
|
7c48db7da8 | ||
|
|
bd8d5f6288 | ||
|
|
7413b7c4f6 | ||
|
|
80e3c871ce | ||
|
|
74c1e02274 | ||
|
|
efb0f6f24a | ||
|
|
dbf8580dc3 | ||
|
|
f110a01ffe | ||
|
|
eced40a761 | ||
|
|
5ac315bc3a | ||
|
|
32df4daa63 | ||
|
|
5836e456e5 | ||
|
|
dc6ab69387 | ||
|
|
7301c56753 | ||
|
|
3b76d657bd | ||
|
|
2adb6240e4 | ||
|
|
e11af496da | ||
|
|
f6e33406d7 | ||
|
|
6eab138d68 | ||
|
|
33287115de | ||
|
|
8e36056dd8 | ||
|
|
4a34f596a8 | ||
|
|
7616a3e743 | ||
|
|
c64353c324 | ||
|
|
8eac22d37a | ||
|
|
35fab12330 | ||
|
|
a46988bc50 | ||
|
|
26e1d6fe5c | ||
|
|
ec68739585 | ||
|
|
33de0f821f | ||
|
|
86ce11134a | ||
|
|
bef4905416 | ||
|
|
baa8152248 | ||
|
|
34fe103c2b | ||
|
|
0d08014bd5 | ||
|
|
dd0130180b | ||
|
|
accdf9a6a8 | ||
|
|
c891432c9d | ||
|
|
1a4efd9d81 | ||
|
|
bf462e535a | ||
|
|
5cf228e362 | ||
|
|
4dcccc553c | ||
|
|
7e53db8aac | ||
|
|
4a83584934 | ||
|
|
c735d1f6ac | ||
|
|
7bd0fdf3da | ||
|
|
b570dfcd09 | ||
|
|
2bc35539f0 | ||
|
|
80e05319c6 | ||
|
|
49459b3774 | ||
|
|
0788032003 | ||
|
|
d4c7c205cb | ||
|
|
96ce33792d | ||
|
|
13bf8a20b0 | ||
|
|
6b9b478492 | ||
|
|
c4e8bcb876 | ||
|
|
28b4fe5cb6 | ||
|
|
58b5e645c6 | ||
|
|
3e00ee4155 | ||
|
|
d1169a0f37 | ||
|
|
c8c22d3dd2 | ||
|
|
689fd03250 | ||
|
|
56fe6480ce | ||
|
|
017d5f2991 | ||
|
|
ae43b1565e | ||
|
|
3206e1b12c | ||
|
|
93d4eca2d4 | ||
|
|
57b5e493a4 | ||
|
|
fc184984a0 | ||
|
|
2178ff1c48 | ||
|
|
ae1df38c88 | ||
|
|
162e498347 | ||
|
|
172023afca | ||
|
|
18c7ea50b4 | ||
|
|
bdddb238f8 | ||
|
|
8d46237935 | ||
|
|
3fcf83e685 | ||
|
|
d374af4341 | ||
|
|
f32ad617a2 | ||
|
|
62656b24eb | ||
|
|
12763e19d8 | ||
|
|
89fd726e07 | ||
|
|
0b428987b1 | ||
|
|
1e29fad5f0 | ||
|
|
19524a4459 | ||
|
|
7043d565c9 | ||
|
|
d6f856f2f2 | ||
|
|
24f0451c10 | ||
|
|
3c4460ca98 | ||
|
|
cbf33fa14b | ||
|
|
d782654819 | ||
|
|
3c39cbf333 | ||
|
|
bd746e5151 | ||
|
|
b32c346eed | ||
|
|
77b8e204ad | ||
|
|
93dfe19c35 | ||
|
|
6dc8df5178 | ||
|
|
237fd73702 | ||
|
|
5f2d0142d1 | ||
|
|
572d576d5b | ||
|
|
6606f51636 | ||
|
|
36da65120a | ||
|
|
b6c1e1a609 | ||
|
|
5d003ec772 | ||
|
|
b9210a2ba4 | ||
|
|
f3c559ea13 | ||
|
|
6cee6b6429 | ||
|
|
84f6aabf5b | ||
|
|
9ce947d6ea | ||
|
|
0f23ad0d7e | ||
|
|
1b760b6c53 | ||
|
|
cdf64bf016 | ||
|
|
f3726023c2 | ||
|
|
cb41683f47 | ||
|
|
629a8ad055 | ||
|
|
4ba0fa00b4 | ||
|
|
f1e73c015a | ||
|
|
926c3540ff | ||
|
|
1aebd83e45 | ||
|
|
8225351145 | ||
|
|
379add8d6f | ||
|
|
ea11ce8664 | ||
|
|
82e9e96f0c | ||
|
|
8c4e426534 | ||
|
|
636771e566 | ||
|
|
363b20bdd2 | ||
|
|
b16317e2ca | ||
|
|
2c5c869228 | ||
|
|
3f5f218e0b | ||
|
|
c9cc425aad | ||
|
|
9a2b0b6995 | ||
|
|
50f8aeeaf6 | ||
|
|
fe291dd769 | ||
|
|
58850a0e14 | ||
|
|
518057489c | ||
|
|
cf0b2389a3 | ||
|
|
6179cfc670 | ||
|
|
e6ccc2d178 | ||
|
|
db719eafac | ||
|
|
a4db27a807 | ||
|
|
111c123435 | ||
|
|
75d067e411 | ||
|
|
fbeb991f7d | ||
|
|
ea2db51bbb | ||
|
|
15f4c476c3 | ||
|
|
a7c5b8c634 | ||
|
|
1aeafcaebf | ||
|
|
8d743e9511 | ||
|
|
958d4d8a6a | ||
|
|
05fb09f56c | ||
|
|
cdcf8ed3bd | ||
|
|
572466eed1 | ||
|
|
4c644b8556 | ||
|
|
c989a7198b | ||
|
|
084b028eac | ||
|
|
699d88e393 | ||
|
|
8c6566580a | ||
|
|
effe30ad3f | ||
|
|
e91b8d4556 | ||
|
|
76fca0641e | ||
|
|
7ec803222f | ||
|
|
03f0f065ee | ||
|
|
63e5be6ff0 | ||
|
|
4ccd2afd78 | ||
|
|
98519bf326 | ||
|
|
82d11b80dd | ||
|
|
cf3662442f | ||
|
|
0be5347e6a | ||
|
|
1b39c42e92 | ||
|
|
5b4f5a1e2a | ||
|
|
4eb8b1db01 | ||
|
|
b5555b9a8d | ||
|
|
67bb426eb2 | ||
|
|
cf3a088a53 | ||
|
|
a79d024c09 | ||
|
|
253de1eeca | ||
|
|
4e6d5d3f1e | ||
|
|
82a5733ec5 | ||
|
|
4822fa989e | ||
|
|
fe0e1adb2a | ||
|
|
850a8218db | ||
|
|
bf3fc5fb92 | ||
|
|
a19d1fc140 | ||
|
|
593eb1d952 | ||
|
|
75ec801941 | ||
|
|
5a1bd93518 | ||
|
|
f849f383cb | ||
|
|
ac3080f0e2 | ||
|
|
0935dd053c | ||
|
|
7e78f30739 | ||
|
|
d0f34e99a6 | ||
|
|
c781825b00 | ||
|
|
7199c62b76 | ||
|
|
2074a0d958 | ||
|
|
3e2b626107 | ||
|
|
abf515ece9 | ||
|
|
07de9c021d | ||
|
|
ff420b6495 | ||
|
|
78908e5b93 | ||
|
|
bd6643a523 | ||
|
|
71fddeb1f5 | ||
|
|
9f708be8fd | ||
|
|
a13f815591 | ||
|
|
b5ac06e652 | ||
|
|
e56d259b8e | ||
|
|
11d13c406a | ||
|
|
d5448e6902 | ||
|
|
777b9eb68e | ||
|
|
ff1585acfe | ||
|
|
cb515157b3 | ||
|
|
da39fb2880 | ||
|
|
eb3a2126ee | ||
|
|
9c1c399716 | ||
|
|
e209c3329b | ||
|
|
802147e255 | ||
|
|
1a7291276c | ||
|
|
6d6273af48 | ||
|
|
b7d967b6bc | ||
|
|
779a06fa72 | ||
|
|
0656a5079a | ||
|
|
a1669267b3 | ||
|
|
bbb40f2a21 | ||
|
|
c5b3e43b6c | ||
|
|
55dc354e68 | ||
|
|
0ec7e6c36f | ||
|
|
b1da76eefa | ||
|
|
5c6e55d37f | ||
|
|
5d496216e0 | ||
|
|
e92ed67021 | ||
|
|
b074533b29 | ||
|
|
f3665ddfab | ||
|
|
dd2b6119b3 | ||
|
|
ada3f9e547 | ||
|
|
0372242d12 | ||
|
|
9838a336d5 | ||
|
|
debd9fe419 | ||
|
|
73a06b0e9e | ||
|
|
fdfba4ea04 | ||
|
|
953253de99 | ||
|
|
da0009a46b | ||
|
|
d7e1e53450 | ||
|
|
4a3c57054f | ||
|
|
41b9495588 | ||
|
|
cdbc096990 | ||
|
|
53f2df115e | ||
|
|
0593158a86 | ||
|
|
c1f8372efc | ||
|
|
6e3db0be3d | ||
|
|
0f084faca5 | ||
|
|
c6829766bb | ||
|
|
e7931b0121 | ||
|
|
aeb82e7fb0 | ||
|
|
1e6fe7785a | ||
|
|
4edbe0ea4f | ||
|
|
0788b98ae4 | ||
|
|
8a267894f3 | ||
|
|
0510cd47f4 | ||
|
|
5dbbed3dcc | ||
|
|
7b130dc220 | ||
|
|
d28caf15b2 | ||
|
|
44df11c443 | ||
|
|
63a50ec066 | ||
|
|
3d0cff1f47 | ||
|
|
97a8b718dd | ||
|
|
fc8e147e4a | ||
|
|
af4083a8b7 | ||
|
|
7c7933efa9 | ||
|
|
317ecbc9fa | ||
|
|
67445a22d3 | ||
|
|
62997956a0 | ||
|
|
df7790fdfe | ||
|
|
34d06fa3e9 | ||
|
|
a981b46ec9 | ||
|
|
84dcf8fd27 | ||
|
|
11268ffa16 | ||
|
|
c0ec60c113 | ||
|
|
ca7587c084 | ||
|
|
33ecfc6f84 | ||
|
|
83bbcf0aa1 | ||
|
|
ba32e481ca | ||
|
|
af9da2e495 | ||
|
|
77f7672e98 | ||
|
|
9dd8185f37 | ||
|
|
12f61fd24f | ||
|
|
c9864c994f | ||
|
|
9e476127d3 | ||
|
|
fae99a24bf | ||
|
|
8d9ab15c40 | ||
|
|
ccafdacc6f | ||
|
|
4a996c1f76 | ||
|
|
d743aff4bc | ||
|
|
0f3ff4e2d9 | ||
|
|
a4d9d948ab | ||
|
|
32e6c0c6a6 | ||
|
|
ba2efaacd8 | ||
|
|
37e3e29c8c | ||
|
|
90722ecbe7 | ||
|
|
5a2eaa24d0 | ||
|
|
071986138b | ||
|
|
d61c4a9569 | ||
|
|
9fff829ab4 | ||
|
|
4682da83c1 | ||
|
|
c93c87e8fe | ||
|
|
f3e2a42c29 | ||
|
|
b063c8cda1 | ||
|
|
d360d077d1 | ||
|
|
a548c31d50 | ||
|
|
6c44b4f451 | ||
|
|
b76491ba82 | ||
|
|
e10919496f | ||
|
|
543b7dcf94 | ||
|
|
271c39cc9d | ||
|
|
18186da90e | ||
|
|
02d29d4816 | ||
|
|
82934b84d6 | ||
|
|
6177a7d71f | ||
|
|
1f4fdb174a | ||
|
|
a94b94cab0 | ||
|
|
399c700939 | ||
|
|
077097c112 | ||
|
|
f70c9842f5 | ||
|
|
0f020d5b37 | ||
|
|
2eccc81fee | ||
|
|
9fdaef1da6 | ||
|
|
eb42edff09 | ||
|
|
07f27d0f54 | ||
|
|
48d2aa14c8 | ||
|
|
3c1c8ecd20 | ||
|
|
dcb8fcece4 | ||
|
|
958ccadc09 | ||
|
|
c48a42bec5 | ||
|
|
50858322d6 | ||
|
|
62912a800a | ||
|
|
1ded78a98c | ||
|
|
90c6c2a366 | ||
|
|
fbe84698c4 | ||
|
|
2c642406d8 | ||
|
|
b811976018 | ||
|
|
3ee7e5f800 | ||
|
|
945cbca387 | ||
|
|
30c7ff341f | ||
|
|
12d7c7314a | ||
|
|
ce3cd691cc | ||
|
|
81f144df15 | ||
|
|
78854d4a10 | ||
|
|
dc3ad80d24 | ||
|
|
ed1188dc61 | ||
|
|
52347ced85 | ||
|
|
5fd6c6b9a1 | ||
|
|
9e7031f5d8 | ||
|
|
cca590c20a | ||
|
|
863fff8620 | ||
|
|
18f42fe4c1 | ||
|
|
2a3cc71641 | ||
|
|
bd67814485 | ||
|
|
40dbf7f1c8 | ||
|
|
42a7023203 | ||
|
|
14b33a845e | ||
|
|
56fcbb95ab | ||
|
|
de100ac67c | ||
|
|
2a96d2621c | ||
|
|
a097f5df23 | ||
|
|
6a901ea048 | ||
|
|
dbc1ade5a9 | ||
|
|
c2a924a5ea | ||
|
|
e06d40cb31 | ||
|
|
45d89cfe55 | ||
|
|
d45a8309cb | ||
|
|
9cd8637e9c | ||
|
|
38992e25d7 | ||
|
|
f25b3c2aee | ||
|
|
e3e2261005 | ||
|
|
38a7e77058 | ||
|
|
a920919b13 | ||
|
|
625f0f77bb | ||
|
|
12604072fc | ||
|
|
0341b64748 | ||
|
|
e0620fbb1d | ||
|
|
9114bda24c | ||
|
|
4cf73204a2 | ||
|
|
55e7f69768 | ||
|
|
d2a16bc8e8 | ||
|
|
5fdeb3b3b4 | ||
|
|
9ad5ef8b2d | ||
|
|
c244bcd978 | ||
|
|
7eb8e1df79 | ||
|
|
74c4e94c3d | ||
|
|
275b8ce2e7 | ||
|
|
ff1b0a7e1b | ||
|
|
39026bc45c | ||
|
|
3d9a95d0cd | ||
|
|
085bc09dfb | ||
|
|
886309850f | ||
|
|
ba005e991a | ||
|
|
912c46fc57 | ||
|
|
5675944c0c | ||
|
|
6b9c280214 | ||
|
|
19b882a0bd | ||
|
|
323d5dba7e | ||
|
|
cd9755ffb3 | ||
|
|
fbcdf352ac | ||
|
|
015fe9054e | ||
|
|
9a031c5b0c | ||
|
|
de0f225c45 | ||
|
|
41533bffdd | ||
|
|
cdf7c4bf97 | ||
|
|
57db384953 | ||
|
|
9f0785a160 | ||
|
|
4541cf8807 | ||
|
|
fe07306ff1 | ||
|
|
726d736aac | ||
|
|
db0360dc81 | ||
|
|
4ba35d4a93 | ||
|
|
1d51fca879 | ||
|
|
67ca1902a0 | ||
|
|
1ef326e220 | ||
|
|
0e483f81ac | ||
|
|
e969dea3b7 | ||
|
|
89b4f59efa | ||
|
|
95dc87cf04 | ||
|
|
3fc29e0d11 | ||
|
|
cc3b71154d | ||
|
|
e4e9e29949 | ||
|
|
7a1785e1e8 | ||
|
|
5d2baaac38 | ||
|
|
b479510f6c | ||
|
|
8033e9fef5 | ||
|
|
83b8c8ea12 | ||
|
|
a447ba7d76 | ||
|
|
450e1c2f95 | ||
|
|
cf3a01f502 | ||
|
|
3925e18964 | ||
|
|
2650c7dd9e | ||
|
|
0f18fedf13 | ||
|
|
f18a56682f | ||
|
|
af94e07618 | ||
|
|
7eba3b6cbc | ||
|
|
e5ef9d9062 | ||
|
|
b72dbc973d | ||
|
|
55d0e23c38 | ||
|
|
d3489712a6 | ||
|
|
56193f6902 | ||
|
|
2dad179285 | ||
|
|
19f0e2303d | ||
|
|
c152624634 | ||
|
|
212906cf7d | ||
|
|
bb5c5a8e4f | ||
|
|
9cf5348c36 | ||
|
|
edf4e14e4c | ||
|
|
8fa737f01c | ||
|
|
f16e22fbec | ||
|
|
19e0406459 | ||
|
|
354d7c2740 | ||
|
|
00edb6058e | ||
|
|
597267d1d0 | ||
|
|
ad4665e638 | ||
|
|
b21850dd15 | ||
|
|
4098f2d383 | ||
|
|
5eba754c60 | ||
|
|
b35084062d | ||
|
|
1d20472759 | ||
|
|
c0e336a971 | ||
|
|
d76e757d53 | ||
|
|
43ea58ef48 | ||
|
|
17f485d614 | ||
|
|
35f3312a1e | ||
|
|
ca3c49099f | ||
|
|
6631bb0eac | ||
|
|
0adbbc6d62 | ||
|
|
cc4f9ddad8 | ||
|
|
5a182d3d13 | ||
|
|
c60d3af60b | ||
|
|
4e67a92ec4 | ||
|
|
e43c3118d4 | ||
|
|
ffc0919790 | ||
|
|
2af145879e | ||
|
|
35517d3e6f | ||
|
|
e9e8ef7210 | ||
|
|
ee198ca863 | ||
|
|
0681e6a9b6 | ||
|
|
965a6dfd30 | ||
|
|
d55fde9eea | ||
|
|
231f054bc3 | ||
|
|
43fafd85f8 | ||
|
|
8a5a7b8807 | ||
|
|
2c24cc1341 | ||
|
|
0fc93118f2 | ||
|
|
ac2a33d09f | ||
|
|
68423b3603 | ||
|
|
6d18223f17 | ||
|
|
0443e5ad7f | ||
|
|
4619921780 | ||
|
|
df89266c03 | ||
|
|
36ca3838a6 | ||
|
|
60ce88cf25 | ||
|
|
5a2f2767ad | ||
|
|
6e73d3fac8 | ||
|
|
d08ae5466d | ||
|
|
fc175732e1 | ||
|
|
dfe41217f8 | ||
|
|
4870d07cbb | ||
|
|
2dd9fd83a3 | ||
|
|
0b93153656 | ||
|
|
714d64c417 | ||
|
|
b823af00ff | ||
|
|
77f456bd9c | ||
|
|
874fe2ed72 | ||
|
|
786f8c7b1f | ||
|
|
0c784346cc | ||
|
|
2ab0ff74c6 | ||
|
|
22cb9b9798 | ||
|
|
2ee1a366fd | ||
|
|
f9844ba3b0 | ||
|
|
7cea233de3 | ||
|
|
e4d8aac3d5 | ||
|
|
354d381372 | ||
|
|
60e589f775 | ||
|
|
f6d4b8e0b0 | ||
|
|
5fafd70b0f | ||
|
|
dcfeab8461 | ||
|
|
2a8e8d4b38 | ||
|
|
e6644aebcb | ||
|
|
654cd54363 | ||
|
|
16005d43e8 | ||
|
|
b08c93032b | ||
|
|
dd08896c70 | ||
|
|
f0ae5dfc73 | ||
|
|
0adc7e4d4b | ||
|
|
5c2056a7cb | ||
|
|
f0e7d26409 | ||
|
|
95ebeebb84 | ||
|
|
a88875f98e | ||
|
|
39da92d8ab | ||
|
|
089d358031 | ||
|
|
6a4885df17 | ||
|
|
d45d553eaf | ||
|
|
2cbbd84987 | ||
|
|
1016586611 | ||
|
|
6bbf014152 | ||
|
|
4fea7bd8ef | ||
|
|
aa63bf71cf | ||
|
|
4c9bd368c6 | ||
|
|
b1c1c497e4 | ||
|
|
86ce72e725 | ||
|
|
ae37b4b09b | ||
|
|
5ffbee1e8c | ||
|
|
19a3635c64 | ||
|
|
3c648c05ec | ||
|
|
5607a3c2ed | ||
|
|
cf04a5a036 | ||
|
|
c12680895e | ||
|
|
0163bf3edb | ||
|
|
af0a24c702 | ||
|
|
7ea1deba8f | ||
|
|
b60c84ecdc | ||
|
|
e09ed038e2 | ||
|
|
9c6ba213f9 | ||
|
|
66341111e6 | ||
|
|
abc1e3f289 | ||
|
|
027c5a57f1 | ||
|
|
0714fd376b | ||
|
|
39f41faf9f | ||
|
|
6b2ffc774f | ||
|
|
f94a5f4e5c | ||
|
|
c421fd56be | ||
|
|
11de87d9d9 | ||
|
|
8f5d42fa11 | ||
|
|
e14fcf5590 | ||
|
|
f5b81c7ed6 | ||
|
|
47a901385f | ||
|
|
819bd5cd70 | ||
|
|
753ad68ca9 | ||
|
|
5498f4e526 | ||
|
|
83a01b6bf4 | ||
|
|
c519013b20 | ||
|
|
78d45eb161 | ||
|
|
eeacac227a | ||
|
|
529e9f83f7 | ||
|
|
5297f7474d | ||
|
|
e06b48a344 | ||
|
|
7ba57ebf62 | ||
|
|
1ec9a8b777 | ||
|
|
1690718710 | ||
|
|
774a6c8c8b | ||
|
|
f06eee8fe1 | ||
|
|
2b12bcc07f | ||
|
|
a30ea2b7f8 | ||
|
|
295e8db04c | ||
|
|
b63ae10a09 | ||
|
|
c8a9336160 | ||
|
|
c0b6078438 | ||
|
|
ccce8c32a3 | ||
|
|
8f8be9c2b1 | ||
|
|
eb8e2225e5 | ||
|
|
397d7d044b | ||
|
|
a681162326 | ||
|
|
f00ec0ff60 | ||
|
|
35982a9e58 | ||
|
|
cf0bdf4d59 | ||
|
|
8a9d43e84d | ||
|
|
578bf963e3 | ||
|
|
292c4ce450 | ||
|
|
8ea589e5a3 | ||
|
|
ad09ccb0f2 | ||
|
|
edfc6903ce | ||
|
|
b94d2b27f4 | ||
|
|
31cb68840a | ||
|
|
89c62377da | ||
|
|
85afda8832 | ||
|
|
5184e4bde3 | ||
|
|
133b580262 | ||
|
|
3e76cf87ce | ||
|
|
f72ff73344 | ||
|
|
9aae346ab5 | ||
|
|
ca65ad6fa3 | ||
|
|
0f4156c564 | ||
|
|
3a0d3dc0b3 | ||
|
|
d68c338304 | ||
|
|
82f8c59bc7 | ||
|
|
c55f485166 | ||
|
|
2762488c81 | ||
|
|
ac13ae727f | ||
|
|
1b59a1c421 | ||
|
|
df00e9545d | ||
|
|
d1496f1eb5 | ||
|
|
14d9bcb08a | ||
|
|
c869774c58 | ||
|
|
18679348b2 | ||
|
|
b3ed4c3f40 | ||
|
|
8f58140419 | ||
|
|
bc8a351558 | ||
|
|
9ae198ef8f | ||
|
|
bc86bc91f7 | ||
|
|
a60f347648 | ||
|
|
dbe44c9e4b | ||
|
|
fb8b9b3933 | ||
|
|
56ebc9fa92 | ||
|
|
7f73609c77 | ||
|
|
3ac70042c1 | ||
|
|
61637a7a74 | ||
|
|
49562e96cc | ||
|
|
58b1868536 | ||
|
|
1cad40e977 | ||
|
|
9fbf23fdcc | ||
|
|
55e53db184 | ||
|
|
f790e8bd47 | ||
|
|
54de2d177e | ||
|
|
ec96771e4c | ||
|
|
99d2647335 | ||
|
|
c346cbc252 | ||
|
|
3c77290c2c | ||
|
|
72d193e852 | ||
|
|
1f7499e841 | ||
|
|
c486fbb7c3 | ||
|
|
fe1050fc0e | ||
|
|
3162d391cc | ||
|
|
e2d61ab5be | ||
|
|
2a026de526 | ||
|
|
c1b7023e3a | ||
|
|
175ff4b955 | ||
|
|
65361d56c4 | ||
|
|
08fae7a0ac | ||
|
|
a7e9030c12 | ||
|
|
aa8282f8f2 | ||
|
|
7155400eb5 | ||
|
|
6760e38d93 | ||
|
|
6bbe995d64 | ||
|
|
85bc8b61df | ||
|
|
a235509fa1 | ||
|
|
2e5b595a82 | ||
|
|
5f8dee8384 | ||
|
|
e97f1a4310 | ||
|
|
c3c5a5446f | ||
|
|
3ce04c3e4b | ||
|
|
3b5951eb2f | ||
|
|
aa8dd4ddf4 | ||
|
|
4cd14aee42 | ||
|
|
0b2726ec33 | ||
|
|
bc7f689165 | ||
|
|
6681652c21 | ||
|
|
ed4b5f179e | ||
|
|
e48e166584 | ||
|
|
e7675e8bab | ||
|
|
cf7eaea88c | ||
|
|
3e0855ff45 | ||
|
|
822c9367c6 | ||
|
|
0e46e2a6a7 | ||
|
|
ade7ef19e7 | ||
|
|
e82a6dedd9 | ||
|
|
2fd6bf7442 | ||
|
|
d10681f27f | ||
|
|
e96ff19a7a | ||
|
|
09e75ea329 | ||
|
|
84b03e9f77 | ||
|
|
55597dcea5 | ||
|
|
3290bf3c35 | ||
|
|
6771429911 | ||
|
|
e428858ad6 | ||
|
|
3e73f860d1 | ||
|
|
4cf5bd8d70 | ||
|
|
bffe0f4a6c | ||
|
|
3b8be26cc7 | ||
|
|
9e95939c47 | ||
|
|
0af7af95cf | ||
|
|
2b3e2ea6f8 | ||
|
|
19870983ca | ||
|
|
6e83b4c1bc | ||
|
|
14f5e10fd6 | ||
|
|
ed41e3cd25 | ||
|
|
4cc58e8535 | ||
|
|
e1d9686eb5 | ||
|
|
c5cb4f9e69 | ||
|
|
4a60413e0b | ||
|
|
245f5d60b5 | ||
|
|
23420adfa6 | ||
|
|
c9828dfece | ||
|
|
f52c843fa2 | ||
|
|
b5e704a934 | ||
|
|
0173959e64 | ||
|
|
b00cd5cbc3 | ||
|
|
00aba7c646 | ||
|
|
34db18ea0a | ||
|
|
457c292d3c | ||
|
|
f481c17732 | ||
|
|
4a049b14ca | ||
|
|
ed2dae5884 | ||
|
|
df61ee4ac3 | ||
|
|
850bc12929 | ||
|
|
559e17eb13 | ||
|
|
4c4f6983d1 | ||
|
|
2dbeb151f3 | ||
|
|
82c137878c | ||
|
|
8845bd6ed3 | ||
|
|
c89d861c0e | ||
|
|
3ed536ace1 | ||
|
|
d13ad4ec4b | ||
|
|
cb5ac1fcf8 | ||
|
|
53797b9ead | ||
|
|
cb164e5cac | ||
|
|
c46ebebbb3 | ||
|
|
ff96036f62 | ||
|
|
6409786f8d | ||
|
|
05eb07caf5 | ||
|
|
f5b2a60549 | ||
|
|
620eaf1ada | ||
|
|
9193a20b44 | ||
|
|
bdcac9aed3 | ||
|
|
e9a28550cc | ||
|
|
f3cd3e74ae | ||
|
|
b853fc30c0 | ||
|
|
63e32a94c0 | ||
|
|
ef596f6a8b | ||
|
|
c830097511 | ||
|
|
d8790a4628 | ||
|
|
e06ef732d8 | ||
|
|
792a3e7db8 | ||
|
|
9b32842f66 | ||
|
|
9816979169 | ||
|
|
a74679dd95 | ||
|
|
a40059729e | ||
|
|
6bab967586 | ||
|
|
bb88b33469 | ||
|
|
c440470276 | ||
|
|
ef6164eecb | ||
|
|
7ad360d872 | ||
|
|
0870a33956 | ||
|
|
3ccc2f538d | ||
|
|
17375f0be2 | ||
|
|
5a987a162e | ||
|
|
5058fb9919 | ||
|
|
3335f8602b | ||
|
|
87ab1bbe54 | ||
|
|
f8d52b33f4 | ||
|
|
bc2dcdf9db | ||
|
|
93d1aacfb6 | ||
|
|
3ddaa4aff9 | ||
|
|
75488d568a | ||
|
|
3df80545bd | ||
|
|
c605fd9783 | ||
|
|
60719e7bff | ||
|
|
e9faa3277a | ||
|
|
35f7388725 | ||
|
|
ef1486a779 | ||
|
|
95c44165e9 | ||
|
|
7b816bb96f | ||
|
|
d2ac51aa4a | ||
|
|
26974b1f3a | ||
|
|
3960c6678d | ||
|
|
30b8991a73 | ||
|
|
75a94bcd96 | ||
|
|
e160cbf32b | ||
|
|
2da2e63245 | ||
|
|
f160ea6012 | ||
|
|
8057bc639d | ||
|
|
6f5ec5aa03 | ||
|
|
e343c9445c | ||
|
|
c73e374f1a | ||
|
|
d9b292f808 | ||
|
|
46ef2f313b | ||
|
|
92a705c79e | ||
|
|
12ebdd2574 | ||
|
|
ed2e951032 | ||
|
|
01a34a8846 | ||
|
|
b13174cb9c | ||
|
|
03ac6cab99 | ||
|
|
532eebaefb | ||
|
|
f825345b14 | ||
|
|
1409477ed7 | ||
|
|
d8e4294432 | ||
|
|
5d13908776 | ||
|
|
2832a73285 | ||
|
|
4152ed5809 | ||
|
|
8a90ed70ee | ||
|
|
e2646c08a5 | ||
|
|
7122ba820f | ||
|
|
efca2658ea | ||
|
|
91a714947c | ||
|
|
5d3ac649ba | ||
|
|
6443e726a6 | ||
|
|
6a755bda45 | ||
|
|
dab555ea3b | ||
|
|
a3bbad0060 | ||
|
|
73db717a0c | ||
|
|
f1552c8354 | ||
|
|
fb87fc32f0 | ||
|
|
b04b0c670d | ||
|
|
b33845df8a | ||
|
|
12c9d8d8f8 | ||
|
|
fe97bbcbbf | ||
|
|
10533c3eba | ||
|
|
b4415c90f9 | ||
|
|
2970bbdf6f | ||
|
|
95a420534d | ||
|
|
be56a21574 | ||
|
|
3741a235fe | ||
|
|
523b6c4c2d | ||
|
|
c3b2300310 | ||
|
|
1c4a20d86f | ||
|
|
f5af475012 | ||
|
|
f149b74332 | ||
|
|
8cd51386cb | ||
|
|
fb2cca88df | ||
|
|
031d4dc85a | ||
|
|
bf66d1c0f5 | ||
|
|
0edfa88755 | ||
|
|
dba1f3bcbc | ||
|
|
e204cc8f12 | ||
|
|
9e3c60f43f | ||
|
|
b03dd5b6b2 | ||
|
|
2aa9886ebb | ||
|
|
225e52b8b9 | ||
|
|
0ae1f9906f | ||
|
|
a5918b50f8 | ||
|
|
fa0374ee61 | ||
|
|
5b1e1aee3d | ||
|
|
3ba11d08fb | ||
|
|
35d0f42d07 | ||
|
|
f08f222337 | ||
|
|
7c4ad278d5 | ||
|
|
d3d2930bd2 | ||
|
|
b571c20acc | ||
|
|
f6cc0302c4 | ||
|
|
d9abcf0c83 | ||
|
|
5346849439 | ||
|
|
9742b0c5b1 | ||
|
|
41cfe26898 | ||
|
|
05a254eee9 | ||
|
|
8ef53aa363 | ||
|
|
470abc25e4 | ||
|
|
7fe6c7e78b | ||
|
|
6c8a4f8d9f | ||
|
|
2a8c8c0cbb | ||
|
|
12bbe5459d | ||
|
|
e0d9e05fd4 | ||
|
|
8bea61cb99 | ||
|
|
d09666aba9 | ||
|
|
48e0ba1d3d | ||
|
|
fb72be41f4 | ||
|
|
ef1db6d089 | ||
|
|
9d4246a285 | ||
|
|
e0f5c39297 | ||
|
|
e4d353b105 | ||
|
|
0d665495b8 | ||
|
|
fdaf857885 | ||
|
|
987b41d2cb | ||
|
|
444080f320 | ||
|
|
b5007ba276 | ||
|
|
bf19d2b156 | ||
|
|
a78515e5bf | ||
|
|
581126c748 | ||
|
|
7b3e345a2a | ||
|
|
cc7cefd3ed | ||
|
|
de6528b7d8 | ||
|
|
9efdfe0de4 | ||
|
|
f936918278 | ||
|
|
00125577a9 | ||
|
|
083c47b0f0 | ||
|
|
8021686154 | ||
|
|
f55ca296da | ||
|
|
0d6bca3e5d | ||
|
|
be1ff61e4a | ||
|
|
e36d41b46f | ||
|
|
b4693dc1b3 | ||
|
|
ca6010789e | ||
|
|
f8a80ccf5f | ||
|
|
6461dccbdc | ||
|
|
b06f4f2574 | ||
|
|
7695e3a9c8 | ||
|
|
ae475b408f | ||
|
|
6d9d048287 | ||
|
|
09e4d101c5 | ||
|
|
36340caf4c | ||
|
|
9a80ab0700 | ||
|
|
339d972d8d | ||
|
|
6d1e1030bd | ||
|
|
8a3665ce55 | ||
|
|
8351f0beab | ||
|
|
c26808c59e | ||
|
|
50b1dfc746 | ||
|
|
2ec8ec2327 | ||
|
|
168480b0ee | ||
|
|
58f78afc2e | ||
|
|
d60020f5ac | ||
|
|
437efe5473 | ||
|
|
5737904cec | ||
|
|
431a8af08b | ||
|
|
be29c4a243 | ||
|
|
0a027fad9a | ||
|
|
e21a8e3cc2 | ||
|
|
4279d6514d | ||
|
|
457db5994b | ||
|
|
71c942d290 | ||
|
|
ee5bc8523b | ||
|
|
70f4112643 | ||
|
|
174f6b7ea8 | ||
|
|
b14fb6f3c4 | ||
|
|
d6e27e776b | ||
|
|
e6839b45e3 | ||
|
|
229134cf31 | ||
|
|
b552173185 | ||
|
|
399a1f8fee | ||
|
|
9293d9b0ed | ||
|
|
4a75952fc7 | ||
|
|
c19906eb87 | ||
|
|
00ea189074 | ||
|
|
c8e2061e2a | ||
|
|
78dc93721d | ||
|
|
33beecddda | ||
|
|
e99d93ca30 | ||
|
|
0cc54484a4 | ||
|
|
4df7d59de0 | ||
|
|
9a54da84dc | ||
|
|
83315f7999 | ||
|
|
eb5ebfd304 | ||
|
|
77c9124a3d | ||
|
|
317da76ced | ||
|
|
e8d8ced006 | ||
|
|
0321f9bddf | ||
|
|
5937892ebc | ||
|
|
e429bea2f4 | ||
|
|
d33ad5c616 | ||
|
|
3e0614a293 | ||
|
|
80e39212b8 | ||
|
|
d7a6ceb3a6 | ||
|
|
9d3a9e9d1e | ||
|
|
e95c789d4b | ||
|
|
a508161265 | ||
|
|
a935c80adc | ||
|
|
1d607bf13e | ||
|
|
ad57467c93 | ||
|
|
430eaefc3e | ||
|
|
3d60724651 | ||
|
|
31d9f663fc | ||
|
|
f324697c7c | ||
|
|
befae7e677 | ||
|
|
7a2c2587ba | ||
|
|
cf3f9d68b3 | ||
|
|
c99f7c554f | ||
|
|
f01c0945da | ||
|
|
1bcd0c4471 | ||
|
|
07f28e6ec7 | ||
|
|
7074f9f776 | ||
|
|
5029a9ad5a | ||
|
|
0bff30e954 | ||
|
|
601d37aa3d | ||
|
|
e2b1ca10c9 | ||
|
|
11942ed6dc | ||
|
|
f65914599b | ||
|
|
392c31f5fe | ||
|
|
f4ddaacb3c | ||
|
|
db64aef666 | ||
|
|
95c8bbd7fb | ||
|
|
67b4f37d53 | ||
|
|
427288c16b | ||
|
|
4202eee084 | ||
|
|
eca53bfab0 | ||
|
|
cd76d109f5 | ||
|
|
2787f9f19b | ||
|
|
4e3c6e52aa | ||
|
|
ae5ceedfe9 | ||
|
|
022e2eb1db | ||
|
|
2fe1ef4774 | ||
|
|
70afb2dd4d | ||
|
|
efa02e3f94 | ||
|
|
5eefd41059 | ||
|
|
6ca1b7c240 | ||
|
|
31191fd48c | ||
|
|
a6ed54ed48 | ||
|
|
95132b4fe1 | ||
|
|
df0c5d99e6 |
9
.gitattributes
vendored
9
.gitattributes
vendored
@@ -1,6 +1,5 @@
|
||||
kitty/wcwidth-std.h linguist-generated=true
|
||||
kitty/emoji.h linguist-generated=true
|
||||
kitty/keys.h linguist-generated=true
|
||||
kitty/charsets.c linguist-generated=true
|
||||
kitty/key_encoding.py linguist-generated=true
|
||||
kitty/unicode-data.c linguist-generated=true
|
||||
@@ -8,6 +7,14 @@ kitty/rgb.py linguist-generated=true
|
||||
kitty/gl-wrapper.* linguist-generated=true
|
||||
kitty/glfw-wrapper.* linguist-generated=true
|
||||
kitty/parse-graphics-command.h linguist-generated=true
|
||||
kitty/options/types.py linguist-generated=true
|
||||
kitty/options/parse.py linguist-generated=true
|
||||
kitty/options/to-c-generated.h linguist-generated=true
|
||||
kittens/diff/options/types.py linguist-generated=true
|
||||
kittens/diff/options/parse.py linguist-generated=true
|
||||
glfw/*.c linguist-vendored=true
|
||||
glfw/*.h linguist-vendored=true
|
||||
kittens/unicode_input/names.h linguist-generated=true
|
||||
|
||||
*.py text diff=python
|
||||
*.m text diff=objc
|
||||
|
||||
10
.github/ISSUE_TEMPLATE/bug_report.md
vendored
10
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -17,17 +17,15 @@ Steps to reproduce the behavior:
|
||||
3. ZZZ
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Environment details**
|
||||
OS: Name and version of operating system(s)
|
||||
|
||||
```
|
||||
Output of kitty --debug-config
|
||||
Press Ctrl+Shift+F6 (cmd+option+, on macOS) in kitty, to copy debug output about kitty and its
|
||||
configuration to the clipboard and paste it here.
|
||||
|
||||
On older versions of kitty, run kitty --debug-config instead
|
||||
```
|
||||
|
||||
**Additional context**
|
||||
|
||||
21
.github/workflows/ci.py
vendored
21
.github/workflows/ci.py
vendored
@@ -5,6 +5,7 @@
|
||||
import io
|
||||
import os
|
||||
import shlex
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
@@ -34,16 +35,22 @@ def install_deps():
|
||||
else:
|
||||
run('sudo apt-get update')
|
||||
run('sudo apt-get install -y libgl1-mesa-dev libxi-dev libxrandr-dev libxinerama-dev'
|
||||
' libxcursor-dev libxcb-xkb-dev libdbus-1-dev libxkbcommon-dev libharfbuzz-dev'
|
||||
' libpng-dev libfontconfig-dev libxkbcommon-x11-dev libcanberra-dev')
|
||||
' libxcursor-dev libxcb-xkb-dev libdbus-1-dev libxkbcommon-dev libharfbuzz-dev libx11-xcb-dev'
|
||||
' libpng-dev liblcms2-dev libfontconfig-dev libxkbcommon-x11-dev libcanberra-dev uuid-dev')
|
||||
if is_bundle:
|
||||
install_bundle()
|
||||
else:
|
||||
run('pip install Pillow pygments')
|
||||
if is_macos:
|
||||
# needed for zlib for pillow, should not be needed after pillow 8.0
|
||||
os.environ['PKG_CONFIG_PATH'] = '/usr/local/opt/zlib/lib/pkgconfig'
|
||||
cmd = 'pip3 install Pillow pygments'
|
||||
if sys.version_info[:2] < (3, 7):
|
||||
cmd += ' importlib-resources'
|
||||
run(cmd)
|
||||
|
||||
|
||||
def build_kitty():
|
||||
python = 'python3' if is_bundle else sys.executable
|
||||
python = shutil.which('python3') if is_bundle else sys.executable
|
||||
cmd = '{} setup.py build --verbose'.format(python)
|
||||
if os.environ.get('KITTY_SANITIZE') == '1':
|
||||
cmd += ' --debug --sanitize'
|
||||
@@ -71,7 +78,7 @@ def replace_in_file(path, src, dest):
|
||||
|
||||
def setup_bundle_env():
|
||||
global SW
|
||||
os.environ['SW'] = SW = '/Users/Shared/buildbot/sw/sw' if is_macos else os.path.join(os.environ['GITHUB_WORKSPACE'], 'sw')
|
||||
os.environ['SW'] = SW = '/Users/Shared/kitty-build/sw/sw' if is_macos else os.path.join(os.environ['GITHUB_WORKSPACE'], 'sw')
|
||||
os.environ['PKG_CONFIG_PATH'] = SW + '/lib/pkgconfig'
|
||||
if is_macos:
|
||||
os.environ['PATH'] = '{}:{}'.format('/usr/local/opt/sphinx-doc/bin', os.environ['PATH'])
|
||||
@@ -85,8 +92,8 @@ def install_bundle():
|
||||
cwd = os.getcwd()
|
||||
os.makedirs(SW)
|
||||
os.chdir(SW)
|
||||
with urlopen('https://download.calibre-ebook.com/travis/kitty/{}.tar.xz'.format(
|
||||
'osx' if is_macos else 'linux-64')) as f:
|
||||
with urlopen('https://download.calibre-ebook.com/ci/kitty/{}-64.tar.xz'.format(
|
||||
'macos' if is_macos else 'linux')) as f:
|
||||
data = f.read()
|
||||
with tarfile.open(fileobj=io.BytesIO(data), mode='r:xz') as tf:
|
||||
tf.extractall()
|
||||
|
||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -76,7 +76,7 @@ jobs:
|
||||
python-version: 3.8
|
||||
|
||||
- name: Install build-only deps
|
||||
run: pip install flake8 mypy sphinx
|
||||
run: pip install flake8 mypy types-requests types-docutils sphinx
|
||||
|
||||
- name: Run pyflakes
|
||||
run: python -m flake8 --count .
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
= kitty - the fast, featureful, GPU based, terminal emulator
|
||||
= kitty - the fast, feature-rich, cross-platform, GPU based terminal
|
||||
|
||||
See https://sw.kovidgoyal.net/kitty/
|
||||
See https://sw.kovidgoyal.net/kitty/[the kitty website].
|
||||
|
||||
image:https://github.com/kovidgoyal/kitty/workflows/CI/badge.svg["Build status", link="https://github.com/kovidgoyal/kitty/actions?query=workflow%3ACI"]
|
||||
|
||||
https://sw.kovidgoyal.net/kitty/faq.html[Frequently Asked Questions]
|
||||
|
||||
To ask other questions about kitty usage, use either the https://github.com/kovidgoyal/kitty/discussions/[discussions on GitHub] or the
|
||||
https://www.reddit.com/r/KittyTerminal[Reddit community]
|
||||
|
||||
Packaging status in various repositories:
|
||||
|
||||
image:https://repology.org/badge/vertical-allrepos/kitty.svg[https://repology.org/project/kitty/versions]
|
||||
|
||||
12
SECURITY.md
Normal file
12
SECURITY.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
There are no security specific releases of kitty. Security bugs are fixed
|
||||
and released just like all other bugs.
|
||||
|
||||
## Reporting a vulnerability
|
||||
|
||||
Preferably send an email to kovid at kovidgoyal.net or open an issue in the
|
||||
GitHub repository, though the latter means you are disclosing the vulnerability
|
||||
publicly before it can be fixed.
|
||||
29
__main__.py
29
__main__.py
@@ -2,8 +2,8 @@
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import sys
|
||||
import os
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
|
||||
@@ -30,8 +30,14 @@ def runpy(args: List[str]) -> None:
|
||||
|
||||
def hold(args: List[str]) -> None:
|
||||
import subprocess
|
||||
import tty
|
||||
from contextlib import suppress
|
||||
ret = subprocess.Popen(args[1:]).wait()
|
||||
sys.stdin.read()
|
||||
with suppress(BaseException):
|
||||
print('\n\x1b[1;32mPress any key to exit', end='', flush=True)
|
||||
with suppress(BaseException):
|
||||
tty.setraw(sys.stdin.fileno())
|
||||
sys.stdin.buffer.read(1)
|
||||
raise SystemExit(ret)
|
||||
|
||||
|
||||
@@ -65,9 +71,23 @@ def run_kitten(args: List[str]) -> None:
|
||||
rk(kitten)
|
||||
|
||||
|
||||
def edit_config_file(args: List[str]) -> None:
|
||||
from kitty.cli import create_default_opts
|
||||
from kitty.fast_data_types import set_options
|
||||
from kitty.utils import edit_config_file as f
|
||||
set_options(create_default_opts())
|
||||
f()
|
||||
|
||||
|
||||
def namespaced(args: List[str]) -> None:
|
||||
func = namespaced_entry_points[args[1]]
|
||||
func(args[1:])
|
||||
try:
|
||||
func = namespaced_entry_points[args[1]]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
func(args[1:])
|
||||
return
|
||||
raise SystemExit(f'{args[1]} is not a known entry point. Choices are: ' + ', '.join(namespaced_entry_points))
|
||||
|
||||
|
||||
entry_points = {
|
||||
@@ -77,6 +97,7 @@ entry_points = {
|
||||
'runpy': runpy,
|
||||
'launch': launch,
|
||||
'kitten': run_kitten,
|
||||
'edit-config': edit_config_file,
|
||||
|
||||
'@': remote_control,
|
||||
'+': namespaced,
|
||||
|
||||
@@ -4,15 +4,17 @@
|
||||
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from contextlib import suppress
|
||||
|
||||
from bypy.constants import (
|
||||
LIBDIR, PREFIX, PYTHON, SRC as KITTY_DIR, ismacos, worker_env
|
||||
)
|
||||
from bypy.utils import run_shell
|
||||
from bypy.utils import run_shell, walk
|
||||
|
||||
|
||||
def read_src_file(name):
|
||||
@@ -40,52 +42,69 @@ def run(*args, **extra_env):
|
||||
if ismacos:
|
||||
env['PKGCONFIG_EXE'] = os.path.join(PREFIX, 'bin', 'pkg-config')
|
||||
cwd = env.pop('cwd', KITTY_DIR)
|
||||
print(' '.join(map(shlex.quote, args)), flush=True)
|
||||
return subprocess.call(list(args), env=env, cwd=cwd)
|
||||
|
||||
|
||||
SETUP_CMD = [PYTHON, 'setup.py', '--build-universal-binary']
|
||||
|
||||
|
||||
def build_frozen_launcher(extra_include_dirs):
|
||||
inc_dirs = [f'--extra-include-dirs={x}' for x in extra_include_dirs]
|
||||
cmd = SETUP_CMD + ['--prefix', build_frozen_launcher.prefix] + inc_dirs + ['build-frozen-launcher']
|
||||
if run(*cmd, cwd=build_frozen_launcher.writeable_src_dir) != 0:
|
||||
print('Building of frozen kitty launcher failed', file=sys.stderr)
|
||||
os.chdir(KITTY_DIR)
|
||||
run_shell()
|
||||
raise SystemExit('Building of kitty launcher failed')
|
||||
return build_frozen_launcher.writeable_src_dir
|
||||
|
||||
|
||||
def run_tests(kitty_exe):
|
||||
with tempfile.TemporaryDirectory() as tdir:
|
||||
env = {
|
||||
'KITTY_CONFIG_DIRECTORY': os.path.join(tdir, 'conf'),
|
||||
'KITTY_CACHE_DIRECTORY': os.path.join(tdir, 'cache')
|
||||
}
|
||||
[os.mkdir(x) for x in env.values()]
|
||||
cmd = [kitty_exe, '+runpy', 'from kitty_tests.main import run_tests; run_tests()']
|
||||
print(*map(shlex.quote, cmd), flush=True)
|
||||
if subprocess.call(cmd, env=env) != 0:
|
||||
print('Checking of kitty build failed', file=sys.stderr)
|
||||
os.chdir(os.path.dirname(kitty_exe))
|
||||
run_shell()
|
||||
raise SystemExit('Checking of kitty build failed')
|
||||
|
||||
|
||||
def sanitize_source_folder(path: str) -> None:
|
||||
for q in walk(path):
|
||||
if os.path.splitext(q)[1] not in ('.py', '.glsl', '.ttf', '.otf'):
|
||||
os.unlink(q)
|
||||
|
||||
|
||||
def build_c_extensions(ext_dir, args):
|
||||
writeable_src_dir = os.path.join(ext_dir, 'src')
|
||||
build_frozen_launcher.writeable_src_dir = writeable_src_dir
|
||||
shutil.copytree(
|
||||
KITTY_DIR, writeable_src_dir, symlinks=True,
|
||||
ignore=shutil.ignore_patterns('b', 'build', 'dist', '*_commands.json', '*.o'))
|
||||
ignore=shutil.ignore_patterns('b', 'build', 'dist', '*_commands.json', '*.o', '*.so', '*.dylib', '*.pyd'))
|
||||
|
||||
# Build the launcher as it is needed for the spawn test
|
||||
with suppress(FileNotFoundError):
|
||||
os.remove(os.path.join(writeable_src_dir, 'kitty', 'launcher', 'kitty'))
|
||||
if run(PYTHON, 'setup.py', 'build-launcher', cwd=writeable_src_dir) != 0:
|
||||
print('Building of kitty launcher failed', file=sys.stderr)
|
||||
os.chdir(KITTY_DIR)
|
||||
run_shell()
|
||||
raise SystemExit('Building of kitty launcher failed')
|
||||
os.unlink(os.path.join(writeable_src_dir, 'kitty', 'launcher', 'kitty'))
|
||||
|
||||
cmd = [PYTHON, 'setup.py']
|
||||
bundle = 'macos-freeze' if ismacos else 'linux-freeze'
|
||||
cmd.append(bundle)
|
||||
cmd = SETUP_CMD + ['macos-freeze' if ismacos else 'linux-freeze']
|
||||
if args.dont_strip:
|
||||
cmd.append('--debug')
|
||||
dest = kitty_constants['appname'] + ('.app' if ismacos else '')
|
||||
dest = os.path.join(ext_dir, dest)
|
||||
cmd += ['--prefix', dest]
|
||||
dest = build_frozen_launcher.prefix = os.path.join(ext_dir, dest)
|
||||
cmd += ['--prefix', dest, '--full']
|
||||
if run(*cmd, cwd=writeable_src_dir) != 0:
|
||||
print('Building of kitty package failed', file=sys.stderr)
|
||||
os.chdir(KITTY_DIR)
|
||||
os.chdir(writeable_src_dir)
|
||||
run_shell()
|
||||
raise SystemExit('Building of kitty package failed')
|
||||
return ext_dir
|
||||
|
||||
|
||||
def run_tests(path_to_kitty, cwd_on_failure):
|
||||
kw = {'cwd': cwd_on_failure}
|
||||
if not ismacos:
|
||||
# this is needed for the spawn test which starts an interpreter
|
||||
# using the kitty launcher.
|
||||
kw['PYTHONHOME'] = PREFIX
|
||||
ret = run(PYTHON, 'test.py', **kw)
|
||||
if ret != 0:
|
||||
os.chdir(cwd_on_failure)
|
||||
print(
|
||||
'running kitty tests failed with return code:', ret, file=sys.stderr)
|
||||
run_shell()
|
||||
raise SystemExit('running kitty tests failed')
|
||||
|
||||
|
||||
if __name__ == 'program':
|
||||
kitty_constants = initialize_constants()
|
||||
|
||||
@@ -13,12 +13,14 @@ import time
|
||||
from bypy.constants import (
|
||||
OUTPUT_DIR, PREFIX, is64bit, python_major_minor_version
|
||||
)
|
||||
from bypy.utils import get_dll_path, py_compile, walk
|
||||
from bypy.freeze import (
|
||||
extract_extension_modules, freeze_python, path_to_freeze_dir
|
||||
)
|
||||
from bypy.utils import get_dll_path, mkdtemp, py_compile, walk
|
||||
|
||||
j = os.path.join
|
||||
self_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
arch = 'x86_64' if is64bit else 'i686'
|
||||
|
||||
self_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
py_ver = '.'.join(map(str, python_major_minor_version()))
|
||||
iv = globals()['init_env']
|
||||
kitty_constants = iv['kitty_constants']
|
||||
@@ -26,16 +28,12 @@ kitty_constants = iv['kitty_constants']
|
||||
|
||||
def binary_includes():
|
||||
return tuple(map(get_dll_path, (
|
||||
'expat', 'sqlite3', 'ffi', 'z', 'lzma', 'png16',
|
||||
|
||||
# dont include freetype because fontconfig is closely coupled to it
|
||||
# and also distros often patch freetype
|
||||
# 'iconv.so.2', 'pcre.so.1', 'graphite2.so.3', 'glib-2.0.so.0', 'freetype.so.6',
|
||||
|
||||
'expat', 'sqlite3', 'ffi', 'z', 'lzma', 'png16', 'lcms2', 'crypt',
|
||||
'iconv', 'pcre', 'graphite2', 'glib-2.0', 'freetype',
|
||||
'harfbuzz', 'xkbcommon', 'xkbcommon-x11',
|
||||
'ncursesw', 'readline',
|
||||
'ncursesw', 'readline', 'brotlicommon', 'brotlienc', 'brotlidec'
|
||||
))) + (
|
||||
get_dll_path('bz2', 2), get_dll_path('ssl', 3), get_dll_path('crypto', 3),
|
||||
get_dll_path('bz2', 2), get_dll_path('ssl', 2), get_dll_path('crypto', 2),
|
||||
get_dll_path('python' + py_ver, 2),
|
||||
)
|
||||
|
||||
@@ -48,6 +46,7 @@ class Env:
|
||||
self.py_dir = j(self.lib_dir, 'python' + py_ver)
|
||||
os.makedirs(self.py_dir)
|
||||
self.bin_dir = j(self.base, 'bin')
|
||||
self.obj_dir = mkdtemp('launchers-')
|
||||
|
||||
|
||||
def ignore_in_lib(base, items, ignored_dirs=None):
|
||||
@@ -75,7 +74,7 @@ def import_site_packages(srcdir, dest):
|
||||
if ext in ('py', 'so'):
|
||||
shutil.copy2(f, dest)
|
||||
elif ext == 'pth' and x != 'setuptools.pth':
|
||||
for line in open(f, 'rb').read().splitlines():
|
||||
for line in open(f):
|
||||
src = os.path.abspath(j(srcdir, line))
|
||||
if os.path.exists(src) and os.path.isdir(src):
|
||||
import_site_packages(src, dest)
|
||||
@@ -105,10 +104,31 @@ def copy_python(env):
|
||||
shutil.copy2(y, env.py_dir)
|
||||
|
||||
srcdir = j(srcdir, 'site-packages')
|
||||
dest = j(env.py_dir, 'site-packages')
|
||||
import_site_packages(srcdir, dest)
|
||||
site_packages_dir = j(env.py_dir, 'site-packages')
|
||||
import_site_packages(srcdir, site_packages_dir)
|
||||
|
||||
pdir = os.path.join(env.lib_dir, 'kitty-extensions')
|
||||
os.makedirs(pdir, exist_ok=True)
|
||||
kitty_dir = os.path.join(env.lib_dir, 'kitty')
|
||||
bases = ('kitty', 'kittens', 'kitty_tests')
|
||||
for x in bases:
|
||||
dest = os.path.join(env.py_dir, x)
|
||||
os.rename(os.path.join(kitty_dir, x), dest)
|
||||
if x == 'kitty':
|
||||
shutil.rmtree(os.path.join(dest, 'launcher'))
|
||||
os.rename(os.path.join(kitty_dir, '__main__.py'), os.path.join(env.py_dir, 'kitty_main.py'))
|
||||
shutil.rmtree(os.path.join(kitty_dir, '__pycache__'))
|
||||
print('Extracting extension modules from', env.py_dir, 'to', pdir)
|
||||
ext_map = extract_extension_modules(env.py_dir, pdir)
|
||||
shutil.copy(os.path.join(os.path.dirname(self_dir), 'site.py'), os.path.join(env.py_dir, 'site.py'))
|
||||
for x in bases:
|
||||
iv['sanitize_source_folder'](os.path.join(env.py_dir, x))
|
||||
py_compile(env.py_dir)
|
||||
py_compile(os.path.join(env.base, 'lib', 'kitty'))
|
||||
freeze_python(env.py_dir, pdir, env.obj_dir, ext_map, develop_mode_env_var='KITTY_DEVELOP_FROM', remove_pyc_files=True)
|
||||
|
||||
|
||||
def build_launcher(env):
|
||||
iv['build_frozen_launcher']([path_to_freeze_dir(), env.obj_dir])
|
||||
|
||||
|
||||
def is_elf(path):
|
||||
@@ -192,16 +212,16 @@ def create_tarfile(env, compression_level='9'):
|
||||
def main():
|
||||
args = globals()['args']
|
||||
ext_dir = globals()['ext_dir']
|
||||
if not args.skip_tests:
|
||||
run_tests = iv['run_tests']
|
||||
run_tests(None, os.path.join(ext_dir, 'src'))
|
||||
env = Env(os.path.join(ext_dir, kitty_constants['appname']))
|
||||
copy_libs(env)
|
||||
copy_python(env)
|
||||
build_launcher(env)
|
||||
files = find_binaries(env)
|
||||
fix_permissions(files)
|
||||
if not args.dont_strip:
|
||||
strip_binaries(files)
|
||||
if not args.skip_tests:
|
||||
iv['run_tests'](os.path.join(env.base, 'bin', 'kitty'))
|
||||
create_tarfile(env, args.compression_level)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# Requires installation of XCode 10.3 and Python 3 and
|
||||
# python3 -m pip install certifi
|
||||
|
||||
vm_name 'macos-kitty-build'
|
||||
vm_name 'macos-kitty'
|
||||
root '/Users/Shared/kitty-build'
|
||||
python '/usr/local/bin/python3'
|
||||
universal 'true'
|
||||
deploy_target '10.14'
|
||||
|
||||
@@ -13,16 +13,23 @@ import tempfile
|
||||
import zipfile
|
||||
|
||||
from bypy.constants import PREFIX, PYTHON, SW, python_major_minor_version
|
||||
from bypy.freeze import (
|
||||
extract_extension_modules, freeze_python, path_to_freeze_dir
|
||||
)
|
||||
from bypy.macos_sign import (
|
||||
codesign, create_entitlements_file, make_certificate_useable, notarize_app,
|
||||
verify_signature
|
||||
)
|
||||
from bypy.utils import current_dir, py_compile, run_shell, timeit, walk
|
||||
from bypy.utils import (
|
||||
current_dir, mkdtemp, py_compile, run_shell, timeit, walk
|
||||
)
|
||||
|
||||
iv = globals()['init_env']
|
||||
kitty_constants = iv['kitty_constants']
|
||||
self_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
join = os.path.join
|
||||
basename = os.path.basename
|
||||
dirname = os.path.dirname
|
||||
abspath = os.path.abspath
|
||||
APPNAME = kitty_constants['appname']
|
||||
VERSION = kitty_constants['version']
|
||||
@@ -134,8 +141,9 @@ class Freeze(object):
|
||||
|
||||
FID = '@executable_path/../Frameworks'
|
||||
|
||||
def __init__(self, build_dir, dont_strip=False, sign_installers=False, notarize=False):
|
||||
def __init__(self, build_dir, dont_strip=False, sign_installers=False, notarize=False, skip_tests=False):
|
||||
self.build_dir = build_dir
|
||||
self.skip_tests = skip_tests
|
||||
self.sign_installers = sign_installers
|
||||
self.notarize = notarize
|
||||
self.dont_strip = dont_strip
|
||||
@@ -147,6 +155,7 @@ class Freeze(object):
|
||||
self.py_ver = py_ver
|
||||
self.python_stdlib = join(self.resources_dir, 'Python', 'lib', 'python' + self.py_ver)
|
||||
self.site_packages = self.python_stdlib # hack to avoid needing to add site-packages to path
|
||||
self.obj_dir = mkdtemp('launchers-')
|
||||
|
||||
self.run()
|
||||
|
||||
@@ -160,10 +169,11 @@ class Freeze(object):
|
||||
self.add_site_packages()
|
||||
self.add_stdlib()
|
||||
self.add_misc_libraries()
|
||||
self.compile_py_modules()
|
||||
self.fix_dependencies_in_kitty()
|
||||
self.freeze_python()
|
||||
if not self.dont_strip:
|
||||
self.strip_files()
|
||||
if not self.skip_tests:
|
||||
self.run_tests()
|
||||
# self.run_shell()
|
||||
|
||||
ret = self.makedmg(self.build_dir, APPNAME + '-' + VERSION)
|
||||
@@ -175,6 +185,10 @@ class Freeze(object):
|
||||
print('\nStripping files...')
|
||||
strip_files(self.to_strip)
|
||||
|
||||
@flush
|
||||
def run_tests(self):
|
||||
iv['run_tests'](os.path.join(self.contents_dir, 'MacOS', 'kitty'))
|
||||
|
||||
@flush
|
||||
def set_id(self, path_to_lib, new_id):
|
||||
old_mode = flipwritable(path_to_lib)
|
||||
@@ -239,7 +253,6 @@ class Freeze(object):
|
||||
self.set_id(
|
||||
join(currd, 'Python'),
|
||||
self.FID + '/Python.framework/Versions/%s/Python' % basename(curr))
|
||||
self.fix_dependencies_in_lib(join(self.contents_dir, 'MacOS', 'kitty'))
|
||||
# The following is needed for codesign
|
||||
with current_dir(x):
|
||||
os.symlink(basename(curr), 'Versions/Current')
|
||||
@@ -262,8 +275,9 @@ class Freeze(object):
|
||||
'z.1',
|
||||
'harfbuzz.0',
|
||||
'png16.16',
|
||||
'crypto.1.0.0',
|
||||
'ssl.1.0.0',
|
||||
'lcms2.2',
|
||||
'crypto.1.1',
|
||||
'ssl.1.1',
|
||||
):
|
||||
print('\nAdding', x)
|
||||
x = 'lib%s.dylib' % x
|
||||
@@ -272,11 +286,6 @@ class Freeze(object):
|
||||
dest = join(self.frameworks_dir, x)
|
||||
self.set_id(dest, self.FID + '/' + x)
|
||||
self.fix_dependencies_in_lib(dest)
|
||||
base = join(self.frameworks_dir, 'kitty')
|
||||
for lib in walk(base):
|
||||
if lib.endswith('.so'):
|
||||
self.set_id(lib, self.FID + '/' + os.path.relpath(lib, self.frameworks_dir))
|
||||
self.fix_dependencies_in_lib(lib)
|
||||
|
||||
@flush
|
||||
def add_package_dir(self, x, dest=None):
|
||||
@@ -294,21 +303,10 @@ class Freeze(object):
|
||||
dest = self.site_packages
|
||||
dest = join(dest, basename(x))
|
||||
shutil.copytree(x, dest, symlinks=True, ignore=ignore)
|
||||
self.postprocess_package(x, dest)
|
||||
for f in walk(dest):
|
||||
if f.endswith('.so'):
|
||||
self.fix_dependencies_in_lib(f)
|
||||
|
||||
@flush
|
||||
def fix_dependencies_in_kitty(self):
|
||||
for f in walk(join(self.resources_dir, 'kitty')):
|
||||
if f.endswith('.so'):
|
||||
self.fix_dependencies_in_lib(f)
|
||||
|
||||
@flush
|
||||
def postprocess_package(self, src_path, dest_path):
|
||||
pass
|
||||
|
||||
@flush
|
||||
def add_stdlib(self):
|
||||
print('\nAdding python stdlib')
|
||||
@@ -330,6 +328,35 @@ class Freeze(object):
|
||||
if dest2.endswith('.so'):
|
||||
self.fix_dependencies_in_lib(dest2)
|
||||
|
||||
@flush
|
||||
def freeze_python(self):
|
||||
print('\nFreezing python')
|
||||
kitty_dir = join(self.resources_dir, 'kitty')
|
||||
bases = ('kitty', 'kittens', 'kitty_tests')
|
||||
for x in bases:
|
||||
dest = os.path.join(self.python_stdlib, x)
|
||||
os.rename(os.path.join(kitty_dir, x), dest)
|
||||
if x == 'kitty':
|
||||
shutil.rmtree(os.path.join(dest, 'launcher'))
|
||||
os.rename(os.path.join(kitty_dir, '__main__.py'), os.path.join(self.python_stdlib, 'kitty_main.py'))
|
||||
shutil.rmtree(os.path.join(kitty_dir, '__pycache__'))
|
||||
pdir = os.path.join(dirname(self.python_stdlib), 'kitty-extensions')
|
||||
os.mkdir(pdir)
|
||||
print('Extracting extension modules from', self.python_stdlib, 'to', pdir)
|
||||
ext_map = extract_extension_modules(self.python_stdlib, pdir)
|
||||
shutil.copy(os.path.join(os.path.dirname(self_dir), 'site.py'), os.path.join(self.python_stdlib, 'site.py'))
|
||||
for x in bases:
|
||||
iv['sanitize_source_folder'](os.path.join(self.python_stdlib, x))
|
||||
self.compile_py_modules()
|
||||
freeze_python(self.python_stdlib, pdir, self.obj_dir, ext_map, develop_mode_env_var='KITTY_DEVELOP_FROM', remove_pyc_files=True)
|
||||
iv['build_frozen_launcher']([path_to_freeze_dir(), self.obj_dir])
|
||||
os.rename(join(dirname(self.contents_dir), 'bin', 'kitty'), join(self.contents_dir, 'MacOS', 'kitty'))
|
||||
shutil.rmtree(join(dirname(self.contents_dir), 'bin'))
|
||||
self.fix_dependencies_in_lib(join(self.contents_dir, 'MacOS', 'kitty'))
|
||||
for f in walk(pdir):
|
||||
if f.endswith('.so') or f.endswith('.dylib'):
|
||||
self.fix_dependencies_in_lib(f)
|
||||
|
||||
@flush
|
||||
def add_site_packages(self):
|
||||
print('\nAdding site-packages')
|
||||
@@ -388,14 +415,11 @@ class Freeze(object):
|
||||
|
||||
@flush
|
||||
def compile_py_modules(self):
|
||||
print('\nCompiling Python modules')
|
||||
self.remove_bytecode(join(self.resources_dir, 'Python'))
|
||||
py_compile(join(self.resources_dir, 'Python'))
|
||||
self.remove_bytecode(join(self.resources_dir, 'kitty'))
|
||||
py_compile(join(self.resources_dir, 'kitty'))
|
||||
|
||||
@flush
|
||||
def makedmg(self, d, volname, internet_enable=True, format='ULFO'):
|
||||
def makedmg(self, d, volname, format='ULFO'):
|
||||
''' Copy a directory d into a dmg named volname '''
|
||||
print('\nMaking dmg...')
|
||||
sys.stdout.flush()
|
||||
@@ -431,9 +455,6 @@ class Freeze(object):
|
||||
print('\nCreating dmg...')
|
||||
with timeit() as times:
|
||||
subprocess.check_call(cmd + [dmg])
|
||||
if internet_enable:
|
||||
subprocess.check_call(
|
||||
['/usr/bin/hdiutil', 'internet-enable', '-yes', dmg])
|
||||
print('dmg created in %d minutes and %d seconds' % tuple(times))
|
||||
shutil.rmtree(tdir)
|
||||
size = os.stat(dmg).st_size / (1024 * 1024.)
|
||||
@@ -444,14 +465,12 @@ class Freeze(object):
|
||||
def main():
|
||||
args = globals()['args']
|
||||
ext_dir = globals()['ext_dir']
|
||||
if not args.skip_tests:
|
||||
run_tests = iv['run_tests']
|
||||
run_tests(None, os.path.join(ext_dir, 'src'))
|
||||
Freeze(
|
||||
os.path.join(ext_dir, kitty_constants['appname'] + '.app'),
|
||||
dont_strip=args.dont_strip,
|
||||
sign_installers=args.sign_installers,
|
||||
notarize=args.notarize
|
||||
notarize=args.notarize,
|
||||
skip_tests=args.skip_tests
|
||||
)
|
||||
|
||||
|
||||
|
||||
31
bypy/site.py
Normal file
31
bypy/site.py
Normal file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import builtins
|
||||
import sys
|
||||
|
||||
import _sitebuiltins
|
||||
|
||||
|
||||
def set_quit():
|
||||
eof = 'Ctrl-D (i.e. EOF)'
|
||||
builtins.quit = _sitebuiltins.Quitter('quit', eof)
|
||||
builtins.exit = _sitebuiltins.Quitter('exit', eof)
|
||||
|
||||
|
||||
def set_helper():
|
||||
builtins.help = _sitebuiltins._Helper()
|
||||
|
||||
|
||||
def main():
|
||||
sys.argv[0] = sys.calibre_basename
|
||||
set_helper()
|
||||
set_quit()
|
||||
mod = __import__(sys.calibre_module, fromlist=[1])
|
||||
func = getattr(mod, sys.calibre_function)
|
||||
return func()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -28,13 +28,34 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "cmake",
|
||||
"os": "macos",
|
||||
"unix": {
|
||||
"filename": "cmake-3.19.4.tar.gz",
|
||||
"hash": "sha256:7d0232b9f1c57e8de81f38071ef8203e6820fe7eec8ae46a1df125d88dbcc2e1",
|
||||
"urls": ["https://cmake.org/files/v3.19/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"name": "expat",
|
||||
"unix": {
|
||||
"filename": "expat-2.2.6.tar.bz2",
|
||||
"hash": "sha256:17b43c2716d521369f82fc2dc70f359860e90fa440bea65b3b85f0b246ea81f2",
|
||||
"urls": ["https://github.com/libexpat/libexpat/releases/download/R_2_2_6/{filename}"]
|
||||
"filename": "expat-2.2.10.tar.bz2",
|
||||
"hash": "sha256:b2c160f1b60e92da69de8e12333096aeb0c3bf692d41c60794de278af72135a5",
|
||||
"urls": ["https://github.com/libexpat/libexpat/releases/download/R_2_2_10/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"name": "libxml2",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"filename": "libxml2-2.9.10.tar.gz",
|
||||
"hash": "sha256:aafee193ffb8fe0c82d4afef6ef91972cbaf5feea100edc2f262750611b4be1f",
|
||||
"urls": ["ftp://xmlsoft.org/libxml2/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -43,8 +64,8 @@
|
||||
"name": "xkbcommon",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"filename": "libxkbcommon-0.10.0.tar.xz",
|
||||
"hash": "sha256:57c3630cdc38fb4734cd57fa349e92244f5ae3862813e533cedbd86721a0b6f2",
|
||||
"filename": "libxkbcommon-1.0.3.tar.xz",
|
||||
"hash": "sha256:a2202f851e072b84e64a395212cbd976ee18a8ee602008b0bad02a13247dbc52",
|
||||
"urls": ["http://xkbcommon.org/download/{filename}"]
|
||||
}
|
||||
},
|
||||
@@ -52,27 +73,28 @@
|
||||
{
|
||||
"name": "sqlite",
|
||||
"unix": {
|
||||
"filename": "sqlite-autoconf-3310100.tar.gz",
|
||||
"hash": "sha1:0c30f5b22152a8166aa3bebb0f4bc1f3e9cc508b",
|
||||
"urls": ["https://www.sqlite.org/2020/{filename}"]
|
||||
"filename": "sqlite-autoconf-3340100.tar.gz",
|
||||
"hash": "sha256:2a3bca581117b3b88e5361d0ef3803ba6d8da604b1c1a47d902ef785c1b53e89",
|
||||
"urls": ["https://www.sqlite.org/2021/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"name": "libffi",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"filename": "libffi-3.2.1.tar.gz",
|
||||
"hash": "sha1:280c265b789e041c02e5c97815793dfc283fb1e6",
|
||||
"urls": ["ftp://sourceware.org/pub/libffi/{filename}"]
|
||||
"filename": "libffi-3.3.0.tar.gz",
|
||||
"hash": "sha256:72fba7922703ddfa7a028d513ac15a85c8d54c8d67f55fa5a4802885dc652056",
|
||||
"urls": ["https://github.com/libffi/libffi/releases/download/v3.3/libffi-3.3.tar.gz"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "openssl",
|
||||
"unix": {
|
||||
"filename": "openssl-1.0.2u.tar.gz",
|
||||
"hash": "sha256:ecd0c6ffb493dd06707d38b14bb4d8c2288bb7033735606569d8f90f89669d16",
|
||||
"filename": "openssl-1.1.1i.tar.gz",
|
||||
"hash": "sha256:e8be6a35fe41d10603c3cc635e93289ed00bf34b79671a3a4de64fcee00d5242",
|
||||
"urls": ["https://www.openssl.org/source/{filename}"]
|
||||
}
|
||||
},
|
||||
@@ -91,15 +113,14 @@
|
||||
"name": "readline",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"filename": "readline-8.0.tar.gz",
|
||||
"hash": "sha256:e339f51971478d369f8a053a330a190781acb9864cf4c541060f12078948e461",
|
||||
"filename": "readline-8.1.tar.gz",
|
||||
"hash": "sha256:f8ceb4ee131e3232226a17f51b164afc46cd0b9e6cef344be87c65962cb82b02",
|
||||
"urls": ["http://ftp.gnu.org/gnu/readline/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "xz",
|
||||
"os": "macos,linux",
|
||||
"unix": {
|
||||
"filename": "xz-5.2.5.tar.gz",
|
||||
"hash": "sha256:f6f4910fd033078738bd82bfba4f49219d03b17eb0794eb91efbae419f4aba10",
|
||||
@@ -107,20 +128,30 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "xcrypt",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"filename": "xcrypt-4.4.17.tar.gz",
|
||||
"hash": "sha256:7665168d0409574a03f7b484682e68334764c29c21ca5df438955a381384ca07",
|
||||
"urls": ["https://github.com/besser82/libxcrypt/archive/v4.4.17.tar.gz"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "python",
|
||||
"unix": {
|
||||
"filename": "Python-3.8.3.tar.xz",
|
||||
"hash": "sha256:dfab5ec723c218082fe3d5d7ae17ecbdebffa9a1aea4d64aa3a2ecdd2e795864",
|
||||
"urls": ["https://www.python.org/ftp/python/3.8.3/{filename}"]
|
||||
"filename": "Python-3.9.4.tar.xz",
|
||||
"hash": "sha256:4b0e6644a76f8df864ae24ac500a51bbf68bd098f6a173e27d3b61cdca9aa134",
|
||||
"urls": ["https://www.python.org/ftp/python/3.9.4/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "setuptools",
|
||||
"unix": {
|
||||
"filename": "setuptools-41.0.1.zip",
|
||||
"hash": "sha256:a222d126f5471598053c9a77f4b5d4f26eaa1f150ad6e01dcf1a42e185d05613",
|
||||
"filename": "setuptools-53.0.0.tar.gz",
|
||||
"hash": "sha256:1b18ef17d74ba97ac9c0e4b4265f123f07a8ae85d9cd093949fa056d3eeeead5",
|
||||
"urls": ["pypi"]
|
||||
}
|
||||
},
|
||||
@@ -128,22 +159,12 @@
|
||||
{
|
||||
"name": "pygments",
|
||||
"unix": {
|
||||
"filename": "Pygments-2.6.1.tar.gz",
|
||||
"hash": "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44",
|
||||
"filename": "Pygments-2.7.4.tar.gz",
|
||||
"hash": "sha256:df49d09b498e83c1a73128295860250b0b7edd4c723a32e9bc0d295c7c2ec337",
|
||||
"urls": ["pypi"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "cmake",
|
||||
"os": "macos",
|
||||
"unix": {
|
||||
"filename": "cmake-3.6.0.tar.gz",
|
||||
"hash": "sha1:6b0d2d7d93c2e74f8890c4b8b824deb3b36d24b6",
|
||||
"urls": ["https://cmake.org/files/v3.6/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "libpng",
|
||||
"unix": {
|
||||
@@ -153,12 +174,21 @@
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "lcms2",
|
||||
"unix": {
|
||||
"filename": "lcms2-2.12.tar.gz",
|
||||
"hash": "sha256:e501f1482fc424550ef3abbf86bf1c66090e1661249e89552d39ed5bf935df66",
|
||||
"urls": ["https://github.com/mm2/Little-CMS/archive/2.12/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "graphite",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"filename": "graphite2-1.3.5.tgz",
|
||||
"hash": "md5:5b8d22a8bbf031838e31432868c0109c",
|
||||
"filename": "graphite2-1.3.14.tgz",
|
||||
"hash": "sha256:f99d1c13aa5fa296898a181dff9b82fb25f6cc0933dbaa7a475d8109bd54209d",
|
||||
"urls": ["http://downloads.sourceforge.net/silgraphite/{filename}"]
|
||||
}
|
||||
},
|
||||
@@ -167,8 +197,8 @@
|
||||
"name": "pcre",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"filename": "pcre-8.42.tar.bz2",
|
||||
"hash": "md5:085b6aa253e0f91cae70b3cdbe8c1ac2",
|
||||
"filename": "pcre-8.44.tar.bz2",
|
||||
"hash": "sha256:19108658b23b3ec5058edc9f66ac545ea19f9537234be1ec62b714c84399366d",
|
||||
"urls": ["https://ftp.pcre.org/pub/pcre/{filename}"]
|
||||
}
|
||||
},
|
||||
@@ -179,7 +209,7 @@
|
||||
"unix": {
|
||||
"filename": "libiconv-1.16.tar.gz",
|
||||
"hash": "sha256:e6a1b1b589654277ee790cce3734f07876ac4ccfaecbee8afa0b649cf529cc04",
|
||||
"urls": ["http://ftp.gnu.org/pub/gnu/libiconv/{filename}"]
|
||||
"urls": ["https://ftp.gnu.org/pub/gnu/libiconv/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -187,19 +217,28 @@
|
||||
"name": "glib",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"filename": "glib-2.57.1.tar.xz",
|
||||
"hash": "sha256:d029e7c4536835f1f103472f7510332c28d58b9b7d6cd0e9f45c2653e670d9b4",
|
||||
"urls": ["http://ftp.gnome.org/pub/GNOME/sources/glib/2.57/{filename}"]
|
||||
"filename": "glib-2.66.6.tar.xz",
|
||||
"hash": "sha256:80fff9c63d2725834328071c42003c311f77f91caf2285195c587c62f5638329",
|
||||
"urls": ["https://ftp.gnome.org/pub/GNOME/sources/glib/2.66/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "brotli",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"filename": "brotli-1.0.9.tar.gz",
|
||||
"hash": "sha256:f9e8d81d0405ba66d181529af42a3354f838c939095ff99930da6aa9cdf6fe46",
|
||||
"urls": ["https://github.com/google/brotli/archive/v1.0.9/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "freetype",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"filename": "freetype-2.9.1.tar.bz2",
|
||||
"hash": "md5:60ef7d8160cd4bf8cb118ee9d65367ca",
|
||||
"filename": "freetype-2.10.4.tar.xz",
|
||||
"hash": "sha256:86a854d8905b19698bbc8f23b860bc104246ce4854dcea8e3b0fb21284f75784",
|
||||
"urls": ["https://download.savannah.gnu.org/releases/freetype/{filename}"]
|
||||
}
|
||||
},
|
||||
@@ -208,8 +247,8 @@
|
||||
"name": "fontconfig",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"filename": "fontconfig-2.12.0.tar.bz2",
|
||||
"hash": "sha256:b433e4efff1f68fdd8aac221ed1df3ff1e580ffedbada020a703fe64017d8224",
|
||||
"filename": "fontconfig-2.13.1.tar.bz2",
|
||||
"hash": "sha256:f655dd2a986d7aa97e052261b36aa67b0a64989496361eca8d604e6414006741",
|
||||
"urls": ["http://www.fontconfig.org/release/{filename}"]
|
||||
}
|
||||
},
|
||||
@@ -217,19 +256,9 @@
|
||||
{
|
||||
"name": "harfbuzz",
|
||||
"unix": {
|
||||
"filename": "harfbuzz-1.7.2.tar.bz2",
|
||||
"hash": "sha256:a790585e35c1a87f0dcc23580c84b7cc2324e6f67a2946178d278c2a36c790cb",
|
||||
"urls": ["https://www.freedesktop.org/software/harfbuzz/release/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "libxml2",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"filename": "libxml2-2.9.4.tar.gz",
|
||||
"hash": "sha1:958ae70baf186263a4bd801a81dd5d682aedd1db",
|
||||
"urls": ["ftp://xmlsoft.org/libxml2/{filename}"]
|
||||
"filename": "harfbuzz-2.7.4.tar.xz",
|
||||
"hash": "sha256:6ad11d653347bd25d8317589df4e431a2de372c0cf9be3543368e07ec23bb8e7",
|
||||
"urls": ["https://github.com/harfbuzz/harfbuzz/releases/download/2.7.4/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -237,8 +266,8 @@
|
||||
"name": "wayland",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"filename": "wayland-1.18.0.tar.xz",
|
||||
"hash": "sha256:4675a79f091020817a98fd0484e7208c8762242266967f55a67776936c2e294d",
|
||||
"filename": "wayland-1.19.0.tar.xz",
|
||||
"hash": "sha256:baccd902300d354581cd5ad3cc49daa4921d55fb416a5883e218750fef166d15",
|
||||
"urls": ["https://wayland.freedesktop.org/releases/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -4,8 +4,6 @@ import subprocess
|
||||
|
||||
files_to_exclude = '''\
|
||||
kitty/wcwidth-std.h
|
||||
kitty/glfw.c
|
||||
kitty/keys.h
|
||||
kitty/charsets.c
|
||||
kitty/unicode-data.c
|
||||
kitty/key_encoding.py
|
||||
@@ -18,6 +16,11 @@ kitty/glfw-wrapper.c
|
||||
kitty/emoji.h
|
||||
kittens/unicode_input/names.h
|
||||
kitty/parse-graphics-command.h
|
||||
kitty/options/types.py
|
||||
kitty/options/parse.py
|
||||
kitty/options/to-c-generated.h
|
||||
kittens/diff/options/types.py
|
||||
kittens/diff/options/parse.py
|
||||
'''
|
||||
|
||||
p = subprocess.Popen([
|
||||
|
||||
4
docs/_static/custom.css
vendored
4
docs/_static/custom.css
vendored
@@ -21,6 +21,10 @@ div.body p, div.body dd, div.body li, div.body blockquote {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
div.body {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
128
docs/basic.rst
Normal file
128
docs/basic.rst
Normal file
@@ -0,0 +1,128 @@
|
||||
Tabs and Windows
|
||||
-------------------
|
||||
|
||||
|kitty| is capable of running multiple programs organized into tabs and
|
||||
windows. The top level of organization is the *Tab*. Each tab consists
|
||||
of one or more *windows*. The windows can be arranged in multiple
|
||||
different layouts, like windows are organized in a tiling window
|
||||
manager. The keyboard controls (which are all customizable) for tabs and
|
||||
windows are:
|
||||
|
||||
Scrolling
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
======================== =======================
|
||||
Action Shortcut
|
||||
======================== =======================
|
||||
Scroll line up :sc:`scroll_line_up` (also :kbd:`⌥+⌘+⇞` and :kbd:`⌘+↑` on macOS)
|
||||
Scroll line down :sc:`scroll_line_down` (also :kbd:`⌥+⌘+⇟` and :kbd:`⌘+↓` on macOS)
|
||||
Scroll page up :sc:`scroll_page_up` (also :kbd:`⌘+⇞` on macOS)
|
||||
Scroll page down :sc:`scroll_page_down` (also :kbd:`⌘+⇟` on macOS)
|
||||
Scroll to top :sc:`scroll_home` (also :kbd:`⌘+↖` on macOS)
|
||||
Scroll to bottom :sc:`scroll_end` (also :kbd:`⌘+↘` on macOS)
|
||||
======================== =======================
|
||||
|
||||
Tabs
|
||||
~~~~~~~~~~~
|
||||
|
||||
======================== =======================
|
||||
Action Shortcut
|
||||
======================== =======================
|
||||
New tab :sc:`new_tab` (also :kbd:`⌘+t` on macOS)
|
||||
Close tab :sc:`close_tab` (also :kbd:`⌘+w` on macOS)
|
||||
Next tab :sc:`next_tab` (also :kbd:`^+⇥` and :kbd:`⇧+⌘+]` on macOS)
|
||||
Previous tab :sc:`previous_tab` (also :kbd:`⇧+^+⇥` and :kbd:`⇧+⌘+[` on macOS)
|
||||
Next layout :sc:`next_layout`
|
||||
Move tab forward :sc:`move_tab_forward`
|
||||
Move tab backward :sc:`move_tab_backward`
|
||||
Set tab title :sc:`set_tab_title` (also :kbd:`⇧+⌘+i` on macOS)
|
||||
======================== =======================
|
||||
|
||||
|
||||
Windows
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
======================== =======================
|
||||
Action Shortcut
|
||||
======================== =======================
|
||||
New window :sc:`new_window` (also :kbd:`⌘+↩` on macOS)
|
||||
New OS window :sc:`new_os_window` (also :kbd:`⌘+n` on macOS)
|
||||
Close window :sc:`close_window` (also :kbd:`⇧+⌘+d` on macOS)
|
||||
Next window :sc:`next_window`
|
||||
Previous window :sc:`previous_window`
|
||||
Move window forward :sc:`move_window_forward`
|
||||
Move window backward :sc:`move_window_backward`
|
||||
Move window to top :sc:`move_window_to_top`
|
||||
Focus specific window :sc:`first_window`, :sc:`second_window` ... :sc:`tenth_window`
|
||||
(also :kbd:`⌘+1`, :kbd:`⌘+2` ... :kbd:`⌘+9` on macOS)
|
||||
(clockwise from the top-left)
|
||||
======================== =======================
|
||||
|
||||
Additionally, you can define shortcuts in :file:`kitty.conf` to focus neighboring
|
||||
windows and move windows around (similar to window movement in vim)::
|
||||
|
||||
map ctrl+left neighboring_window left
|
||||
map shift+left move_window right
|
||||
map ctrl+down neighboring_window down
|
||||
map shift+down move_window up
|
||||
...
|
||||
|
||||
You can also define a shortcut to switch to the previously active window::
|
||||
|
||||
map ctrl+p nth_window -1
|
||||
|
||||
``nth_window`` will focus the nth window for positive numbers and the
|
||||
previously active windows for negative numbers.
|
||||
|
||||
.. _detach_window:
|
||||
|
||||
You can define shortcuts to detach the current window and
|
||||
move it to another tab or another OS window::
|
||||
|
||||
# moves the window into a new OS window
|
||||
map ctrl+f2 detach_window
|
||||
# moves the window into a new Tab
|
||||
map ctrl+f3 detach_window new-tab
|
||||
# asks which tab to move the window into
|
||||
map ctrl+f4 detach_window ask
|
||||
|
||||
Similarly, you can detach the current tab, with::
|
||||
|
||||
# moves the tab into a new OS window
|
||||
map ctrl+f2 detach_tab
|
||||
# asks which OS Window to move the tab into
|
||||
map ctrl+f4 detach_tab ask
|
||||
|
||||
Finally, you can define a shortcut to close all windows in a tab other than
|
||||
the currently active window::
|
||||
|
||||
map f9 close_other_windows_in_tab
|
||||
|
||||
|
||||
Other keyboard shortcuts
|
||||
----------------------------------
|
||||
|
||||
================================== =======================
|
||||
Action Shortcut
|
||||
================================== =======================
|
||||
Copy to clipboard :sc:`copy_to_clipboard` (also :kbd:`⌘+c` on macOS)
|
||||
Paste from clipboard :sc:`paste_from_clipboard` (also :kbd:`⌘+v` on macOS)
|
||||
Paste from selection :sc:`paste_from_selection`
|
||||
Increase font size :sc:`increase_font_size` (also :kbd:`⌘++` on macOS)
|
||||
Decrease font size :sc:`decrease_font_size` (also :kbd:`⌘+-` on macOS)
|
||||
Restore font size :sc:`reset_font_size` (also :kbd:`⌘+0` on macOS)
|
||||
Toggle fullscreen :sc:`toggle_fullscreen` (also :kbd:`^+⌘+f` on macOS)
|
||||
Toggle maximized :sc:`toggle_maximized`
|
||||
Input unicode character :sc:`input_unicode_character` (also :kbd:`^+⌘+space` on macOS)
|
||||
Click URL using the keyboard :sc:`open_url`
|
||||
Reset the terminal :sc:`reset_terminal`
|
||||
Reload :file:`kitty.conf` :sc:`reload_config_file` (also :kbd:`^+⌘+f5` on macOS)
|
||||
Debug :file:`kitty.conf` :sc:`debug_config` (also :kbd:`⌘+option+f6` on macOS)
|
||||
Pass current selection to program :sc:`pass_selection_to_program`
|
||||
Edit |kitty| config file :sc:`edit_config_file`
|
||||
Open a |kitty| shell :sc:`kitty_shell`
|
||||
Increase background opacity :sc:`increase_background_opacity`
|
||||
Decrease background opacity :sc:`decrease_background_opacity`
|
||||
Full background opacity :sc:`full_background_opacity`
|
||||
Reset background opacity :sc:`reset_background_opacity`
|
||||
================================== =======================
|
||||
@@ -44,10 +44,17 @@ particular desktop, but it should work for most major desktop environments.
|
||||
# your PATH)
|
||||
ln -s ~/.local/kitty.app/bin/kitty ~/.local/bin/
|
||||
# Place the kitty.desktop file somewhere it can be found by the OS
|
||||
cp ~/.local/kitty.app/share/applications/kitty.desktop ~/.local/share/applications
|
||||
cp ~/.local/kitty.app/share/applications/kitty.desktop ~/.local/share/applications/
|
||||
# Update the path to the kitty icon in the kitty.desktop file
|
||||
sed -i "s|Icon=kitty|Icon=/home/$USER/.local/kitty.app/share/icons/hicolor/256x256/apps/kitty.png|g" ~/.local/share/applications/kitty.desktop
|
||||
|
||||
.. note::
|
||||
If you use the venerable `stow <https://www.gnu.org/software/stow/>`_
|
||||
command to manage your manual installations, the following takes care of the
|
||||
above for you (use with :file:`dest=~/.local/stow`)::
|
||||
|
||||
cd ~/.local/stow
|
||||
stow -v kitty.app
|
||||
|
||||
|
||||
Customizing the installation
|
||||
|
||||
@@ -6,22 +6,34 @@ Building kitty from source
|
||||
:target: https://github.com/kovidgoyal/kitty/actions?query=workflow%3ACI
|
||||
|
||||
|
||||
|kitty| is designed to run from source, for easy hackability. Make sure
|
||||
|kitty| is designed to run from source, for easy hack-ability. Make sure
|
||||
the following dependencies are installed first.
|
||||
|
||||
|
||||
.. note::
|
||||
If you are making small changes only to the python parts of kitty, there is no need to
|
||||
build kitty at all, instead, assuming you have installed the official kitty
|
||||
binaries, you can simply set the KITTY_DEVELOP_FROM enviroment variable to
|
||||
point to the directory into which you have checked out the kitty source
|
||||
code. kitty will then load its python code from there. You should use a
|
||||
version of the source that matches the binary version as closely as
|
||||
possible, since the two are tightly coupled.
|
||||
|
||||
|
||||
Dependencies
|
||||
----------------
|
||||
|
||||
Run-time dependencies:
|
||||
|
||||
* python >= 3.5
|
||||
* harfbuzz >= 1.5.0
|
||||
* python >= 3.6
|
||||
* harfbuzz >= 2.2.0
|
||||
* zlib
|
||||
* libpng
|
||||
* liblcms2
|
||||
* freetype (not needed on macOS)
|
||||
* fontconfig (not needed on macOS)
|
||||
* libcanberra (not needed on macOS)
|
||||
* ImageMagick (optional, needed to use the ``kitty icat`` tool to display images in the terminal)
|
||||
* ImageMagick (optional, needed to use the ``kitty +kitten icat`` tool to display images in the terminal)
|
||||
* pygments (optional, need for syntax highlighting in ``kitty +kitten diff``)
|
||||
|
||||
Build-time dependencies:
|
||||
@@ -29,7 +41,7 @@ Build-time dependencies:
|
||||
* gcc or clang
|
||||
* pkg-config
|
||||
* For building on Linux in addition to the above dependencies you might also need to install the ``-dev`` packages for:
|
||||
``libdbus-1-dev``, ``libxcursor-dev``, ``libxrandr-dev``, ``libxi-dev``, ``libxinerama-dev``, ``libgl1-mesa-dev``, ``libxkbcommon-x11-dev``, ``libfontconfig-dev``, and ``libpython-dev``,
|
||||
``libdbus-1-dev``, ``libxcursor-dev``, ``libxrandr-dev``, ``libxi-dev``, ``libxinerama-dev``, ``libgl1-mesa-dev``, ``libxkbcommon-x11-dev``, ``libfontconfig-dev``, ``libx11-xcb-dev``, ``liblcms2-dev``, and ``libpython3-dev``,
|
||||
if they are not already installed by your distro.
|
||||
|
||||
Install and run from source
|
||||
@@ -63,10 +75,31 @@ This :file:`kitty.app` unlike the released one does not include its own copy of
|
||||
python and the other dependencies. So if you ever un-install/upgrade those dependencies
|
||||
you might have to rebuild the app.
|
||||
|
||||
Note that the released :file:`kitty.dmg` includes all dependencies, unlike the
|
||||
:file:`kitty.app` built above and is built automatically by using the :file:`kitty` branch of
|
||||
`build-calibre <https://github.com/kovidgoyal/build-calibre>`_ however, that
|
||||
is designed to run on Linux and is not for the faint of heart.
|
||||
.. note::
|
||||
The released :file:`kitty.dmg` includes all dependencies, unlike the
|
||||
:file:`kitty.app` built above and is built automatically by using the
|
||||
<https://github.com/kovidgoyal/bypy>`_ however, that is designed to
|
||||
run on Linux and is not for the faint of heart.
|
||||
|
||||
|
||||
.. note::
|
||||
Apple disallows certain functionality, such as notifications for unsigned applications.
|
||||
If you need this functionality, you can try signing the built kitty.app with
|
||||
a self signed certificate, see for example, `here
|
||||
<https://stackoverflow.com/questions/27474751/how-can-i-codesign-an-app-without-being-in-the-mac-developer-program/27474942>`_.
|
||||
|
||||
Build and run from source with Nix
|
||||
-------------------------------------------
|
||||
|
||||
On NixOS or any other Linux or macOS system with the Nix package manager
|
||||
installed, execute `nix-shell
|
||||
<https://nixos.org/guides/nix-pills/developing-with-nix-shell.html>`_ to create
|
||||
the correct environment to build kitty or use ``nix-shell --pure`` instead to
|
||||
eliminate most of the influence of the outside system, e.g. globally installed
|
||||
packages. ``nix-shell`` will automatically fetch all required dependencies and
|
||||
make them available in the newly spawned shell.
|
||||
|
||||
Then proceed with ``make`` or ``make app`` according to the platform specific instructions above.
|
||||
|
||||
|
||||
Note for Linux/macOS packagers
|
||||
|
||||
@@ -1,9 +1,545 @@
|
||||
Changelog
|
||||
==============
|
||||
|
||||
|kitty| is a feature full, cross-platform, *fast*, GPU based terminal emulator.
|
||||
|kitty| is a feature-rich, cross-platform, *fast*, GPU based terminal.
|
||||
To update |kitty|, :doc:`follow the instructions <binary>`.
|
||||
|
||||
0.21.2 [2021-06-28]
|
||||
----------------------
|
||||
|
||||
- A new :opt:`adjust_baseline` option to adjust the vertical alignment of text
|
||||
inside a line (:pull:`3734`)
|
||||
|
||||
- A new :opt:`url_excluded_characters` option to exclude additional characters
|
||||
when detecting URLs under the mouse (:pull:`3738`)
|
||||
|
||||
- Fix a regression in 0.21.0 that broke rendering of private use Unicode symbols followed
|
||||
by spaces, when they also exist not followed by spaces (:iss:`3729`)
|
||||
|
||||
- ssh kitten: Support systems where the login shell is a non-POSIX shell
|
||||
(:iss:`3405`)
|
||||
|
||||
- ssh kitten: Add completion (:iss:`3760`)
|
||||
|
||||
- ssh kitten: Fix "Connection closed" message being printed by ssh when running
|
||||
remote commands
|
||||
|
||||
- Add support for the XTVERSION escape code
|
||||
|
||||
- macOS: Fix a regression in 0.21.0 that broke middle-click to paste from clipboard (:iss:`3730`)
|
||||
|
||||
- macOS: Fix shortcuts in the global menu bar responding slowly when cursor blink
|
||||
is disabled/timed out (:iss:`3693`)
|
||||
|
||||
- When displaying scrollback ensure that the window does not quit if the amount
|
||||
of scrollback is less than a screen and the user has the ``--quit-if-one-screen``
|
||||
option enabled for less (:iss:`3740`)
|
||||
|
||||
- Linux: Fix Emoji/bitmapped fonts not use able in symbol_map
|
||||
|
||||
- query terminal kitten: Allow querying font face and size information
|
||||
(:iss:`3756`)
|
||||
|
||||
- hyperlinked grep kitten: Fix context options not generating contextual output (:iss:`3759`)
|
||||
|
||||
- Allow using superscripts in tab titles (:iss:`3763`)
|
||||
|
||||
- Unicode input kitten: Fix searching when a word has more than 1024 matches (:iss:`3773`)
|
||||
|
||||
|
||||
0.21.1 [2021-06-14]
|
||||
----------------------
|
||||
|
||||
- macOS: Fix a regression in the previous release that broke rendering of
|
||||
strikeout (:iss:`3717`)
|
||||
|
||||
- macOS: Fix a crash when rendering ligatures larger than 128 characters
|
||||
(:iss:`3724`)
|
||||
|
||||
- Fix a regression in the previous release that could cause a crash when
|
||||
changing layouts and mousing (:iss:`3713`)
|
||||
|
||||
|
||||
0.21.0 [2021-06-12]
|
||||
----------------------
|
||||
|
||||
- Allow reloading the :file:`kitty.conf` config file by pressing
|
||||
:sc:`reload_config_file`. (:iss:`1292`)
|
||||
|
||||
- Allow clicking URLs to open them without needing to also hold
|
||||
:kbd:`ctrl+shift`
|
||||
|
||||
- Allow remapping all mouse button press/release events to perform arbitrary
|
||||
actions. :ref:`See details <conf-kitty-mouse.mousemap>` (:iss:`1033`)
|
||||
|
||||
- Support infinite length ligatures (:iss:`3504`)
|
||||
|
||||
- **Backward incompatibility**: The options to control which modifiers keys to
|
||||
press for various mouse actions have been removed, if you used these options,
|
||||
you will need to replace them with configuration using the new
|
||||
:ref:`mouse actions framework <conf-kitty-mouse.mousemap>` as they will be
|
||||
ignored. The options were: ``terminal_select_modifiers``,
|
||||
``rectangle_select_modifiers`` and ``open_url_modifiers``.
|
||||
|
||||
- Add a configurable mouse action (:kbd:`ctrl+alt+triplepress` to select from the
|
||||
clicked point to the end of the line. (:iss:`3585`)
|
||||
|
||||
- Add the ability to un-scroll the screen to the ``kitty @ scroll-window``
|
||||
remote control command (:iss:`3604`)
|
||||
|
||||
- A new option, :opt:`tab_bar_margin_height` to add margins around the
|
||||
top and bottom edges of the tab bar (:iss:`3247`)
|
||||
|
||||
- Unicode input kitten: Fix a regression in 0.20.0 that broke keyboard handling
|
||||
when the NumLock or CapsLock modifiers were engaged. (:iss:`3587`)
|
||||
|
||||
- Fix a regression in 0.20.0 that sent incorrect bytes for the :kbd:`F1-F4` keys
|
||||
in rmkx mode (:iss:`3586`)
|
||||
|
||||
- macOS: When the Apple Color Emoji font lacks an emoji glyph search for it in other
|
||||
installed fonts (:iss:`3591`)
|
||||
|
||||
- macOS: Fix rendering getting stuck on some machines after sleep/screensaver
|
||||
(:iss:`2016`)
|
||||
|
||||
- macOS: Add a new ``Shell`` menu to the global menubar with some commonly used
|
||||
actions (:pull:`3653`)
|
||||
|
||||
- macOS: Fix the baseline for text not matching other CoreText based
|
||||
applications for some fonts (:iss:`2022`)
|
||||
|
||||
- Add a few more special commandline arguments for the launch command. Now all
|
||||
``KITTY_PIPE_DATA`` is also available via command line argument substitution
|
||||
(:iss:`3593`)
|
||||
|
||||
- Fix dynamically changing the background color in a window causing rendering
|
||||
artifacts in the tab bar (:iss:`3595`)
|
||||
|
||||
- Fix passing STDIN to launched background processes causing them to not inherit
|
||||
environment variables (:pull:`3603`)
|
||||
|
||||
- Fix deleting windows that are not the last window via remote control leaving
|
||||
no window focused (:iss:`3619`)
|
||||
|
||||
- Add an option :option:`kitty @ get-text --add-cursor` to also get the current
|
||||
cursor position and state as ANSI escape codes (:iss:`3625`)
|
||||
|
||||
- Add an option :option:`kitty @ get-text --add-wrap-markers` to add line wrap
|
||||
markers to the output (:pull:`3633`)
|
||||
|
||||
- Improve rendering of curly underlines on HiDPI screens (:pull:`3637`)
|
||||
|
||||
- ssh kitten: Mimic behavior of ssh command line client more closely by
|
||||
executing any command specified on the command line via the users' shell
|
||||
just as ssh does (:iss:`3638`)
|
||||
|
||||
- Fix trailing parentheses in URLs not being detected (:iss:`3688`)
|
||||
|
||||
- Tab bar: Use a lower contrast color for tab separators (:pull:`3666`)
|
||||
|
||||
- Fix a regression that caused using the ``title`` command in session files
|
||||
to stop working (:iss:`3676`)
|
||||
|
||||
- macOS: Fix a rare crash on exit (:iss:`3686`)
|
||||
|
||||
- Fix ligatures not working with the `Iosevka
|
||||
<https://github.com/be5invis/Iosevka>`_ font (requires Iosevka >= 7.0.4)
|
||||
(:iss:`297`)
|
||||
|
||||
- Remote control: Allow matching tabs by index number in currently active OS
|
||||
Window (:iss:`3708`)
|
||||
|
||||
- ssh kitten: Fix non-standard properties in terminfo such as the ones used for
|
||||
true color not being copied (:iss:`312`)
|
||||
|
||||
|
||||
0.20.3 [2021-05-06]
|
||||
----------------------
|
||||
|
||||
- macOS: Distribute universal binaries with both ARM and Intel architectures
|
||||
|
||||
- A new ``show_key`` kitten to easily see the bytes generated by the terminal
|
||||
for key presses in the various keyboard modes (:pull:`3556`)
|
||||
|
||||
- Linux: Fix keyboard layout change keys defined via compose rules not being
|
||||
ignored
|
||||
|
||||
- macOS: Fix Spotlight search of global menu not working in non-English locales
|
||||
(:pull:`3567`)
|
||||
|
||||
- Fix tab activity symbol not appearing if no other changes happen in tab bar even when
|
||||
there is activity in a tab (:iss:`3571`)
|
||||
|
||||
- Fix focus changes not being sent to windows when focused window changes
|
||||
because of the previously focused window being closed (:iss:`3571`)
|
||||
|
||||
|
||||
0.20.2 [2021-04-28]
|
||||
----------------------
|
||||
|
||||
- A new protocol extension to :ref:`unscroll <unscroll>` text from the
|
||||
scrollback buffer onto the screen. Useful, for example, to restore
|
||||
the screen after showing completions below the shell prompt.
|
||||
|
||||
- A new remote control command :ref:`at_env` to change the default
|
||||
environment passed to newly created windows (:iss:`3529`)
|
||||
|
||||
- Linux: Fix binary kitty builds not able to load fonts in WOFF2 format
|
||||
(:iss:`3506`)
|
||||
|
||||
- macOS: Prevent :kbd:`option` based shortcuts for being used for global menu
|
||||
actions (:iss:`3515`)
|
||||
|
||||
- Fix ``kitty @ close-tab`` not working with pipe based remote control
|
||||
(:iss:`3510`)
|
||||
|
||||
- Fix removal of inactive tab that is before the currently active tab causing
|
||||
the highlighted tab to be incorrect (:iss:`3516`)
|
||||
|
||||
- icat kitten: Respect EXIF orientation when displaying JPEG images
|
||||
(:iss:`3518`)
|
||||
|
||||
- GNOME: Fix maximize state not being remembered when focus changes and window
|
||||
decorations are hidden (:iss:`3507`)
|
||||
|
||||
- GNOME: Add a new :opt:`wayland_titlebar_color` option to control the color of the
|
||||
kitty window title bar
|
||||
|
||||
- Fix reading :option:`kitty --session` from ``STDIN`` not working when the
|
||||
:option:`kitty --detach` option is used (:iss:`3523`)
|
||||
|
||||
- Special case rendering of the few remaining Powerline box drawing chars
|
||||
(:iss:`3535`)
|
||||
|
||||
- Fix ``kitty @ set-colors`` not working for the :opt:`active_tab_foreground`.
|
||||
|
||||
|
||||
0.20.1 [2021-04-19]
|
||||
----------------------
|
||||
|
||||
- icat: Fix some broken GIF images with no frame delays not being animated
|
||||
(:iss:`3498`)
|
||||
|
||||
- hints kitten: Fix sending hyperlinks to their default handler not working
|
||||
(:pull:`3500`)
|
||||
|
||||
- Wayland: Fix regression in previous release causing window decorations to
|
||||
be drawn even when compositor supports server side decorations (:iss:`3501`)
|
||||
|
||||
|
||||
0.20.0 [2021-04-19]
|
||||
----------------------
|
||||
|
||||
- Support display of animated images ``kitty +kitten icat animation.gif``. See
|
||||
:ref:`animation_protocol` for details on animation support in the kitty
|
||||
graphics protocol.
|
||||
|
||||
- A new keyboard reporting protocol with various advanced features that can be
|
||||
used by full screen terminal programs and even games, see
|
||||
:doc:`keyboard-protocol` (:iss:`3248`)
|
||||
|
||||
- **Backward incompatibility**: Session files now use the full :doc:`launch <launch>`
|
||||
command with all its capabilities. However, the syntax of the command is
|
||||
slightly different from before. In particular watchers are now specified
|
||||
directly on launch and environment variables are set using ``--env``.
|
||||
|
||||
- Allow setting colors when creating windows using the :doc:`launch <launch>` command.
|
||||
|
||||
- A new option :opt:`tab_powerline_style` to control the appearance of the tab
|
||||
bar when using the powerline tab bar style.
|
||||
|
||||
- A new option :opt:`scrollback_fill_enlarged_window` to fill extra lines in
|
||||
the window when the window is expanded with lines from the scrollback
|
||||
(:pull:`3371`)
|
||||
|
||||
- diff kitten: Implement recursive diff over SSH (:iss:`3268`)
|
||||
|
||||
- ssh kitten: Allow using python instead of the shell on the server, useful if
|
||||
the shell used is a non-POSIX compliant one, such as fish (:iss:`3277`)
|
||||
|
||||
- Add support for the color settings stack that XTerm copied from us without
|
||||
acknowledgement and decided to use incompatible escape codes for.
|
||||
|
||||
- Add entries to the terminfo file for some user capabilities that are shared
|
||||
with XTerm (:pull:`3193`)
|
||||
|
||||
- The launch command now does more sophisticated resolving of executables to
|
||||
run. The system-wide PATH is used first, then system specific default paths,
|
||||
and finally the PATH inside the shell.
|
||||
|
||||
- Double clicking on empty tab bar area now opens a new tab (:iss:`3201`)
|
||||
|
||||
- kitty @ ls: Show only environment variables that are different for each
|
||||
window, by default.
|
||||
|
||||
- When passing a directory or a non-executable file as the program to run to
|
||||
kitty opens it with the shell or by parsing the shebang, instead of just failing.
|
||||
|
||||
- Linux: Fix rendering of emoji followed by the graphics variation selector not
|
||||
being colored with some fonts (:iss:`3211`)
|
||||
|
||||
- Unicode input: Fix using index in select by name mode not working for indices
|
||||
larger than 16. Also using an index does not filter the list of matches. (:pull:`3219`)
|
||||
|
||||
- Wayland: Add support for the text input protocol (:iss:`3410`)
|
||||
|
||||
- Wayland: Fix mouse handling when using client side decorations
|
||||
|
||||
- Wayland: Fix un-maximizing a window not restoring its size to what it was
|
||||
before being maximized
|
||||
|
||||
- GNOME/Wayland: Improve window decorations the titlebar now shows the window
|
||||
title. Allow running under Wayland on GNOME by default. (:iss:`3284`)
|
||||
|
||||
- Panel kitten: Allow setting WM_CLASS (:iss:`3233`)
|
||||
|
||||
- macOS: Add menu items to close the OS window and the current tab (:pull:`3240`, :iss:`3246`)
|
||||
|
||||
- macOS: Allow opening script and command files with kitty (:iss:`3366`)
|
||||
|
||||
- Also detect ``gemini://`` URLs when hovering with the mouse (:iss:`3370`)
|
||||
|
||||
- When using a non-US keyboard layout and pressing :kbd:`ctrl+key` when
|
||||
the key matches an English key, send that to the program running in the
|
||||
terminal automatically (:iss:`2000`)
|
||||
|
||||
- When matching shortcuts, also match on shifted keys, so a shortcut defined as
|
||||
:kbd:`ctrl+plus` will match a keyboard where you have to press
|
||||
:kbd:`shift+equal` to get the plus key (:iss:`2000`)
|
||||
|
||||
- Fix extra space at bottom of OS window when using the fat layout with the tab bar at the
|
||||
top (:iss:`3258`)
|
||||
|
||||
- Fix window icon not working on X11 with 64bits (:iss:`3260`)
|
||||
|
||||
- Fix OS window sizes under 100px resulting in scaled display (:iss:`3307`)
|
||||
|
||||
- Fix rendering of ligatures in the latest release of Cascadia code, which for
|
||||
some reason puts empty glyphs after the ligature glyph rather than before it
|
||||
(:iss:`3313`)
|
||||
|
||||
- Improve handling of infinite length ligatures in newer versions of FiraCode
|
||||
and CascadiaCode. Now such ligatures are detected based on glyph naming
|
||||
convention. This removes the gap in the ligatures at cell boundaries (:iss:`2695`)
|
||||
|
||||
- macOS: Disable the native operating system tabs as they are non-functional
|
||||
and can be confusing (:iss:`3325`)
|
||||
|
||||
- hints kitten: When using the linenumber action with a background action,
|
||||
preserve the working directory (:iss:`3352`)
|
||||
|
||||
- Graphics protocol: Fix suppression of responses not working for chunked
|
||||
transmission (:iss:`3375`)
|
||||
|
||||
- Fix inactive tab closing causing active tab to change (:iss:`3398`)
|
||||
|
||||
- Fix a crash on systems using musl as libc (:iss:`3395`)
|
||||
|
||||
- Improve rendering of rounded corners by using a rectircle equation rather
|
||||
than a cubic bezier (:iss:`3409`)
|
||||
|
||||
- Graphics protocol: Add a control to allow clients to specify that the cursor
|
||||
should not move when displaying an image (:iss:`3411`)
|
||||
|
||||
- Fix marking of text not working on lines that contain zero cells
|
||||
(:iss:`3403`)
|
||||
|
||||
- Fix the selection getting changed if the screen contents scroll while
|
||||
the selection is in progress (:iss:`3431`)
|
||||
|
||||
- X11: Fix :opt:`resize_in_steps` being applied even when window is maximized
|
||||
(:iss:`3473`)
|
||||
|
||||
|
||||
0.19.3 [2020-12-19]
|
||||
-------------------
|
||||
|
||||
- Happy holidays to all kitty users!
|
||||
|
||||
- A new :doc:`broadcast <kittens/broadcast>` kitten to type in all kitty windows
|
||||
simultaneously (:iss:`1569`)
|
||||
|
||||
- Add a new mappable `select_tab` action to choose a tab to switch to even
|
||||
when the tab bar is hidden (:iss:`3115`)
|
||||
|
||||
- Allow specifying text formatting in :opt:`tab_title_template` (:iss:`3146`)
|
||||
|
||||
- Linux: Read :opt:`font_features` from the FontConfig database as well, so
|
||||
that they can be configured in a single, central location (:pull:`3174`)
|
||||
|
||||
- Graphics protocol: Add support for giving individual image placements their
|
||||
own ids and for asking the terminal emulator to assign ids for images. Also
|
||||
allow suppressing responses from the terminal to commands.
|
||||
These are backwards compatible protocol extensions. (:iss:`3133`,
|
||||
:iss:`3163`)
|
||||
|
||||
- Distribute extra pixels among all eight-blocks rather than adding them
|
||||
all to the last block (:iss:`3097`)
|
||||
|
||||
- Fix drawing of a few sextant characters incorrect (:pull:`3105`)
|
||||
|
||||
- macOS: Fix minimize not working for chromeless windows (:iss:`3112`)
|
||||
|
||||
- Preserve lines in the scrollback if a scrolling region is defined that
|
||||
is contiguous with the top of the screen (:iss:`3113`)
|
||||
|
||||
- Wayland: Fix key repeat being stopped by the release of an unrelated key
|
||||
(:iss:`2191`)
|
||||
|
||||
- Add an option, :opt:`detect_urls` to control whether kitty will detect URLs
|
||||
when the mouse moves over them (:pull:`3118`)
|
||||
|
||||
- Graphics protocol: Dont return filename in the error message when opening file
|
||||
fails, since filenames can contain control characters (:iss:`3128`)
|
||||
|
||||
- macOS: Partial fix for traditional fullscreen not working on Big Sur
|
||||
(:iss:`3100`)
|
||||
|
||||
- Fix one ANSI formatting escape code not being removed from the pager history
|
||||
buffer when piping it as plain text (:iss:`3132`)
|
||||
|
||||
- Match the save/restore cursor behavior of other terminals, for the sake of
|
||||
interoperability. This means that doing a DECRC without a prior DECSC is now
|
||||
undefined (:iss:`1264`)
|
||||
|
||||
- Fix mapping ``remote_control send-text`` not working (:iss:`3147`)
|
||||
|
||||
- Add a ``right`` option for :opt:`tab_switch_strategy` (:pull:`3155`)
|
||||
|
||||
- Fix a regression in 0.19.0 that caused a rare crash when using the optional
|
||||
:opt:`scrollback_pager_history_size` (:iss:`3049`)
|
||||
|
||||
- Full screen kittens: Fix incorrect cursor position after kitten quits
|
||||
(:iss:`3176`)
|
||||
|
||||
|
||||
0.19.2 [2020-11-13]
|
||||
-------------------
|
||||
|
||||
- A new :doc:`kittens/query_terminal` kitten to easily query the running kitty
|
||||
via escape codes to detect its version, and the values of
|
||||
configuration options that enable or disable terminal features.
|
||||
|
||||
- Options to control mouse pointer shape, :opt:`default_pointer_shape`, and
|
||||
:opt:`pointer_shape_when_dragging` (:pull:`3041`)
|
||||
|
||||
- Font independent rendering for braille characters, which ensures they are properly
|
||||
aligned at all font sizes.
|
||||
|
||||
- Fix a regression in 0.19.0 that caused borders not to be drawn when setting
|
||||
:opt:`window_margin_width` and keeping :opt:`draw_minimal_borders` on
|
||||
(:iss:`3017`)
|
||||
|
||||
- Fix a regression in 0.19.0 that broke rendering of one-eight bar unicode
|
||||
characters at very small font sizes (:iss:`3025`)
|
||||
|
||||
- Wayland: Fix a crash under GNOME when using multiple OS windows
|
||||
(:pull:`3066`)
|
||||
|
||||
- Fix selections created by dragging upwards not being auto-cleared when
|
||||
screen contents change (:pull:`3028`)
|
||||
|
||||
- macOS: Fix kitty not being added to PATH automatically when using pre-built
|
||||
binaries (:iss:`3063`)
|
||||
|
||||
- Allow adding MIME definitions to kitty by placing a ``mime.types`` file in
|
||||
the kitty config directory (:iss:`3056`)
|
||||
|
||||
- Dont ignore :option:`--title` when using a session file that defines no
|
||||
windows (:iss:`3055`)
|
||||
|
||||
- Fix the send_text action not working in URL handlers (:iss:`3081`)
|
||||
|
||||
- Fix last character of URL not being detected if it is the only character on a
|
||||
new line (:iss:`3088`)
|
||||
|
||||
- Don't restrict the ICH,DCH,REP control codes to only the current scroll region (:iss:`3090`, :iss:`3096`)
|
||||
|
||||
|
||||
0.19.1 [2020-10-06]
|
||||
-------------------
|
||||
|
||||
- hints kitten: Add an ``ip`` type for easy selection of IP addresses
|
||||
(:pull:`3009`)
|
||||
|
||||
- Fix a regression that caused a segfault when using
|
||||
:opt:`scrollback_pager_history_size` and it needs to be expanded (:iss:`3011`)
|
||||
|
||||
- Fix update available notifications repeating (:pull:`3006`)
|
||||
|
||||
|
||||
0.19.0 [2020-10-04]
|
||||
-------------------
|
||||
|
||||
- Add support for `hyperlinks from terminal programs
|
||||
<https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda>`_.
|
||||
Controlled via :opt:`allow_hyperlinks` (:iss:`68`)
|
||||
|
||||
- Add support for easily editing or downloading files over SSH sessions
|
||||
without the need for any special software, see :doc:`kittens/remote_file`
|
||||
|
||||
- A new :doc:`kittens/hyperlinked_grep` kitten to easily search files and open
|
||||
the results at the matched line by clicking on them.
|
||||
|
||||
- Allow customizing the :doc:`actions kitty takes <open_actions>` when clicking on URLs
|
||||
|
||||
- Improve rendering of borders when using minimal borders. Use less space and
|
||||
do not display a box around active windows
|
||||
|
||||
- Add a new extensible escape code to allow terminal programs to trigger
|
||||
desktop notifications. See :ref:`desktop_notifications` (:iss:`1474`)
|
||||
|
||||
- Implement special rendering for various characters from the set of "Symbols
|
||||
for Legacy Computing" from the Unicode 13 standard
|
||||
|
||||
- Unicode input kitten: Allow choosing symbols from the NERD font as well.
|
||||
These are mostly Private Use symbols not in any standard, however are common. (:iss:`2972`)
|
||||
|
||||
- Allow specifying border sizes in either pts or pixels. Change the default to
|
||||
0.5pt borders as this works best with the new minimal border style
|
||||
|
||||
- Add support for displaying correct colors with non-sRGB PNG files (Adds a
|
||||
dependency on liblcms2)
|
||||
|
||||
- hints kitten: Add a new :option:`kitty +kitten hints --type` of ``hyperlink`` useful
|
||||
for activating hyperlinks using just the keyboard
|
||||
|
||||
- Allow tracking focus change events in watchers (:iss:`2918`)
|
||||
|
||||
- Allow specifying watchers in session files and via a command line argument
|
||||
(:iss:`2933`)
|
||||
|
||||
- Add a setting :opt:`tab_activity_symbol` to show a symbol in the tab title
|
||||
if one of the windows has some activity after it was last focused
|
||||
(:iss:`2515`)
|
||||
|
||||
- macOS: Switch to using the User Notifications framework for notifications.
|
||||
The current notifications framework has been deprecated in Big Sur. The new
|
||||
framework only allows notifications from signed and notarized applications,
|
||||
so people using kitty from homebrew/source are out of luck. Complain to
|
||||
Apple.
|
||||
|
||||
- When in the main screen and a program grabs the mouse, do not use the scroll
|
||||
wheel events to scroll the scrollback buffer, instead send them to the
|
||||
program (:iss:`2939`)
|
||||
|
||||
- Fix unfocused windows in which a bell occurs not changing their border color
|
||||
to red until a relayout
|
||||
|
||||
- Linux: Fix automatic detection of bold/italic faces for fonts such as IBM
|
||||
Plex Mono that have the regular face with a full name that is the same as the
|
||||
family name (:iss:`2951`)
|
||||
|
||||
- Fix a regression that broke :opt:`kitten_alias` (:iss:`2952`)
|
||||
|
||||
- Fix a regression that broke the ``move_window_to_top`` action (:pull:`2953`)
|
||||
|
||||
- Fix a memory leak when changing font sizes
|
||||
|
||||
- Fix some lines in the scrollback buffer not being properly rendered after a
|
||||
window resize/font size change (:iss:`2619`)
|
||||
|
||||
|
||||
0.18.3 [2020-08-11]
|
||||
-------------------
|
||||
|
||||
@@ -293,7 +829,7 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
|
||||
beam and underline cursors (:iss:`2337` and :pull:`2342`)
|
||||
|
||||
- When the application running in the terminal grabs the mouse, pass middle
|
||||
clicks to the application unless :opt:`terminal_select_modifiers` are
|
||||
clicks to the application unless `terminal_select_modifiers` are
|
||||
pressed (:iss:`2368`)
|
||||
|
||||
- A new ``copy_and_clear_or_interrupt`` function (:iss:`2403`)
|
||||
@@ -401,7 +937,7 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
|
||||
- macOS: Add a :code:`titlebar-only` setting to
|
||||
:opt:`hide_window_decorations` to only hide the title bar (:pull:`2286`)
|
||||
|
||||
- Fix a segfault when using :option:`kitty --debug-config` with maps (:iss:`2270`)
|
||||
- Fix a segfault when using ``--debug-config`` with maps (:iss:`2270`)
|
||||
|
||||
- ``goto_tab`` now maps numbers larger than the last tab to the last tab
|
||||
(:iss:`2291`)
|
||||
@@ -573,7 +1109,7 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
|
||||
the mouse pointer shape when the terminal programs grabs the pointer
|
||||
(:iss:`1808`)
|
||||
|
||||
- Add an option :opt:`terminal_select_modifiers` to control which modifiers
|
||||
- Add an option `terminal_select_modifiers` to control which modifiers
|
||||
are used to override mouse selection even when a terminal application has
|
||||
grabbed the mouse (:iss:`1774`)
|
||||
|
||||
@@ -1277,8 +1813,8 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
|
||||
|
||||
- Support "-T" as an alias for "--title" (:pull:`659`)
|
||||
|
||||
- Fix a regression in the previous release that broke using :option:`kitty
|
||||
--debug-config` with custom key mappings (:iss:`695`)
|
||||
- Fix a regression in the previous release that broke using
|
||||
``--debug-config`` with custom key mappings (:iss:`695`)
|
||||
|
||||
|
||||
0.11.1 [2018-06-17]
|
||||
|
||||
133
docs/conf.py
133
docs/conf.py
@@ -13,10 +13,7 @@ import subprocess
|
||||
import sys
|
||||
import time
|
||||
from functools import partial
|
||||
from typing import (
|
||||
Any, Callable, Dict, Iterable, List, Match, Optional, Sequence, Tuple,
|
||||
Union
|
||||
)
|
||||
from typing import Any, Callable, Dict, Iterable, List, Match, Optional, Tuple
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst.roles import set_classes
|
||||
@@ -24,7 +21,7 @@ from pygments.lexer import RegexLexer, bygroups # type: ignore
|
||||
from pygments.token import ( # type: ignore
|
||||
Comment, Keyword, Literal, Name, Number, String, Whitespace
|
||||
)
|
||||
from sphinx import addnodes # type: ignore
|
||||
from sphinx import addnodes, version_info # type: ignore
|
||||
from sphinx.environment.adapters.toctree import TocTree # type: ignore
|
||||
from sphinx.util.logging import getLogger # type: ignore
|
||||
|
||||
@@ -32,10 +29,9 @@ kitty_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
if kitty_src not in sys.path:
|
||||
sys.path.insert(0, kitty_src)
|
||||
|
||||
from kitty.conf.definition import Option, Shortcut # noqa
|
||||
from kitty.conf.types import Definition # noqa
|
||||
from kitty.constants import str_version # noqa
|
||||
|
||||
|
||||
# config {{{
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
@@ -140,9 +136,6 @@ html_theme_options = {
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static', '../logo/kitty.png']
|
||||
html_context = {
|
||||
'css_files': ['_static/custom.css']
|
||||
}
|
||||
html_favicon = '../logo/kitty.png'
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
@@ -170,8 +163,8 @@ html_show_sourcelink = False
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('invocation', 'kitty', 'kitty Documentation',
|
||||
[author], 1)
|
||||
('invocation', 'kitty', 'kitty Documentation', [author], 1),
|
||||
('conf', 'kitty.conf', 'kitty.conf Documentation', [author], 5)
|
||||
]
|
||||
|
||||
|
||||
@@ -182,7 +175,7 @@ man_pages = [
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'kitty', 'kitty Documentation',
|
||||
author, 'kitty', 'A cross-platform, fast, feature full, GPU based terminal emulator',
|
||||
author, 'kitty', 'Cross-platform, fast, feature-rich, GPU based terminal',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
# }}}
|
||||
@@ -251,8 +244,8 @@ def add_html_context(app: Any, pagename: str, templatename: str, context: Any, *
|
||||
|
||||
# CLI docs {{{
|
||||
def write_cli_docs(all_kitten_names: Iterable[str]) -> None:
|
||||
from kitty.launch import options_spec as launch_options_spec
|
||||
from kitty.cli import option_spec_as_rst
|
||||
from kitty.launch import options_spec as launch_options_spec
|
||||
with open('generated/launch.rst', 'w') as f:
|
||||
f.write(option_spec_as_rst(
|
||||
appname='launch', ospec=launch_options_spec, heading_char='_',
|
||||
@@ -267,7 +260,7 @@ if you specify a program-to-run you can use the special placeholder
|
||||
'kitty --to', 'kitty @ --to'))
|
||||
as_rst = partial(option_spec_as_rst, heading_char='_')
|
||||
from kitty.rc.base import all_command_names, command_for_name
|
||||
from kitty.remote_control import global_options_spec, cli_msg
|
||||
from kitty.remote_control import cli_msg, global_options_spec
|
||||
with open('generated/cli-kitty-at.rst', 'w') as f:
|
||||
p = partial(print, file=f)
|
||||
p('kitty @\n' + '-' * 80)
|
||||
@@ -296,7 +289,9 @@ if you specify a program-to-run you can use the special placeholder
|
||||
|
||||
|
||||
def write_remote_control_protocol_docs() -> None: # {{{
|
||||
from kitty.rc.base import all_command_names, command_for_name, RemoteCommand
|
||||
from kitty.rc.base import (
|
||||
RemoteCommand, all_command_names, command_for_name
|
||||
)
|
||||
field_pat = re.compile(r'\s*([a-zA-Z0-9_+]+)\s*:\s*(.+)')
|
||||
|
||||
def format_cmd(p: Callable, name: str, cmd: RemoteCommand) -> None:
|
||||
@@ -393,12 +388,14 @@ class SessionLexer(RegexLexer):
|
||||
|
||||
|
||||
def link_role(name: str, rawtext: str, text: str, lineno: int, inliner: Any, options: Any = {}, content: Any = []) -> Tuple[List, List]:
|
||||
text = text.replace('\n', ' ')
|
||||
m = re.match(r'(.+)\s+<(.+?)>', text)
|
||||
if m is None:
|
||||
msg = inliner.reporter.error(f'link "{text}" not recognized', line=lineno)
|
||||
prb = inliner.problematic(rawtext, rawtext, msg)
|
||||
return [prb], [msg]
|
||||
text, url = m.group(1, 2)
|
||||
url = url.replace(' ', '')
|
||||
set_classes(options)
|
||||
node = nodes.reference(rawtext, text, refuri=url, **options)
|
||||
return [node], []
|
||||
@@ -450,87 +447,6 @@ def parse_shortcut_node(env: Any, sig: str, signode: Any) -> str:
|
||||
return sig
|
||||
|
||||
|
||||
def render_conf(conf_name: str, all_options: Iterable[Union['Option', Sequence['Shortcut']]]) -> str:
|
||||
from kitty.conf.definition import merged_opts, Option, Group
|
||||
ans = ['.. default-domain:: conf', '']
|
||||
a = ans.append
|
||||
current_group: Optional[Group] = None
|
||||
all_options_ = list(all_options)
|
||||
kitty_mod = 'kitty_mod'
|
||||
|
||||
def render_group(group: Group) -> None:
|
||||
a('')
|
||||
a(f'.. _conf-{conf_name}-{group.name}:')
|
||||
a('')
|
||||
a(group.short_text)
|
||||
heading_level = '+' if '.' in group.name else '^'
|
||||
a(heading_level * (len(group.short_text) + 20))
|
||||
a('')
|
||||
if group.start_text:
|
||||
a(group.start_text)
|
||||
a('')
|
||||
|
||||
def handle_group_end(group: Group) -> None:
|
||||
if group.end_text:
|
||||
assert current_group is not None
|
||||
a(''), a(current_group.end_text)
|
||||
|
||||
def handle_group(new_group: Group, new_group_is_shortcut: bool = False) -> None:
|
||||
nonlocal current_group
|
||||
if new_group is not current_group:
|
||||
if current_group:
|
||||
handle_group_end(current_group)
|
||||
current_group = new_group
|
||||
render_group(current_group)
|
||||
|
||||
def handle_option(i: int, opt: Option) -> None:
|
||||
nonlocal kitty_mod
|
||||
if not opt.long_text or not opt.add_to_docs:
|
||||
return
|
||||
handle_group(opt.group)
|
||||
if opt.name == 'kitty_mod':
|
||||
kitty_mod = opt.defval_as_string
|
||||
mopts = list(merged_opts(all_options_, opt, i))
|
||||
a('.. opt:: ' + ', '.join(conf_name + '.' + mo.name for mo in mopts))
|
||||
a('.. code-block:: conf')
|
||||
a('')
|
||||
sz = max(len(x.name) for x in mopts)
|
||||
for mo in mopts:
|
||||
a((' {:%ds} {}' % sz).format(mo.name, mo.defval_as_string))
|
||||
a('')
|
||||
if opt.long_text:
|
||||
a(expand_opt_references(conf_name, opt.long_text))
|
||||
a('')
|
||||
|
||||
def handle_shortcuts(shortcuts: Sequence[Shortcut]) -> None:
|
||||
sc = shortcuts[0]
|
||||
handle_group(sc.group, True)
|
||||
sc_text = f'{conf_name}.{sc.short_text}'
|
||||
a('.. shortcut:: ' + sc_text)
|
||||
shortcuts = [s for s in shortcuts if s.add_to_default]
|
||||
shortcut_slugs[f'{conf_name}.{sc.name}'] = (sc_text, sc.key.replace('kitty_mod', kitty_mod))
|
||||
if shortcuts:
|
||||
a('.. code-block:: conf')
|
||||
a('')
|
||||
for x in shortcuts:
|
||||
if x.add_to_default:
|
||||
a(' map {} {}'.format(x.key.replace('kitty_mod', kitty_mod), x.action_def))
|
||||
a('')
|
||||
if sc.long_text:
|
||||
a(expand_opt_references(conf_name, sc.long_text))
|
||||
a('')
|
||||
|
||||
for i, opt in enumerate(all_options_):
|
||||
if isinstance(opt, Option):
|
||||
handle_option(i, opt)
|
||||
else:
|
||||
handle_shortcuts(opt)
|
||||
|
||||
if current_group:
|
||||
handle_group_end(current_group)
|
||||
return '\n'.join(ans)
|
||||
|
||||
|
||||
def process_opt_link(env: Any, refnode: Any, has_explicit_title: bool, title: str, target: str) -> Tuple[str, str]:
|
||||
conf_name, opt = target.partition('.')[::2]
|
||||
if not opt:
|
||||
@@ -555,7 +471,7 @@ def process_shortcut_link(env: Any, refnode: Any, has_explicit_title: bool, titl
|
||||
|
||||
|
||||
def write_conf_docs(app: Any, all_kitten_names: Iterable[str]) -> None:
|
||||
app.add_lexer('conf', ConfLexer())
|
||||
app.add_lexer('conf', ConfLexer() if version_info[0] < 3 else ConfLexer)
|
||||
app.add_object_type(
|
||||
'opt', 'opt',
|
||||
indextemplate="pair: %s; Config Setting",
|
||||
@@ -574,26 +490,26 @@ def write_conf_docs(app: Any, all_kitten_names: Iterable[str]) -> None:
|
||||
sc_role = app.registry.domain_roles['std']['sc']
|
||||
sc_role.warn_dangling = True
|
||||
sc_role.process_link = process_shortcut_link
|
||||
shortcut_slugs.clear()
|
||||
|
||||
def generate_default_config(all_options: Dict[str, Union[Option, Sequence[Shortcut]]], name: str) -> None:
|
||||
from kitty.conf.definition import as_conf_file
|
||||
def generate_default_config(definition: Definition, name: str) -> None:
|
||||
with open(f'generated/conf-{name}.rst', 'w', encoding='utf-8') as f:
|
||||
print('.. highlight:: conf\n', file=f)
|
||||
f.write(render_conf(name, all_options.values()))
|
||||
f.write('\n'.join(definition.as_rst(name, shortcut_slugs)))
|
||||
|
||||
conf_name = re.sub(r'^kitten-', '', name) + '.conf'
|
||||
with open(f'generated/conf/{conf_name}', 'w', encoding='utf-8') as f:
|
||||
text = '\n'.join(as_conf_file(all_options.values()))
|
||||
text = '\n'.join(definition.as_conf())
|
||||
print(text, file=f)
|
||||
|
||||
from kitty.config_data import all_options
|
||||
generate_default_config(all_options, 'kitty')
|
||||
from kitty.options.definition import definition
|
||||
generate_default_config(definition, 'kitty')
|
||||
|
||||
from kittens.runner import get_kitten_conf_docs
|
||||
for kitten in all_kitten_names:
|
||||
all_options = get_kitten_conf_docs(kitten)
|
||||
if all_options:
|
||||
generate_default_config(all_options, f'kitten-{kitten}')
|
||||
definition = get_kitten_conf_docs(kitten)
|
||||
if definition:
|
||||
generate_default_config(definition, f'kitten-{kitten}')
|
||||
# }}}
|
||||
|
||||
|
||||
@@ -604,7 +520,8 @@ def setup(app: Any) -> None:
|
||||
write_cli_docs(kn)
|
||||
write_remote_control_protocol_docs()
|
||||
write_conf_docs(app, kn)
|
||||
app.add_lexer('session', SessionLexer())
|
||||
app.add_css_file('custom.css')
|
||||
app.add_lexer('session', SessionLexer() if version_info[0] < 3 else SessionLexer)
|
||||
app.add_role('link', link_role)
|
||||
app.add_role('iss', partial(num_role, 'issues'))
|
||||
app.add_role('pull', partial(num_role, 'pull'))
|
||||
|
||||
@@ -5,13 +5,14 @@ Configuring kitty
|
||||
|
||||
.. highlight:: conf
|
||||
|
||||
|kitty| is highly customizable, everything from keyboard shortcuts, to painting
|
||||
frames-per-second. See below for an overview of all customization
|
||||
|kitty| is highly customizable, everything from keyboard shortcuts, to
|
||||
rendering frames-per-second. See below for an overview of all customization
|
||||
possibilities.
|
||||
|
||||
You can open the config file within kitty by pressing :sc:`edit_config_file`.
|
||||
You can also display the current configuration by running ``kitty
|
||||
--debug-config``.
|
||||
You can reload the config file within kitty by pressing
|
||||
:sc:`reload_config_file` or sending kitty the ``SIGUSR1`` signal. You can also
|
||||
display the current configuration by pressing the :sc:`debug_config` key.
|
||||
|
||||
.. _confloc:
|
||||
|
||||
@@ -39,6 +40,16 @@ expanded, so :code:`${USER}.conf` becomes :file:`name.conf` if
|
||||
Sample kitty.conf
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can download a sample :file:`kitty.conf` file with all default settings and
|
||||
comments describing each setting by clicking: :download:`sample kitty.conf
|
||||
</generated/conf/kitty.conf>`.
|
||||
.. only:: html
|
||||
|
||||
You can download a sample :file:`kitty.conf` file with all default settings and
|
||||
comments describing each setting by clicking: :download:`sample kitty.conf
|
||||
</generated/conf/kitty.conf>`.
|
||||
|
||||
.. only:: man
|
||||
|
||||
You can edit a fully commented sample kitty.conf by pressing the
|
||||
:sc:`edit_config_file` shortcut in kitty. This will generate a config
|
||||
file with full documentation and all settings commented out. If you
|
||||
have a pre-existing kitty.conf, then that will be used instead, delete
|
||||
it to see the sample file.
|
||||
|
||||
160
docs/faq.rst
160
docs/faq.rst
@@ -4,6 +4,7 @@ Frequently Asked Questions
|
||||
.. highlight:: sh
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Some special symbols are rendered small/truncated in kitty?
|
||||
-----------------------------------------------------------
|
||||
@@ -47,12 +48,26 @@ terminfo files to the server::
|
||||
|
||||
kitty +kitten ssh myserver
|
||||
|
||||
This ssh kitten takes all the same command line arguments
|
||||
as ssh, you can alias it to ssh in your shell's rc files to avoid having to
|
||||
type it each time::
|
||||
|
||||
alias ssh="kitty +kitten ssh"
|
||||
|
||||
Remember to also setup :ref:`completion`.
|
||||
|
||||
If for some reason that does not work (typically because the server is using a
|
||||
non POSIX compliant shell), you can use the following one-liner instead (it
|
||||
non POSIX compliant shell as ``/bin/sh``), you can try using it with ``python``
|
||||
instead::
|
||||
|
||||
kitty +kitten ssh use-python myserver
|
||||
|
||||
If that also fails, perhaps because python is not installed on the remote
|
||||
server, use the following one-liner instead (it
|
||||
is slower as it needs to ssh into the server twice, but will work with most
|
||||
servers)::
|
||||
|
||||
infocmp xterm-kitty | ssh myserver tic -x -o \~/.terminfo /dev/stdin
|
||||
infocmp -a xterm-kitty | ssh myserver tic -x -o \~/.terminfo /dev/stdin
|
||||
|
||||
If you are behind a proxy (like Balabit) that prevents this, you must redirect the
|
||||
1st command to a file, copy that to the server and run ``tic`` manually. If you
|
||||
@@ -158,6 +173,19 @@ You can, of course, also run |kitty| from a terminal with command line options,
|
||||
And within |kitty| itself, you can always run |kitty| using just `kitty` as it
|
||||
cleverly adds itself to the ``PATH``.
|
||||
|
||||
I catted a binary file and now kitty is hung?
|
||||
-----------------------------------------------
|
||||
|
||||
**Never** output unknown binary data directly into a terminal.
|
||||
|
||||
Terminals have a single channel for both data and control. Certain bytes
|
||||
are control codes. Some of these control codes are of arbitrary length, so
|
||||
if the binary data you output into the terminal happens to contain the starting
|
||||
sequence for one of these control codes, the terminal will hang waiting for
|
||||
the closing sequence. Press :kbd:`ctrl+shift+delete` to reset the terminal.
|
||||
|
||||
If you do want to cat unknown data, use ``cat -v``.
|
||||
|
||||
|
||||
kitty is not able to use my favorite font?
|
||||
---------------------------------------------
|
||||
@@ -165,9 +193,12 @@ kitty is not able to use my favorite font?
|
||||
|kitty| achieves its stellar performance by caching alpha masks of each rendered
|
||||
character on the GPU, so that every character needs to be rendered only once.
|
||||
This means it is a strictly character cell based display. As such it can use
|
||||
only monospace fonts, since every cell in the grid has to be the same size. If
|
||||
your font is not listed in ``kitty list-fonts`` it means that it is not
|
||||
monospace. On Linux you can list all monospace fonts with::
|
||||
only monospace fonts, since every cell in the grid has to be the same size.
|
||||
Furthermore, it needs fonts to be freely resizable, so it does not support
|
||||
bitmapped fonts.
|
||||
|
||||
If your font is not listed in ``kitty list-fonts`` it means that it is not
|
||||
monospace or is a bitmapped font. On Linux you can list all monospace fonts with::
|
||||
|
||||
fc-list : family spacing outline scalable | grep -e spacing=100 -e spacing=90 | grep -e outline=True | grep -e scalable=True
|
||||
|
||||
@@ -179,7 +210,7 @@ following :file:`~/.config/fontconfig/fonts.conf`::
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
|
||||
<fontconfig>
|
||||
<match target="font">
|
||||
<match target="scan">
|
||||
<test name="family">
|
||||
<string>Your Font Family Name</string>
|
||||
</test>
|
||||
@@ -212,23 +243,114 @@ How do I map key presses in kitty to different keys in the terminal program?
|
||||
This is accomplished by using ``map`` with :sc:`send_text <send_text>` in :file:`kitty.conf`.
|
||||
For example::
|
||||
|
||||
map alt+s send_text all \x13
|
||||
map alt+s send_text normal,application \x13
|
||||
|
||||
This maps :kbd:`alt+s` to :kbd:`ctrl+s`. To figure out what bytes to use for
|
||||
the :sc:`send_text <send_text>` you can use the ``showkey`` utility. Run::
|
||||
the :sc:`send_text <send_text>` you can use the ``show_key`` kitten. Run::
|
||||
|
||||
showkey -a
|
||||
kitty +kitten show_key
|
||||
|
||||
Then press the key you want to emulate. On macOS, this utility is currently not
|
||||
available. The manual way to figure it out is:
|
||||
Then press the key you want to emulate.
|
||||
|
||||
1. Look up your key's decimal value in the table at the bottom of `this
|
||||
page <http://ascii-table.com/ansi-escape-sequences.php>`_ or any
|
||||
ANSI escape sequence table. There are different modifiers for :kbd:`ctrl`,
|
||||
:kbd:`alt`, etc. For e.g., for :kbd:`ctrl+s`, find the ``S`` row and look at
|
||||
the third column value, ``19``.
|
||||
How do I open a new window or tab with the same working directory as the current window?
|
||||
--------------------------------------------------------------------------------------------
|
||||
|
||||
2. Convert the decimal value to hex with ``kitty +runpy "print(hex(19))"``.
|
||||
This shows the hex value, ``13`` in this case.
|
||||
In :file:`kitty.conf` add the following::
|
||||
|
||||
3. Use ``\x(hexval)`` in your ``send_text`` command in kitty. So in this example, ``\x13``
|
||||
map f1 launch --cwd=current
|
||||
map f2 launch --cwd=current --type=tab
|
||||
|
||||
Pressing :kbd:`F1` will open a new kitty window with the same working directory
|
||||
as the current window. The :doc:`launch command <launch>` is very powerful,
|
||||
explore :doc:`its documentation <launch>`.
|
||||
|
||||
|
||||
Things behave differently when running kitty from system launcher vs. from another terminal?
|
||||
-----------------------------------------------------------------------------------------------
|
||||
|
||||
This will be because of environment variables. When you run kitty from the
|
||||
system launcher, it gets a default set of system environment variables. When
|
||||
you run kitty from another terminal, you are actually running it from a shell,
|
||||
and the shell's rc files will have setup a whole different set of environment
|
||||
variables which kitty will now inherit.
|
||||
|
||||
You need to make sure that the environment variables you define in your shell's
|
||||
rc files are either also defined system wide or via the :opt:`env` directive in
|
||||
:file:`kitty.conf`. Common environment variables that cause issues are those
|
||||
related to localization, such as ``LANG, LC_*`` and loading of configuration
|
||||
files such as ``XDG_*, KITTY_CONFIG_DIRECTORY``.
|
||||
|
||||
To see the environment variables that kitty sees, you can add the following
|
||||
mapping to :file:`kitty.conf`::
|
||||
|
||||
map f1 show_kitty_env_vars
|
||||
|
||||
then pressing :kbd:`F1` will show you the environment variables kitty sees.
|
||||
|
||||
This problem is most common on macOS, as Apple makes it exceedingly difficult to
|
||||
setup environment variables system-wide, so people end up putting them in all
|
||||
sorts of places where they may or may not work.
|
||||
|
||||
|
||||
I am using tmux and have a problem
|
||||
--------------------------------------
|
||||
|
||||
First, terminal multiplexers are `a bad idea
|
||||
<https://github.com/kovidgoyal/kitty/issues/391#issuecomment-638320745>`_, do
|
||||
not use them, if at all possible. kitty contains features that do all of what
|
||||
tmux does, but better, with the exception of remote persistence (:iss:`391`).
|
||||
If you still want to use tmux, read on.
|
||||
|
||||
Image display will not work, see `tmux issue
|
||||
<https://github.com/tmux/tmux/issues/1391>`_.
|
||||
|
||||
If you are using tmux with multiple terminals or you start it under one
|
||||
terminal and then switch to another and these terminals have different TERM
|
||||
variables, tmux will break. You will need to restart it as tmux does not
|
||||
support multiple terminfo definitions.
|
||||
|
||||
Copying to clipboard via OSC 52 will not work, because tmux does not support
|
||||
the extended version of that protocol, you will need to add ``no-append`` to
|
||||
:opt:`clipboard_control` in kitty.conf.
|
||||
|
||||
If you use any of the advanced features that kitty has innovated, such as
|
||||
styled underlines, desktop notifications, extended keyboard support, etc.
|
||||
they may or may not work, depending on the whims of tmux's maintainer, your
|
||||
version of tmux, etc.
|
||||
|
||||
|
||||
I opened and closed a lot of windows/tabs and top shows kitty's memory usage is very high?
|
||||
-------------------------------------------------------------------------------------------
|
||||
|
||||
``top`` is not a good way to measure process memory usage. That is because on
|
||||
modern systems, when allocating memory to a process, the C library functions
|
||||
will typically allocate memory in large blocks, and give the process chunks of
|
||||
these blocks. When the process frees a chunk, the C library will not
|
||||
necessarily release the underlying block back to the OS. So even though the
|
||||
application has released the memory, ``top`` will still claim the process is
|
||||
using it.
|
||||
|
||||
To check for memory leaks, instead use a tool like ``valgrind``. Run::
|
||||
|
||||
PYTHONMALLOC=malloc valgrind --tool=massif kitty
|
||||
|
||||
Now open lots of tabs/windows, generate lots of output using tools like find/yes
|
||||
etc. Then close all but one window. Do some random work for a few seconds in
|
||||
that window, maybe run yes or find again. Then quit kitty and run::
|
||||
|
||||
massif-visualizer massif.out.*
|
||||
|
||||
You will see the allocations graph goes up when you opened the windows, then
|
||||
goes back down when you closed them, indicating there were no memory leaks.
|
||||
|
||||
For those interested, you can get a similar profile out of ``valgrind`` as you get
|
||||
with ``top`` by adding ``--pages-as-heap=yes`` then you will see that memory
|
||||
allocated in malloc is not freed in free. This can be further refined if you
|
||||
use `glibc`` as your C library by setting the environment variable
|
||||
``MALLOC_MMAP_THRESHOLD_=64``. This will cause free to actually free memory
|
||||
allocated in sizes of more than 64 bytes. With this set, memory usage will
|
||||
climb high, then fall when closing windows, but not fall all the way back. The
|
||||
remaining used memory can be investigated using valgrind again, and it will
|
||||
come from arenas in the GPU drivers and the per thread arenas glibc's malloc
|
||||
maintains. These too allocate memory in large blocks and dont release it back
|
||||
to the OS immediately.
|
||||
|
||||
@@ -28,7 +28,7 @@ alpha-blending and text over graphics.
|
||||
:alt: Demo of graphics rendering in kitty
|
||||
:align: center
|
||||
|
||||
Some programs that use the kitty graphics protocol:
|
||||
Some programs and libraries that use the kitty graphics protocol:
|
||||
|
||||
* `termpdf.py <https://github.com/dsanson/termpdf.py>`_ - a terminal PDF/DJVU/CBR viewer
|
||||
* `ranger <https://github.com/ranger/ranger>`_ - a terminal file manager, with
|
||||
@@ -37,9 +37,16 @@ Some programs that use the kitty graphics protocol:
|
||||
* `pixcat <https://github.com/mirukana/pixcat>`_ - a third party CLI and python library that wraps the graphics protocol
|
||||
* `neofetch <https://github.com/dylanaraps/neofetch>`_ - A command line system
|
||||
information tool
|
||||
* `viu <https://github.com/atanunq/viu>`_ - a terminal image viewer
|
||||
* `glkitty <https://github.com/michaeljclark/glkitty>`_ - C library to draw OpenGL shaders in the terminal with a glgears demo
|
||||
* `ctx.graphics <https://ctx.graphics/>`_ - Library for drawing graphics
|
||||
* `timg <https://github.com/hzeller/timg>`_ - a terminal image and video viewer
|
||||
* `notcurses <https://github.com/dankamongmen/notcurses>`_ - C library for terminal graphics with bindings for C++, Rust and Python
|
||||
* `rasterm <https://github.com/BourgeoisBear/rasterm>`_ - Go library to display images in the the terminal
|
||||
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
|
||||
Getting the window size
|
||||
@@ -54,27 +61,34 @@ In C:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct ttysize ts;
|
||||
ioctl(0, TIOCGWINSZ, &ts);
|
||||
printf("number of columns: %i, number of rows: %i, screen width: %i, screen height: %i\n", sz.ws_col, sz.ws_row, sz.ws_xpixel, sz.ws_ypixel);
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
struct winsize sz;
|
||||
ioctl(0, TIOCGWINSZ, &sz);
|
||||
printf("number of rows: %i, number of columns: %i, screen width: %i, screen height: %i\n", sz.ws_row, sz.ws_col, sz.ws_xpixel, sz.ws_ypixel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
In Python:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import array, fcntl, termios
|
||||
import array, fcntl, sys, termios
|
||||
buf = array.array('H', [0, 0, 0, 0])
|
||||
fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, buf)
|
||||
print('number of columns: {}, number of rows: {}, screen width: {}, screen height: {}'.format(*buf))
|
||||
print('number of rows: {}, number of columns: {}, screen width: {}, screen height: {}'.format(*buf))
|
||||
|
||||
Note that some terminals return ``0`` for the width and height values. Such
|
||||
terminals should be modified to return the correct values. Examples of
|
||||
terminals that return correct values: ``kitty, xterm``
|
||||
|
||||
You can also use the *CSI t* escape code to get the screen size. Send
|
||||
``<ESC>[14t`` to *stdout* and kitty will reply on *stdin* with
|
||||
``<ESC>[4;<height>;<width>t`` where *height* and *width* are the window size in
|
||||
pixels. This escape code is supported in many terminals, not just kitty.
|
||||
``<ESC>[14t`` to ``STDOUT`` and kitty will reply on ``STDIN`` with
|
||||
``<ESC>[4;<height>;<width>t`` where ``height`` and ``width`` are the window
|
||||
size in pixels. This escape code is supported in many terminals, not just
|
||||
kitty.
|
||||
|
||||
A minimal example
|
||||
------------------
|
||||
@@ -87,7 +101,8 @@ features of the graphics protocol:
|
||||
import sys
|
||||
from base64 import standard_b64encode
|
||||
|
||||
def serialize_gr_command(cmd, payload=None):
|
||||
def serialize_gr_command(**cmd):
|
||||
payload = cmd.pop('payload', None)
|
||||
cmd = ','.join('{}={}'.format(k, v) for k, v in cmd.items())
|
||||
ans = []
|
||||
w = ans.append
|
||||
@@ -98,18 +113,17 @@ features of the graphics protocol:
|
||||
w(b'\033\\')
|
||||
return b''.join(ans)
|
||||
|
||||
def write_chunked(cmd, data):
|
||||
data = standard_b64encode(data)
|
||||
def write_chunked(**cmd):
|
||||
data = standard_b64encode(cmd.pop('data'))
|
||||
while data:
|
||||
chunk, data = data[:4096], data[4096:]
|
||||
m = 1 if data else 0
|
||||
cmd['m'] = m
|
||||
sys.stdout.buffer.write(serialize_gr_command(cmd, chunk))
|
||||
sys.stdout.buffer.write(serialize_gr_command(payload=chunk, m=m, **cmd))
|
||||
sys.stdout.flush()
|
||||
cmd.clear()
|
||||
|
||||
with open(sys.argv[-1], 'rb') as f:
|
||||
write_chunked({'a': 'T', 'f': 100}, f.read())
|
||||
write_chunked(a='T', f=100, data=f.read())
|
||||
|
||||
|
||||
Save this script as :file:`png.py`, then you can use it to display any PNG
|
||||
@@ -135,6 +149,8 @@ The meaning of the payload is interpreted based on the control data.
|
||||
|
||||
The first step is to transmit the actual image data.
|
||||
|
||||
.. _transferring_pixel_data:
|
||||
|
||||
Transferring pixel data
|
||||
--------------------------
|
||||
|
||||
@@ -154,9 +170,10 @@ of transmitting paletted images.
|
||||
RGB and RGBA data
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In these formats the pixel data is stored directly as 3 or 4 bytes per pixel, respectively.
|
||||
When specifying images in this format, the image dimensions **must** be sent in the control data.
|
||||
For example::
|
||||
In these formats the pixel data is stored directly as 3 or 4 bytes per pixel,
|
||||
respectively. The colors in the data **must** be in the *sRGB color space*. When
|
||||
specifying images in this format, the image dimensions **must** be sent in the
|
||||
control data. For example::
|
||||
|
||||
<ESC>_Gf=24,s=10,v=20;<payload><ESC>\
|
||||
|
||||
@@ -180,16 +197,17 @@ compression, then you must provide the ``S`` key with the size of the PNG data.
|
||||
Compression
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The client can send compressed image data to the terminal emulator, by specifying the
|
||||
``o`` key. Currently, only zlib based deflate compression is supported, which is specified using
|
||||
``o=z``. For example::
|
||||
The client can send compressed image data to the terminal emulator, by
|
||||
specifying the ``o`` key. Currently, only :rfc:`1950` ZLIB based deflate
|
||||
compression is supported, which is specified using ``o=z``. For example::
|
||||
|
||||
<ESC>_Gf=24,s=10,v=20,o=z;<payload><ESC>\
|
||||
|
||||
This is the same as the example from the RGB data section, except that the
|
||||
payload is now compressed using deflate. The terminal emulator will decompress
|
||||
it before rendering. You can specify compression for any format. The terminal
|
||||
emulator will decompress before interpreting the pixel data.
|
||||
payload is now compressed using deflate (this occurs prior to base64-encoding).
|
||||
The terminal emulator will decompress it before rendering. You can specify
|
||||
compression for any format. The terminal emulator will decompress before
|
||||
interpreting the pixel data.
|
||||
|
||||
|
||||
The transmission medium
|
||||
@@ -208,8 +226,12 @@ Value of `t` Meaning
|
||||
is in a known temporary directory, such as :file:`/tmp`,
|
||||
:file:`/dev/shm`, :file:`TMPDIR env var if present` and any platform
|
||||
specific temporary directories.
|
||||
``s`` A `POSIX shared memory object <http://man7.org/linux/man-pages/man7/shm_overview.7.html>`_.
|
||||
The terminal emulator will delete it after reading the pixel data
|
||||
``s`` A *shared memory object*, which on POSIX systems is a `POSIX shared memory object
|
||||
<http://man7.org/linux/man-pages/man7/shm_overview.7.html>`_ and on Windows is a
|
||||
`Named shared memory object <https://docs.microsoft.com/en-us/windows/win32/memory/creating-named-shared-memory>`_.
|
||||
The terminal emulator must read the data from the memory
|
||||
object and then unlink and close it on POSIX and just
|
||||
close it on Windows.
|
||||
================== ============
|
||||
|
||||
Local client
|
||||
@@ -255,7 +277,7 @@ sequence of escape codes to the terminal emulator::
|
||||
<ESC>_Gm=0;<encoded pixel data last chunk><ESC>\
|
||||
|
||||
Note that only the first escape code needs to have the full set of control
|
||||
codes such as width, height, format etc. Subsequent chunks must have
|
||||
codes such as width, height, format etc. Subsequent chunks **must** have
|
||||
only the ``m`` key. The client **must** finish sending all chunks for a single image
|
||||
before sending any other graphics related escape codes. Note that the cursor
|
||||
position used to display the image **must** be the position when the final chunk is
|
||||
@@ -294,7 +316,7 @@ While as of May 2020, kitty is the only terminal emulator to support this
|
||||
graphics protocol, we intend that any terminal emulator that wishes to support
|
||||
it can. To check if a terminal emulator supports the graphics protocol the best way
|
||||
is to send the above *query action* followed by a request for the
|
||||
`primary device attributes <https://vt100.net/docs/vt510-rm/DA1.html>`. If you
|
||||
`primary device attributes <https://vt100.net/docs/vt510-rm/DA1.html>`_. If you
|
||||
get back an answer for the device attributes without getting back an answer for
|
||||
the *query action* the terminal emulator does not support the graphics
|
||||
protocol.
|
||||
@@ -305,7 +327,7 @@ terminal emulators handle input in a FIFO manner, anyway.
|
||||
|
||||
So for example, you could send::
|
||||
|
||||
<ESC>_Gi=31,s=1,v=1,a=q,t=d,f=24;<NUL><NUL><NUL><ESC>\<ESC>[c
|
||||
<ESC>_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA<ESC>\<ESC>[c
|
||||
|
||||
If you get back a response to the graphics query, the terminal emulator supports
|
||||
the protocol, if you get back a response to the device attributes query without
|
||||
@@ -317,11 +339,12 @@ Display images on screen
|
||||
|
||||
Every transmitted image can be displayed an arbitrary number of times on the
|
||||
screen, in different locations, using different parts of the source image, as
|
||||
needed. You can either simultaneously transmit and display an image using the
|
||||
action ``a=T``, or first transmit the image with a id, such as ``i=10`` and then display
|
||||
it with ``a=p,i=10`` which will display the previously transmitted image at the current
|
||||
cursor position. When specifying an image id, the terminal emulator will reply with an
|
||||
acknowledgement code, which will be either::
|
||||
needed. Each such display of an image is called a *placement*. You can either
|
||||
simultaneously transmit and display an image using the action ``a=T``, or first
|
||||
transmit the image with a id, such as ``i=10`` and then display it with
|
||||
``a=p,i=10`` which will display the previously transmitted image at the current
|
||||
cursor position. When specifying an image id, the terminal emulator will reply
|
||||
to the placement request with an acknowledgement code, which will be either::
|
||||
|
||||
<ESC>_Gi=<id>;OK<ESC>\
|
||||
|
||||
@@ -334,6 +357,24 @@ scheme described above for querying available transmission media, except that
|
||||
here we are querying if the image with the specified id is available or needs to
|
||||
be re-transmitted.
|
||||
|
||||
Since there can be many placements per image, you can also give placements an
|
||||
id. To do so add the ``p`` key with a number between ``1`` and ``4294967295``.
|
||||
When you specify a placement id, it will be added to the acknowledgement code
|
||||
above. Every placement is uniquely identified by the pair of the ``image id``
|
||||
and the ``placement id``. If you specify a placement id for an image that does
|
||||
not have an id, it will be ignored. An example response::
|
||||
|
||||
<ESC>_Gi=<image id>,p=<placement id>;OK<ESC>\
|
||||
|
||||
If you send two placements with the same ``image id`` and ``placement id`` the
|
||||
second one will replace the first. This can be used to resize or move
|
||||
placements around the screen, without flicker.
|
||||
|
||||
|
||||
.. versionadded:: 0.19.3
|
||||
Support for specifying placement ids (see :doc:`kittens/query_terminal` to query kitty version)
|
||||
|
||||
|
||||
Controlling displayed image layout
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -360,6 +401,19 @@ allows rendering of text on top of images. Negative z-index values below
|
||||
INT32_MIN/2 (-1,073,741,824) will be drawn under cells with non-default background
|
||||
colors.
|
||||
|
||||
.. note:: After placing an image on the screen the cursor must be moved to the
|
||||
right by the number of cols in the image placement rectangle and down by the
|
||||
number of rows in the image placement rectangle. If either of these cause
|
||||
the cursor to leave either the screen or the scroll area, the exact
|
||||
positioning of the cursor is undefined, and up to implementations.
|
||||
The client can ask the terminal emulator to not move the cursor at all
|
||||
by specifying ``C=1`` in the command, which sets the cursor movement policy
|
||||
to no movement for placing the current image.
|
||||
|
||||
.. versionadded:: 0.20.0
|
||||
Support for the C=1 cursor movement policy
|
||||
|
||||
|
||||
Deleting images
|
||||
---------------------
|
||||
|
||||
@@ -376,33 +430,218 @@ scrollback buffer. The values of the ``x`` and ``y`` keys are the same as cursor
|
||||
================= ============
|
||||
Value of ``d`` Meaning
|
||||
================= ============
|
||||
``a`` or ``A`` Delete all images visible on screen
|
||||
``i`` or ``I`` Delete all images with the specified id, specified using the ``i`` key.
|
||||
``c`` or ``C`` Delete all images that intersect with the current cursor position.
|
||||
``p`` or ``P`` Delete all images that intersect a specific cell, the cell is specified using the ``x`` and ``y`` keys
|
||||
``q`` or ``Q`` Delete all images that intersect a specific cell having a specific z-index. The cell and z-index is specified using the ``x``, ``y`` and ``z`` keys.
|
||||
``x`` or ``X`` Delete all images that intersect the specified column, specified using the ``x`` key.
|
||||
``y`` or ``Y`` Delete all images that intersect the specified row, specified using the ``y`` key.
|
||||
``z`` or ``Z`` Delete all images that have the specified z-index, specified using the ``z`` key.
|
||||
``a`` or ``A`` Delete all placements visible on screen
|
||||
``i`` or ``I`` Delete all images with the specified id, specified using the ``i`` key. If you specify a ``p`` key for the placement id as well, then only the placement with the specified image id and placement id will be deleted.
|
||||
``n`` or ``N`` Delete newest image with the specified number, specified using the ``I`` key. If you specify a ``p`` key for the
|
||||
placement id as well, then only the placement with the specified number and placement id will be deleted.
|
||||
``c`` or ``C`` Delete all placements that intersect with the current cursor position.
|
||||
``f`` or ``F`` Delete animation frames.
|
||||
``p`` or ``P`` Delete all placements that intersect a specific cell, the cell is specified using the ``x`` and ``y`` keys
|
||||
``q`` or ``Q`` Delete all placements that intersect a specific cell having a specific z-index. The cell and z-index is specified using the ``x``, ``y`` and ``z`` keys.
|
||||
``x`` or ``X`` Delete all placements that intersect the specified column, specified using the ``x`` key.
|
||||
``y`` or ``Y`` Delete all placements that intersect the specified row, specified using the ``y`` key.
|
||||
``z`` or ``Z`` Delete all placements that have the specified z-index, specified using the ``z`` key.
|
||||
================= ============
|
||||
|
||||
|
||||
Note when all placements for an image have been deleted, the image is also
|
||||
deleted, if the capital letter form above is specified. Also, when the terminal
|
||||
is running out of quota space for new images, existing images without
|
||||
placements will be preferentially deleted.
|
||||
|
||||
Some examples::
|
||||
|
||||
<ESC>_Ga=d<ESC>\ # delete all visible images
|
||||
<ESC>_Ga=d,d=i,i=10<ESC>\ # delete the image with id=10, without freeing data
|
||||
<ESC>_Ga=d,d=Z,z=-1<ESC>\ # delete the images with z-index -1, also freeing up image data
|
||||
<ESC>_Ga=d,d=p,x=3,y=4<ESC>\ # delete all images that intersect the cell at (3, 4), without freeing data
|
||||
<ESC>_Ga=d<ESC>\ # delete all visible placements
|
||||
<ESC>_Ga=d,d=i,i=10<ESC>\ # delete the image with id=10, without freeing data
|
||||
<ESC>_Ga=d,d=i,i=10,p=7<ESC>\ # delete the image with id=10 and placement id=7, without freeing data
|
||||
<ESC>_Ga=d,d=Z,z=-1<ESC>\ # delete the placements with z-index -1, also freeing up image data
|
||||
<ESC>_Ga=d,d=p,x=3,y=4<ESC>\ # delete all placements that intersect the cell at (3, 4), without freeing data
|
||||
|
||||
|
||||
Suppressing responses from the terminal
|
||||
-------------------------------------------
|
||||
|
||||
If you are using the graphics protocol from a limited client, such as a shell
|
||||
script, it might be useful to avoid having to process responses from the
|
||||
terminal. For this, you can use the ``q`` key. Set it to ``1`` to suppress
|
||||
``OK`` responses and to ``2`` to suppress failure responses.
|
||||
|
||||
.. versionadded:: 0.19.3
|
||||
The ability to suppress responses (see :doc:`kittens/query_terminal` to query kitty version)
|
||||
|
||||
|
||||
Requesting image ids from the terminal
|
||||
-------------------------------------------
|
||||
|
||||
If you are writing a program that is going to share the screen with other
|
||||
programs and you still want to use image ids, it is not possible to know
|
||||
what image ids are free to use. In this case, instead of using the ``i``
|
||||
key to specify an image id use the ``I`` key to specify an image number
|
||||
instead. These numbers are not unique.
|
||||
When creating a new image, even if an existing image has the same number a new
|
||||
one is created. And the terminal will reply with the id of the newly created
|
||||
image. For example, when creating an image with ``I=13``, the terminal will
|
||||
send the response::
|
||||
|
||||
<ESC>_Gi=99,I=13;OK<ESC>\
|
||||
|
||||
Here, the value of ``i`` is the id for the newly created image and the value of
|
||||
``I`` is the same as was sent in the creation command.
|
||||
|
||||
All future commands that refer to images using the image number, such as
|
||||
creating placements or deleting images, will act on only the newest image with
|
||||
that number. This allows the client program to send a bunch of commands dealing
|
||||
with an image by image number without waiting for a response from the terminal
|
||||
with the image id. Once such a response is received, the client program should
|
||||
use the ``i`` key with the image id for all future communication.
|
||||
|
||||
.. note:: Specifying both ``i`` and ``I`` keys in any command is an error. The
|
||||
terminal must reply with an EINVAL error message, unless silenced.
|
||||
|
||||
.. versionadded:: 0.19.3
|
||||
The ability to use image numbers (see :doc:`kittens/query_terminal` to query kitty version)
|
||||
|
||||
|
||||
.. _animation_protocol:
|
||||
|
||||
Animation
|
||||
-------------------------------------------
|
||||
|
||||
.. versionadded:: 0.20.0
|
||||
Animation support (see :doc:`kittens/query_terminal` to query kitty version)
|
||||
|
||||
When designing support for animation, the two main considerations were:
|
||||
|
||||
#. There should be a way for both client and terminal driven animations.
|
||||
Since there is unknown and variable latency between client and terminal,
|
||||
especially over SSH, client driven animations are not sufficient.
|
||||
|
||||
#. Animations often consist of small changes from one frame to the next, the
|
||||
protocol should thus allow transmitting these deltas for efficiency and
|
||||
performance reasons.
|
||||
|
||||
Animation support is added to the protocol by adding two new modes for the
|
||||
``a`` (action) key. A ``f`` mode for transmitting frame data and an ``a`` mode
|
||||
for controlling the animation of an image. Animation proceeds in two steps,
|
||||
first a normal image is created as described earlier. Then animation frames are
|
||||
added to the image to make it into an animation. Since every animation is
|
||||
associated with a single image, all animation escape codes must specify either
|
||||
the ``i`` or ``I`` keys to identify the image being operated on.
|
||||
|
||||
|
||||
Transferring animation frame data
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Transferring animation frame data is very similar to
|
||||
:ref:`transferring_pixel_data` above. The main difference is that the image
|
||||
the frame belongs to must be specified and it is possible to transmit data for
|
||||
only part of a frame, declaring the rest of the frame to be filled in by data
|
||||
from a previous frame, or left blank. To transfer frame data the ``a=f``
|
||||
key must be used in all escape codes.
|
||||
|
||||
First, to transfer a simple frame that has data for the full image area, the
|
||||
escape codes used are exactly the same as for transferring image data, with the
|
||||
addition of: ``a=f,i=<image id>`` or ``a=f,I=<image number>``.
|
||||
|
||||
If the frame has data for only a part of the image, you can specify the
|
||||
rectangle for it using the ``x, y, s, v`` keys, for example::
|
||||
|
||||
x=10,y=5,s=100,v=200 # A 100x200 rectangle with its top left corner at (10, 5)
|
||||
|
||||
Frames are created by composing the transmitted data onto a background canvas.
|
||||
This canvas can be either a single color, or the pixels from a previous frame.
|
||||
The composition can be of two types, either a simple replacement (``X=1``) key
|
||||
or a full alpha blend (the default).
|
||||
|
||||
To use a background color for the canvas, specify the ``Y`` key as a 32-bit
|
||||
RGBA color. For example::
|
||||
|
||||
Y=4278190335 # 0xff0000ff opaque red
|
||||
Y=16711816 # 0x00ff0088 translucent green (alpha=0.53)
|
||||
|
||||
The default background color when none is specified is ``0`` i.e. a black,
|
||||
transparent pixel.
|
||||
|
||||
To use the data from a previous frame, specify the ``c`` key which is a 1-based
|
||||
frame number. Thus ``c=1`` refers to the root frame (the base image data),
|
||||
``c=2`` refers to the second frame and so on.
|
||||
|
||||
If the frame is composed of multiple rectangular blocks, these can be expressed
|
||||
by using the ``r`` key. When specifying the ``r`` key the data for an existing
|
||||
frame is edited. The same composition operation as above happens, but now the
|
||||
background canvas is the existing frame itself. ``r`` is a 1-based index, so
|
||||
``r=1`` is the root frame (base image data), ``r=2`` is the second frame and so
|
||||
on.
|
||||
|
||||
Finally, while transferring frame data, the frame *gap* can also be specified
|
||||
using the ``z`` key. The gap is the number of milliseconds to wait before
|
||||
displaying the next frame when the animation is running. A value of ``z=0`` is
|
||||
ignored, ``z=positive number`` sets the gap to the specified number of
|
||||
milliseconds and ``z=negative number`` creates a *gapless* frame. Gapless
|
||||
frames are not displayed to the user since they are instantly skipped over,
|
||||
however they can be useful as the base data for subsequent frames. For example,
|
||||
for an animation where the background remains the same and a small object or two
|
||||
move.
|
||||
|
||||
Controlling animations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Clients can control animations by using the ``a=a`` key in the escape code sent
|
||||
to the terminal.
|
||||
|
||||
The simplest is client driven animations, where the client transmits the frame
|
||||
data and the also instructs the terminal to make a particular frame the current
|
||||
frame. To change the current frame, use the ``c`` key::
|
||||
|
||||
<ESC>_Ga=a,i=3,c=7<ESC>\
|
||||
|
||||
This will make the seventh frame in the image with id ``3`` the current frame.
|
||||
|
||||
However, client driven animations can be sub-optimal, since the latency between
|
||||
the client and terminal is unknown and variable especially over the network.
|
||||
Also they require the client to remain running for the lifetime of the
|
||||
animation, which is not desirable for cat like utilities.
|
||||
|
||||
Terminal driven animations are achieved by the client specifying *gaps* (time
|
||||
in milliseconds) between frames and instructing the terminal to stop or start
|
||||
the animation.
|
||||
|
||||
The animation state is controlled by the ``s`` key. ``s=1`` stops the
|
||||
animation. ``s=2`` runs the animation, but in *loading* mode, in this mode when
|
||||
reaching the last frame, instead of looping, the terminal will wait for the
|
||||
arrival of more frames. ``s=3`` runs the animation normally, after the last
|
||||
frame, the terminal loops back to the first frame. The number of loops can be
|
||||
controlled by the ``v`` key. ``v=0`` is ignored, ``v=1`` is loop infinitely,
|
||||
and any other positive number is loop ``number - 1`` times. Note that stopping
|
||||
the animation resets the loop counter.
|
||||
|
||||
Finally, the *gap* for frames can be set using the ``z`` key. This can be
|
||||
specified either when the frame is created as part of the transmit escape code
|
||||
or separately using the animation control escape code. The *gap* is the time in
|
||||
milliseconds to wait before displaying the next frame in the animation.
|
||||
For example::
|
||||
|
||||
<ESC>_Ga=a,i=7,r=3,z=48<ESC>\
|
||||
|
||||
This sets the gap for the third frame of the image with id ``7`` to ``48``
|
||||
milliseconds. Note that *gapless* frames are not displayed to the user since
|
||||
the next frame comes immediately, however they can be useful to store base data
|
||||
for subsequent frames, such as in an animation with an object moving against a
|
||||
static background.
|
||||
|
||||
In particular, the first frame or *root frame* is created with the base image
|
||||
data and has no gap, so its gap must be set using this control code.
|
||||
|
||||
Image persistence and storage quotas
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
-----------------------------------------
|
||||
|
||||
In order to avoid *Denial-of-Service* attacks, terminal emulators should have a
|
||||
maximum storage quota for image data. It should allow at least a few full
|
||||
screen images. For example the quota in kitty is 320MB per buffer. When adding
|
||||
a new image, if the total size exceeds the quota, the terminal emulator should
|
||||
delete older images to make space for the new one.
|
||||
delete older images to make space for the new one. In kitty, for animations,
|
||||
the additional frame data is stored on disk and has a separate, larger quota of
|
||||
five times the base quota.
|
||||
|
||||
|
||||
Control data reference
|
||||
@@ -415,7 +654,13 @@ take, and the default value they take when missing. All integers are 32-bit.
|
||||
Key Value Default Description
|
||||
======= ==================== ========= =================
|
||||
``a`` Single character. ``t`` The overall action this graphics command is performing.
|
||||
``(t, T, q, p, d)``
|
||||
``(t, T, q, p, d)`` ``t`` - transmit data, ``T`` - transmit data and display image,
|
||||
``q`` - query terminal, ``p`` - put (display) previous transmitted image,
|
||||
``d`` - delete image, ``f`` - transmit data for animation frames,
|
||||
``a`` - control animation
|
||||
|
||||
``q`` ``0, 1, 2`` ``0`` Suppress responses from the terminal to this graphics command.
|
||||
|
||||
**Keys for image transmission**
|
||||
-----------------------------------------------------------
|
||||
``f`` Positive integer. ``32`` The format in which the image data is sent.
|
||||
@@ -428,26 +673,63 @@ Key Value Default Description
|
||||
``O`` Positive integer. ``0`` The offset from which to read data from a file.
|
||||
``i`` Positive integer.
|
||||
``(0 - 4294967295)`` ``0`` The image id
|
||||
``I`` Positive integer.
|
||||
``(0 - 4294967295)`` ``0`` The image number
|
||||
``p`` Positive integer.
|
||||
``(0 - 4294967295)`` ``0`` The placement id
|
||||
``o`` Single character. ``null`` The type of data compression.
|
||||
``only z``
|
||||
``m`` zero or one ``0`` Whether there is more chunked data available.
|
||||
|
||||
**Keys for image display**
|
||||
-----------------------------------------------------------
|
||||
``x`` Positive integer ``0`` The left edge (in pixels) of the image area to display
|
||||
``y`` Positive integer ``0`` The top edge (in pixels) of the image area to display
|
||||
``w`` Positive integer ``0`` The width (in pixels) of the image area to display. By default, the entire width is used.
|
||||
``w`` Positive integer ``0`` The width (in pixels) of the image area to display. By default, the entire width is used
|
||||
``h`` Positive integer ``0`` The height (in pixels) of the image area to display. By default, the entire height is used
|
||||
``X`` Positive integer ``0`` The x-offset within the first cell at which to start displaying the image
|
||||
``Y`` Positive integer ``0`` The y-offset within the first cell at which to start displaying the image
|
||||
``c`` Positive integer ``0`` The number of columns to display the image over
|
||||
``r`` Positive integer ``0`` The number of rows to display the image over
|
||||
``C`` Positive integer ``0`` Cursor movement policy. ``0`` is the default, to move the cursor to after the image.
|
||||
``1`` is to not move the cursor at all when placing the image.
|
||||
``z`` 32-bit integer ``0`` The *z-index* vertical stacking order of the image
|
||||
|
||||
**Keys for animation frame loading**
|
||||
-----------------------------------------------------------
|
||||
``x`` Positive integer ``0`` The left edge (in pixels) of where the frame data should be updated
|
||||
``y`` Positive integer ``0`` The top edge (in pixels) of where the frame data should be updated
|
||||
``c`` Positive integer ``0`` The 1-based frame number of the frame whose image data serves as the base data
|
||||
when creating a new frame, by default the base data is black, fully transparent pixels
|
||||
``r`` Positive integer ``0`` The 1-based frame number of the frame that is being edited. By default, a new frame is created
|
||||
``z`` 32-bit integer ``0`` The gap (in milliseconds) of this frame from the next one. A value of
|
||||
zero is ignored. Negative values create a *gapless* frame. If not specified,
|
||||
frames have a default gap of ``40ms``. The root frame defaults to zero gap.
|
||||
``X`` Positive integer ``0`` The composition mode for blending pixels when creating a new frame or
|
||||
editing a frame's data. The default is full alpha blending. ``1`` means a
|
||||
simple overwrite.
|
||||
``Y`` Positive integer ``0`` The background color for pixels not
|
||||
specified in the frame data. Must be in 32-bit RGBA format
|
||||
|
||||
|
||||
**Keys for animation control**
|
||||
-----------------------------------------------------------
|
||||
``s`` Positive integer ``0`` ``1`` - stop animation, ``2`` - run animation, but wait for new frames, ``3`` - run animation
|
||||
``r`` Positive integer ``0`` The 1-based frame number of the frame that is being affected
|
||||
``z`` 32-bit integer ``0`` The gap (in milliseconds) of this frame from the next one. A value of
|
||||
zero is ignored. Negative values create a *gapless* frame.
|
||||
``c`` Positive integer ``0`` The 1-based frame number of the frame that should be made the current frame
|
||||
``v`` Positive integer ``0`` The number of loops to play. ``0`` is
|
||||
ignored, ``1`` is play infinite and is the default and larger number
|
||||
means play that number ``-1`` loops
|
||||
|
||||
|
||||
**Keys for deleting images**
|
||||
-----------------------------------------------------------
|
||||
``d`` Single character. ``a`` What to delete.
|
||||
``(a, A, c, C, i,
|
||||
I, p, P, q, Q, x, X,
|
||||
y, Y, z, Z)``.
|
||||
``(a, A, c, C, n, N,
|
||||
i, I, p, P, q, Q, x,
|
||||
X, y, Y, z, Z)``.
|
||||
======= ==================== ========= =================
|
||||
|
||||
|
||||
|
||||
226
docs/index.rst
226
docs/index.rst
@@ -10,10 +10,12 @@ kitty - the fast, featureful, GPU based terminal emulator
|
||||
buttery smooth scrolling. Uses threaded rendering to minimize input latency.
|
||||
|
||||
* Supports all modern terminal features: :doc:`graphics (images)
|
||||
<graphics-protocol>`, unicode, true-color, OpenType ligatures, mouse
|
||||
protocol, focus tracking, `bracketed paste
|
||||
<https://cirw.in/blog/bracketed-paste>`_ and several :doc:`new terminal
|
||||
protocol extensions <protocol-extensions>`.
|
||||
<graphics-protocol>`, unicode, `true-color
|
||||
<https://gist.github.com/XVilka/8346728>`_,
|
||||
OpenType ligatures, mouse protocol, :doc:`hyperlinks <open_actions>`,
|
||||
focus tracking, `bracketed paste <https://cirw.in/blog/bracketed-paste>`_
|
||||
and several :doc:`new terminal protocol extensions
|
||||
<protocol-extensions>`.
|
||||
|
||||
* Supports tiling multiple terminal windows side by side in different
|
||||
:ref:`layouts <layouts>` without needing to use an extra program like tmux
|
||||
@@ -47,35 +49,34 @@ kitty - the fast, featureful, GPU based terminal emulator
|
||||
Screenshot, showing vim, tig and git running in |kitty| with the 'Tall' layout
|
||||
|
||||
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 1
|
||||
|
||||
|
||||
.. _quickstart:
|
||||
|
||||
Quickstart
|
||||
--------------
|
||||
|
||||
Pre-built binaries of |kitty| are available for both macOS and Linux.
|
||||
See the :doc:`binary install instructions </binary>`. You can
|
||||
See the :doc:`binary install instructions </binary>`. You can also
|
||||
:doc:`build from source </build>`.
|
||||
|
||||
You can also use your favorite package manager to install the |kitty| package.
|
||||
|kitty| packages are available for:
|
||||
`macOS with Homebrew (Cask) <https://formulae.brew.sh/cask/kitty>`_,
|
||||
`macOS and Linux with Nix <https://nixos.org/nixos/packages.html?channel=nixpkgs-unstable&query=kitty>`_,
|
||||
`Ubuntu <https://launchpad.net/ubuntu/+source/kitty>`_,
|
||||
`Debian <https://packages.debian.org/buster/kitty>`_,
|
||||
`openSUSE <https://build.opensuse.org/package/show/X11:terminals/kitty>`_,
|
||||
`Arch Linux <https://www.archlinux.org/packages/community/x86_64/kitty/>`_,
|
||||
`Gentoo <https://packages.gentoo.org/packages/x11-terms/kitty>`_,
|
||||
`Fedora <https://src.fedoraproject.org/rpms/kitty>`_,
|
||||
`Void Linux <https://github.com/void-linux/void-packages/blob/master/srcpkgs/kitty/template>`_,
|
||||
and `Solus <https://dev.getsol.us/source/kitty/>`_.
|
||||
Additionally, you can use your favorite package manager to install the |kitty|
|
||||
package, but note that some Linux distribution packages are woefully outdated.
|
||||
|kitty| is available in a vast number of package repositories for macOS
|
||||
and Linux.
|
||||
|
||||
.. image:: https://repology.org/badge/tiny-repos/kitty.svg
|
||||
:target: https://repology.org/project/kitty/versions
|
||||
:alt: Number of repositories kitty is available in
|
||||
|
||||
See :doc:`Configuring kitty <conf>` for help on configuring |kitty| and
|
||||
:doc:`Invocation <invocation>` for the command line arguments |kitty| supports.
|
||||
|
||||
|
||||
.. contents::
|
||||
|
||||
|
||||
Design philosophy
|
||||
-------------------
|
||||
|
||||
@@ -97,133 +98,7 @@ styled (curly) underlines. One of the design goals of |kitty| is to be
|
||||
easily extensible so that new features can be added in the future with
|
||||
relatively little effort.
|
||||
|
||||
Tabs and Windows
|
||||
-------------------
|
||||
|
||||
|kitty| is capable of running multiple programs organized into tabs and
|
||||
windows. The top level of organization is the *Tab*. Each tab consists
|
||||
of one or more *windows*. The windows can be arranged in multiple
|
||||
different layouts, like windows are organized in a tiling window
|
||||
manager. The keyboard controls (which are all customizable) for tabs and
|
||||
windows are:
|
||||
|
||||
Scrolling
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
======================== =======================
|
||||
Action Shortcut
|
||||
======================== =======================
|
||||
Scroll line up :sc:`scroll_line_up` (also :kbd:`⌥+⌘+⇞` and :kbd:`⌘+↑` on macOS)
|
||||
Scroll line down :sc:`scroll_line_down` (also :kbd:`⌥+⌘+⇟` and :kbd:`⌘+↓` on macOS)
|
||||
Scroll page up :sc:`scroll_page_up` (also :kbd:`⌘+⇞` on macOS)
|
||||
Scroll page down :sc:`scroll_page_down` (also :kbd:`⌘+⇟` on macOS)
|
||||
Scroll to top :sc:`scroll_home` (also :kbd:`⌘+↖` on macOS)
|
||||
Scroll to bottom :sc:`scroll_end` (also :kbd:`⌘+↘` on macOS)
|
||||
======================== =======================
|
||||
|
||||
Tabs
|
||||
~~~~~~~~~~~
|
||||
|
||||
======================== =======================
|
||||
Action Shortcut
|
||||
======================== =======================
|
||||
New tab :sc:`new_tab` (also :kbd:`⌘+t` on macOS)
|
||||
Close tab :sc:`close_tab` (also :kbd:`⌘+w` on macOS)
|
||||
Next tab :sc:`next_tab` (also :kbd:`^+⇥` and :kbd:`⇧+⌘+]` on macOS)
|
||||
Previous tab :sc:`previous_tab` (also :kbd:`⇧+^+⇥` and :kbd:`⇧+⌘+[` on macOS)
|
||||
Next layout :sc:`next_layout`
|
||||
Move tab forward :sc:`move_tab_forward`
|
||||
Move tab backward :sc:`move_tab_backward`
|
||||
Set tab title :sc:`set_tab_title` (also :kbd:`⇧+⌘+i` on macOS)
|
||||
======================== =======================
|
||||
|
||||
|
||||
Windows
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
======================== =======================
|
||||
Action Shortcut
|
||||
======================== =======================
|
||||
New window :sc:`new_window` (also :kbd:`⌘+↩` on macOS)
|
||||
New OS window :sc:`new_os_window` (also :kbd:`⌘+n` on macOS)
|
||||
Close window :sc:`close_window` (also :kbd:`⇧+⌘+d` on macOS)
|
||||
Next window :sc:`next_window`
|
||||
Previous window :sc:`previous_window`
|
||||
Move window forward :sc:`move_window_forward`
|
||||
Move window backward :sc:`move_window_backward`
|
||||
Move window to top :sc:`move_window_to_top`
|
||||
Focus specific window :sc:`first_window`, :sc:`second_window` ... :sc:`tenth_window`
|
||||
(also :kbd:`⌘+1`, :kbd:`⌘+2` ... :kbd:`⌘+9` on macOS)
|
||||
(clockwise from the top-left)
|
||||
======================== =======================
|
||||
|
||||
Additionally, you can define shortcuts in :file:`kitty.conf` to focus neighboring
|
||||
windows and move windows around (similar to window movement in vim)::
|
||||
|
||||
map ctrl+left neighboring_window left
|
||||
map shift+left move_window right
|
||||
map ctrl+down neighboring_window down
|
||||
map shift+down move_window up
|
||||
...
|
||||
|
||||
You can also define a shortcut to switch to the previously active window::
|
||||
|
||||
map ctrl+p nth_window -1
|
||||
|
||||
``nth_window`` will focus the nth window for positive numbers and the
|
||||
previously active windows for negative numbers.
|
||||
|
||||
.. _detach_window:
|
||||
|
||||
You can define shortcuts to detach the current window and
|
||||
move it to another tab or another OS window::
|
||||
|
||||
# moves the window into a new OS window
|
||||
map ctrl+f2 detach_window
|
||||
# moves the window into a new Tab
|
||||
map ctrl+f3 detach_window new-tab
|
||||
# asks which tab to move the window into
|
||||
map ctrl+f4 detach_window ask
|
||||
|
||||
Similarly, you can detach the current tab, with::
|
||||
|
||||
# moves the tab into a new OS window
|
||||
map ctrl+f2 detach_tab
|
||||
# asks which OS Window to move the tab into
|
||||
map ctrl+f4 detach_tab ask
|
||||
|
||||
Finally, you can define a shortcut to close all windows in a tab other than
|
||||
the currently active window::
|
||||
|
||||
map f9 close_other_windows_in_tab
|
||||
|
||||
|
||||
Other keyboard shortcuts
|
||||
----------------------------------
|
||||
|
||||
================================== =======================
|
||||
Action Shortcut
|
||||
================================== =======================
|
||||
Copy to clipboard :sc:`copy_to_clipboard` (also :kbd:`⌘+c` on macOS)
|
||||
Paste from clipboard :sc:`paste_from_clipboard` (also :kbd:`⌘+v` on macOS)
|
||||
Paste from selection :sc:`paste_from_selection`
|
||||
Increase font size :sc:`increase_font_size` (also :kbd:`⌘++` on macOS)
|
||||
Decrease font size :sc:`decrease_font_size` (also :kbd:`⌘+-` on macOS)
|
||||
Restore font size :sc:`reset_font_size` (also :kbd:`⌘+0` on macOS)
|
||||
Toggle fullscreen :sc:`toggle_fullscreen` (also :kbd:`^+⌘+f` on macOS)
|
||||
Toggle maximized :sc:`toggle_maximized`
|
||||
Input unicode character :sc:`input_unicode_character`
|
||||
Click URL using the keyboard :sc:`open_url`
|
||||
Reset the terminal :sc:`reset_terminal`
|
||||
Pass current selection to program :sc:`pass_selection_to_program`
|
||||
Edit |kitty| config file :sc:`edit_config_file`
|
||||
Open a |kitty| shell :sc:`kitty_shell`
|
||||
Increase background opacity :sc:`increase_background_opacity`
|
||||
Decrease background opacity :sc:`decrease_background_opacity`
|
||||
Full background opacity :sc:`full_background_opacity`
|
||||
Reset background opacity :sc:`reset_background_opacity`
|
||||
================================== =======================
|
||||
|
||||
.. include:: basic.rst
|
||||
|
||||
.. _layouts:
|
||||
|
||||
@@ -233,7 +108,7 @@ Layouts
|
||||
A layout is an arrangement of multiple kitty *windows* inside a top-level OS window. You can create a new window
|
||||
using the :sc:`new_window` key combination.
|
||||
|
||||
Currently, there are six layouts available:
|
||||
Currently, there are seven layouts available:
|
||||
|
||||
* **Fat** -- One (or optionally more) windows are shown full width on the top, the rest of the windows are shown side-by-side on the bottom
|
||||
* **Grid** -- All windows are shown in a grid
|
||||
@@ -276,13 +151,30 @@ Some prominent kittens:
|
||||
|
||||
:doc:`Hints <kittens/hints>`
|
||||
Select and open/paste/insert arbitrary text snippets such as URLs,
|
||||
filenames, words, lines, etc from the terminal screen.
|
||||
filenames, words, lines, etc. from the terminal screen.
|
||||
|
||||
|
||||
:doc:`Remote file <kittens/remote_file>`
|
||||
Edit, open, or download remote files over SSH easily, by simply clicking on
|
||||
the filename.
|
||||
|
||||
|
||||
:doc:`Hyperlinked grep <kittens/hyperlinked_grep>`
|
||||
Search your files using `ripgrep <https://github.com/BurntSushi/ripgrep>`_
|
||||
and open the results directly in your favorite editor in the terminal,
|
||||
at the line containing the search result, simply by clicking on the result you want.
|
||||
|
||||
|
||||
:doc:`Broadcast <kittens/broadcast>`
|
||||
Type in one kitty window and have it broadcast to all (or a subset) of
|
||||
other kitty windows.
|
||||
|
||||
|
||||
:doc:`Panel <kittens/panel>`
|
||||
Draw a GPU accelerated dock panel on your desktop showing the output
|
||||
from an arbitrary terminal program.
|
||||
|
||||
|
||||
:doc:`Clipboard <kittens/clipboard>`
|
||||
Copy/paste to the clipboard from shell scripts, even over SSH.
|
||||
|
||||
@@ -293,8 +185,9 @@ Configuring kitty
|
||||
-------------------
|
||||
|
||||
|kitty| is highly configurable, everything from keyboard shortcuts to
|
||||
painting frames-per-second. For details and a sample :file:`kitty.conf`,
|
||||
see the :doc:`configuration docs <conf>`.
|
||||
painting frames-per-second. Press :sc:`edit_config_file` in kitty
|
||||
to open its fully commented sample config file in your text editor.
|
||||
For details see the :doc:`configuration docs <conf>`.
|
||||
|
||||
|
||||
Remote control
|
||||
@@ -326,10 +219,9 @@ For example:
|
||||
launch zsh
|
||||
# Create a window with some environment variables set and run
|
||||
# vim in it
|
||||
launch env FOO=BAR vim
|
||||
launch --env FOO=BAR vim
|
||||
# Set the title for the next window
|
||||
title Chat with x
|
||||
launch irssi --profile x
|
||||
launch --title "Chat with x" irssi --profile x
|
||||
|
||||
# Create a new tab (the part after new_tab is the optional tab
|
||||
# name which will be displayed in the tab bar, if omitted, the
|
||||
@@ -353,21 +245,31 @@ For example:
|
||||
focus
|
||||
launch emacs
|
||||
|
||||
.. note::
|
||||
The :doc:`launch <launch>` command when used in a session file
|
||||
cannot create new OS windows, or tabs.
|
||||
|
||||
|
||||
Mouse features
|
||||
-------------------
|
||||
|
||||
* You can hold down :kbd:`ctrl+shift` and click on a URL to open it in a browser.
|
||||
* You can click on a URL to open it in a browser.
|
||||
* You can double click to select a word and then drag to select more words.
|
||||
* You can triple click to select a line and then drag to select more lines.
|
||||
* You can triple click while holding :kbd:`ctrl+alt` to select from clicked
|
||||
point to end of line.
|
||||
* You can right click to extend a previous selection.
|
||||
* You can hold down :kbd:`ctrl+alt` and drag with the mouse to select in
|
||||
columns (see also :opt:`rectangle_select_modifiers`).
|
||||
columns.
|
||||
* Selecting text automatically copies it to the primary clipboard (on
|
||||
platforms with a primary clipboard).
|
||||
* You can middle click to paste from the primary clipboard (on platforms
|
||||
with a primary clipboard).
|
||||
* You can select text with kitty even when a terminal program has grabbed
|
||||
the mouse by holding down the :kbd:`shift` key (see also
|
||||
:opt:`terminal_select_modifiers`).
|
||||
the mouse by holding down the :kbd:`shift` key.
|
||||
|
||||
All these actions can be customized in :file:`kitty.conf` as described
|
||||
:ref:`here <conf-kitty-mouse.mousemap>`.
|
||||
|
||||
|
||||
Font control
|
||||
@@ -405,6 +307,10 @@ arbitrary, command running in a new window, tab or overlay, for example::
|
||||
Would open the scrollback buffer in a new window when you press the :kbd:`F1`
|
||||
key. See :sc:`show_scrollback` for details.
|
||||
|
||||
If you want to use it with an editor such as vim to get more powerful features,
|
||||
you can see tips for doing so, in
|
||||
`this thread <https://github.com/kovidgoyal/kitty/issues/719>`_.
|
||||
|
||||
If you wish to store very large amounts of scrollback to view using the piping or
|
||||
:sc:`show_scrollback` features, you can use the :opt:`scrollback_pager_history_size`
|
||||
option.
|
||||
@@ -439,8 +345,6 @@ Frequently Asked Questions
|
||||
|
||||
The list of Frequently Asked Questions (*FAQ*) is :doc:`available here <faq>`.
|
||||
|
||||
.. _completion:
|
||||
|
||||
|
||||
Cool integrations for kitty with other CLI tools
|
||||
--------------------------------------------------
|
||||
@@ -450,6 +354,8 @@ kitty provides extremely powerful interfaces such as :doc:`remote-control` and
|
||||
that allow it to be integrated with other tools seamlessly. For a list of such
|
||||
user created integrations, see: :doc:`integrations`.
|
||||
|
||||
.. _completion:
|
||||
|
||||
Completion for kitty
|
||||
---------------------------------
|
||||
|
||||
|
||||
@@ -28,7 +28,23 @@ images and other types of documents directly in your terminal, even over SSH.
|
||||
another terminal file manager, with previews of file contents powered by kitty's graphics protocol.
|
||||
|
||||
`koneko <https://github.com/twenty5151/koneko>`_
|
||||
browse images from the pixiv artist community directly in kitty
|
||||
browse images from the pixiv artist community directly in kitty.
|
||||
|
||||
`viu <https://github.com/atanunq/viu>`_
|
||||
view images in the terminal, similar to kitty's icat.
|
||||
|
||||
`nb <https://github.com/xwmx/nb>`_
|
||||
command line and local web note-taking, bookmarking, archiving, and
|
||||
knowledge base application that uses kitty's graphics protocol for images.
|
||||
|
||||
`w3m <https://github.com/tats/w3m>`_
|
||||
A text mode WWW browser that supports kitty's graphics protocol to display
|
||||
images.
|
||||
|
||||
`timg <https://github.com/hzeller/timg>`_
|
||||
A terminal image and video viewer, that displays static and animated
|
||||
images or plays videos. Fast multi-threaded loading, JPEG exif rotation,
|
||||
grid view and connecting to the webcam make it a versatile terminal utility.
|
||||
|
||||
|
||||
System and data visualisation tools
|
||||
@@ -43,6 +59,10 @@ System and data visualisation tools
|
||||
`KittyTerminalImages.jl <https://github.com/simonschoelly/KittyTerminalImages.jl>`_
|
||||
show images from Julia directly in kitty
|
||||
|
||||
`euporie <https://github.com/joouha/euporie>`_
|
||||
a text-based user interface for running and editing Jupyter notebooks,
|
||||
powered by kitty's graphics protocol for displaying plots
|
||||
|
||||
`gnuplot <http://www.gnuplot.info/>`_
|
||||
a graphing and data visualization tool that can be made to display its
|
||||
output in kitty with the following bash snippet::
|
||||
@@ -63,6 +83,22 @@ System and data visualisation tools
|
||||
|
||||
iplot 'sin(x*3)*exp(x*.2)'
|
||||
|
||||
`onefetch <https://github.com/o2sh/onefetch>`_
|
||||
a tool to fetch information about your git repositories
|
||||
|
||||
`patat <https://github.com/jaspervdj/patat>`_
|
||||
terminal based presentations using pandoc and kitty's image protocol for
|
||||
images
|
||||
|
||||
`wttr.in <https://github.com/chubin/wttr.in>`_
|
||||
a tool to display weather information in your terminal with curl
|
||||
|
||||
`wl-clipboard-manager <https://github.com/maximbaz/wl-clipboard-manager>`_
|
||||
view and manage the system clipboard under Wayland in your kitty terminal
|
||||
|
||||
`dmenu-term <https://github.com/maximbaz/dmenu-term>`_
|
||||
run applications on your system with fuzzy find inside a kitty window
|
||||
|
||||
|
||||
Editor integration
|
||||
-----------------------
|
||||
@@ -83,6 +119,9 @@ such a split windows, previews, REPLs etc.
|
||||
`vim-test <https://github.com/vim-test/vim-test>`_
|
||||
allows easily running tests in a terminal window
|
||||
|
||||
`hologram.nvim <https://github.com/edluffy/hologram.nvim>`_
|
||||
terminal image viewer for nvim
|
||||
|
||||
|
||||
Scrollback manipulation
|
||||
-------------------------
|
||||
@@ -116,3 +155,6 @@ Miscellaneous
|
||||
`weechat-hints <https://github.com/GermainZ/kitty-weechat-hints>`_
|
||||
URL hints kitten for WeeChat that works without having to use WeeChat's
|
||||
raw-mode.
|
||||
|
||||
`glkitty <https://github.com/michaeljclark/glkitty>`_
|
||||
C library to draw OpenGL shaders in the terminal with a glgears demo
|
||||
|
||||
@@ -4,3 +4,10 @@ The kitty command line interface
|
||||
.. program:: kitty
|
||||
|
||||
.. include:: generated/cli-kitty.rst
|
||||
|
||||
.. include:: basic.rst
|
||||
|
||||
See also
|
||||
-----------
|
||||
|
||||
See kitty.conf(5)
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
Key encoding for extended keyboard protocol
|
||||
===============================================
|
||||
|
||||
See :ref:`extended-key-protocol` for more information and `this table in JSON
|
||||
format <https://github.com/kovidgoyal/kitty/blob/master/key_encoding.json>`_.
|
||||
|
||||
===================== ======================
|
||||
Name Encoded representation
|
||||
0 ``G``
|
||||
1 ``H``
|
||||
2 ``I``
|
||||
3 ``J``
|
||||
4 ``K``
|
||||
5 ``L``
|
||||
6 ``M``
|
||||
7 ``N``
|
||||
8 ``O``
|
||||
9 ``P``
|
||||
A ``S``
|
||||
APOSTROPHE ``B``
|
||||
B ``T``
|
||||
BACKSLASH ``t``
|
||||
BACKSPACE ``1``
|
||||
C ``U``
|
||||
CAPS LOCK ``:``
|
||||
COMMA ``C``
|
||||
D ``V``
|
||||
DELETE ``3``
|
||||
DOWN ``6``
|
||||
E ``W``
|
||||
END ``-``
|
||||
ENTER ``z``
|
||||
EQUAL ``R``
|
||||
ESCAPE ``y``
|
||||
F ``X``
|
||||
F1 ``/``
|
||||
F10 ``]``
|
||||
F11 ``{``
|
||||
F12 ``}``
|
||||
F13 ``@``
|
||||
F14 ``%``
|
||||
F15 ``$``
|
||||
F16 ``#``
|
||||
F17 ``BA``
|
||||
F18 ``BB``
|
||||
F19 ``BC``
|
||||
F2 ``*``
|
||||
F20 ``BD``
|
||||
F21 ``BE``
|
||||
F22 ``BF``
|
||||
F23 ``BG``
|
||||
F24 ``BH``
|
||||
F25 ``BI``
|
||||
F3 ``?``
|
||||
F4 ``&``
|
||||
F5 ``<``
|
||||
F6 ``>``
|
||||
F7 ``(``
|
||||
F8 ``)``
|
||||
F9 ``[``
|
||||
G ``Y``
|
||||
GRAVE ACCENT ``v``
|
||||
H ``Z``
|
||||
HOME ``.``
|
||||
I ``a``
|
||||
INSERT ``2``
|
||||
J ``b``
|
||||
K ``c``
|
||||
KP 0 ``BJ``
|
||||
KP 1 ``BK``
|
||||
KP 2 ``BL``
|
||||
KP 3 ``BM``
|
||||
KP 4 ``BN``
|
||||
KP 5 ``BO``
|
||||
KP 6 ``BP``
|
||||
KP 7 ``BQ``
|
||||
KP 8 ``BR``
|
||||
KP 9 ``BS``
|
||||
KP ADD ``BX``
|
||||
KP DECIMAL ``BT``
|
||||
KP DIVIDE ``BU``
|
||||
KP ENTER ``BY``
|
||||
KP EQUAL ``BZ``
|
||||
KP MULTIPLY ``BV``
|
||||
KP SUBTRACT ``BW``
|
||||
L ``d``
|
||||
LEFT ``5``
|
||||
LEFT ALT ``Bc``
|
||||
LEFT BRACKET ``s``
|
||||
LEFT CONTROL ``Bb``
|
||||
LEFT SHIFT ``Ba``
|
||||
LEFT SUPER ``Bd``
|
||||
M ``e``
|
||||
MINUS ``D``
|
||||
N ``f``
|
||||
NUM LOCK ``=``
|
||||
O ``g``
|
||||
P ``h``
|
||||
PAGE DOWN ``9``
|
||||
PAGE UP ``8``
|
||||
PAUSE ``!``
|
||||
PERIOD ``E``
|
||||
PRINT SCREEN ``^``
|
||||
Q ``i``
|
||||
R ``j``
|
||||
RIGHT ``4``
|
||||
RIGHT ALT ``Bg``
|
||||
RIGHT BRACKET ``u``
|
||||
RIGHT CONTROL ``Bf``
|
||||
RIGHT SHIFT ``Be``
|
||||
RIGHT SUPER ``Bh``
|
||||
S ``k``
|
||||
SCROLL LOCK ``+``
|
||||
SEMICOLON ``Q``
|
||||
SLASH ``F``
|
||||
SPACE ``A``
|
||||
T ``l``
|
||||
TAB ``0``
|
||||
U ``m``
|
||||
UP ``7``
|
||||
V ``n``
|
||||
W ``o``
|
||||
WORLD 1 ``w``
|
||||
WORLD 2 ``x``
|
||||
X ``p``
|
||||
Y ``q``
|
||||
Z ``r``
|
||||
===================== ======================
|
||||
665
docs/keyboard-protocol.rst
Normal file
665
docs/keyboard-protocol.rst
Normal file
@@ -0,0 +1,665 @@
|
||||
A protocol for comprehensive keyboard handling in terminals
|
||||
=================================================================
|
||||
|
||||
There are various problems with the current state of keyboard handling in
|
||||
terminals. They include:
|
||||
|
||||
* No way to use modifiers other than ``ctrl`` and ``alt``
|
||||
|
||||
* No way to reliably use multiple modifier keys, other than, ``shift+alt`` and
|
||||
``ctrl+alt``.
|
||||
|
||||
* Many of the existing escape codes used to encode these events are ambiguous
|
||||
with different key presses mapping to the same escape code.
|
||||
|
||||
* No way to handle different types of keyboard events, such as press, release or repeat
|
||||
|
||||
* No reliable way to distinguish single ``Esc`` key presses from the start of a
|
||||
escape sequence. Currently, client programs use fragile timing related hacks
|
||||
for this, leading to bugs, for example:
|
||||
`neovim #2035 <https://github.com/neovim/neovim/issues/2035>`_.
|
||||
|
||||
To solve these issues and others, kitty has created a new keyboard protocol,
|
||||
that is backward compatible but allows applications to opt-in to support more
|
||||
advanced usages. The protocol is based on initial work in `fixterms
|
||||
<http://www.leonerd.org.uk/hacks/fixterms/>`_, however, it corrects various
|
||||
issues in that proposal, listed at the :ref:`bottom of this document
|
||||
<fixterms_bugs>`. For public discussion of this spec, see :iss:`3248`.
|
||||
|
||||
You can see this protocol with all enhancements in action by running::
|
||||
|
||||
kitty +kitten show_key -m kitty
|
||||
|
||||
inside the kitty terminal to report key events.
|
||||
|
||||
.. versionadded:: 0.20.0
|
||||
|
||||
Quickstart
|
||||
---------------
|
||||
|
||||
If you are an application or library developer just interested in using this
|
||||
protocol to make keyboard handling simpler and more robust in your application,
|
||||
without too many changes, do the following:
|
||||
|
||||
#. Emit the escape code ``CSI > 1 u`` at application startup if using the main
|
||||
screen or when entering alternate screen mode, if using the alternate
|
||||
screen.
|
||||
#. All key events will now be sent in only a few forms to your application,
|
||||
that are easy to parse unambiguously.
|
||||
#. Emit the escape sequence ``CSI < u`` at application exit if using the main
|
||||
screen or just before leaving alternate screen mode if using the alternate screen,
|
||||
to restore the previously used keyboard mode.
|
||||
|
||||
Key events will all be delivered to your application either as plain UTF-8
|
||||
text, or using the following escape codes, for those keys that do not produce
|
||||
text (``CSI`` is the bytes ``0x1b 0x5b``)::
|
||||
|
||||
CSI number ; modifiers [u~]
|
||||
CSI 1; modifiers [ABCDEFHPQRS]
|
||||
0x0d - for the Enter key
|
||||
0x7f or 0x08 - for Backspace
|
||||
0x09 - for Tab
|
||||
|
||||
The ``number`` in the first form above will be either the Unicode codepoint for a
|
||||
key, such as ``97`` for the :kbd:`a` key, or one of the numbers from the
|
||||
:ref:`functional` table below. The ``modifiers`` optional parameter encodes any
|
||||
modifiers pressed for the key event. The encoding is described in the
|
||||
:ref:`modifiers` section.
|
||||
|
||||
The second form is used for a few functional keys, such as the :kbd:`Home, End,
|
||||
Arrow keys and F1-F4`, they are enumerated in the :ref:`functional` table below.
|
||||
Note that if no modifiers are present the parameters are omitted entirely
|
||||
giving an escape code of the form ``CSI [ABCDEFHPQRS]``.
|
||||
|
||||
If you want support for more advanced features such as repeat and release
|
||||
events, alternate keys for shortcut matching et cetera, these can be turned on
|
||||
using :ref:`progressive_enhancement` as documented in the rest of this
|
||||
specification.
|
||||
|
||||
An overview
|
||||
------------------
|
||||
|
||||
Key events are divided into two types, those that produce text and those that
|
||||
do not. When a key event produces text, the text is sent directly as UTF-8
|
||||
encoded bytes. This is safe as UTF-8 contains no C0 control codes.
|
||||
When the key event does not have text, the key event is encoded as an escape code. In
|
||||
legacy compatibility mode (the default) this uses legacy escape codes, so old terminal
|
||||
applications continue to work. Key events that could not be represented in
|
||||
legacy mode are encoded using a ``CSI u`` escape code, that most terminal
|
||||
programs should just ignore. For more advanced features, such as release/repeat
|
||||
reporting etc., applications can tell the terminal they want this information by
|
||||
sending an escape code to :ref:`progressively enhance <progressive_enhancement>` the data reported for
|
||||
key events.
|
||||
|
||||
The central escape code used to encode key events is::
|
||||
|
||||
CSI unicode-key-code:alternate-key-codes ; modifiers:event-type ; text-as-codepoints u
|
||||
|
||||
Spaces in the above definition are present for clarity and should be ignored.
|
||||
``CSI`` is the bytes ``0x1b 0x5b``. All parameters are decimal numbers. Fields
|
||||
are separated by the semi-colon and sub-fields by the colon. Only the
|
||||
``unicode-key-code`` field is mandatory, everything else is optional. The
|
||||
escape code is terminated by the ``u`` character (the byte ``0x75``).
|
||||
|
||||
|
||||
.. _key_codes:
|
||||
|
||||
Key codes
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
The ``unicode-key-code`` above is the Unicode codepoint representing the key, as a
|
||||
decimal number. For example, the :kbd:`A` key is represented as ``97`` which is
|
||||
the unicode code for lowercase ``a``. Note that the codepoint used is *always*
|
||||
the lower-case (or more technically, un-shifted) version of the key. If the
|
||||
user presses, for example, :kbd:`ctrl+shift+a` the escape code would be ``CSI
|
||||
97;modifiers u``. It *must not* be ``CSI 65; modifiers u``.
|
||||
|
||||
If *alternate key reporting* is requested by the program running in the
|
||||
terminal, the terminal can send two additional Unicode codepoints, the
|
||||
*shifted key* and *base layout key*, separated by colons.
|
||||
The shifted key is simply the upper-case version of ``unicode-codepoint``, or
|
||||
more technically, the shifted version. So `a` becomes `A` and so on, based on
|
||||
the current keyboard layout. This is needed to be able to match against a
|
||||
shortcut such as :kbd:`ctrl+plus` which depending on the type of keyboard could
|
||||
be either :kbd:`ctrl+shift+equal` or :kbd:`ctrl+plus`. Note that the shifted
|
||||
key must be present only if shift is also present in the modifiers.
|
||||
|
||||
The *base layout key* is the key corresponding to the physical key in the
|
||||
standard PC-101 key layout. So for example, if the user is using a Cyrillic
|
||||
keyboard with a Cyrillic keyboard layout pressing the :kbd:`ctrl+С` key will
|
||||
be :kbd:`ctrl+c` in the standard layout. So the terminal should send the *base
|
||||
layout key* as ``99`` corresponding to the ``c`` key.
|
||||
|
||||
If only one alternate key is present, it is the *shifted key* if the terminal
|
||||
wants to send only a base layout key but no shifted key, it must use an empty
|
||||
sub-field for the shifted key, like this::
|
||||
|
||||
CSI unicode-key-code::base-layout-key
|
||||
|
||||
|
||||
.. _modifiers:
|
||||
|
||||
Modifiers
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
This protocol supports six modifier keys, :kbd:`shift, alt, ctrl, super, hyper
|
||||
and meta` as well as :kbd:`num_lock and caps_lock`. Here :kbd:`super` is either
|
||||
the *Windows/Linux* key or the *Cmd* key on mac keyboards. :kbd:`hyper` and
|
||||
:kbd:`meta` are typically present only on X11 based systems with special XKB
|
||||
rules. Modifiers are encoded as a bit field with::
|
||||
|
||||
shift 0b1 (1)
|
||||
alt 0b10 (2)
|
||||
ctrl 0b100 (4)
|
||||
super 0b1000 (8)
|
||||
hyper 0b10000 (16)
|
||||
meta 0b100000 (32)
|
||||
caps_lock 0b1000000 (64)
|
||||
num_lock 0b10000000 (128)
|
||||
|
||||
In the escape code, the modifier value is encoded as a decimal number which is
|
||||
``1 + actual modifiers``. So to represent :kbd:`shift` only, the value would be ``1 +
|
||||
1 = 2``, to represent :kbd:`ctrl+shift` the value would be ``1 + 0b101 = 6``
|
||||
and so on. If the modifier field is not present in the escape code, its default
|
||||
value is ``1`` which means no modifiers.
|
||||
|
||||
|
||||
.. _event_types:
|
||||
|
||||
Event types
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
There are three key event types: ``press, repeat and release``. They are
|
||||
reported (if requested ``0b10``) as a sub-field of the modifiers field
|
||||
(separated by a colon). If no modifiers are present, the modifiers field must
|
||||
have the value ``1`` and the event type sub-field the type of event. The
|
||||
``press`` event type has value ``1`` and is the default if no event type sub
|
||||
field is present. The ``repeat`` type is ``2`` and the ``release`` type is
|
||||
``3``. So for example::
|
||||
|
||||
CSI key-code # this is a press event
|
||||
CSI key-code;modifier # this is a press event
|
||||
CSI key-code;modifier:1 # this is a press event
|
||||
CSI key-code;modifier:2 # this is a repeat event
|
||||
CSI key-code;modifier:3 # this is a release event
|
||||
|
||||
|
||||
.. note:: Key events that result in text are reported as plain UTF-8 text, so
|
||||
events are not supported for them, unless the application requests *key
|
||||
report mode*, see below.
|
||||
|
||||
.. _text_as_codepoints:
|
||||
|
||||
Text as code points
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The terminal can optionally send the text associated with key events as a
|
||||
sequence of Unicode code points. This behavior is opt-in by the :ref:`progressive
|
||||
enhancement <progressive_enhancement>` mechanism described below. Some examples::
|
||||
|
||||
shift+a -> CSI 97 ; 2 ; 65 u # The text 'A' is reported as 65
|
||||
option+a -> CSI 97 ; ; 229 u # The text 'å' is reported as 229
|
||||
|
||||
If multiple code points are present, they must be separated by colons.
|
||||
If no known key is associated with the text the key number ``0`` must be used.
|
||||
|
||||
|
||||
Non-Unicode keys
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
There are many keys that don't correspond to letters from human languages, and
|
||||
thus aren't represented in Unicode. Think of functional keys, such as
|
||||
:kbd:`Escape, Play, Pause, F1, Home, etc`. These are encoded using Unicode code
|
||||
points from the Private Use Area (``57344 - 63743``). The mapping of key
|
||||
names to code points for these keys is in the
|
||||
:ref:`Functional key definition table below <functional>`.
|
||||
|
||||
|
||||
.. _progressive_enhancement:
|
||||
|
||||
Progressive enhancement
|
||||
--------------------------
|
||||
|
||||
While, in theory, every key event could be completely represented by this
|
||||
protocol and all would be hunk-dory, in reality there is a vast universe of
|
||||
existing terminal programs that expect legacy control codes for key events and
|
||||
that are not likely to ever be updated. To support these, in default mode,
|
||||
the terminal will emit legacy escape codes for compatibility. If a terminal
|
||||
program wants more robust key handling, it can request it from the terminal,
|
||||
via the mechanism described here. Each enhancement is described in detail
|
||||
below. The escape code for requesting enhancements is::
|
||||
|
||||
CSI = flags ; mode u
|
||||
|
||||
Here ``flags`` is a decimal encoded integer to specify a set of bit-flags. The
|
||||
meanings of the flags are given below. The second, ``mode`` parameter is
|
||||
optional (defaulting to ``1``) and specifies how the flags are applied.
|
||||
The value ``1`` means all set bits are set and all unset bits are reset.
|
||||
The value ``2`` means all set bits are set, unset bits are left unchanged.
|
||||
The value ``3`` means all set bits are reset, unset bits are left unchanged.
|
||||
|
||||
.. csv-table:: The progressive enhancement flags
|
||||
:header: "Bit", "Meaning"
|
||||
|
||||
"0b1 (1)", ":ref:`disambiguate`"
|
||||
"0b10 (2)", ":ref:`report_events`"
|
||||
"0b100 (4)", ":ref:`report_alternates`"
|
||||
"0b1000 (8)", ":ref:`report_all_keys`"
|
||||
"0b10000 (16)", ":ref:`report_text`"
|
||||
|
||||
The program running in the terminal can query the terminal for the
|
||||
current values of the flags by sending::
|
||||
|
||||
CSI ? u
|
||||
|
||||
The terminal will reply with::
|
||||
|
||||
CSI ? flags u
|
||||
|
||||
The program can also push/pop the current flags onto a stack in the
|
||||
terminal with::
|
||||
|
||||
CSI > flags u # for push, if flags ommitted default to zero
|
||||
CSI < number u # to pop number entries, defaulting to 1 if unspecified
|
||||
|
||||
Terminals should limit the size of the stack as appropriate, to prevent
|
||||
Denial-of-Service attacks. Terminals must maintain separate stacks for the main
|
||||
and alternate screens. If a pop request is received that empties the stack,
|
||||
all flags are reset. If a push request is received and the stack is full, the
|
||||
oldest entry from the stack must be evicted.
|
||||
|
||||
.. note:: The main and alternate screens in the terminal emulator must maintain
|
||||
their own, independent, keyboard mode stacks. This is so that a program that
|
||||
uses the alternate screen such as an editor, can change the keyboard mode
|
||||
in the alternate screen only, without affecting the mode in the main screen
|
||||
or even knowing what that mode is. Without this, and if no stack is
|
||||
implemented for keyboard modes (such as in some legacy terminal emulators)
|
||||
the editor would have to somehow know what the keyboard mode of the main
|
||||
screen is and restore to that mode on exit.
|
||||
|
||||
.. note:: In the interests of interoperation, the XTerm specific sequences
|
||||
`CSI > 4; 1 m` and `CSI > 4; 0 m` are treated as `CSI > 1 u` and `CSI < 1 u`.
|
||||
These codes cause XTerm to use the CSI u encoding for more keys and are therefore
|
||||
treated as similar to the disambiguate progressive enhancement.
|
||||
|
||||
.. _disambiguate:
|
||||
|
||||
Disambiguate escape codes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This type of progressive enhancement (``0b1``) fixes the problem of some legacy key press
|
||||
encodings overlapping with other control codes. For instance, pressing the
|
||||
:kbd:`Esc` key generates the byte ``0x1b`` which also is used to indicate the
|
||||
start of an escape code. Similarly pressing the key :kbd:`alt+[` will generate
|
||||
the bytes used for CSI control codes.
|
||||
|
||||
Turning on this flag will cause the terminal to report the :kbd:`Esc, alt+key,
|
||||
ctrl+key, ctrl+alt+key, shift+alt+key` keys using ``CSI u`` sequences instead
|
||||
of legacy ones. Here key is any ASCII key as described in :ref:`legacy_text`.
|
||||
Additionally, all keypad keys will be reported as separate keys with ``CSI u``
|
||||
encoding, using dedicated numbers from the :ref:`table below <functional>`.
|
||||
|
||||
With this flag turned on, all key events that do not generate text are
|
||||
represented in one of the following two forms::
|
||||
|
||||
CSI number; modifier u
|
||||
CSI 1; modifier [~ABCDEFHPQRS]
|
||||
|
||||
This makes it very easy to parse key events in an application. In particular,
|
||||
:kbd:`ctrl+c` will no longer generate the ``SIGINT`` signal, but instead be
|
||||
delivered as a ``CSI u`` escape code. This has the nice side effect of making it
|
||||
much easier to integrate into the application event loop. The only exceptions
|
||||
are the :kbd:`Enter, Tab and Backspace` keys which still generate the same
|
||||
bytes as in legacy mode this is to allow the user to type and execute commands
|
||||
in the shell such as ``reset`` after a program that sets this mode crashes
|
||||
without clearing it.
|
||||
|
||||
.. _report_events:
|
||||
|
||||
Report event types
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This progressive enhancement (``0b10``) causes the terminal to report key repeat
|
||||
and key release events. Normally only key press events are reported and key
|
||||
repeat events are treated as key press events. See :ref:`event_types` for
|
||||
details on how these are reported.
|
||||
|
||||
.. _report_alternates:
|
||||
|
||||
Report alternate keys
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This progressive enhancement (``0b100``) causes the terminal to report
|
||||
alternate key values in addition to the main value, to aid in shortcut
|
||||
matching. See :ref:`key_codes` for details on how these are reported.
|
||||
|
||||
.. _report_all_keys:
|
||||
|
||||
Report all keys as escape codes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Key events that generate text, such as plain key presses without modifiers,
|
||||
result in just the text being sent, in the legacy protocol. There is no way to
|
||||
be notified of key repeat/release events. These types of events are needed for
|
||||
some applications, such as games (think of movement using the ``WASD`` keys).
|
||||
|
||||
This progressive enhancement (``0b1000``) turns on key reporting even for key
|
||||
events that generate text. When it is enabled, text will not be sent, instead
|
||||
only key events are sent. If the text is needed as well, combine with the
|
||||
Report associated text enhancement below.
|
||||
|
||||
Additionally, with this mode, events for pressing modifier keys are reported.
|
||||
Note that *all* keys are reported as escape codes, including :kbd:`Enter, Tab,
|
||||
Backspace` etc.
|
||||
|
||||
.. _report_text:
|
||||
|
||||
Report associated text
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This progressive enhancement (``0b10000``) causes key events that generate text
|
||||
to be reported as ``CSI u`` escape codes with the text embedded in the escape
|
||||
code. See :ref:`text_as_codepoints` above for details on the mechanism.
|
||||
|
||||
|
||||
.. _detection:
|
||||
|
||||
Detection of support for this protocol
|
||||
------------------------------------------
|
||||
|
||||
An application can query the terminal for support of this protocol by sending
|
||||
the escape code querying for the :ref:`current progressive enhancement
|
||||
<progressive_enhancement>` status
|
||||
followed by request for the `primary device attributes
|
||||
<https://vt100.net/docs/vt510-rm/DA1.html>`. If an answer for the device
|
||||
attributes is received without getting back an answer for the progressive
|
||||
enhancement the terminal does not support this protocol.
|
||||
|
||||
|
||||
Legacy key event encoding
|
||||
--------------------------------
|
||||
|
||||
In the default mode, the terminal uses a legacy encoding for key events. In
|
||||
this encoding, only key press and repeat events are sent and there is no
|
||||
way to distinguish between them. Text is sent directly as UTF-8 bytes.
|
||||
|
||||
Any key events not described in this section are sent using the standard
|
||||
``CSI u`` encoding. This includes keys that are not encodable in the legacy
|
||||
encoding, thereby increasing the space of usable key combinations even without
|
||||
progressive enhancement.
|
||||
|
||||
Legacy functional keys
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
These keys are encoded using three schemes::
|
||||
|
||||
CSI number ; modifier ~
|
||||
CSI 1 ; modifier {ABCDEFHPQRS}
|
||||
SS3 {ABCDEFHPQRS}
|
||||
|
||||
In the above, if there are no modifiers, the modifier parameter is omitted.
|
||||
The modifier value is encoded as described in the :ref:`modifiers` section,
|
||||
above. When the second form is used, the number is always ``1`` and must be
|
||||
omitted if the modifiers field is also absent. The third form becomes the
|
||||
second form when modifiers are present (``SS3 is the bytes 0x1b 0x4f``).
|
||||
|
||||
These sequences must match entries in the terminfo database for maximum
|
||||
compatibility. The table below lists the key, its terminfo entry name and
|
||||
the escape code used for it by kitty. A different terminal would use whatever
|
||||
escape code is present in its terminfo database for the key.
|
||||
Some keys have an alternate representation when the terminal is in *cursor key
|
||||
mode* (the ``smkx/rmkx`` terminfo capabilities). This form is used only in
|
||||
*cursor key mode* and only when no modifiers are present.
|
||||
|
||||
.. csv-table:: Legacy functional encoding
|
||||
:header: "Name", "Terminfo name", "Escape code"
|
||||
|
||||
"INSERT", "kich1", "CSI 2 ~"
|
||||
"DELETE", "kdch1", "CSI 3 ~"
|
||||
"PAGE_UP", "kpp", "CSI 5 ~"
|
||||
"PAGE_DOWN", "knp", "CSI 6 ~"
|
||||
"UP", "cuu1,kcuu1", "CSI A, SS3 A"
|
||||
"DOWN", "cud1,kcud1", "CSI B, SS3 B"
|
||||
"RIGHT", "cuf1,kcuf1", "CSI C, SS3 C"
|
||||
"LEFT", "cub1,kcub1", "CSI D, SS3 D"
|
||||
"HOME", "home,khome", "CSI H, SS3 H"
|
||||
"END", "-,kend", "CSI F, SS3 F"
|
||||
"F1", "kf1", "SS3 P"
|
||||
"F2", "kf2", "SS3 Q"
|
||||
"F3", "kf3", "SS3 R"
|
||||
"F4", "kf4", "SS3 S"
|
||||
"F5", "kf5", "CSI 15 ~"
|
||||
"F6", "kf6", "CSI 17 ~"
|
||||
"F7", "kf7", "CSI 18 ~"
|
||||
"F8", "kf8", "CSI 19 ~"
|
||||
"F9", "kf9", "CSI 20 ~"
|
||||
"F10", "kf10", "CSI 21 ~"
|
||||
"F11", "kf11", "CSI 23 ~"
|
||||
"F12", "kf12", "CSI 24 ~"
|
||||
|
||||
There are a few more functional keys that have special cased legacy encodings.
|
||||
These are present because they are commonly used and for the sake of legacy
|
||||
terminal applications that get confused when seeing CSI u escape codes:
|
||||
|
||||
.. csv-table:: C0 controls
|
||||
:header: "Key", "No mods", "Ctrl", "Alt", "Shift", "Ctrl + Shift", "Alt + Shift", "Ctrl + Alt"
|
||||
|
||||
"Enter", "0xd", "0xd", "0x1b 0xd", "0xd", "0xd", "0x1b 0xd", "0x1b 0xd"
|
||||
"Escape", "0x1b", "0x1b", "0x1b 0x1b", "0x1b", "0x1b", "0x1b 0x1b", "0x1b 0x1b"
|
||||
"Backspace", "0x7f", "0x8", "0x1b 0x7f", "0x7f", "0x8", "0x1b 0x7f", "0x1b 0x8"
|
||||
"Tab", "0x9", "0x9", "0x1b 0x9", "CSI Z", "CSI Z", "0x1b CSI Z", "0x1b 0x9"
|
||||
"Space", "0x20", "0x0", "0x1b 0x20", "0x20", "0x0", "0x1b 0x20", "0x1b 0x0"
|
||||
|
||||
Note that :kbd:`Backspace` and :kbd:`ctrl+Backspace` are swapped in some
|
||||
terminals, this can be detected using the ``kbs`` terminfo property that
|
||||
must correspond to the :kbd:`Backspace` key.
|
||||
|
||||
All keypad keys are reported as their equivalent non-keypad keys. To
|
||||
distinguish these, use the :ref:`disambiguate <disambiguate>` flag.
|
||||
|
||||
.. _legacy_text:
|
||||
|
||||
Legacy text keys
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For legacy compatibility, the keys
|
||||
:kbd:`a-z 0-9 \` - = [ ] \ ; ' , . /` with the modifiers
|
||||
:kbd:`shift, alt, ctrl, shift+alt, ctrl+alt` are output using the
|
||||
following algorithm:
|
||||
|
||||
#. If the :kbd:`alt` key is pressed output the byte for ``ESC (0x1b)``
|
||||
#. If the :kbd:`ctrl` modifier is pressed map the key using the table
|
||||
in :ref:`ctrl_mapping`.
|
||||
#. Otherwise, if the :kbd:`shift` modifier is pressed, output the shifted key,
|
||||
for example, ``A`` for ``a`` and ``$`` for ``4``.
|
||||
#. Otherwise, output the key unmodified
|
||||
|
||||
Additionally, :kbd:`ctrl+space` is output as the NULL byte ``(0x0)``.
|
||||
|
||||
Any other combination of modifiers with these keys is output as the appropriate
|
||||
``CSI u`` escape code.
|
||||
|
||||
.. csv-table:: Example encodings
|
||||
:header: "Key", "Plain", "shift", "alt", "ctrl", "shift+alt", "alt+ctrl", "ctrl+shift"
|
||||
|
||||
"i", "i (105)", "I (73)", "ESC i", ") (41)", "ESC I", "ESC )", "CSI 105; 6 u"
|
||||
"3", "3 (51)", "# (35)", "ESC 3", "3 (51)", "ESC #", "ESC 3", "CSI 51; 6 u"
|
||||
";", "; (59)", ": (58)", "ESC ;", "; (59)", "ESC :", "ESC ;", "CSI 59; 6 u"
|
||||
|
||||
.. note::
|
||||
Many of the legacy escape codes are ambiguous with multiple different key
|
||||
presses yielding the same escape code(s), for example, :kbd:`ctrl+i` is the
|
||||
same as :kbd:`tab`, :kbd:`ctrl+m` is the same as :kbd:`Enter`, :kbd:`ctrl+r`
|
||||
is the same :kbd:`ctrl+shift+r`, etc. To resolve these use the
|
||||
:ref:`disambiguate progressive enhancement <disambiguate>`.
|
||||
|
||||
|
||||
.. _functional:
|
||||
|
||||
Functional key definitions
|
||||
----------------------------
|
||||
|
||||
All numbers are in the Unicode Private Use Area (``57344 - 63743``) except
|
||||
for a handful of keys that use numbers under 32 and 127 (C0 control codes) for legacy
|
||||
compatibility reasons.
|
||||
|
||||
.. {{{
|
||||
.. start functional key table (auto generated by gen-key-constants.py do not edit)
|
||||
|
||||
.. csv-table:: Functional key codes
|
||||
:header: "Name", "CSI", "Name", "CSI"
|
||||
|
||||
"ESCAPE", "``27 u``", "ENTER", "``13 u``"
|
||||
"TAB", "``9 u``", "BACKSPACE", "``127 u``"
|
||||
"INSERT", "``2 ~``", "DELETE", "``3 ~``"
|
||||
"LEFT", "``1 D``", "RIGHT", "``1 C``"
|
||||
"UP", "``1 A``", "DOWN", "``1 B``"
|
||||
"PAGE_UP", "``5 ~``", "PAGE_DOWN", "``6 ~``"
|
||||
"HOME", "``1 H or 7 ~``", "END", "``1 F or 8 ~``"
|
||||
"CAPS_LOCK", "``57358 u``", "SCROLL_LOCK", "``57359 u``"
|
||||
"NUM_LOCK", "``57360 u``", "PRINT_SCREEN", "``57361 u``"
|
||||
"PAUSE", "``57362 u``", "MENU", "``57363 u``"
|
||||
"F1", "``1 P or 11 ~``", "F2", "``1 Q or 12 ~``"
|
||||
"F3", "``1 R or 13 ~``", "F4", "``1 S or 14 ~``"
|
||||
"F5", "``15 ~``", "F6", "``17 ~``"
|
||||
"F7", "``18 ~``", "F8", "``19 ~``"
|
||||
"F9", "``20 ~``", "F10", "``21 ~``"
|
||||
"F11", "``23 ~``", "F12", "``24 ~``"
|
||||
"F13", "``57376 u``", "F14", "``57377 u``"
|
||||
"F15", "``57378 u``", "F16", "``57379 u``"
|
||||
"F17", "``57380 u``", "F18", "``57381 u``"
|
||||
"F19", "``57382 u``", "F20", "``57383 u``"
|
||||
"F21", "``57384 u``", "F22", "``57385 u``"
|
||||
"F23", "``57386 u``", "F24", "``57387 u``"
|
||||
"F25", "``57388 u``", "F26", "``57389 u``"
|
||||
"F27", "``57390 u``", "F28", "``57391 u``"
|
||||
"F29", "``57392 u``", "F30", "``57393 u``"
|
||||
"F31", "``57394 u``", "F32", "``57395 u``"
|
||||
"F33", "``57396 u``", "F34", "``57397 u``"
|
||||
"F35", "``57398 u``", "KP_0", "``57399 u``"
|
||||
"KP_1", "``57400 u``", "KP_2", "``57401 u``"
|
||||
"KP_3", "``57402 u``", "KP_4", "``57403 u``"
|
||||
"KP_5", "``57404 u``", "KP_6", "``57405 u``"
|
||||
"KP_7", "``57406 u``", "KP_8", "``57407 u``"
|
||||
"KP_9", "``57408 u``", "KP_DECIMAL", "``57409 u``"
|
||||
"KP_DIVIDE", "``57410 u``", "KP_MULTIPLY", "``57411 u``"
|
||||
"KP_SUBTRACT", "``57412 u``", "KP_ADD", "``57413 u``"
|
||||
"KP_ENTER", "``57414 u``", "KP_EQUAL", "``57415 u``"
|
||||
"KP_SEPARATOR", "``57416 u``", "KP_LEFT", "``57417 u``"
|
||||
"KP_RIGHT", "``57418 u``", "KP_UP", "``57419 u``"
|
||||
"KP_DOWN", "``57420 u``", "KP_PAGE_UP", "``57421 u``"
|
||||
"KP_PAGE_DOWN", "``57422 u``", "KP_HOME", "``57423 u``"
|
||||
"KP_END", "``57424 u``", "KP_INSERT", "``57425 u``"
|
||||
"KP_DELETE", "``57426 u``", "KP_BEGIN", "``1 E or 57427 ~``"
|
||||
"MEDIA_PLAY", "``57428 u``", "MEDIA_PAUSE", "``57429 u``"
|
||||
"MEDIA_PLAY_PAUSE", "``57430 u``", "MEDIA_REVERSE", "``57431 u``"
|
||||
"MEDIA_STOP", "``57432 u``", "MEDIA_FAST_FORWARD", "``57433 u``"
|
||||
"MEDIA_REWIND", "``57434 u``", "MEDIA_TRACK_NEXT", "``57435 u``"
|
||||
"MEDIA_TRACK_PREVIOUS", "``57436 u``", "MEDIA_RECORD", "``57437 u``"
|
||||
"LOWER_VOLUME", "``57438 u``", "RAISE_VOLUME", "``57439 u``"
|
||||
"MUTE_VOLUME", "``57440 u``", "LEFT_SHIFT", "``57441 u``"
|
||||
"LEFT_CONTROL", "``57442 u``", "LEFT_ALT", "``57443 u``"
|
||||
"LEFT_SUPER", "``57444 u``", "LEFT_HYPER", "``57445 u``"
|
||||
"LEFT_META", "``57446 u``", "RIGHT_SHIFT", "``57447 u``"
|
||||
"RIGHT_CONTROL", "``57448 u``", "RIGHT_ALT", "``57449 u``"
|
||||
"RIGHT_SUPER", "``57450 u``", "RIGHT_HYPER", "``57451 u``"
|
||||
"RIGHT_META", "``57452 u``", "ISO_LEVEL3_SHIFT", "``57453 u``"
|
||||
"ISO_LEVEL5_SHIFT", "``57454 u``"
|
||||
|
||||
.. end functional key table
|
||||
.. }}}
|
||||
|
||||
Note that the escape codes above of the form ``CSI 1 letter`` will omit the
|
||||
``1`` if there are no modifiers, since ``1`` is the default value.
|
||||
|
||||
.. _ctrl_mapping:
|
||||
|
||||
Legacy :kbd:`ctrl` mapping of ASCII keys
|
||||
------------------------------------------
|
||||
|
||||
When the :kbd:`ctrl` key and another key are pressed on the keyboard, terminals
|
||||
map the result *for some keys* to a *C0 control code* i.e. an value from ``0 -
|
||||
31``. This mapping was historically dependent on the layout of hardware
|
||||
terminal keyboards and is not specified anywhere, completely. The best known
|
||||
reference is `Table 3-5 in the VT-100 docs <https://vt100.net/docs/vt100-ug/chapter3.html>`_.
|
||||
|
||||
The table below provides a mapping that is a commonly used superset of the table above.
|
||||
Any ASCII keys not in the table must be left untouched by :kbd:`ctrl`.
|
||||
|
||||
.. {{{
|
||||
.. start ctrl mapping (auto generated by gen-key-constants.py do not edit)
|
||||
.. csv-table:: Emitted bytes when :kbd:`ctrl` is held down and a key is pressed
|
||||
:header: "Key", "Byte", "Key", "Byte", "Key", "Byte"
|
||||
|
||||
"SPC ", "0", "/", "31", "0", "48"
|
||||
"1", "49", "2", "0", "3", "27"
|
||||
"4", "28", "5", "29", "6", "30"
|
||||
"7", "31", "8", "127", "9", "57"
|
||||
"?", "127", "@", "0", "[", "27"
|
||||
"\\", "28", "]", "29", "^", "30"
|
||||
"_", "31", "a", "1", "b", "2"
|
||||
"c", "3", "d", "4", "e", "5"
|
||||
"f", "6", "g", "7", "h", "8"
|
||||
"i", "9", "j", "10", "k", "11"
|
||||
"l", "12", "m", "13", "n", "14"
|
||||
"o", "15", "p", "16", "q", "17"
|
||||
"r", "18", "s", "19", "t", "20"
|
||||
"u", "21", "v", "22", "w", "23"
|
||||
"x", "24", "y", "25", "z", "26"
|
||||
"~", "30"
|
||||
|
||||
.. end ctrl mapping
|
||||
.. }}}
|
||||
|
||||
.. _fixterms_bugs:
|
||||
|
||||
Bugs in fixterms
|
||||
-------------------
|
||||
|
||||
The following is a list of errata in the `original fixterms proposal
|
||||
<http://www.leonerd.org.uk/hacks/fixterms/>`_, corrected in this
|
||||
specification.
|
||||
|
||||
* No way to disambiguate :kbd:`Esc` key presses, other than using 8-bit controls
|
||||
which are undesirable for other reasons
|
||||
|
||||
* Incorrectly claims special keys are sometimes encoded using ``CSI letter`` encodings when it
|
||||
is actually ``SS3 letter`` in all terminals newer than a VT-52, which is
|
||||
pretty much everything.
|
||||
|
||||
* :kbd:`ctrl+shift+tab` should be ``CSI 9 ; 6 u`` not ``CSI 1 ; 5 Z``
|
||||
(shift+tab is not a separate key from tab)
|
||||
|
||||
* No support for the :kbd:`super` modifier.
|
||||
|
||||
* Makes no mention of cursor key mode and how it changes encodings
|
||||
|
||||
* Incorrectly encoding shifted keys when shift modifier is used, for instance,
|
||||
for :kbd:`ctrl+shift+i` is encoded as :kbd:`ctrl+I`.
|
||||
|
||||
* No way to have non-conflicting escape codes for :kbd:`alt+letter,
|
||||
ctrl+letter, ctrl+alt+letter` key presses
|
||||
|
||||
* No way to specify both shifted and unshifted keys for robust shortcut
|
||||
matching (think matching :kbd:`ctrl+shift+equal` and :kbd:`ctrl+plus`)
|
||||
|
||||
* No way to specify alternate layout key. This is useful for keyboard layouts
|
||||
such as Cyrillic where you want the shortcut :kbd:`ctrl+c` to work when
|
||||
pressing the :kbd:`ctrl+С` on the keyboard.
|
||||
|
||||
* No way to report repeat and release key events, only key press events
|
||||
|
||||
* No way to report key events for presses that generate text, useful for
|
||||
gaming. Think of using the :kbd:`WASD` keys to control movement.
|
||||
|
||||
* Only a small subset of all possible functional keys are assigned numbers.
|
||||
|
||||
* Claims the ``CSI u`` escape code has no fixed meaning, but has been used for
|
||||
decades as ``SCORC`` for instance by xterm and ansi.sys and `DECSMBV
|
||||
<https://vt100.net/docs/vt510-rm/DECSMBV.html>`_ by the VT-510 hardware
|
||||
terminal. This doesn't really matter since these uses are for communication
|
||||
to the terminal not from the terminal.
|
||||
|
||||
* Handwaves that :kbd:`ctrl` *tends to* mask with ``0x1f``. In actual fact it
|
||||
does this only for some keys. The action of :kbd:`ctrl` is not specified and
|
||||
varies between terminals, historically because of different keyboard layouts.
|
||||
23
docs/kittens/broadcast.rst
Normal file
23
docs/kittens/broadcast.rst
Normal file
@@ -0,0 +1,23 @@
|
||||
broadcast - type text in all kitty windows
|
||||
==================================================
|
||||
|
||||
The ``broadcast`` kitten can be used to type text simultaneously in
|
||||
all kitty windows (or a subset as desired).
|
||||
|
||||
To use it, simply create a mapping in :file:`kitty.conf` such as::
|
||||
|
||||
map F1 launch --allow-remote-control kitty +kitten broadcast
|
||||
|
||||
Then press the :kbd:`F1` key and whatever you type in the newly created widow
|
||||
will be sent to all kitty windows.
|
||||
|
||||
You can use the options described below to control which windows
|
||||
are selected.
|
||||
|
||||
.. program:: kitty +kitten broadcast
|
||||
|
||||
|
||||
Command Line Interface
|
||||
--------------------------
|
||||
|
||||
.. include:: /generated/cli-kitten-broadcast.rst
|
||||
@@ -20,6 +20,9 @@ your machine).
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from typing import List
|
||||
from kitty.boss import Boss
|
||||
|
||||
def main(args: List[str]) -> str:
|
||||
# this is the main entry point of the kitten, it will be executed in
|
||||
# the overlay window when the kitten is launched
|
||||
@@ -28,7 +31,7 @@ your machine).
|
||||
# handle_result() function
|
||||
return answer
|
||||
|
||||
def handle_result(args: List[str], answer: str, target_window_id: int, boss: kitty.boss.Boss) -> None:
|
||||
def handle_result(args: List[str], answer: str, target_window_id: int, boss: Boss) -> None:
|
||||
# get the kitty window into which to paste answer
|
||||
w = boss.window_id_map.get(target_window_id)
|
||||
if w is not None:
|
||||
@@ -156,8 +159,8 @@ from ``kitty.fast_data_types``.
|
||||
|
||||
For example, to send a left click at position x: 2, y: 3 to the active window::
|
||||
|
||||
from kitty.fast_data_types import send_mouse_event, GLFW_MOUSE_BUTTON_LEFT, PRESS
|
||||
send_mouse_event(boss.active_window.screen, 2, 3, GLFW_MOUSE_BUTTON_LEFT, PRESS, 0)
|
||||
from kitty.fast_data_types import send_mouse_event, PRESS
|
||||
send_mouse_event(boss.active_window.screen, 2, 3, 1, PRESS, 0)
|
||||
|
||||
The function will only send the event if the program is receiving events of
|
||||
that type, and will return ``True`` if it sent the event, and ``False`` if not.
|
||||
@@ -182,6 +185,104 @@ The output of print statements will go to the ``STDOUT`` of the kitty process.
|
||||
So if you run kitty from another kitty instance, the output will be visible
|
||||
in the first kitty instance.
|
||||
|
||||
Adding options to kittens
|
||||
----------------------------
|
||||
|
||||
If you would like to use kitty's config framework to make your kittens
|
||||
configurable, you will need some boilerplate. In the directory
|
||||
of your kitten make the following files.
|
||||
|
||||
:file:`kitten_options_definition.py`
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from kitty.conf.types import Action, Definition
|
||||
|
||||
definition = Definition(
|
||||
'!kitten_options_utils',
|
||||
Action(
|
||||
'map', 'parse_map',
|
||||
{'key_definitions': 'kitty.conf.utils.KittensKeyMap'},
|
||||
['kitty.types.ParsedShortcut', 'kitty.conf.utils.KeyAction']
|
||||
),
|
||||
)
|
||||
|
||||
agr = definition.add_group
|
||||
egr = definition.end_group
|
||||
opt = definition.add_option
|
||||
map = definition.add_map
|
||||
|
||||
# main options {{{
|
||||
agr('main', 'Main')
|
||||
|
||||
opt('some_option', '33',
|
||||
option_type='some_option_parser',
|
||||
long_text='''
|
||||
Help text for this option
|
||||
'''
|
||||
)
|
||||
egr() # }}}
|
||||
|
||||
# shortcuts {{{
|
||||
agr('shortcuts', 'Keyboard shortcuts')
|
||||
|
||||
map('Quit', 'quit q quit')
|
||||
egr() # }}}
|
||||
|
||||
|
||||
:file:`kitten_options_utils.py`
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from kitty.conf.utils import KittensKeyDefinition, key_func, parse_kittens_key
|
||||
|
||||
func_with_args, args_funcs = key_func()
|
||||
FuncArgsType = Tuple[str, Sequence[Any]]
|
||||
|
||||
def some_option_parser(val: str) -> int:
|
||||
return int(val) + 3000
|
||||
|
||||
def parse_map(val: str) -> Iterable[KittensKeyDefinition]:
|
||||
x = parse_kittens_key(val, args_funcs)
|
||||
if x is not None:
|
||||
yield x
|
||||
|
||||
Then run::
|
||||
|
||||
kitty +runpy 'from kitty.conf.generate import main; main()' /path/to/kitten_options_definition.py
|
||||
|
||||
You can parse and read the options in your kitten using the following code:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from .kitten_options_types import Options, defaults
|
||||
from kitty.conf.utils import load_config as _load_config, parse_config_base
|
||||
from typing import Optional, Iterable, Dict, Any
|
||||
|
||||
def load_config(*paths: str, overrides: Optional[Iterable[str]] = None) -> Options:
|
||||
from .kitten_options_parse import (
|
||||
create_result_dict, merge_result_dicts, parse_conf_item
|
||||
)
|
||||
|
||||
def parse_config(lines: Iterable[str]) -> Dict[str, Any]:
|
||||
ans: Dict[str, Any] = create_result_dict()
|
||||
parse_config_base(
|
||||
lines,
|
||||
parse_conf_item,
|
||||
ans,
|
||||
)
|
||||
return ans
|
||||
|
||||
overrides = tuple(overrides) if overrides is not None else ()
|
||||
opts_dict, paths = _load_config(defaults, parse_config, merge_result_dicts, *paths, overrides=overrides)
|
||||
opts = Options(opts_dict)
|
||||
opts.config_paths = paths
|
||||
opts.config_overrides = overrides
|
||||
return opts
|
||||
|
||||
See the code for the builtin diff kitten for examples of creating more options
|
||||
and keyboard shortcuts.
|
||||
|
||||
.. _external_kittens:
|
||||
|
||||
Kittens created by kitty users
|
||||
|
||||
@@ -26,6 +26,7 @@ Major Features
|
||||
Screenshot, showing a sample diff
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
|
||||
Installation
|
||||
|
||||
@@ -28,11 +28,17 @@ to be used can be modified using options passed to the kitten. For example::
|
||||
will open the selected file in a new tab inside neovim when you press
|
||||
:kbd:`ctrl+g`.
|
||||
|
||||
Pressing :sc:`open_selected_hyperlink` will open hyperlinks, i.e. a URL
|
||||
that has been marked as such by the program running in the terminal,
|
||||
for example, by ``ls --hyperlink=auto``. You can also :doc:`customize what actions are
|
||||
taken for different types of URLs <../open_actions>`.
|
||||
|
||||
The hints kitten is very powerful to see more detailed help on its various
|
||||
options and modes of operation, see below. You can use these options to
|
||||
create mappings in :file:`kitty.conf` to select various different text
|
||||
snippets. See :sc:`insert_selected_path` for examples.
|
||||
|
||||
|
||||
Completely customizing the matching and actions of the kitten
|
||||
---------------------------------------------------------------
|
||||
|
||||
|
||||
71
docs/kittens/hyperlinked_grep.rst
Normal file
71
docs/kittens/hyperlinked_grep.rst
Normal file
@@ -0,0 +1,71 @@
|
||||
Hyperlinked grep
|
||||
=================
|
||||
|
||||
|
||||
This kitten allows you to search your files using `ripgrep
|
||||
<https://www.google.com/search?q=ripgrep>`_ and open the results
|
||||
directly in your favorite editor in the terminal, at the line containing
|
||||
the search result, simply by clicking on the result you want.
|
||||
|
||||
.. versionadded:: 0.19.0
|
||||
|
||||
To set it up, first create :file:`~/.config/kitty/open-actions.conf` with the
|
||||
following contents:
|
||||
|
||||
.. code:: conf
|
||||
|
||||
# Open any file with a fragment in vim, fragments are generated
|
||||
# by the hyperlink_grep kitten and nothing else so far.
|
||||
protocol file
|
||||
fragment_matches [0-9]+
|
||||
action launch --type=overlay vim +${FRAGMENT} ${FILE_PATH}
|
||||
|
||||
# Open text files without fragments in the editor
|
||||
protocol file
|
||||
mime text/*
|
||||
action launch --type=overlay ${EDITOR} ${FILE_PATH}
|
||||
|
||||
|
||||
Now, run a search with::
|
||||
|
||||
kitty +kitten hyperlinked_grep something
|
||||
|
||||
Hold down the :kbd:`ctrl+shift` keys and click on any of the
|
||||
result lines, to open the file in vim at the matching line. If
|
||||
you use some editor other than vim, you should adjust the
|
||||
:file:`open-actions.conf` file accordingly.
|
||||
|
||||
Finally, add an alias to your shell's rc files to invoke the kitten as ``hg``::
|
||||
|
||||
alias hg='kitty +kitten hyperlinked_grep'
|
||||
|
||||
|
||||
You can now run searches with::
|
||||
|
||||
hg some-search-term
|
||||
|
||||
If you want to enable completion, for the kitten, you can delegate completion
|
||||
to rg. For that, instead of using an alias create a simple wrapper script named
|
||||
:file:`hg` somewhere in your ``PATH``:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
#!/bin/sh
|
||||
exec kitty +kitten hyperlinked_grep "$@"
|
||||
|
||||
Then, for example, for ZSH, add the following to :file:`.zshrc`::
|
||||
|
||||
compdef _rg hg
|
||||
|
||||
To learn more about kitty's powerful framework for customizing URL click
|
||||
actions, :doc:`see here <../open_actions>`.
|
||||
|
||||
Hopefully, someday this functionality will make it into some `upstream grep
|
||||
<https://github.com/BurntSushi/ripgrep/issues/665>`_
|
||||
program directly removing the need for this kitten.
|
||||
|
||||
|
||||
.. note::
|
||||
While you can pass any of ripgrep's comand line options to the kitten and
|
||||
they will be forwarded to rg, do not use options that change the output
|
||||
formatting as the kitten works by parsing the output from ripgrep.
|
||||
21
docs/kittens/query_terminal.rst
Normal file
21
docs/kittens/query_terminal.rst
Normal file
@@ -0,0 +1,21 @@
|
||||
Query terminal
|
||||
=================
|
||||
|
||||
Used to query kitty from terminal programs about version, values of various
|
||||
runtime options controlling its features, etc.
|
||||
|
||||
The querying is done using the (*semi*) standard XTGETTCAP escape sequence
|
||||
pioneered by XTerm, so it works over SSH as well. The downside is that it
|
||||
is slow, since it requires a roundtrip to the terminal emulator and back.
|
||||
|
||||
If you want to do some of the same querying in your terminal program without
|
||||
depending on the kitten, you can do so, by processing the same escape codes.
|
||||
Search `this page <https://invisible-island.net/xterm/ctlseqs/ctlseqs.html>`_
|
||||
for *XTGETTCAP* to see the syntax for the escape code and read the source
|
||||
of this kitten to find the values of the keys for the various queries.
|
||||
|
||||
|
||||
Command Line Interface
|
||||
-------------------------
|
||||
|
||||
.. include:: ../generated/cli-kitten-query_terminal.rst
|
||||
37
docs/kittens/remote_file.rst
Normal file
37
docs/kittens/remote_file.rst
Normal file
@@ -0,0 +1,37 @@
|
||||
Remote files
|
||||
==============
|
||||
|
||||
|kitty| has the ability to easily *Edit*, *Open* or *Download* files
|
||||
from a computer into which you are SSHed. In your SSH session run::
|
||||
|
||||
ls --hyperlink=auto
|
||||
|
||||
Then hold down :kbd:`ctrl+shift` and click the name of the file.
|
||||
|
||||
.. figure:: ../screenshots/remote_file.png
|
||||
:alt: Remote file actions
|
||||
:align: center
|
||||
:scale: 100%
|
||||
|
||||
Remote file actions
|
||||
|
||||
|kitty| will ask you what you want to do with the remote file. You can choose
|
||||
to *Edit* it in which case kitty will download it and open it locally in your
|
||||
``EDITOR``. As you make changes to the file, they are automatically transferred
|
||||
to the remote computer. Note that this happens without needing to install *any*
|
||||
special software on the server, beyond ``ls`` that supports hyperlinks.
|
||||
|
||||
.. versionadded:: 0.19.0
|
||||
|
||||
.. note::
|
||||
Nested SSH sessions are not supported. The kitten will always try to copy
|
||||
remote files from the first SSH host. This is because there is no way for
|
||||
|kitty| to detect and follow a nested SSH session robustly.
|
||||
|
||||
.. note::
|
||||
If you have not setup automatic password-less SSH access, then, when
|
||||
editing starts you will be asked to enter your password just once,
|
||||
thereafter the SSH connection will be re-used.
|
||||
|
||||
Similarly, you can choose to save the file to the local computer or download
|
||||
and open it in its default file handler.
|
||||
@@ -18,13 +18,14 @@ typing a leading period and then the two character index and pressing Enter.
|
||||
The up and down arrow keys can be used to choose the previous and next unicode
|
||||
symbol respectively.
|
||||
|
||||
In :guilabel:`Name` mode you instead type words from the character name and use the arrow
|
||||
keys/tab to select the character from the displayed matches. You can also type
|
||||
a leading period and the index for the match if you don't like to use arrow
|
||||
keys.
|
||||
In :guilabel:`Name` mode you instead type words from the character name and use
|
||||
the arrow keys/tab to select the character from the displayed matches. You can
|
||||
also type a space followed by a period and the index for the match if you don't
|
||||
like to use arrow keys.
|
||||
|
||||
You can switch between modes using either the function keys or by pressing
|
||||
:kbd:`Ctrl+[` and :kbd:`Ctrl+]`.
|
||||
:kbd:`Ctrl+[` and :kbd:`Ctrl+]` or by pressing :kbd:`Ctrl+Tab` and
|
||||
:kbd:`Ctrl+Shift+Tab`.
|
||||
|
||||
|
||||
Command Line Interface
|
||||
|
||||
@@ -19,7 +19,6 @@ launch::
|
||||
|
||||
map f1 launch vim path/to/some/file
|
||||
|
||||
|
||||
To open a new window with the same working directory as the currently
|
||||
active window::
|
||||
|
||||
@@ -29,6 +28,10 @@ To open the new window in a new tab::
|
||||
|
||||
map f1 launch --type=tab
|
||||
|
||||
To run multiple commands in a shell, use::
|
||||
|
||||
map f1 launch sh -c "ls && zsh"
|
||||
|
||||
To pass the contents of the current screen and scrollback to the started process::
|
||||
|
||||
map f1 launch --stdin-source=@screen_scrollback less
|
||||
@@ -54,9 +57,34 @@ Special arguments
|
||||
-------------------
|
||||
|
||||
There are a few special placeholder arguments that can be specified as part of
|
||||
the command line. Namely ``@selection`` which is replaced by the current
|
||||
selection and ``@active-kitty-window-id`` which is replaced by the id of the
|
||||
currently active kitty window. For example::
|
||||
the command line:
|
||||
|
||||
|
||||
``@selection``
|
||||
replaced by the currently selected text
|
||||
|
||||
``@active-kitty-window-id``
|
||||
replaced by the id of the currently active kitty window
|
||||
|
||||
``@line-count``
|
||||
replaced by the number of lines in STDIN. Only present when passing some
|
||||
data to STDIN
|
||||
|
||||
``@input-line-number``
|
||||
replaced the number of lines a pager should scroll to match the current
|
||||
scroll position in kitty. See :opt:`scrollback_pager` for details
|
||||
|
||||
``@scrolled-by``
|
||||
replaced by the number of lines kitty is currently scrolled by
|
||||
|
||||
``@cursor-x``
|
||||
replaced by the current cursor x position with 1 being the leftmost cell
|
||||
|
||||
``@cursor-y``
|
||||
replaced by the current cursor y position with 1 being the topmost cell
|
||||
|
||||
|
||||
For example::
|
||||
|
||||
map f1 launch my-program @active-kitty-window-id
|
||||
|
||||
@@ -74,6 +102,9 @@ functions for the events you are interested in, for example:
|
||||
def on_resize(boss, window, data):
|
||||
# Here data will contain old_geometry and new_geometry
|
||||
|
||||
def on_focus_change(boss, window, data):
|
||||
# Here data kill contain focused
|
||||
|
||||
def on_close(boss, window, data):
|
||||
# called when window is closed, typically when the program running in
|
||||
# it exits.
|
||||
@@ -90,6 +121,16 @@ in the window and ``window.id`` is the internal kitty ``id`` of the
|
||||
window.
|
||||
|
||||
|
||||
Finding executables
|
||||
-----------------------
|
||||
|
||||
When you specify a command to run as just a name rather than an absolute path,
|
||||
it is searched for in the system-wide ``PATH`` environment variable. Note that
|
||||
this **may not** be the value of ``PATH`` inside a shell, as shell startup scripts
|
||||
often change the value of this variable. If it is not found there, then a
|
||||
system specific list of default paths is searched. If it is still not found,
|
||||
then your shell is run and the value of ``PATH`` inside the shell is used.
|
||||
|
||||
Syntax reference
|
||||
------------------
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ are available use :opt:`enabled_layouts`, the first listed layout becomes
|
||||
the default. Individual layouts and how to use them are described below.
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
|
||||
The Stack Layout
|
||||
@@ -171,6 +172,8 @@ are placed into vertical or horizontal splits, by default::
|
||||
│ │ │
|
||||
└──────────────┴───────────────┘
|
||||
|
||||
.. versionadded:: 0.17.0
|
||||
The Splits layout
|
||||
|
||||
|
||||
The Horizontal Layout
|
||||
|
||||
@@ -19,12 +19,12 @@ If you want to make it case-insensitive, use::
|
||||
|
||||
To make it match only complete words, use::
|
||||
|
||||
map f1 toggle_marker regex 1 \bERROR\b
|
||||
map f1 toggle_marker regex 1 \\bERROR\\b
|
||||
|
||||
Suppose you want to highlight both :code:`ERROR` and :code:`WARNING`, case
|
||||
insensitively::
|
||||
|
||||
map f1 toggle_marker iregex 1 \bERROR\b 2 \bWARNING\b
|
||||
map f1 toggle_marker iregex 1 \\bERROR\\b 2 \\bWARNING\\b
|
||||
|
||||
kitty supports up to 3 mark groups (the numbers in the commands above). You
|
||||
can control the colors used for these groups in :file:`kitty.conf` with::
|
||||
|
||||
95
docs/open_actions.rst
Normal file
95
docs/open_actions.rst
Normal file
@@ -0,0 +1,95 @@
|
||||
Customizing the actions taken when clicking on links
|
||||
======================================================
|
||||
|
||||
|kitty| has support for `terminal hyperlinks <https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda>`_. These
|
||||
are generated by many terminal programs, such as ``ls``, ``gcc``, ``systemd``,
|
||||
``mdcat``, etc. You can customize exactly what happens when clicking on these hyperlinks
|
||||
in |kitty|.
|
||||
|
||||
You can tell kitty to take arbitrarily many, complex actions
|
||||
when a link is clicked. Let us illustrate with some examples, first. Create
|
||||
the file :file:`~/.config/kitty/open-actions.conf` with the following:
|
||||
|
||||
.. code:: conf
|
||||
|
||||
# Open any image in the full kitty window by clicking on it
|
||||
protocol file
|
||||
mime image/*
|
||||
action launch --type=overlay kitty +kitten icat --hold ${FILE_PATH}
|
||||
|
||||
Now, run ``ls --hyperlink=auto`` in kitty and click on the filename of an
|
||||
image, holding down :kbd:`ctrl+shift`. It will be opened over the current
|
||||
window. Press any key to close it.
|
||||
|
||||
Each entry in :file:`open-actions.conf` consists of one or more
|
||||
:ref:`matching_criteria`, such as ``protocol`` and ``mime`` and one or more
|
||||
``action`` entries. In the example above kitty uses the :doc:`launch <launch>`
|
||||
action which can be used to run external programs. Entries are separated by
|
||||
blank lines.
|
||||
|
||||
Actions are very powerful, anything that you can map to a key combination in
|
||||
`kitty.conf` can be used as an action. You can specify more than one action per
|
||||
entry if you like, for example:
|
||||
|
||||
|
||||
.. code:: conf
|
||||
|
||||
# Tail a log file (*.log) in a new OS Window and reduce its font size
|
||||
protocol file
|
||||
ext log
|
||||
action launch --title ${FILE} --type=os-window tail -f ${FILE_PATH}
|
||||
action change_font_size current -2
|
||||
|
||||
|
||||
In the action specification you can expand environment variables, as shown in
|
||||
the examples above. In addition to regular environment variables, there are
|
||||
some special variables, documented below:
|
||||
|
||||
``URL``
|
||||
The full URL being opened
|
||||
|
||||
``FILE_PATH``
|
||||
The path portion of the URL (unquoted)
|
||||
|
||||
``FILE``
|
||||
The file portion of the path of the URL (unquoted)
|
||||
|
||||
``FRAGMENT``
|
||||
The fragment (unquoted), if any of the URL or the empty string.
|
||||
|
||||
.. _matching_criteria:
|
||||
|
||||
Matching criteria
|
||||
------------------
|
||||
|
||||
An entry in :file:`open-actions.conf` must have one or more matching criteria.
|
||||
URLs that match all criteria for an entry will trigger that entry's actions.
|
||||
Processing stops at the first matching entry, so put more specific matching
|
||||
criteria at the start of the list. Entries in the file are separated by blank
|
||||
lines. The various available criteria are:
|
||||
|
||||
``protocol``
|
||||
A comma separated list of protocols, for example: ``http, https``. If
|
||||
absent, there is no constraint on protocol
|
||||
|
||||
``url``
|
||||
A regular expression that must match against the entire (unquoted) URL
|
||||
|
||||
``fragment_matches``
|
||||
A regular expression that must match against the fragment (part after #) in
|
||||
the URL
|
||||
|
||||
``mime``
|
||||
A comma separated list of MIME types, for example: ``text/*, image/*,
|
||||
application/pdf``. You can add MIME types to kitty by creating the
|
||||
:file:`mime.types` in the kitty configuration directory. Useful if your
|
||||
system MIME database does not have definitions you need. This file is
|
||||
in the standard format of one definition per line, like: ``text/plain rst
|
||||
md``.
|
||||
|
||||
``ext``
|
||||
A comma separated list of file extensions, for example: ``jpeg, tar.gz``
|
||||
|
||||
``file``
|
||||
A shell glob pattern that must match the filename, for example:
|
||||
``image-??.png``
|
||||
@@ -16,9 +16,11 @@ is to make it as easy to implement these protocol extensions as possible,
|
||||
thereby hopefully encouraging their widespread adoption.
|
||||
|
||||
If you wish to discuss these extensions, propose additions/changes to them
|
||||
please do so by opening issues in the github bug tracker.
|
||||
please do so by opening issues in the `GitHub
|
||||
<https://github.com/kovidgoyal/kitty/issues>`_ bug tracker.
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Colored and styled underlines
|
||||
-------------------------------
|
||||
@@ -69,91 +71,9 @@ of this protocol to enable drawing of arbitrary raster images in the terminal.
|
||||
Keyboard handling
|
||||
-------------------
|
||||
|
||||
There are various problems with the current state of keyboard handling. They
|
||||
include:
|
||||
|
||||
* No way to use modifiers other than ``Ctrl`` and ``Alt``
|
||||
|
||||
* No way to reliably use multiple modifier keys, other than, ``Shift+Alt``.
|
||||
|
||||
* No way to handle different types of keyboard events, such as press, release or repeat
|
||||
|
||||
* No reliable way to distinguish single ``Esc`` keypresses from the start of a
|
||||
escape sequence. Currently, client programs use fragile timing related hacks
|
||||
for this, leading to bugs, for example:
|
||||
`neovim #2035 <https://github.com/neovim/neovim/issues/2035>`_.
|
||||
|
||||
There are already two distinct keyboard handling modes, *normal mode* and
|
||||
*application mode*. These modes generate different escape sequences for the
|
||||
various special keys (arrow keys, function keys, home/end etc.) Most terminals
|
||||
start out in normal mode, however, most shell programs like ``bash`` switch them to
|
||||
application mode. We propose adding a third mode, named *full mode* that addresses
|
||||
the shortcomings listed above.
|
||||
|
||||
Switching to the new *full mode* is accomplished using the standard private
|
||||
mode DECSET escape sequence::
|
||||
|
||||
<ESC>[?2017h
|
||||
|
||||
and to leave *full mode*, use DECRST::
|
||||
|
||||
<ESC>[?2017l
|
||||
|
||||
The number ``2017`` above is not used for any existing modes, as far as I know.
|
||||
Client programs can query if the terminal emulator is in *full mode* by using
|
||||
the standard `DECRQM <https://vt100.net/docs/vt510-rm/DECRQM.html>`_ escape sequence.
|
||||
|
||||
The new mode works as follows:
|
||||
|
||||
* All printable key presses without modifier keys are sent just as in the
|
||||
*normal mode*. This means all printable ASCII characters and in addition,
|
||||
``Enter``, ``Space`` and ``Backspace``. Also any unicode characters generated by
|
||||
platform specific extended input modes, such as using the ``AltGr`` key. This
|
||||
is done so that client programs that are not aware of this mode can still
|
||||
handle basic text entry, so if a *full mode* using program crashes and does
|
||||
not reset, the user can still issue a ``reset`` command in the shell to restore
|
||||
normal key handling. Note that this includes pressing the ``Shift`` modifier
|
||||
and printable keys. Note that this means there are no repeat and release
|
||||
events for these keys and also for the left and right shift keys.
|
||||
|
||||
* For non printable keys and key combinations including one or more modifiers,
|
||||
an escape sequence encoding the key event is sent. For details on the
|
||||
escape sequence, see below.
|
||||
|
||||
The escape sequence encodes the following properties:
|
||||
|
||||
* Type of event: ``press,repeat,release``
|
||||
* Modifiers pressed at the time of the event
|
||||
* The actual key being pressed
|
||||
|
||||
Schematically::
|
||||
|
||||
<ESC>_K<type><modifiers><key><ESC>\
|
||||
|
||||
Where ``<type>`` is one of ``p`` -- press, ``r`` -- release and ``t`` -- repeat.
|
||||
Modifiers is a bitmask represented as a single base64 digit. Shift -- ``0x1``,
|
||||
Alt -- ``0x2``, Control -- ``0x4`` and Super -- ``0x8``. ``<key>`` is a number
|
||||
(encoded in base85) corresponding to the key pressed. The key name to number
|
||||
mapping is defined in :doc:`this table <key-encoding>`.
|
||||
|
||||
Client programs must ignore events for keys they do not know. The mapping in
|
||||
the above table is stable and will never change, however, new codes might be
|
||||
added to it in the future, for new keys.
|
||||
|
||||
For example::
|
||||
|
||||
<ESC>_KpGp<ESC>\ is <Ctrl>+<Alt>+x (press)
|
||||
<ESC>_KrP8<ESC>\ is <Ctrl>+<Alt>+<Shift>+<Super>+PageUp (release)
|
||||
|
||||
This encoding means each key event is represented by 8 or 9 printable ascii
|
||||
only bytes, for maximum robustness.
|
||||
|
||||
To see the full mode in action, run::
|
||||
|
||||
kitty +kitten key_demo
|
||||
|
||||
Support for this mode is indicated by the ``fullkbd`` boolean capability
|
||||
in the terminfo database, in case querying for it via DECQRM is inconvenient.
|
||||
kitty has a :doc:`keyboard protocol <keyboard-protocol>` for reporting key
|
||||
presses to terminal applications that solves all key handling issues in
|
||||
terminal applications.
|
||||
|
||||
.. _ext_styles:
|
||||
|
||||
@@ -180,23 +100,32 @@ rectangular region of the screen from (3, 4) to (10, 11), you use::
|
||||
<ESC>[2*x<ESC>[4;3;11;10;44$r<ESC>[*x
|
||||
|
||||
|
||||
Saving and restoring the default foreground/background/selection/cursor colors
|
||||
Saving and restoring colors
|
||||
---------------------------------------------------------------------------------
|
||||
|
||||
It is often useful for a full screen application with its own color themes
|
||||
to set the default foreground, background, selection and cursor colors. This
|
||||
allows for various performance optimizations when drawing the screen. The
|
||||
problem is that if the user previously used the escape codes to change these
|
||||
colors herself, then running the full screen application will lose her
|
||||
changes even after it exits. To avoid this, kitty introduces a new pair of
|
||||
*OSC* escape codes to push and pop the current color values from a stack::
|
||||
It is often useful for a full screen application with its own color themes to
|
||||
set the default foreground, background, selection and cursor colors and the
|
||||
ANSI color table. This allows for various performance optimizations when
|
||||
drawing the screen. The problem is that if the user previously used the escape
|
||||
codes to change these colors herself, then running the full screen application
|
||||
will lose her changes even after it exits. To avoid this, kitty introduces a
|
||||
new pair of *OSC* escape codes to push and pop the current color values from a
|
||||
stack::
|
||||
|
||||
<ESC>]30001<ESC>\ # push onto stack
|
||||
<ESC>]30101<ESC>\ # pop from stack
|
||||
|
||||
These escape codes save/restore the so called *dynamic colors*, default
|
||||
These escape codes save/restore the colors, default
|
||||
background, default foreground, selection background, selection foreground and
|
||||
cursor color.
|
||||
cursor color and the 256 colors of the ANSI color table.
|
||||
|
||||
.. note:: In July 2020, after several years, XTerm copied this protocol
|
||||
extension, without acknowledgement, and using incompatible escape codes
|
||||
(XTPUSHCOLORS, XTPOPCOLORS, XTREPORTCOLORS). And they decided to save not
|
||||
just the dynamic colors but the entire ANSI color table. In the interests of
|
||||
promoting interoperability, kitty added support for XTerm's escape codes as
|
||||
well, and changed this extension to also save/restore the entire ANSI color
|
||||
table.
|
||||
|
||||
|
||||
Pasting to clipboard
|
||||
@@ -228,3 +157,163 @@ no ill-effects in other terminal emulators.
|
||||
In case you're using software that can't be easily adapted to this
|
||||
protocol extension, it can be disabled by specifying ``no-append`` to the
|
||||
:opt:`clipboard_control` setting.
|
||||
|
||||
|
||||
.. _unscroll:
|
||||
|
||||
Unscrolling the screen
|
||||
-----------------------
|
||||
|
||||
This is a small extension to the `SD (Pan up) escape code
|
||||
<https://vt100.net/docs/vt510-rm/SD.html>`_ from the VT-420 terminal. The
|
||||
``SD`` escape code normally causes the text on screen to scroll down by the
|
||||
specified number of lines, with empty lines appearing at the top of the screen.
|
||||
This extension allows the new lines to be filled in from the scrollback buffer
|
||||
instead of being blank.
|
||||
|
||||
The motivation for this is that many modern shells will show completions in a
|
||||
block of lines under the cursor, this causes some of the on-screen text to be
|
||||
lost even after the completion is completed, because it has scrolled off
|
||||
screen. This escape code allows that text to be restored.
|
||||
|
||||
If the scrollback buffer is empty or there is no scrollback buffer, such as for
|
||||
the alternate screen, then the newly inserted lines must be empty, just as with
|
||||
the original ``SD`` escape code. The maximum number of lines that can be
|
||||
scrolled down is implementation defined, but must be at least one screen worth.
|
||||
|
||||
The syntax of the escape code is identical to that of ``SD`` except that it has
|
||||
a trailing ``+`` modifier. This is legal under the `ECMA 48 standard
|
||||
<https://www.ecma-international.org/publications-and-standards/standards/ecma-48/>`_
|
||||
and unused for any other purpose as far as I can tell. So for example, to
|
||||
unscroll three lines, the escape code would be::
|
||||
|
||||
CSI 3 + T
|
||||
|
||||
See `discussion here
|
||||
<https://gitlab.freedesktop.org/terminal-wg/specifications/-/issues/30>`_.
|
||||
|
||||
.. versionadded:: 0.20.2
|
||||
|
||||
|
||||
.. _desktop_notifications:
|
||||
|
||||
|
||||
Desktop notifications
|
||||
---------------------------------
|
||||
|
||||
|kitty| implements an extensible escape code (OSC 99) to show desktop
|
||||
notifications. It is easy to use from shell scripts and fully extensible to
|
||||
show title and body. Clicking on the notification can optionally focus the
|
||||
window it came from, and/or send an escape code back to the application running
|
||||
in that window.
|
||||
|
||||
The design of the escape code is partially based on the discussion in
|
||||
the defunct
|
||||
`terminal-wg <https://gitlab.freedesktop.org/terminal-wg/specifications/-/issues/13>`_
|
||||
|
||||
The escape code has the form::
|
||||
|
||||
<OSC> 99 ; metadata ; payload <terminator>
|
||||
|
||||
Here ``<OSC>`` is :code:`<ESC>]` and ``<terminator>`` is
|
||||
:code:`<ESC><backslash>`. The metadata is a section of colon separated
|
||||
:code:`key=value` pairs. Every key must be a single character from the set
|
||||
:code:`a-zA-Z` and every value must be a word consisting of characters from
|
||||
the set :code:`a-zA-Z0-9-_/\+.,(){}[]*&^%$#@!`~`. The payload must be
|
||||
interpreted based on the metadata section. The two semi-colons *must* always be
|
||||
present even when no metadata is present.
|
||||
|
||||
Before going into details, lets see how one can display a simple, single line
|
||||
notification from a shell script::
|
||||
|
||||
printf '\x1b]99;;Hello world\x1b\\'
|
||||
|
||||
To show a message with a title and a body::
|
||||
|
||||
printf '\x1b]99;i=1:d=0;Hello world\x1b\\'
|
||||
printf '\x1b]99;i=1:d=1:p=body;This is cool\x1b\\'
|
||||
|
||||
The most important key in the metadata is the ``p`` key, it controls how the
|
||||
payload is interpreted. A value of ``title`` means the payload is setting the
|
||||
title for the notification. A value of ``body`` means it is setting the body,
|
||||
and so on, see the table below for full details.
|
||||
|
||||
The design of the escape code is fundamentally chunked, this is because
|
||||
different terminal emulators have different limits on how large a single escape
|
||||
code can be. Chunking is accomplished by the ``i`` and ``d`` keys. The ``i``
|
||||
key is the *notification id* which can be any string containing the characters
|
||||
``[a-zA-Z0-9_-+.]``. The ``d`` key stands for *done* and
|
||||
can only take the values ``0`` and ``1``. A value of ``0`` means the
|
||||
notification is not yet done and the terminal emulator should hold off
|
||||
displaying it. A value of ``1`` means the notification is done, and should be
|
||||
displayed. You can specify the title or body multiple times and the terminal
|
||||
emulator will concatenate them, thereby allowing arbitrarily long text
|
||||
(terminal emulators are free to impose a sensible limit to avoid
|
||||
Denial-of-Service attacks).
|
||||
|
||||
Both the ``title`` and ``body`` payloads must be either UTF-8 encoded plain
|
||||
text with no embedded escape codes, or UTF-8 text that is base64 encoded, in
|
||||
which case there must be an ``e=1`` key in the metadata to indicate the payload
|
||||
is base64 encoded.
|
||||
|
||||
When the user clicks the notification, a couple of things can happen, the
|
||||
terminal emulator can focus the window from which the notification came, and/or
|
||||
it can send back an escape code to the application indicating the notification
|
||||
was activated. This is controlled by the ``a`` key which takes a comma
|
||||
separated set of values, ``report`` and ``focus``. The value ``focus`` means
|
||||
focus the window from which the notification was issued and is the default.
|
||||
``report`` means send an escape code back to the application. The format of the
|
||||
returned escape code is::
|
||||
|
||||
<OSC> 99 ; i=identifier ; <terminator>
|
||||
|
||||
The value of ``identifier`` comes from the ``i`` key in the escape code sent by
|
||||
the application. If the application sends no identifier, then the terminal
|
||||
*must* use ``i=0``. Actions can be preceded by a negative sign to turn them
|
||||
off, so for example if you do not want any action, turn off the default
|
||||
``focus`` action with::
|
||||
|
||||
a=-focus
|
||||
|
||||
Complete specification of all the metadata keys is in the table below. If a
|
||||
terminal emulator encounters a key in the metadata it does not understand,
|
||||
the key *must* be ignored, to allow for future extensibility of this escape
|
||||
code. Similarly if values for known keys are unknown, the terminal emulator
|
||||
*should* either ignore the entire escape code or perform a best guess effort
|
||||
to display it based on what it does understand.
|
||||
|
||||
.. note::
|
||||
It is possible to extend this escape code to allow specifying an icon for
|
||||
the notification, however, given that some platforms, such as macOS, dont
|
||||
allow displaying custom icons on a notification, at all, it was decided to
|
||||
leave it out of the spec for the time being.
|
||||
|
||||
Similarly, features such as scheduled notifications could be added in future
|
||||
revisions.
|
||||
|
||||
|
||||
======= ==================== ========= =================
|
||||
Key Value Default Description
|
||||
======= ==================== ========= =================
|
||||
``a`` Comma separated list ``focus`` What action to perform when the
|
||||
of ``report``, notification is clicked
|
||||
``focus``, with
|
||||
optional leading
|
||||
``-``
|
||||
|
||||
``d`` ``0`` or ``1`` ``1`` Indicates if the notification is
|
||||
complete or not.
|
||||
|
||||
``e`` ``0`` or ``1`` ``0`` If set to ``1`` means the payload is base64 encoded UTF-8,
|
||||
otherwise it is plain UTF-8 text with no C0 control codes in it
|
||||
|
||||
``i`` ``[a-zA-Z0-9-_+.]`` ``0`` Identifier for the notification
|
||||
|
||||
``p`` One of ``title`` or ``title`` Whether the payload is the notification title or body. If a
|
||||
``body``. notification has no title, the body will be used as title.
|
||||
======= ==================== ========= =================
|
||||
|
||||
|
||||
.. note::
|
||||
|kitty| also supports the legacy OSC 9 protocol developed by iTerm2 for
|
||||
desktop notifications.
|
||||
|
||||
@@ -12,7 +12,7 @@ Where ``<ESC>`` is the byte ``0x1b``. The JSON object has the form::
|
||||
{
|
||||
"cmd": "command name",
|
||||
"version": <kitty version>,
|
||||
"no_response": Optional Boolean,
|
||||
"no_response": <Optional Boolean>,
|
||||
"payload": <Optional JSON object>,
|
||||
}
|
||||
|
||||
@@ -26,4 +26,16 @@ Set ``no_response`` to ``true`` if you don't want a response from kitty.
|
||||
The optional payload is a JSON object that is specific to the actual command being sent.
|
||||
The fields in the object for every command are documented below.
|
||||
|
||||
As a quick example showing how easy to use this protocol is, we will implement
|
||||
the ``@ ls`` command from the shell using only shell tools. First, run kitty
|
||||
as::
|
||||
|
||||
kitty -o allow_remote_control=socket-only --listen-on unix:/tmp/test
|
||||
|
||||
Now, in a different terminal, you can get the pretty printed ``@ ls`` output
|
||||
with the following command line::
|
||||
|
||||
echo -en '\eP@kitty-cmd{"cmd":"ls","version":[0,14,2]}\e\' | socat - unix:/tmp/test | awk '{ print substr($0, 13, length($0) - 14) }' | jq -c '.data | fromjson' | jq .
|
||||
|
||||
|
||||
.. include:: generated/rc.rst
|
||||
|
||||
@@ -115,8 +115,10 @@ shell. Run ``kitty @`` with no arguments and you will be dropped into the |kitty
|
||||
shell with completion for |kitty| command names and options.
|
||||
|
||||
You can even open the |kitty| shell inside a running |kitty| using a simple
|
||||
keyboard shortcut (:sc:`kitty_shell` by default). This has the added
|
||||
advantage that you don't need to use ``allow_remote_control`` to make it work.
|
||||
keyboard shortcut (:sc:`kitty_shell` by default).
|
||||
|
||||
.. note:: This has the added advantage that you don't need to use
|
||||
``allow_remote_control`` to make it work.
|
||||
|
||||
|
||||
Allowing only some windows to control kitty
|
||||
@@ -134,6 +136,12 @@ still write to the pipes of any other program on the same computer and
|
||||
therefore can control |kitty|. It can, however, be useful to block programs
|
||||
running on other computers (for example, over ssh) or as other users.
|
||||
|
||||
.. note:: You dont need ``allow_remote_control`` to make this work as it is
|
||||
limited to only programs running in that specific window. Be careful with
|
||||
what programs you run in such windows, since they can effectively control
|
||||
kitty, as if you were running with ``allow_remote_control`` turned on.
|
||||
|
||||
|
||||
Mapping key presses to remote control commands
|
||||
--------------------------------------------------
|
||||
|
||||
@@ -146,6 +154,23 @@ Then pressing the :kbd:`F1` key will set the active window margins to 30.
|
||||
The syntax for what follows :code:`remote_control` is exactly the same
|
||||
as the syntax for what follows :code:`kitty @` above.
|
||||
|
||||
.. note:: You do not need ``allow_remote_control`` to use these mappings,
|
||||
as they are not actual remote programs, but are simply a way to resuse
|
||||
the remote control infrastructure via keybings.
|
||||
|
||||
|
||||
Broadcasting what you type to all kitty windows
|
||||
--------------------------------------------------
|
||||
|
||||
As a simple illustration of the power of remote control, lets
|
||||
have what we type sent to all open kitty windows. To do that define the
|
||||
following mapping in :file:`kitty.conf`::
|
||||
|
||||
map F1 launch --allow-remote-control kitty +kitten broadcast
|
||||
|
||||
Now press, F1 and start typing, what you type will be sent to all windows,
|
||||
live, as you type it.
|
||||
|
||||
|
||||
Documentation for the remote control protocol
|
||||
-----------------------------------------------
|
||||
|
||||
BIN
docs/screenshots/remote_file.png
Normal file
BIN
docs/screenshots/remote_file.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
@@ -250,13 +250,16 @@ def write_header(text: str, path: str) -> None:
|
||||
def graphics_parser() -> None:
|
||||
flag = frozenset
|
||||
keymap: KeymapType = {
|
||||
'a': ('action', flag('tTqpd')),
|
||||
'd': ('delete_action', flag('aAiIcCpPqQxXyYzZ')),
|
||||
'a': ('action', flag('tTqpdfa')),
|
||||
'd': ('delete_action', flag('aAiIcCfFnNpPqQxXyYzZ')),
|
||||
't': ('transmission_type', flag('dfts')),
|
||||
'o': ('compressed', flag('z')),
|
||||
'f': ('format', 'uint'),
|
||||
'm': ('more', 'uint'),
|
||||
'i': ('id', 'uint'),
|
||||
'I': ('image_number', 'uint'),
|
||||
'p': ('placement_id', 'uint'),
|
||||
'q': ('quiet', 'uint'),
|
||||
'w': ('width', 'uint'),
|
||||
'h': ('height', 'uint'),
|
||||
'x': ('x_offset', 'uint'),
|
||||
@@ -270,6 +273,7 @@ def graphics_parser() -> None:
|
||||
'X': ('cell_x_offset', 'uint'),
|
||||
'Y': ('cell_y_offset', 'uint'),
|
||||
'z': ('z_index', 'int'),
|
||||
'C': ('cursor_movement', 'uint'),
|
||||
}
|
||||
text = generate('parse_graphics_code', 'screen_handle_graphics_command', 'graphics_command', keymap, 'GraphicsCommand')
|
||||
write_header(text, 'kitty/parse-graphics-command.h')
|
||||
|
||||
17
gen-config.py
Executable file
17
gen-config.py
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
|
||||
from kitty.conf.generate import write_output
|
||||
|
||||
|
||||
def main() -> None:
|
||||
from kitty.options.definition import definition
|
||||
write_output('kitty', definition)
|
||||
from kittens.diff.options.definition import definition as kd
|
||||
write_output('kittens.diff', kd)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
412
gen-key-constants.py
Executable file
412
gen-key-constants.py
Executable file
@@ -0,0 +1,412 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import string
|
||||
from typing import Dict, List, Any
|
||||
from pprint import pformat
|
||||
|
||||
functional_key_defs = '''# {{{
|
||||
# kitty XKB macVK macU
|
||||
escape Escape 0x35 -
|
||||
enter Return 0x24 NSCarriageReturnCharacter
|
||||
tab Tab 0x30 NSTabCharacter
|
||||
backspace BackSpace 0x33 NSBackspaceCharacter
|
||||
insert Insert 0x72 Insert
|
||||
delete Delete 0x75 Delete
|
||||
left Left 0x7B LeftArrow
|
||||
right Right 0x7C RightArrow
|
||||
up Up 0x7E UpArrow
|
||||
down Down 0x7D DownArrow
|
||||
page_up Page_Up 0x74 PageUp
|
||||
page_down Page_Down 0x79 PageDown
|
||||
home Home 0x73 Home
|
||||
end End 0x77 End
|
||||
caps_lock Caps_Lock 0x39 -
|
||||
scroll_lock Scroll_Lock - ScrollLock
|
||||
num_lock Num_Lock 0x47 ClearLine
|
||||
print_screen Print - PrintScreen
|
||||
pause Pause - Pause
|
||||
menu Menu 0x6E Menu
|
||||
f1 F1 0x7A F1
|
||||
f2 F2 0x78 F2
|
||||
f3 F3 0x63 F3
|
||||
f4 F4 0x76 F4
|
||||
f5 F5 0x60 F5
|
||||
f6 F6 0x61 F6
|
||||
f7 F7 0x62 F7
|
||||
f8 F8 0x64 F8
|
||||
f9 F9 0x65 F9
|
||||
f10 F10 0x6D F10
|
||||
f11 F11 0x67 F11
|
||||
f12 F12 0x6F F12
|
||||
f13 F13 0x69 F13
|
||||
f14 F14 0x6B F14
|
||||
f15 F15 0x71 F15
|
||||
f16 F16 0x6A F16
|
||||
f17 F17 0x40 F17
|
||||
f18 F18 0x4F F18
|
||||
f19 F19 0x50 F19
|
||||
f20 F20 0x5A F20
|
||||
f21 F21 - F21
|
||||
f22 F22 - F22
|
||||
f23 F23 - F23
|
||||
f24 F24 - F24
|
||||
f25 F25 - F25
|
||||
f26 F26 - F26
|
||||
f27 F27 - F27
|
||||
f28 F28 - F28
|
||||
f29 F29 - F29
|
||||
f30 F30 - F30
|
||||
f31 F31 - F31
|
||||
f32 F32 - F32
|
||||
f33 F33 - F33
|
||||
f34 F34 - F34
|
||||
f35 F35 - F35
|
||||
kp_0 KP_0 0x52 -
|
||||
kp_1 KP_1 0x53 -
|
||||
kp_2 KP_2 0x54 -
|
||||
kp_3 KP_3 0x55 -
|
||||
kp_4 KP_4 0x56 -
|
||||
kp_5 KP_5 0x57 -
|
||||
kp_6 KP_6 0x58 -
|
||||
kp_7 KP_7 0x59 -
|
||||
kp_8 KP_8 0x5B -
|
||||
kp_9 KP_9 0x5C -
|
||||
kp_decimal KP_Decimal 0x41 -
|
||||
kp_divide KP_Divide 0x4B -
|
||||
kp_multiply KP_Multiply 0x43 -
|
||||
kp_subtract KP_Subtract 0x4E -
|
||||
kp_add KP_Add 0x45 -
|
||||
kp_enter KP_Enter 0x4C NSEnterCharacter
|
||||
kp_equal KP_Equal 0x51 -
|
||||
kp_separator KP_Separator - -
|
||||
kp_left KP_Left - -
|
||||
kp_right KP_Right - -
|
||||
kp_up KP_Up - -
|
||||
kp_down KP_Down - -
|
||||
kp_page_up KP_Page_Up - -
|
||||
kp_page_down KP_Page_Down - -
|
||||
kp_home KP_Home - -
|
||||
kp_end KP_End - -
|
||||
kp_insert KP_Insert - -
|
||||
kp_delete KP_Delete - -
|
||||
kp_begin KP_Begin - -
|
||||
media_play XF86AudioPlay - -
|
||||
media_pause XF86AudioPause - -
|
||||
media_play_pause - - -
|
||||
media_reverse - - -
|
||||
media_stop XF86AudioStop - -
|
||||
media_fast_forward XF86AudioForward - -
|
||||
media_rewind XF86AudioRewind - -
|
||||
media_track_next XF86AudioNext - -
|
||||
media_track_previous XF86AudioPrev - -
|
||||
media_record XF86AudioRecord - -
|
||||
lower_volume XF86AudioLowerVolume - -
|
||||
raise_volume XF86AudioRaiseVolume - -
|
||||
mute_volume XF86AudioMute - -
|
||||
left_shift Shift_L 0x38 -
|
||||
left_control Control_L 0x3B -
|
||||
left_alt Alt_L 0x3A -
|
||||
left_super Super_L 0x37 -
|
||||
left_hyper Hyper_L - -
|
||||
left_meta Meta_L - -
|
||||
right_shift Shift_R 0x3C -
|
||||
right_control Control_R 0x3E -
|
||||
right_alt Alt_R 0x3D -
|
||||
right_super Super_R 0x36 -
|
||||
right_hyper Hyper_R - -
|
||||
right_meta Meta_R - -
|
||||
iso_level3_shift ISO_Level3_Shift - -
|
||||
iso_level5_shift ISO_Level5_Shift - -
|
||||
''' # }}}
|
||||
|
||||
shift_map = {x[0]: x[1] for x in '`~ 1! 2@ 3# 4$ 5% 6^ 7& 8* 9( 0) -_ =+ [{ ]} \\| ;: \'" ,< .> /?'.split()}
|
||||
shift_map.update({x: x.upper() for x in string.ascii_lowercase})
|
||||
functional_encoding_overrides = {
|
||||
'insert': 2, 'delete': 3, 'page_up': 5, 'page_down': 6,
|
||||
'home': 7, 'end': 8, 'tab': 9, 'f1': 11, 'f2': 12, 'f3': 13, 'enter': 13, 'f4': 14,
|
||||
'f5': 15, 'f6': 17, 'f7': 18, 'f8': 19, 'f9': 20, 'f10': 21,
|
||||
'f11': 23, 'f12': 24, 'escape': 27, 'backspace': 127
|
||||
}
|
||||
different_trailer_functionals = {
|
||||
'up': 'A', 'down': 'B', 'right': 'C', 'left': 'D', 'kp_begin': 'E', 'end': 'F', 'home': 'H',
|
||||
'f1': 'P', 'f2': 'Q', 'f3': 'R', 'f4': 'S', 'enter': 'u', 'tab': 'u',
|
||||
'backspace': 'u', 'escape': 'u'
|
||||
}
|
||||
|
||||
macos_ansi_key_codes = { # {{{
|
||||
0x1D: ord('0'),
|
||||
0x12: ord('1'),
|
||||
0x13: ord('2'),
|
||||
0x14: ord('3'),
|
||||
0x15: ord('4'),
|
||||
0x17: ord('5'),
|
||||
0x16: ord('6'),
|
||||
0x1A: ord('7'),
|
||||
0x1C: ord('8'),
|
||||
0x19: ord('9'),
|
||||
0x00: ord('a'),
|
||||
0x0B: ord('b'),
|
||||
0x08: ord('c'),
|
||||
0x02: ord('d'),
|
||||
0x0E: ord('e'),
|
||||
0x03: ord('f'),
|
||||
0x05: ord('g'),
|
||||
0x04: ord('h'),
|
||||
0x22: ord('i'),
|
||||
0x26: ord('j'),
|
||||
0x28: ord('k'),
|
||||
0x25: ord('l'),
|
||||
0x2E: ord('m'),
|
||||
0x2D: ord('n'),
|
||||
0x1F: ord('o'),
|
||||
0x23: ord('p'),
|
||||
0x0C: ord('q'),
|
||||
0x0F: ord('r'),
|
||||
0x01: ord('s'),
|
||||
0x11: ord('t'),
|
||||
0x20: ord('u'),
|
||||
0x09: ord('v'),
|
||||
0x0D: ord('w'),
|
||||
0x07: ord('x'),
|
||||
0x10: ord('y'),
|
||||
0x06: ord('z'),
|
||||
|
||||
0x27: ord('\''),
|
||||
0x2A: ord('\\'),
|
||||
0x2B: ord(','),
|
||||
0x18: ord('='),
|
||||
0x32: ord('`'),
|
||||
0x21: ord('['),
|
||||
0x1B: ord('-'),
|
||||
0x2F: ord('.'),
|
||||
0x1E: ord(']'),
|
||||
0x29: ord(';'),
|
||||
0x2C: ord('/'),
|
||||
0x31: ord(' '),
|
||||
} # }}}
|
||||
|
||||
functional_key_names: List[str] = []
|
||||
name_to_code: Dict[str, int] = {}
|
||||
name_to_xkb: Dict[str, str] = {}
|
||||
name_to_vk: Dict[str, int] = {}
|
||||
name_to_macu: Dict[str, str] = {}
|
||||
start_code = 0xe000
|
||||
for line in functional_key_defs.splitlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
parts = line.split()
|
||||
name = parts[0]
|
||||
functional_key_names.append(name)
|
||||
name_to_code[name] = len(name_to_code) + start_code
|
||||
if parts[1] != '-':
|
||||
name_to_xkb[name] = parts[1]
|
||||
if parts[2] != '-':
|
||||
name_to_vk[name] = int(parts[2], 16)
|
||||
if parts[3] != '-':
|
||||
val = parts[3]
|
||||
if not val.startswith('NS'):
|
||||
val = f'NS{val}FunctionKey'
|
||||
name_to_macu[name] = val
|
||||
last_code = start_code + len(functional_key_names) - 1
|
||||
ctrl_mapping = {
|
||||
' ': 0, '@': 0, 'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6, 'g': 7,
|
||||
'h': 8, 'i': 9, 'j': 10, 'k': 11, 'l': 12, 'm': 13, 'n': 14, 'o': 15, 'p': 16,
|
||||
'q': 17, 'r': 18, 's': 19, 't': 20, 'u': 21, 'v': 22, 'w': 23, 'x': 24,
|
||||
'y': 25, 'z': 26, '[': 27, '\\': 28, ']': 29, '^': 30, '~': 30, '/': 31,
|
||||
'_': 31, '?': 127, '0': 48, '1': 49, '2': 0, '3': 27, '4': 28,
|
||||
'5': 29, '6': 30, '7': 31, '8': 127, '9': 57
|
||||
}
|
||||
|
||||
|
||||
def patch_file(path: str, what: str, text: str, start_marker: str = '/* ', end_marker: str = ' */') -> None:
|
||||
simple_start_q = f'{start_marker}start {what}{end_marker}'
|
||||
start_q = f'{start_marker}start {what} (auto generated by gen-key-constants.py do not edit){end_marker}'
|
||||
end_q = f'{start_marker}end {what}{end_marker}'
|
||||
|
||||
with open(path, 'r+') as f:
|
||||
raw = f.read()
|
||||
try:
|
||||
start = raw.index(start_q)
|
||||
except ValueError:
|
||||
try:
|
||||
start = raw.index(simple_start_q)
|
||||
except ValueError:
|
||||
raise SystemExit(f'Failed to find "{simple_start_q}" in {path}')
|
||||
try:
|
||||
end = raw.index(end_q)
|
||||
except ValueError:
|
||||
raise SystemExit(f'Failed to find "{end_q}" in {path}')
|
||||
raw = raw[:start] + start_q + '\n' + text + '\n' + raw[end:]
|
||||
f.seek(0)
|
||||
f.truncate(0)
|
||||
f.write(raw)
|
||||
|
||||
|
||||
def serialize_dict(x: dict) -> str:
|
||||
return pformat(x, indent=4).replace('{', '{\n ', 1)
|
||||
|
||||
|
||||
def generate_glfw_header() -> None:
|
||||
lines = [
|
||||
'typedef enum {',
|
||||
f' GLFW_FKEY_FIRST = 0x{start_code:x}u,',
|
||||
]
|
||||
klines, pyi, names, knames = [], [], [], []
|
||||
for name, code in name_to_code.items():
|
||||
lines.append(f' GLFW_FKEY_{name.upper()} = 0x{code:x}u,')
|
||||
klines.append(f' ADDC(GLFW_FKEY_{name.upper()});')
|
||||
pyi.append(f'GLFW_FKEY_{name.upper()}: int')
|
||||
names.append(f' case GLFW_FKEY_{name.upper()}: return "{name.upper()}";')
|
||||
knames.append(f' case GLFW_FKEY_{name.upper()}: return PyUnicode_FromString("{name}");')
|
||||
lines.append(f' GLFW_FKEY_LAST = 0x{last_code:x}u')
|
||||
lines.append('} GLFWFunctionKey;')
|
||||
patch_file('glfw/glfw3.h', 'functional key names', '\n'.join(lines))
|
||||
patch_file('kitty/glfw.c', 'glfw functional keys', '\n'.join(klines))
|
||||
patch_file('kitty/fast_data_types.pyi', 'glfw functional keys', '\n'.join(pyi), start_marker='# ', end_marker='')
|
||||
patch_file('glfw/input.c', 'functional key names', '\n'.join(names))
|
||||
patch_file('kitty/glfw.c', 'glfw functional key names', '\n'.join(knames))
|
||||
|
||||
|
||||
def generate_xkb_mapping() -> None:
|
||||
lines, rlines = [], []
|
||||
for name, xkb in name_to_xkb.items():
|
||||
lines.append(f' case XKB_KEY_{xkb}: return GLFW_FKEY_{name.upper()};')
|
||||
rlines.append(f' case GLFW_FKEY_{name.upper()}: return XKB_KEY_{xkb};')
|
||||
patch_file('glfw/xkb_glfw.c', 'xkb to glfw', '\n'.join(lines))
|
||||
patch_file('glfw/xkb_glfw.c', 'glfw to xkb', '\n'.join(rlines))
|
||||
|
||||
|
||||
def generate_functional_table() -> None:
|
||||
lines = [
|
||||
'',
|
||||
'.. csv-table:: Functional key codes',
|
||||
' :header: "Name", "CSI", "Name", "CSI"',
|
||||
''
|
||||
]
|
||||
line_items = []
|
||||
enc_lines = []
|
||||
tilde_trailers = set()
|
||||
for name, code in name_to_code.items():
|
||||
if name in functional_encoding_overrides or name in different_trailer_functionals:
|
||||
trailer = different_trailer_functionals.get(name, '~')
|
||||
if trailer == '~':
|
||||
tilde_trailers.add(code)
|
||||
code = oc = functional_encoding_overrides.get(name, code)
|
||||
code = code if trailer in '~u' else 1
|
||||
enc_lines.append((' ' * 8) + f"case GLFW_FKEY_{name.upper()}: S({code}, '{trailer}');")
|
||||
if code == 1 and name not in ('up', 'down', 'left', 'right'):
|
||||
trailer += f' or {oc} ~'
|
||||
else:
|
||||
trailer = 'u'
|
||||
line_items.append(name.upper())
|
||||
line_items.append(f'``{code}\xa0{trailer}``')
|
||||
for li in chunks(line_items, 4):
|
||||
lines.append(' ' + ', '.join(f'"{x}"' for x in li))
|
||||
lines.append('')
|
||||
patch_file('docs/keyboard-protocol.rst', 'functional key table', '\n'.join(lines), start_marker='.. ', end_marker='')
|
||||
patch_file('kitty/key_encoding.c', 'special numbers', '\n'.join(enc_lines))
|
||||
code_to_name = {v: k.upper() for k, v in name_to_code.items()}
|
||||
csi_map = {v: name_to_code[k] for k, v in functional_encoding_overrides.items()}
|
||||
letter_trailer_codes = {
|
||||
v: functional_encoding_overrides.get(k, name_to_code.get(k))
|
||||
for k, v in different_trailer_functionals.items() if v in 'ABCDEHFPQRSZ'}
|
||||
text = f'functional_key_number_to_name_map = {serialize_dict(code_to_name)}'
|
||||
text += f'\ncsi_number_to_functional_number_map = {serialize_dict(csi_map)}'
|
||||
text += f'\nletter_trailer_to_csi_number_map = {letter_trailer_codes!r}'
|
||||
text += f'\ntilde_trailers = {tilde_trailers!r}'
|
||||
patch_file('kitty/key_encoding.py', 'csi mapping', text, start_marker='# ', end_marker='')
|
||||
|
||||
|
||||
def generate_legacy_text_key_maps() -> None:
|
||||
tests = []
|
||||
tp = ' ' * 8
|
||||
shift, alt, ctrl = 1, 2, 4
|
||||
|
||||
def simple(c: str) -> None:
|
||||
shifted = shift_map.get(c, c)
|
||||
ctrled = chr(ctrl_mapping.get(c, ord(c)))
|
||||
call = f'enc(ord({c!r}), shifted_key=ord({shifted!r})'
|
||||
for m in range(16):
|
||||
if m == 0:
|
||||
tests.append(f'{tp}ae({call}), {c!r})')
|
||||
elif m == shift:
|
||||
tests.append(f'{tp}ae({call}, mods=shift), {shifted!r})')
|
||||
elif m == alt:
|
||||
tests.append(f'{tp}ae({call}, mods=alt), "\\x1b" + {c!r})')
|
||||
elif m == ctrl:
|
||||
tests.append(f'{tp}ae({call}, mods=ctrl), {ctrled!r})')
|
||||
elif m == shift | alt:
|
||||
tests.append(f'{tp}ae({call}, mods=shift | alt), "\\x1b" + {shifted!r})')
|
||||
elif m == ctrl | alt:
|
||||
tests.append(f'{tp}ae({call}, mods=ctrl | alt), "\\x1b" + {ctrled!r})')
|
||||
|
||||
for k in shift_map:
|
||||
simple(k)
|
||||
|
||||
patch_file('kitty_tests/keys.py', 'legacy letter tests', '\n'.join(tests), start_marker='# ', end_marker='')
|
||||
|
||||
|
||||
def chunks(lst: List, n: int) -> Any:
|
||||
"""Yield successive n-sized chunks from lst."""
|
||||
for i in range(0, len(lst), n):
|
||||
yield lst[i:i + n]
|
||||
|
||||
|
||||
def generate_ctrl_mapping() -> None:
|
||||
lines = [
|
||||
'.. csv-table:: Emitted bytes when :kbd:`ctrl` is held down and a key is pressed',
|
||||
' :header: "Key", "Byte", "Key", "Byte", "Key", "Byte"',
|
||||
''
|
||||
]
|
||||
items = []
|
||||
mi = []
|
||||
for k in sorted(ctrl_mapping):
|
||||
prefix = '\\' if k == '\\' else ('SPC' if k == ' ' else '')
|
||||
items.append(prefix + k)
|
||||
val = str(ctrl_mapping[k])
|
||||
items.append(val)
|
||||
if k in "\\'":
|
||||
k = '\\' + k
|
||||
mi.append(f" case '{k}': return {val};")
|
||||
|
||||
for line_items in chunks(items, 6):
|
||||
lines.append(' ' + ', '.join(f'"{x}"' for x in line_items))
|
||||
lines.append('')
|
||||
patch_file('docs/keyboard-protocol.rst', 'ctrl mapping', '\n'.join(lines), start_marker='.. ', end_marker='')
|
||||
patch_file('kitty/key_encoding.c', 'ctrl mapping', '\n'.join(mi))
|
||||
|
||||
|
||||
def generate_macos_mapping() -> None:
|
||||
lines = []
|
||||
for k in sorted(macos_ansi_key_codes):
|
||||
v = macos_ansi_key_codes[k]
|
||||
lines.append(f' case 0x{k:x}: return 0x{v:x};')
|
||||
patch_file('glfw/cocoa_window.m', 'vk to unicode', '\n'.join(lines))
|
||||
lines = []
|
||||
for name, vk in name_to_vk.items():
|
||||
lines.append(f' case 0x{vk:x}: return GLFW_FKEY_{name.upper()};')
|
||||
patch_file('glfw/cocoa_window.m', 'vk to functional', '\n'.join(lines))
|
||||
lines = []
|
||||
for name, mac in name_to_macu.items():
|
||||
lines.append(f' case {mac}: return GLFW_FKEY_{name.upper()};')
|
||||
patch_file('glfw/cocoa_window.m', 'macu to functional', '\n'.join(lines))
|
||||
lines = []
|
||||
for name, mac in name_to_macu.items():
|
||||
lines.append(f' case GLFW_FKEY_{name.upper()}: return {mac};')
|
||||
patch_file('glfw/cocoa_window.m', 'functional to macu', '\n'.join(lines))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
generate_glfw_header()
|
||||
generate_xkb_mapping()
|
||||
generate_functional_table()
|
||||
generate_legacy_text_key_maps()
|
||||
generate_ctrl_mapping()
|
||||
generate_macos_mapping()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -98,10 +98,23 @@ def parse_ucd() -> None:
|
||||
elif category.startswith('S'):
|
||||
all_symbols.add(codepoint)
|
||||
|
||||
with open('nerd-fonts-glyphs.txt') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
code, category, name = line.split(' ', 2)
|
||||
codepoint = int(code, 16)
|
||||
if name and codepoint not in name_map:
|
||||
name_map[codepoint] = name.upper()
|
||||
for word in name.lower().split():
|
||||
add_word(word, codepoint)
|
||||
|
||||
# Some common synonyms
|
||||
word_search_map['bee'] |= word_search_map['honeybee']
|
||||
word_search_map['lambda'] |= word_search_map['lamda']
|
||||
word_search_map['lamda'] |= word_search_map['lambda']
|
||||
word_search_map['diamond'] |= word_search_map['gem']
|
||||
|
||||
|
||||
def parse_range_spec(spec: str) -> Set[int]:
|
||||
@@ -492,7 +505,7 @@ def gen_wcwidth() -> None:
|
||||
p('\t\t// }}}\n')
|
||||
|
||||
with create_header('kitty/wcwidth-std.h') as p:
|
||||
p('static int\nwcwidth_std(int32_t code) {')
|
||||
p('static inline int\nwcwidth_std(int32_t code) {')
|
||||
p('\tif (LIKELY(0x20 <= code && code <= 0x7e)) return 1;')
|
||||
p('\tswitch(code) {')
|
||||
|
||||
@@ -512,7 +525,7 @@ def gen_wcwidth() -> None:
|
||||
p('\t}')
|
||||
p('\treturn 1;\n}')
|
||||
|
||||
p('static bool\nis_emoji_presentation_base(uint32_t code) {')
|
||||
p('static inline bool\nis_emoji_presentation_base(uint32_t code) {')
|
||||
p('\tswitch(code) {')
|
||||
for spec in get_ranges(list(emoji_presentation_bases)):
|
||||
write_case(spec, p)
|
||||
|
||||
70
glfw/backend_utils.c
vendored
70
glfw/backend_utils.c
vendored
@@ -8,6 +8,7 @@
|
||||
#define _GNU_SOURCE
|
||||
#include "backend_utils.h"
|
||||
#include "internal.h"
|
||||
#include "memfd.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -350,3 +351,72 @@ GLFWAPI char* utf_8_strndup(const char* source, size_t max_length) {
|
||||
result[length] = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new, unique, anonymous file of the given size, and
|
||||
* return the file descriptor for it. The file descriptor is set
|
||||
* CLOEXEC. The file is immediately suitable for mmap()'ing
|
||||
* the given size at offset zero.
|
||||
*
|
||||
* The file should not have a permanent backing store like a disk,
|
||||
* but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
|
||||
*
|
||||
* The file name is deleted from the file system.
|
||||
*
|
||||
* The file is suitable for buffer sharing between processes by
|
||||
* transmitting the file descriptor over Unix sockets using the
|
||||
* SCM_RIGHTS methods.
|
||||
*
|
||||
* posix_fallocate() is used to guarantee that disk space is available
|
||||
* for the file at the given size. If disk space is insufficient, errno
|
||||
* is set to ENOSPC. If posix_fallocate() is not supported, program may
|
||||
* receive SIGBUS on accessing mmap()'ed file contents instead.
|
||||
*/
|
||||
int createAnonymousFile(off_t size) {
|
||||
int ret, fd = -1, shm_anon = 0;
|
||||
#ifdef HAS_MEMFD_CREATE
|
||||
fd = memfd_create("glfw-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING);
|
||||
if (fd < 0) return -1;
|
||||
// We can add this seal before calling posix_fallocate(), as the file
|
||||
// is currently zero-sized anyway.
|
||||
//
|
||||
// There is also no need to check for the return value, we couldn’t do
|
||||
// anything with it anyway.
|
||||
fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
|
||||
#elif defined(SHM_ANON)
|
||||
fd = shm_open(SHM_ANON, O_RDWR | O_CLOEXEC, 0600);
|
||||
if (fd < 0) return -1;
|
||||
shm_anon = 1;
|
||||
#else
|
||||
static const char template[] = "/glfw-shared-XXXXXX";
|
||||
const char* path;
|
||||
char* name;
|
||||
|
||||
path = getenv("XDG_RUNTIME_DIR");
|
||||
if (!path)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
name = calloc(strlen(path) + sizeof(template), 1);
|
||||
strcpy(name, path);
|
||||
strcat(name, template);
|
||||
|
||||
fd = createTmpfileCloexec(name);
|
||||
|
||||
free(name);
|
||||
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
#endif
|
||||
// posix_fallocate does not work on SHM descriptors
|
||||
ret = shm_anon ? ftruncate(fd, size) : posix_fallocate(fd, 0, size);
|
||||
if (ret != 0)
|
||||
{
|
||||
close(fd);
|
||||
errno = ret;
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
6
glfw/backend_utils.h
vendored
6
glfw/backend_utils.h
vendored
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.4 Wayland - www.glfw.org
|
||||
// GLFW 3.4
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
||||
// Copyright (c) 2014 Kovid Goyal
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __has_include
|
||||
#if __has_include(<sys/eventfd.h>)
|
||||
@@ -96,3 +97,4 @@ void finalizePollData(EventLoopData *eld);
|
||||
bool initPollData(EventLoopData *eld, int display_fd);
|
||||
void wakeupEventLoop(EventLoopData *eld);
|
||||
char* utf_8_strndup(const char* source, size_t max_length);
|
||||
int createAnonymousFile(off_t size);
|
||||
|
||||
@@ -175,138 +175,6 @@ static void createMenuBar(void)
|
||||
[NSApp performSelector:setAppleMenuSelector withObject:appMenu];
|
||||
}
|
||||
|
||||
// Create key code translation tables
|
||||
//
|
||||
static void createKeyTables(void)
|
||||
{
|
||||
int keycode;
|
||||
|
||||
memset(_glfw.ns.keycodes, -1, sizeof(_glfw.ns.keycodes));
|
||||
memset(_glfw.ns.key_to_keycode, -1, sizeof(_glfw.ns.key_to_keycode));
|
||||
|
||||
_glfw.ns.keycodes[0x1D] = GLFW_KEY_0;
|
||||
_glfw.ns.keycodes[0x12] = GLFW_KEY_1;
|
||||
_glfw.ns.keycodes[0x13] = GLFW_KEY_2;
|
||||
_glfw.ns.keycodes[0x14] = GLFW_KEY_3;
|
||||
_glfw.ns.keycodes[0x15] = GLFW_KEY_4;
|
||||
_glfw.ns.keycodes[0x17] = GLFW_KEY_5;
|
||||
_glfw.ns.keycodes[0x16] = GLFW_KEY_6;
|
||||
_glfw.ns.keycodes[0x1A] = GLFW_KEY_7;
|
||||
_glfw.ns.keycodes[0x1C] = GLFW_KEY_8;
|
||||
_glfw.ns.keycodes[0x19] = GLFW_KEY_9;
|
||||
_glfw.ns.keycodes[0x00] = GLFW_KEY_A;
|
||||
_glfw.ns.keycodes[0x0B] = GLFW_KEY_B;
|
||||
_glfw.ns.keycodes[0x08] = GLFW_KEY_C;
|
||||
_glfw.ns.keycodes[0x02] = GLFW_KEY_D;
|
||||
_glfw.ns.keycodes[0x0E] = GLFW_KEY_E;
|
||||
_glfw.ns.keycodes[0x03] = GLFW_KEY_F;
|
||||
_glfw.ns.keycodes[0x05] = GLFW_KEY_G;
|
||||
_glfw.ns.keycodes[0x04] = GLFW_KEY_H;
|
||||
_glfw.ns.keycodes[0x22] = GLFW_KEY_I;
|
||||
_glfw.ns.keycodes[0x26] = GLFW_KEY_J;
|
||||
_glfw.ns.keycodes[0x28] = GLFW_KEY_K;
|
||||
_glfw.ns.keycodes[0x25] = GLFW_KEY_L;
|
||||
_glfw.ns.keycodes[0x2E] = GLFW_KEY_M;
|
||||
_glfw.ns.keycodes[0x2D] = GLFW_KEY_N;
|
||||
_glfw.ns.keycodes[0x1F] = GLFW_KEY_O;
|
||||
_glfw.ns.keycodes[0x23] = GLFW_KEY_P;
|
||||
_glfw.ns.keycodes[0x0C] = GLFW_KEY_Q;
|
||||
_glfw.ns.keycodes[0x0F] = GLFW_KEY_R;
|
||||
_glfw.ns.keycodes[0x01] = GLFW_KEY_S;
|
||||
_glfw.ns.keycodes[0x11] = GLFW_KEY_T;
|
||||
_glfw.ns.keycodes[0x20] = GLFW_KEY_U;
|
||||
_glfw.ns.keycodes[0x09] = GLFW_KEY_V;
|
||||
_glfw.ns.keycodes[0x0D] = GLFW_KEY_W;
|
||||
_glfw.ns.keycodes[0x07] = GLFW_KEY_X;
|
||||
_glfw.ns.keycodes[0x10] = GLFW_KEY_Y;
|
||||
_glfw.ns.keycodes[0x06] = GLFW_KEY_Z;
|
||||
|
||||
_glfw.ns.keycodes[0x27] = GLFW_KEY_APOSTROPHE;
|
||||
_glfw.ns.keycodes[0x2A] = GLFW_KEY_BACKSLASH;
|
||||
_glfw.ns.keycodes[0x2B] = GLFW_KEY_COMMA;
|
||||
_glfw.ns.keycodes[0x18] = GLFW_KEY_EQUAL;
|
||||
_glfw.ns.keycodes[0x32] = GLFW_KEY_GRAVE_ACCENT;
|
||||
_glfw.ns.keycodes[0x21] = GLFW_KEY_LEFT_BRACKET;
|
||||
_glfw.ns.keycodes[0x1B] = GLFW_KEY_MINUS;
|
||||
_glfw.ns.keycodes[0x2F] = GLFW_KEY_PERIOD;
|
||||
_glfw.ns.keycodes[0x1E] = GLFW_KEY_RIGHT_BRACKET;
|
||||
_glfw.ns.keycodes[0x29] = GLFW_KEY_SEMICOLON;
|
||||
_glfw.ns.keycodes[0x2C] = GLFW_KEY_SLASH;
|
||||
_glfw.ns.keycodes[0x0A] = GLFW_KEY_WORLD_1;
|
||||
|
||||
_glfw.ns.keycodes[0x33] = GLFW_KEY_BACKSPACE;
|
||||
_glfw.ns.keycodes[0x39] = GLFW_KEY_CAPS_LOCK;
|
||||
_glfw.ns.keycodes[0x75] = GLFW_KEY_DELETE;
|
||||
_glfw.ns.keycodes[0x7D] = GLFW_KEY_DOWN;
|
||||
_glfw.ns.keycodes[0x77] = GLFW_KEY_END;
|
||||
_glfw.ns.keycodes[0x24] = GLFW_KEY_ENTER;
|
||||
_glfw.ns.keycodes[0x35] = GLFW_KEY_ESCAPE;
|
||||
_glfw.ns.keycodes[0x7A] = GLFW_KEY_F1;
|
||||
_glfw.ns.keycodes[0x78] = GLFW_KEY_F2;
|
||||
_glfw.ns.keycodes[0x63] = GLFW_KEY_F3;
|
||||
_glfw.ns.keycodes[0x76] = GLFW_KEY_F4;
|
||||
_glfw.ns.keycodes[0x60] = GLFW_KEY_F5;
|
||||
_glfw.ns.keycodes[0x61] = GLFW_KEY_F6;
|
||||
_glfw.ns.keycodes[0x62] = GLFW_KEY_F7;
|
||||
_glfw.ns.keycodes[0x64] = GLFW_KEY_F8;
|
||||
_glfw.ns.keycodes[0x65] = GLFW_KEY_F9;
|
||||
_glfw.ns.keycodes[0x6D] = GLFW_KEY_F10;
|
||||
_glfw.ns.keycodes[0x67] = GLFW_KEY_F11;
|
||||
_glfw.ns.keycodes[0x6F] = GLFW_KEY_F12;
|
||||
_glfw.ns.keycodes[0x69] = GLFW_KEY_F13;
|
||||
_glfw.ns.keycodes[0x6B] = GLFW_KEY_F14;
|
||||
_glfw.ns.keycodes[0x71] = GLFW_KEY_F15;
|
||||
_glfw.ns.keycodes[0x6A] = GLFW_KEY_F16;
|
||||
_glfw.ns.keycodes[0x40] = GLFW_KEY_F17;
|
||||
_glfw.ns.keycodes[0x4F] = GLFW_KEY_F18;
|
||||
_glfw.ns.keycodes[0x50] = GLFW_KEY_F19;
|
||||
_glfw.ns.keycodes[0x5A] = GLFW_KEY_F20;
|
||||
_glfw.ns.keycodes[0x73] = GLFW_KEY_HOME;
|
||||
_glfw.ns.keycodes[0x72] = GLFW_KEY_INSERT;
|
||||
_glfw.ns.keycodes[0x7B] = GLFW_KEY_LEFT;
|
||||
_glfw.ns.keycodes[0x3A] = GLFW_KEY_LEFT_ALT;
|
||||
_glfw.ns.keycodes[0x3B] = GLFW_KEY_LEFT_CONTROL;
|
||||
_glfw.ns.keycodes[0x38] = GLFW_KEY_LEFT_SHIFT;
|
||||
_glfw.ns.keycodes[0x37] = GLFW_KEY_LEFT_SUPER;
|
||||
_glfw.ns.keycodes[0x6E] = GLFW_KEY_MENU;
|
||||
_glfw.ns.keycodes[0x47] = GLFW_KEY_NUM_LOCK;
|
||||
_glfw.ns.keycodes[0x79] = GLFW_KEY_PAGE_DOWN;
|
||||
_glfw.ns.keycodes[0x74] = GLFW_KEY_PAGE_UP;
|
||||
_glfw.ns.keycodes[0x7C] = GLFW_KEY_RIGHT;
|
||||
_glfw.ns.keycodes[0x3D] = GLFW_KEY_RIGHT_ALT;
|
||||
_glfw.ns.keycodes[0x3E] = GLFW_KEY_RIGHT_CONTROL;
|
||||
_glfw.ns.keycodes[0x3C] = GLFW_KEY_RIGHT_SHIFT;
|
||||
_glfw.ns.keycodes[0x36] = GLFW_KEY_RIGHT_SUPER;
|
||||
_glfw.ns.keycodes[0x31] = GLFW_KEY_SPACE;
|
||||
_glfw.ns.keycodes[0x30] = GLFW_KEY_TAB;
|
||||
_glfw.ns.keycodes[0x7E] = GLFW_KEY_UP;
|
||||
|
||||
_glfw.ns.keycodes[0x52] = GLFW_KEY_KP_0;
|
||||
_glfw.ns.keycodes[0x53] = GLFW_KEY_KP_1;
|
||||
_glfw.ns.keycodes[0x54] = GLFW_KEY_KP_2;
|
||||
_glfw.ns.keycodes[0x55] = GLFW_KEY_KP_3;
|
||||
_glfw.ns.keycodes[0x56] = GLFW_KEY_KP_4;
|
||||
_glfw.ns.keycodes[0x57] = GLFW_KEY_KP_5;
|
||||
_glfw.ns.keycodes[0x58] = GLFW_KEY_KP_6;
|
||||
_glfw.ns.keycodes[0x59] = GLFW_KEY_KP_7;
|
||||
_glfw.ns.keycodes[0x5B] = GLFW_KEY_KP_8;
|
||||
_glfw.ns.keycodes[0x5C] = GLFW_KEY_KP_9;
|
||||
_glfw.ns.keycodes[0x45] = GLFW_KEY_KP_ADD;
|
||||
_glfw.ns.keycodes[0x41] = GLFW_KEY_KP_DECIMAL;
|
||||
_glfw.ns.keycodes[0x4B] = GLFW_KEY_KP_DIVIDE;
|
||||
_glfw.ns.keycodes[0x4C] = GLFW_KEY_KP_ENTER;
|
||||
_glfw.ns.keycodes[0x51] = GLFW_KEY_KP_EQUAL;
|
||||
_glfw.ns.keycodes[0x43] = GLFW_KEY_KP_MULTIPLY;
|
||||
_glfw.ns.keycodes[0x4E] = GLFW_KEY_KP_SUBTRACT;
|
||||
|
||||
for (keycode = 0; keycode < 256; keycode++)
|
||||
{
|
||||
// Store the reverse translation for faster key name lookup
|
||||
if (_glfw.ns.keycodes[keycode] >= 0)
|
||||
_glfw.ns.key_to_keycode[_glfw.ns.keycodes[keycode]] = keycode;
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve Unicode data for the current keyboard layout
|
||||
//
|
||||
static bool updateUnicodeDataNS(void)
|
||||
@@ -478,10 +346,40 @@ static GLFWapplicationwillfinishlaunchingfun finish_launching_callback = NULL;
|
||||
finish_launching_callback();
|
||||
}
|
||||
|
||||
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename {
|
||||
(void)theApplication;
|
||||
if (!filename || !_glfw.ns.file_open_callback) return NO;
|
||||
const char *path = NULL;
|
||||
@try {
|
||||
path = [[NSFileManager defaultManager] fileSystemRepresentationWithPath: filename];
|
||||
} @catch(NSException *exc) {
|
||||
NSLog(@"Converting openFile filename: %@ failed with error: %@", filename, exc.reason);
|
||||
return NO;
|
||||
}
|
||||
if (!path) return NO;
|
||||
return _glfw.ns.file_open_callback(path);
|
||||
}
|
||||
|
||||
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames {
|
||||
(void)sender;
|
||||
if (!_glfw.ns.file_open_callback || !filenames) return;
|
||||
for (id x in filenames) {
|
||||
NSString *filename = x;
|
||||
const char *path = NULL;
|
||||
@try {
|
||||
path = [[NSFileManager defaultManager] fileSystemRepresentationWithPath: filename];
|
||||
} @catch(NSException *exc) {
|
||||
NSLog(@"Converting openFiles filename: %@ failed with error: %@", filename, exc.reason);
|
||||
}
|
||||
if (path) _glfw.ns.file_open_callback(path);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
(void)notification;
|
||||
[NSApp stop:nil];
|
||||
if (_glfw.ns.file_open_callback) _glfw.ns.file_open_callback(":cocoa::application launched::");
|
||||
|
||||
CGDisplayRegisterReconfigurationCallback(display_reconfigured, NULL);
|
||||
_glfwCocoaPostEmptyEvent();
|
||||
@@ -648,8 +546,12 @@ int _glfwPlatformInit(void)
|
||||
if (_glfw.hints.init.ns.chdir)
|
||||
changeToResourcesDirectory();
|
||||
|
||||
// Press and Hold prevents some keys from emitting repeated characters
|
||||
NSDictionary* defaults = @{@"ApplePressAndHoldEnabled":@NO};
|
||||
NSDictionary* defaults = @{
|
||||
// Press and Hold prevents some keys from emitting repeated characters
|
||||
@"ApplePressAndHoldEnabled": @NO,
|
||||
// Dont generate openFile events from command line arguments
|
||||
@"NSTreatUnknownArgumentsAsOpen": @"NO",
|
||||
};
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
@@ -658,8 +560,6 @@ int _glfwPlatformInit(void)
|
||||
name:NSTextInputContextKeyboardSelectionDidChangeNotification
|
||||
object:nil];
|
||||
|
||||
createKeyTables();
|
||||
|
||||
_glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||
if (!_glfw.ns.eventSource)
|
||||
return false;
|
||||
|
||||
@@ -47,7 +47,7 @@ static char* getDisplayName(CGDirectDisplayID displayID)
|
||||
io_service_t service;
|
||||
CFDictionaryRef info;
|
||||
|
||||
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
|
||||
if (IOServiceGetMatchingServices(kIOMainPortDefault,
|
||||
IOServiceMatching("IODisplayConnect"),
|
||||
&it) != 0)
|
||||
{
|
||||
@@ -89,7 +89,7 @@ static char* getDisplayName(CGDirectDisplayID displayID)
|
||||
if (!service)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Cocoa: Failed to find service port for display");
|
||||
"Cocoa: Failed to find service port for display, cannot get its name, using Unknown");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ static double getFallbackRefreshRate(CGDirectDisplayID displayID)
|
||||
io_iterator_t it;
|
||||
io_service_t service;
|
||||
|
||||
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
|
||||
if (IOServiceGetMatchingServices(kIOMainPortDefault,
|
||||
IOServiceMatching("IOFramebuffer"),
|
||||
&it) != 0)
|
||||
{
|
||||
@@ -316,6 +316,7 @@ void _glfwClearDisplayLinks() {
|
||||
CVDisplayLinkRelease(_glfw.ns.displayLinks.entries[i].displayLink);
|
||||
_glfw.ns.displayLinks.entries[i].displayLink = nil;
|
||||
_glfw.ns.displayLinks.entries[i].lastRenderFrameRequestedAt = 0;
|
||||
_glfw.ns.displayLinks.entries[i].first_unserviced_render_frame_request_at = 0;
|
||||
}
|
||||
}
|
||||
_glfw.ns.displayLinks.count = 0;
|
||||
@@ -326,14 +327,21 @@ static CVReturn displayLinkCallback(
|
||||
const CVTimeStamp* now UNUSED, const CVTimeStamp* outputTime UNUSED,
|
||||
CVOptionFlags flagsIn UNUSED, CVOptionFlags* flagsOut UNUSED, void* userInfo)
|
||||
{
|
||||
CGDirectDisplayID displayID = (CGDirectDisplayID)userInfo;
|
||||
CGDirectDisplayID displayID = (uintptr_t)userInfo;
|
||||
NSNumber *arg = [NSNumber numberWithUnsignedInt:displayID];
|
||||
[NSApp performSelectorOnMainThread:@selector(render_frame_received:) withObject:arg waitUntilDone:NO];
|
||||
[arg release];
|
||||
return kCVReturnSuccess;
|
||||
}
|
||||
|
||||
static inline void createDisplayLink(CGDirectDisplayID displayID) {
|
||||
void
|
||||
_glfw_create_cv_display_link(_GLFWDisplayLinkNS *entry) {
|
||||
CVDisplayLinkCreateWithCGDisplay(entry->displayID, &entry->displayLink);
|
||||
CVDisplayLinkSetOutputCallback(entry->displayLink, &displayLinkCallback, (void*)(uintptr_t)entry->displayID);
|
||||
}
|
||||
|
||||
static void
|
||||
createDisplayLink(CGDirectDisplayID displayID) {
|
||||
if (_glfw.ns.displayLinks.count >= sizeof(_glfw.ns.displayLinks.entries)/sizeof(_glfw.ns.displayLinks.entries[0]) - 1) return;
|
||||
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
||||
if (_glfw.ns.displayLinks.entries[i].displayID == displayID) return;
|
||||
@@ -341,8 +349,7 @@ static inline void createDisplayLink(CGDirectDisplayID displayID) {
|
||||
_GLFWDisplayLinkNS *entry = &_glfw.ns.displayLinks.entries[_glfw.ns.displayLinks.count++];
|
||||
memset(entry, 0, sizeof(_GLFWDisplayLinkNS));
|
||||
entry->displayID = displayID;
|
||||
CVDisplayLinkCreateWithCGDisplay(displayID, &entry->displayLink);
|
||||
CVDisplayLinkSetOutputCallback(entry->displayLink, &displayLinkCallback, (void*)(uintptr_t)displayID);
|
||||
_glfw_create_cv_display_link(entry);
|
||||
}
|
||||
|
||||
// Poll for changes in the set of connected monitors
|
||||
@@ -529,7 +536,6 @@ void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor,
|
||||
*width = (int)frameRect.size.width;
|
||||
if (height)
|
||||
*height = (int)frameRect.size.height;
|
||||
|
||||
}
|
||||
|
||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
||||
|
||||
14
glfw/cocoa_platform.h
vendored
14
glfw/cocoa_platform.h
vendored
@@ -39,6 +39,9 @@ typedef void* CVDisplayLinkRef;
|
||||
// NOTE: Many Cocoa enum values have been renamed and we need to build across
|
||||
// SDK versions where one is unavailable or the other deprecated
|
||||
// We use the newer names in code and these macros to handle compatibility
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED < 120000) // Before macOS 12 Monterey
|
||||
#define kIOMainPortDefault kIOMasterPortDefault
|
||||
#endif
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
|
||||
#define NSBitmapFormatAlphaNonpremultiplied NSAlphaNonpremultipliedBitmapFormat
|
||||
#define NSEventMaskAny NSAnyEventMask
|
||||
@@ -67,6 +70,7 @@ typedef void* CVDisplayLinkRef;
|
||||
|
||||
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int, unsigned long);
|
||||
typedef bool (* GLFWapplicationshouldhandlereopenfun)(int);
|
||||
typedef bool (* GLFWhandlefileopen)(const char*);
|
||||
typedef void (* GLFWapplicationwillfinishlaunchingfun)(void);
|
||||
typedef bool (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
|
||||
typedef void (* GLFWcocoarenderframefun)(GLFWwindow*);
|
||||
@@ -128,6 +132,9 @@ typedef struct _GLFWwindowNS
|
||||
|
||||
bool maximized;
|
||||
bool retina;
|
||||
bool in_traditional_fullscreen;
|
||||
bool titlebar_hidden;
|
||||
unsigned long pre_full_screen_style_mask;
|
||||
|
||||
// Cached window properties to filter out duplicate events
|
||||
int width, height;
|
||||
@@ -154,7 +161,7 @@ typedef struct _GLFWDisplayLinkNS
|
||||
{
|
||||
CVDisplayLinkRef displayLink;
|
||||
CGDirectDisplayID displayID;
|
||||
monotonic_t lastRenderFrameRequestedAt;
|
||||
monotonic_t lastRenderFrameRequestedAt, first_unserviced_render_frame_request_at;
|
||||
} _GLFWDisplayLinkNS;
|
||||
|
||||
// Cocoa-specific global data
|
||||
@@ -175,8 +182,6 @@ typedef struct _GLFWlibraryNS
|
||||
|
||||
char keyName[64];
|
||||
char text[256];
|
||||
short int keycodes[256];
|
||||
short int key_to_keycode[GLFW_KEY_LAST + 1];
|
||||
char* clipboardString;
|
||||
CGPoint cascadePoint;
|
||||
// Where to place the cursor when re-enabled
|
||||
@@ -196,6 +201,8 @@ typedef struct _GLFWlibraryNS
|
||||
_GLFWDisplayLinkNS entries[256];
|
||||
size_t count;
|
||||
} displayLinks;
|
||||
// the callback to handle file open events
|
||||
GLFWhandlefileopen file_open_callback;
|
||||
|
||||
} _GLFWlibraryNS;
|
||||
|
||||
@@ -242,3 +249,4 @@ void _glfwDispatchTickCallback(void);
|
||||
void _glfwDispatchRenderFrame(CGDirectDisplayID);
|
||||
void _glfwShutdownCVDisplayLink(unsigned long long, void*);
|
||||
void _glfwCocoaPostEmptyEvent(void);
|
||||
void _glfw_create_cv_display_link(_GLFWDisplayLinkNS *entry);
|
||||
|
||||
1044
glfw/cocoa_window.m
1044
glfw/cocoa_window.m
File diff suppressed because it is too large
Load Diff
33
glfw/glfw.py
33
glfw/glfw.py
@@ -10,6 +10,7 @@ from typing import Callable, Dict, List, Optional, Tuple
|
||||
|
||||
_plat = sys.platform.lower()
|
||||
is_linux = 'linux' in _plat
|
||||
is_openbsd = 'openbsd' in _plat
|
||||
base = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
@@ -54,7 +55,7 @@ def wayland_protocol_file_name(base: str, ext: str = 'c') -> str:
|
||||
return 'wayland-{}-client-protocol.{}'.format(base, ext)
|
||||
|
||||
|
||||
def init_env(env: Env, pkg_config: Callable, at_least_version: Callable, test_compile: Callable, module: str = 'x11') -> Env:
|
||||
def init_env(env: Env, pkg_config: Callable, pkg_version: Callable, at_least_version: Callable, test_compile: Callable, module: str = 'x11') -> Env:
|
||||
ans = env.copy()
|
||||
ans.cflags.append('-fPIC')
|
||||
ans.cppflags.append('-D_GLFW_' + module.upper())
|
||||
@@ -72,9 +73,14 @@ def init_env(env: Env, pkg_config: Callable, at_least_version: Callable, test_co
|
||||
|
||||
if module in ('x11', 'wayland'):
|
||||
ans.cflags.append('-pthread')
|
||||
ans.ldpaths.append('-pthread')
|
||||
ans.ldpaths.extend('-lrt -lm -ldl'.split())
|
||||
at_least_version('xkbcommon', 0, 5)
|
||||
ans.ldpaths.extend('-pthread -lm'.split())
|
||||
if not is_openbsd:
|
||||
ans.ldpaths.extend('-lrt -ldl'.split())
|
||||
major, minor = pkg_version('xkbcommon')
|
||||
if (major, minor) < (0, 5):
|
||||
raise SystemExit('libxkbcommon >= 0.5 required')
|
||||
if major < 1:
|
||||
ans.cflags.append('-DXKB_HAS_NO_UTF32')
|
||||
|
||||
if module == 'x11':
|
||||
for dep in 'x11 xrandr xinerama xcursor xkbcommon xkbcommon-x11 x11-xcb dbus-1'.split():
|
||||
@@ -83,7 +89,7 @@ def init_env(env: Env, pkg_config: Callable, at_least_version: Callable, test_co
|
||||
|
||||
elif module == 'cocoa':
|
||||
ans.cppflags.append('-DGL_SILENCE_DEPRECATION')
|
||||
for f_ in 'Cocoa IOKit CoreFoundation CoreVideo'.split():
|
||||
for f_ in 'Cocoa Carbon IOKit CoreFoundation CoreVideo'.split():
|
||||
ans.ldpaths.extend(('-framework', f_))
|
||||
|
||||
elif module == 'wayland':
|
||||
@@ -173,13 +179,12 @@ class Function:
|
||||
)
|
||||
|
||||
def load(self) -> str:
|
||||
ans = '*(void **) (&{name}_impl) = dlsym(handle, "{name}");'.format(
|
||||
name=self.name
|
||||
)
|
||||
ans = f'*(void **) (&{self.name}_impl) = dlsym(handle, "{self.name}");'
|
||||
ans += f'\n if ({self.name}_impl == NULL) '
|
||||
if self.check_fail:
|
||||
ans += '\n if ({name}_impl == NULL) fail("Failed to load glfw function {name} with error: %s", dlerror());'.format(
|
||||
name=self.name
|
||||
)
|
||||
ans += f'fail("Failed to load glfw function {self.name} with error: %s", dlerror());'
|
||||
else:
|
||||
ans += 'dlerror(); // clear error indicator'
|
||||
return ans
|
||||
|
||||
|
||||
@@ -197,13 +202,15 @@ def generate_wrappers(glfw_header: str) -> None:
|
||||
functions.append(Function(decl))
|
||||
for line in '''\
|
||||
void* glfwGetCocoaWindow(GLFWwindow* window)
|
||||
void glfwHideCocoaTitlebar(GLFWwindow* window, bool yes)
|
||||
void* glfwGetNSGLContext(GLFWwindow *window)
|
||||
uint32_t glfwGetCocoaMonitor(GLFWmonitor* monitor)
|
||||
GLFWcocoatextinputfilterfun glfwSetCocoaTextInputFilter(GLFWwindow* window, GLFWcocoatextinputfilterfun callback)
|
||||
GLFWhandlefileopen glfwSetCocoaFileOpenCallback(GLFWhandlefileopen callback)
|
||||
GLFWcocoatogglefullscreenfun glfwSetCocoaToggleFullscreenIntercept(GLFWwindow *window, GLFWcocoatogglefullscreenfun callback)
|
||||
GLFWapplicationshouldhandlereopenfun glfwSetApplicationShouldHandleReopen(GLFWapplicationshouldhandlereopenfun callback)
|
||||
GLFWapplicationwillfinishlaunchingfun glfwSetApplicationWillFinishLaunching(GLFWapplicationwillfinishlaunchingfun callback)
|
||||
void glfwGetCocoaKeyEquivalent(int glfw_key, int glfw_mods, char* cocoa_key, size_t key_sz, int* cocoa_mods)
|
||||
uint32_t glfwGetCocoaKeyEquivalent(uint32_t glfw_key, int glfw_mods, int* cocoa_mods)
|
||||
void glfwCocoaRequestRenderFrame(GLFWwindow *w, GLFWcocoarenderframefun callback)
|
||||
void* glfwGetX11Display(void)
|
||||
int32_t glfwGetX11Window(GLFWwindow* window)
|
||||
@@ -211,6 +218,7 @@ def generate_wrappers(glfw_header: str) -> None:
|
||||
const char* glfwGetPrimarySelectionString(GLFWwindow* window, void)
|
||||
int glfwGetNativeKeyForName(const char* key_name, int case_sensitive)
|
||||
void glfwRequestWaylandFrameEvent(GLFWwindow *handle, unsigned long long id, GLFWwaylandframecallbackfunc callback)
|
||||
bool glfwWaylandSetTitlebarColor(GLFWwindow *handle, uint32_t color, bool use_system_color)
|
||||
unsigned long long glfwDBusUserNotify(const char *app_name, const char* icon, const char *summary, const char *body, \
|
||||
const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callback, void *data)
|
||||
void glfwDBusSetUserNotificationHandler(GLFWDBusnotificationactivatedfun handler)
|
||||
@@ -241,6 +249,7 @@ const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callbac
|
||||
|
||||
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int,unsigned long);
|
||||
typedef bool (* GLFWapplicationshouldhandlereopenfun)(int);
|
||||
typedef bool (* GLFWhandlefileopen)(const char*);
|
||||
typedef void (* GLFWapplicationwillfinishlaunchingfun)(void);
|
||||
typedef bool (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
|
||||
typedef void (* GLFWcocoarenderframefun)(GLFWwindow*);
|
||||
|
||||
546
glfw/glfw3.h
vendored
546
glfw/glfw3.h
vendored
@@ -300,31 +300,6 @@ extern "C" {
|
||||
#define GLFW_VERSION_REVISION 0
|
||||
/*! @} */
|
||||
|
||||
/*! @name Key and button actions
|
||||
* @{ */
|
||||
/*! @brief The key or mouse button was released.
|
||||
*
|
||||
* The key or mouse button was released.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
#define GLFW_RELEASE 0
|
||||
/*! @brief The key or mouse button was pressed.
|
||||
*
|
||||
* The key or mouse button was pressed.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
#define GLFW_PRESS 1
|
||||
/*! @brief The key was held down until it repeated.
|
||||
*
|
||||
* The key was held down until it repeated.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
#define GLFW_REPEAT 2
|
||||
/*! @} */
|
||||
|
||||
/*! @defgroup hat_state Joystick hat states
|
||||
* @brief Joystick hat states.
|
||||
*
|
||||
@@ -367,200 +342,123 @@ extern "C" {
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* The unknown key */
|
||||
#define GLFW_KEY_UNKNOWN -1
|
||||
|
||||
/* Printable keys */
|
||||
#define GLFW_KEY_SPACE 32
|
||||
#define GLFW_KEY_EXCLAM 33 /* ! */
|
||||
#define GLFW_KEY_DOUBLE_QUOTE 34 /* " */
|
||||
#define GLFW_KEY_NUMBER_SIGN 35 /* # */
|
||||
#define GLFW_KEY_DOLLAR 36 /* $ */
|
||||
#define GLFW_KEY_AMPERSAND 38 /* & */
|
||||
#define GLFW_KEY_APOSTROPHE 39 /* ' */
|
||||
#define GLFW_KEY_PARENTHESIS_LEFT 40 /* ( */
|
||||
#define GLFW_KEY_PARENTHESIS_RIGHT 41 /* ) */
|
||||
#define GLFW_KEY_PLUS 43 /* + */
|
||||
#define GLFW_KEY_COMMA 44 /* , */
|
||||
#define GLFW_KEY_MINUS 45 /* - */
|
||||
#define GLFW_KEY_PERIOD 46 /* . */
|
||||
#define GLFW_KEY_SLASH 47 /* / */
|
||||
#define GLFW_KEY_0 48
|
||||
#define GLFW_KEY_1 49
|
||||
#define GLFW_KEY_2 50
|
||||
#define GLFW_KEY_3 51
|
||||
#define GLFW_KEY_4 52
|
||||
#define GLFW_KEY_5 53
|
||||
#define GLFW_KEY_6 54
|
||||
#define GLFW_KEY_7 55
|
||||
#define GLFW_KEY_8 56
|
||||
#define GLFW_KEY_9 57
|
||||
#define GLFW_KEY_COLON 58 /* : */
|
||||
#define GLFW_KEY_SEMICOLON 59 /* ; */
|
||||
#define GLFW_KEY_LESS 60 /* < */
|
||||
#define GLFW_KEY_EQUAL 61 /* = */
|
||||
#define GLFW_KEY_GREATER 62 /* > */
|
||||
#define GLFW_KEY_AT 64 /* @ */
|
||||
#define GLFW_KEY_A 65
|
||||
#define GLFW_KEY_B 66
|
||||
#define GLFW_KEY_C 67
|
||||
#define GLFW_KEY_D 68
|
||||
#define GLFW_KEY_E 69
|
||||
#define GLFW_KEY_F 70
|
||||
#define GLFW_KEY_G 71
|
||||
#define GLFW_KEY_H 72
|
||||
#define GLFW_KEY_I 73
|
||||
#define GLFW_KEY_J 74
|
||||
#define GLFW_KEY_K 75
|
||||
#define GLFW_KEY_L 76
|
||||
#define GLFW_KEY_M 77
|
||||
#define GLFW_KEY_N 78
|
||||
#define GLFW_KEY_O 79
|
||||
#define GLFW_KEY_P 80
|
||||
#define GLFW_KEY_Q 81
|
||||
#define GLFW_KEY_R 82
|
||||
#define GLFW_KEY_S 83
|
||||
#define GLFW_KEY_T 84
|
||||
#define GLFW_KEY_U 85
|
||||
#define GLFW_KEY_V 86
|
||||
#define GLFW_KEY_W 87
|
||||
#define GLFW_KEY_X 88
|
||||
#define GLFW_KEY_Y 89
|
||||
#define GLFW_KEY_Z 90
|
||||
#define GLFW_KEY_LEFT_BRACKET 91 /* [ */
|
||||
#define GLFW_KEY_BACKSLASH 92 /* \ */
|
||||
#define GLFW_KEY_RIGHT_BRACKET 93 /* ] */
|
||||
#define GLFW_KEY_CIRCUMFLEX 94 /* ^ */
|
||||
#define GLFW_KEY_UNDERSCORE 95 /* _ */
|
||||
#define GLFW_KEY_GRAVE_ACCENT 96 /* ` */
|
||||
#define GLFW_KEY_WORLD_1 161 /* non-US #1 */
|
||||
#define GLFW_KEY_WORLD_2 162 /* non-US #2 */
|
||||
#define GLFW_KEY_PARAGRAPH 167 /* § */
|
||||
#define GLFW_KEY_MASCULINE 186 /* º */
|
||||
#define GLFW_KEY_A_GRAVE 192 /* À */
|
||||
#define GLFW_KEY_A_DIAERESIS 196 /* Ä */
|
||||
#define GLFW_KEY_A_RING 197 /* Å */
|
||||
#define GLFW_KEY_AE 198 /* Æ */
|
||||
#define GLFW_KEY_C_CEDILLA 199 /* Ç */
|
||||
#define GLFW_KEY_E_GRAVE 200 /* È */
|
||||
#define GLFW_KEY_E_ACUTE 201 /* É */
|
||||
#define GLFW_KEY_I_GRAVE 204 /* Ì */
|
||||
#define GLFW_KEY_N_TILDE 209 /* Ñ */
|
||||
#define GLFW_KEY_O_GRAVE 210 /* Ò */
|
||||
#define GLFW_KEY_O_DIAERESIS 214 /* Ö */
|
||||
#define GLFW_KEY_O_SLASH 216 /* Ø */
|
||||
#define GLFW_KEY_U_GRAVE 217 /* Ù */
|
||||
#define GLFW_KEY_U_DIAERESIS 220 /* Ü */
|
||||
#define GLFW_KEY_S_SHARP 222 /* ß */
|
||||
#define GLFW_KEY_CYRILLIC_A 223 /* А */
|
||||
#define GLFW_KEY_CYRILLIC_BE 224 /* Б */
|
||||
#define GLFW_KEY_CYRILLIC_VE 225 /* В */
|
||||
#define GLFW_KEY_CYRILLIC_GHE 226 /* Г */
|
||||
#define GLFW_KEY_CYRILLIC_DE 227 /* Д */
|
||||
#define GLFW_KEY_CYRILLIC_IE 228 /* Е */
|
||||
#define GLFW_KEY_CYRILLIC_ZHE 229 /* Ж */
|
||||
#define GLFW_KEY_CYRILLIC_ZE 230 /* З */
|
||||
#define GLFW_KEY_CYRILLIC_I 231 /* И */
|
||||
#define GLFW_KEY_CYRILLIC_SHORT_I 232 /* Й */
|
||||
#define GLFW_KEY_CYRILLIC_KA 233 /* К */
|
||||
#define GLFW_KEY_CYRILLIC_EL 234 /* Л */
|
||||
#define GLFW_KEY_CYRILLIC_EM 235 /* М */
|
||||
#define GLFW_KEY_CYRILLIC_EN 236 /* Н */
|
||||
#define GLFW_KEY_CYRILLIC_O 237 /* О */
|
||||
#define GLFW_KEY_CYRILLIC_PE 238 /* П */
|
||||
#define GLFW_KEY_CYRILLIC_ER 239 /* Р */
|
||||
#define GLFW_KEY_CYRILLIC_ES 240 /* С */
|
||||
#define GLFW_KEY_CYRILLIC_TE 241 /* Т */
|
||||
#define GLFW_KEY_CYRILLIC_U 242 /* У */
|
||||
#define GLFW_KEY_CYRILLIC_EF 243 /* Ф */
|
||||
#define GLFW_KEY_CYRILLIC_HA 244 /* Х */
|
||||
#define GLFW_KEY_CYRILLIC_TSE 245 /* Ц */
|
||||
#define GLFW_KEY_CYRILLIC_CHE 246 /* Ч */
|
||||
#define GLFW_KEY_CYRILLIC_SHA 247 /* Ш */
|
||||
#define GLFW_KEY_CYRILLIC_SHCHA 248 /* Щ */
|
||||
#define GLFW_KEY_CYRILLIC_HARD_SIGN 249 /* Ъ */
|
||||
#define GLFW_KEY_CYRILLIC_YERU 250 /* Ы */
|
||||
#define GLFW_KEY_CYRILLIC_SOFT_SIGN 251 /* Ь */
|
||||
#define GLFW_KEY_CYRILLIC_E 252 /* Э */
|
||||
#define GLFW_KEY_CYRILLIC_YU 253 /* Ю */
|
||||
#define GLFW_KEY_CYRILLIC_YA 254 /* Я */
|
||||
#define GLFW_KEY_CYRILLIC_IO 255 /* Ё */
|
||||
|
||||
#define GLFW_KEY_LAST_PRINTABLE GLFW_KEY_CYRILLIC_IO
|
||||
|
||||
/* Function keys */
|
||||
#define GLFW_KEY_ESCAPE 256
|
||||
#define GLFW_KEY_ENTER 257
|
||||
#define GLFW_KEY_TAB 258
|
||||
#define GLFW_KEY_BACKSPACE 259
|
||||
#define GLFW_KEY_INSERT 260
|
||||
#define GLFW_KEY_DELETE 261
|
||||
#define GLFW_KEY_RIGHT 262
|
||||
#define GLFW_KEY_LEFT 263
|
||||
#define GLFW_KEY_DOWN 264
|
||||
#define GLFW_KEY_UP 265
|
||||
#define GLFW_KEY_PAGE_UP 266
|
||||
#define GLFW_KEY_PAGE_DOWN 267
|
||||
#define GLFW_KEY_HOME 268
|
||||
#define GLFW_KEY_END 269
|
||||
#define GLFW_KEY_CAPS_LOCK 280
|
||||
#define GLFW_KEY_SCROLL_LOCK 281
|
||||
#define GLFW_KEY_NUM_LOCK 282
|
||||
#define GLFW_KEY_PRINT_SCREEN 283
|
||||
#define GLFW_KEY_PAUSE 284
|
||||
#define GLFW_KEY_F1 290
|
||||
#define GLFW_KEY_F2 291
|
||||
#define GLFW_KEY_F3 292
|
||||
#define GLFW_KEY_F4 293
|
||||
#define GLFW_KEY_F5 294
|
||||
#define GLFW_KEY_F6 295
|
||||
#define GLFW_KEY_F7 296
|
||||
#define GLFW_KEY_F8 297
|
||||
#define GLFW_KEY_F9 298
|
||||
#define GLFW_KEY_F10 299
|
||||
#define GLFW_KEY_F11 300
|
||||
#define GLFW_KEY_F12 301
|
||||
#define GLFW_KEY_F13 302
|
||||
#define GLFW_KEY_F14 303
|
||||
#define GLFW_KEY_F15 304
|
||||
#define GLFW_KEY_F16 305
|
||||
#define GLFW_KEY_F17 306
|
||||
#define GLFW_KEY_F18 307
|
||||
#define GLFW_KEY_F19 308
|
||||
#define GLFW_KEY_F20 309
|
||||
#define GLFW_KEY_F21 310
|
||||
#define GLFW_KEY_F22 311
|
||||
#define GLFW_KEY_F23 312
|
||||
#define GLFW_KEY_F24 313
|
||||
#define GLFW_KEY_F25 314
|
||||
#define GLFW_KEY_KP_0 320
|
||||
#define GLFW_KEY_KP_1 321
|
||||
#define GLFW_KEY_KP_2 322
|
||||
#define GLFW_KEY_KP_3 323
|
||||
#define GLFW_KEY_KP_4 324
|
||||
#define GLFW_KEY_KP_5 325
|
||||
#define GLFW_KEY_KP_6 326
|
||||
#define GLFW_KEY_KP_7 327
|
||||
#define GLFW_KEY_KP_8 328
|
||||
#define GLFW_KEY_KP_9 329
|
||||
#define GLFW_KEY_KP_DECIMAL 330
|
||||
#define GLFW_KEY_KP_DIVIDE 331
|
||||
#define GLFW_KEY_KP_MULTIPLY 332
|
||||
#define GLFW_KEY_KP_SUBTRACT 333
|
||||
#define GLFW_KEY_KP_ADD 334
|
||||
#define GLFW_KEY_KP_ENTER 335
|
||||
#define GLFW_KEY_KP_EQUAL 336
|
||||
#define GLFW_KEY_LEFT_SHIFT 340
|
||||
#define GLFW_KEY_LEFT_CONTROL 341
|
||||
#define GLFW_KEY_LEFT_ALT 342
|
||||
#define GLFW_KEY_LEFT_SUPER 343
|
||||
#define GLFW_KEY_RIGHT_SHIFT 344
|
||||
#define GLFW_KEY_RIGHT_CONTROL 345
|
||||
#define GLFW_KEY_RIGHT_ALT 346
|
||||
#define GLFW_KEY_RIGHT_SUPER 347
|
||||
#define GLFW_KEY_MENU 348
|
||||
|
||||
#define GLFW_KEY_LAST GLFW_KEY_MENU
|
||||
/* start functional key names (auto generated by gen-key-constants.py do not edit) */
|
||||
typedef enum {
|
||||
GLFW_FKEY_FIRST = 0xe000u,
|
||||
GLFW_FKEY_ESCAPE = 0xe000u,
|
||||
GLFW_FKEY_ENTER = 0xe001u,
|
||||
GLFW_FKEY_TAB = 0xe002u,
|
||||
GLFW_FKEY_BACKSPACE = 0xe003u,
|
||||
GLFW_FKEY_INSERT = 0xe004u,
|
||||
GLFW_FKEY_DELETE = 0xe005u,
|
||||
GLFW_FKEY_LEFT = 0xe006u,
|
||||
GLFW_FKEY_RIGHT = 0xe007u,
|
||||
GLFW_FKEY_UP = 0xe008u,
|
||||
GLFW_FKEY_DOWN = 0xe009u,
|
||||
GLFW_FKEY_PAGE_UP = 0xe00au,
|
||||
GLFW_FKEY_PAGE_DOWN = 0xe00bu,
|
||||
GLFW_FKEY_HOME = 0xe00cu,
|
||||
GLFW_FKEY_END = 0xe00du,
|
||||
GLFW_FKEY_CAPS_LOCK = 0xe00eu,
|
||||
GLFW_FKEY_SCROLL_LOCK = 0xe00fu,
|
||||
GLFW_FKEY_NUM_LOCK = 0xe010u,
|
||||
GLFW_FKEY_PRINT_SCREEN = 0xe011u,
|
||||
GLFW_FKEY_PAUSE = 0xe012u,
|
||||
GLFW_FKEY_MENU = 0xe013u,
|
||||
GLFW_FKEY_F1 = 0xe014u,
|
||||
GLFW_FKEY_F2 = 0xe015u,
|
||||
GLFW_FKEY_F3 = 0xe016u,
|
||||
GLFW_FKEY_F4 = 0xe017u,
|
||||
GLFW_FKEY_F5 = 0xe018u,
|
||||
GLFW_FKEY_F6 = 0xe019u,
|
||||
GLFW_FKEY_F7 = 0xe01au,
|
||||
GLFW_FKEY_F8 = 0xe01bu,
|
||||
GLFW_FKEY_F9 = 0xe01cu,
|
||||
GLFW_FKEY_F10 = 0xe01du,
|
||||
GLFW_FKEY_F11 = 0xe01eu,
|
||||
GLFW_FKEY_F12 = 0xe01fu,
|
||||
GLFW_FKEY_F13 = 0xe020u,
|
||||
GLFW_FKEY_F14 = 0xe021u,
|
||||
GLFW_FKEY_F15 = 0xe022u,
|
||||
GLFW_FKEY_F16 = 0xe023u,
|
||||
GLFW_FKEY_F17 = 0xe024u,
|
||||
GLFW_FKEY_F18 = 0xe025u,
|
||||
GLFW_FKEY_F19 = 0xe026u,
|
||||
GLFW_FKEY_F20 = 0xe027u,
|
||||
GLFW_FKEY_F21 = 0xe028u,
|
||||
GLFW_FKEY_F22 = 0xe029u,
|
||||
GLFW_FKEY_F23 = 0xe02au,
|
||||
GLFW_FKEY_F24 = 0xe02bu,
|
||||
GLFW_FKEY_F25 = 0xe02cu,
|
||||
GLFW_FKEY_F26 = 0xe02du,
|
||||
GLFW_FKEY_F27 = 0xe02eu,
|
||||
GLFW_FKEY_F28 = 0xe02fu,
|
||||
GLFW_FKEY_F29 = 0xe030u,
|
||||
GLFW_FKEY_F30 = 0xe031u,
|
||||
GLFW_FKEY_F31 = 0xe032u,
|
||||
GLFW_FKEY_F32 = 0xe033u,
|
||||
GLFW_FKEY_F33 = 0xe034u,
|
||||
GLFW_FKEY_F34 = 0xe035u,
|
||||
GLFW_FKEY_F35 = 0xe036u,
|
||||
GLFW_FKEY_KP_0 = 0xe037u,
|
||||
GLFW_FKEY_KP_1 = 0xe038u,
|
||||
GLFW_FKEY_KP_2 = 0xe039u,
|
||||
GLFW_FKEY_KP_3 = 0xe03au,
|
||||
GLFW_FKEY_KP_4 = 0xe03bu,
|
||||
GLFW_FKEY_KP_5 = 0xe03cu,
|
||||
GLFW_FKEY_KP_6 = 0xe03du,
|
||||
GLFW_FKEY_KP_7 = 0xe03eu,
|
||||
GLFW_FKEY_KP_8 = 0xe03fu,
|
||||
GLFW_FKEY_KP_9 = 0xe040u,
|
||||
GLFW_FKEY_KP_DECIMAL = 0xe041u,
|
||||
GLFW_FKEY_KP_DIVIDE = 0xe042u,
|
||||
GLFW_FKEY_KP_MULTIPLY = 0xe043u,
|
||||
GLFW_FKEY_KP_SUBTRACT = 0xe044u,
|
||||
GLFW_FKEY_KP_ADD = 0xe045u,
|
||||
GLFW_FKEY_KP_ENTER = 0xe046u,
|
||||
GLFW_FKEY_KP_EQUAL = 0xe047u,
|
||||
GLFW_FKEY_KP_SEPARATOR = 0xe048u,
|
||||
GLFW_FKEY_KP_LEFT = 0xe049u,
|
||||
GLFW_FKEY_KP_RIGHT = 0xe04au,
|
||||
GLFW_FKEY_KP_UP = 0xe04bu,
|
||||
GLFW_FKEY_KP_DOWN = 0xe04cu,
|
||||
GLFW_FKEY_KP_PAGE_UP = 0xe04du,
|
||||
GLFW_FKEY_KP_PAGE_DOWN = 0xe04eu,
|
||||
GLFW_FKEY_KP_HOME = 0xe04fu,
|
||||
GLFW_FKEY_KP_END = 0xe050u,
|
||||
GLFW_FKEY_KP_INSERT = 0xe051u,
|
||||
GLFW_FKEY_KP_DELETE = 0xe052u,
|
||||
GLFW_FKEY_KP_BEGIN = 0xe053u,
|
||||
GLFW_FKEY_MEDIA_PLAY = 0xe054u,
|
||||
GLFW_FKEY_MEDIA_PAUSE = 0xe055u,
|
||||
GLFW_FKEY_MEDIA_PLAY_PAUSE = 0xe056u,
|
||||
GLFW_FKEY_MEDIA_REVERSE = 0xe057u,
|
||||
GLFW_FKEY_MEDIA_STOP = 0xe058u,
|
||||
GLFW_FKEY_MEDIA_FAST_FORWARD = 0xe059u,
|
||||
GLFW_FKEY_MEDIA_REWIND = 0xe05au,
|
||||
GLFW_FKEY_MEDIA_TRACK_NEXT = 0xe05bu,
|
||||
GLFW_FKEY_MEDIA_TRACK_PREVIOUS = 0xe05cu,
|
||||
GLFW_FKEY_MEDIA_RECORD = 0xe05du,
|
||||
GLFW_FKEY_LOWER_VOLUME = 0xe05eu,
|
||||
GLFW_FKEY_RAISE_VOLUME = 0xe05fu,
|
||||
GLFW_FKEY_MUTE_VOLUME = 0xe060u,
|
||||
GLFW_FKEY_LEFT_SHIFT = 0xe061u,
|
||||
GLFW_FKEY_LEFT_CONTROL = 0xe062u,
|
||||
GLFW_FKEY_LEFT_ALT = 0xe063u,
|
||||
GLFW_FKEY_LEFT_SUPER = 0xe064u,
|
||||
GLFW_FKEY_LEFT_HYPER = 0xe065u,
|
||||
GLFW_FKEY_LEFT_META = 0xe066u,
|
||||
GLFW_FKEY_RIGHT_SHIFT = 0xe067u,
|
||||
GLFW_FKEY_RIGHT_CONTROL = 0xe068u,
|
||||
GLFW_FKEY_RIGHT_ALT = 0xe069u,
|
||||
GLFW_FKEY_RIGHT_SUPER = 0xe06au,
|
||||
GLFW_FKEY_RIGHT_HYPER = 0xe06bu,
|
||||
GLFW_FKEY_RIGHT_META = 0xe06cu,
|
||||
GLFW_FKEY_ISO_LEVEL3_SHIFT = 0xe06du,
|
||||
GLFW_FKEY_ISO_LEVEL5_SHIFT = 0xe06eu,
|
||||
GLFW_FKEY_LAST = 0xe06eu
|
||||
} GLFWFunctionKey;
|
||||
/* end functional key names */
|
||||
|
||||
/*! @} */
|
||||
|
||||
@@ -577,33 +475,44 @@ extern "C" {
|
||||
* If this bit is set one or more Shift keys were held down.
|
||||
*/
|
||||
#define GLFW_MOD_SHIFT 0x0001
|
||||
/*! @brief If this bit is set one or more Control keys were held down.
|
||||
*
|
||||
* If this bit is set one or more Control keys were held down.
|
||||
*/
|
||||
#define GLFW_MOD_CONTROL 0x0002
|
||||
/*! @brief If this bit is set one or more Alt keys were held down.
|
||||
*
|
||||
* If this bit is set one or more Alt keys were held down.
|
||||
*/
|
||||
#define GLFW_MOD_ALT 0x0004
|
||||
#define GLFW_MOD_ALT 0x0002
|
||||
/*! @brief If this bit is set one or more Alt keys were held down.
|
||||
*
|
||||
* If this bit is set one or more Alt keys were held down.
|
||||
*/
|
||||
#define GLFW_MOD_CONTROL 0x0004
|
||||
/*! @brief If this bit is set one or more Super keys were held down.
|
||||
*
|
||||
* If this bit is set one or more Super keys were held down.
|
||||
*/
|
||||
#define GLFW_MOD_SUPER 0x0008
|
||||
/*! @brief If this bit is set one or more Hyper keys were held down.
|
||||
*
|
||||
* If this bit is set one or more Hyper keys were held down.
|
||||
*/
|
||||
#define GLFW_MOD_HYPER 0x0010
|
||||
/*! @brief If this bit is set one or more Meta keys were held down.
|
||||
*
|
||||
* If this bit is set one or more Meta keys were held down.
|
||||
*/
|
||||
#define GLFW_MOD_META 0x0020
|
||||
/*! @brief If this bit is set the Caps Lock key is enabled.
|
||||
*
|
||||
* If this bit is set the Caps Lock key is enabled and the @ref
|
||||
* GLFW_LOCK_KEY_MODS input mode is set.
|
||||
*/
|
||||
#define GLFW_MOD_CAPS_LOCK 0x0010
|
||||
#define GLFW_MOD_CAPS_LOCK 0x0040
|
||||
/*! @brief If this bit is set the Num Lock key is enabled.
|
||||
*
|
||||
* If this bit is set the Num Lock key is enabled and the @ref
|
||||
* GLFW_LOCK_KEY_MODS input mode is set.
|
||||
*/
|
||||
#define GLFW_MOD_NUM_LOCK 0x0020
|
||||
#define GLFW_MOD_NUM_LOCK 0x0080
|
||||
#define GLFW_LOCK_MASK (GLFW_MOD_NUM_LOCK | GLFW_MOD_CAPS_LOCK)
|
||||
|
||||
/*! @} */
|
||||
|
||||
@@ -614,18 +523,20 @@ extern "C" {
|
||||
*
|
||||
* @ingroup input
|
||||
* @{ */
|
||||
#define GLFW_MOUSE_BUTTON_1 0
|
||||
#define GLFW_MOUSE_BUTTON_2 1
|
||||
#define GLFW_MOUSE_BUTTON_3 2
|
||||
#define GLFW_MOUSE_BUTTON_4 3
|
||||
#define GLFW_MOUSE_BUTTON_5 4
|
||||
#define GLFW_MOUSE_BUTTON_6 5
|
||||
#define GLFW_MOUSE_BUTTON_7 6
|
||||
#define GLFW_MOUSE_BUTTON_8 7
|
||||
#define GLFW_MOUSE_BUTTON_LAST GLFW_MOUSE_BUTTON_8
|
||||
#define GLFW_MOUSE_BUTTON_LEFT GLFW_MOUSE_BUTTON_1
|
||||
#define GLFW_MOUSE_BUTTON_RIGHT GLFW_MOUSE_BUTTON_2
|
||||
#define GLFW_MOUSE_BUTTON_MIDDLE GLFW_MOUSE_BUTTON_3
|
||||
typedef enum GLFWMouseButton {
|
||||
GLFW_MOUSE_BUTTON_1 = 0,
|
||||
GLFW_MOUSE_BUTTON_LEFT = 0,
|
||||
GLFW_MOUSE_BUTTON_2 = 1,
|
||||
GLFW_MOUSE_BUTTON_RIGHT = 1,
|
||||
GLFW_MOUSE_BUTTON_3 = 2,
|
||||
GLFW_MOUSE_BUTTON_MIDDLE = 2,
|
||||
GLFW_MOUSE_BUTTON_4 = 3,
|
||||
GLFW_MOUSE_BUTTON_5 = 4,
|
||||
GLFW_MOUSE_BUTTON_6 = 5,
|
||||
GLFW_MOUSE_BUTTON_7 = 6,
|
||||
GLFW_MOUSE_BUTTON_8 = 7,
|
||||
GLFW_MOUSE_BUTTON_LAST = 7
|
||||
} GLFWMouseButton;
|
||||
/*! @} */
|
||||
|
||||
/*! @defgroup joysticks Joysticks
|
||||
@@ -1202,6 +1113,7 @@ typedef enum {
|
||||
*/
|
||||
#define GLFW_ANGLE_PLATFORM_TYPE 0x00050002
|
||||
#define GLFW_DEBUG_KEYBOARD 0x00050003
|
||||
#define GLFW_DEBUG_RENDERING 0x00050004
|
||||
/*! @brief macOS specific init hint.
|
||||
*
|
||||
* macOS specific [init hint](@ref GLFW_COCOA_CHDIR_RESOURCES_hint).
|
||||
@@ -1285,16 +1197,43 @@ typedef struct GLFWwindow GLFWwindow;
|
||||
*/
|
||||
typedef struct GLFWcursor GLFWcursor;
|
||||
|
||||
typedef enum {
|
||||
GLFW_RELEASE = 0,
|
||||
GLFW_PRESS = 1,
|
||||
GLFW_REPEAT = 2
|
||||
} GLFWKeyAction;
|
||||
|
||||
typedef enum {
|
||||
GLFW_IME_NONE,
|
||||
GLFW_IME_PREEDIT_CHANGED,
|
||||
GLFW_IME_COMMIT_TEXT
|
||||
} GLFWIMEState;
|
||||
|
||||
typedef enum {
|
||||
GLFW_IME_UPDATE_FOCUS = 1,
|
||||
GLFW_IME_UPDATE_CURSOR_POSITION = 2
|
||||
} GLFWIMEUpdateType;
|
||||
|
||||
typedef struct GLFWIMEUpdateEvent {
|
||||
GLFWIMEUpdateType type;
|
||||
const char *before_text, *at_text, *after_text;
|
||||
bool focused;
|
||||
struct {
|
||||
int left, top, width, height;
|
||||
} cursor;
|
||||
} GLFWIMEUpdateEvent;
|
||||
|
||||
|
||||
typedef struct GLFWkeyevent
|
||||
{
|
||||
// The [keyboard key](@ref keys) that was pressed or released.
|
||||
int key;
|
||||
uint32_t key, shifted_key, alternate_key;
|
||||
|
||||
// The platform-specific identifier of the key.
|
||||
int native_key;
|
||||
|
||||
// The event action. Either `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`.
|
||||
int action;
|
||||
GLFWKeyAction action;
|
||||
|
||||
// Bit field describing which [modifier keys](@ref mods) were held down.
|
||||
int mods;
|
||||
@@ -1303,9 +1242,9 @@ typedef struct GLFWkeyevent
|
||||
const char *text;
|
||||
|
||||
// Used for Input Method events. Zero for normal key events.
|
||||
// A value of 1 means the pre-edit text for the input event has been changed.
|
||||
// A value of 2 means the text should be committed.
|
||||
int ime_state;
|
||||
// A value of GLFW_IME_PREEDIT_CHANGED means the pre-edit text for the input event has been changed.
|
||||
// A value of GLFW_IME_COMMIT_TEXT means the text should be committed.
|
||||
GLFWIMEState ime_state;
|
||||
} GLFWkeyevent;
|
||||
|
||||
/*! @brief The function pointer type for error callbacks.
|
||||
@@ -1502,7 +1441,7 @@ typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int);
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] window The window that was maximized or restored.
|
||||
* @param[in] iconified `true` if the window was maximized, or
|
||||
* @param[in] maximized `true` if the window was maximized, or
|
||||
* `false` if it was restored.
|
||||
*
|
||||
* @sa @ref window_maximize
|
||||
@@ -1661,7 +1600,7 @@ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int,int);
|
||||
* This is the function pointer type for key callbacks. A keyboard
|
||||
* key callback function has the following signature:
|
||||
* @code
|
||||
* void function_name(GLFWwindow* window, int key, int native_key, int action, int mods)
|
||||
* void function_name(GLFWwindow* window, uint32_t key, int native_key, int action, int mods)
|
||||
* @endcode
|
||||
* The semantics of this function are that the key that is interacted with on the
|
||||
* keyboard is reported, and the text, if any generated by the key is reported.
|
||||
@@ -1761,6 +1700,7 @@ typedef void (* GLFWjoystickfun)(int,int);
|
||||
|
||||
typedef void (* GLFWuserdatafun)(unsigned long long, void*);
|
||||
typedef void (* GLFWtickcallback)(void*);
|
||||
typedef bool (* GLFWdrawtextfun)(GLFWwindow *window, const char *text, uint32_t fg, uint32_t bg, uint8_t *output_buf, size_t width, size_t height, float x_offset, float y_offset, size_t right_margin);
|
||||
|
||||
/*! @brief Video mode type.
|
||||
*
|
||||
@@ -1917,6 +1857,7 @@ GLFWAPI void glfwStopMainLoop(void);
|
||||
GLFWAPI unsigned long long glfwAddTimer(monotonic_t interval, bool repeats, GLFWuserdatafun callback, void * callback_data, GLFWuserdatafun free_callback);
|
||||
GLFWAPI void glfwUpdateTimer(unsigned long long timer_id, monotonic_t interval, bool enabled);
|
||||
GLFWAPI void glfwRemoveTimer(unsigned long long);
|
||||
GLFWAPI GLFWdrawtextfun glfwSetDrawTextFunction(GLFWdrawtextfun function);
|
||||
|
||||
/*! @brief Terminates the GLFW library.
|
||||
*
|
||||
@@ -4300,108 +4241,19 @@ GLFWAPI int glfwRawMouseMotionSupported(void);
|
||||
* __Do not use this function__ for [text input](@ref input_char). You will
|
||||
* break text input for many languages even if it happens to work for yours.
|
||||
*
|
||||
* If the key is `GLFW_KEY_UNKNOWN`, the keycode is used to identify the key,
|
||||
* If the key is `0`, the keycode is used to identify the key,
|
||||
* otherwise the keycode is ignored. If you specify a non-printable key, or
|
||||
* `GLFW_KEY_UNKNOWN` and a keycode that maps to a non-printable key, this
|
||||
* `0` and a keycode that maps to a non-printable key, this
|
||||
* function returns `NULL` but does not emit an error.
|
||||
*
|
||||
* This behavior allows you to always pass in the arguments in the
|
||||
* [key callback](@ref input_key) without modification.
|
||||
*
|
||||
* The printable keys are:
|
||||
* - `GLFW_KEY_SPACE`
|
||||
* - `GLFW_KEY_EXCLAM`
|
||||
* - `GLFW_KEY_DOUBLE_QUOTE`
|
||||
* - `GLFW_KEY_NUMBER_SIGN`
|
||||
* - `GLFW_KEY_DOLLAR`
|
||||
* - `GLFW_KEY_AMPERSAND`
|
||||
* - `GLFW_KEY_APOSTROPHE`
|
||||
* - `GLFW_KEY_PARENTHESIS_LEFT`
|
||||
* - `GLFW_KEY_PARENTHESIS_RIGHT`
|
||||
* - `GLFW_KEY_PLUS`
|
||||
* - `GLFW_KEY_COMMA`
|
||||
* - `GLFW_KEY_MINUS`
|
||||
* - `GLFW_KEY_PERIOD`
|
||||
* - `GLFW_KEY_SLASH`
|
||||
* - `GLFW_KEY_0` to `GLFW_KEY_9`
|
||||
* - `GLFW_KEY_COLON`
|
||||
* - `GLFW_KEY_SEMICOLON`
|
||||
* - `GLFW_KEY_LESS`
|
||||
* - `GLFW_KEY_EQUAL`
|
||||
* - `GLFW_KEY_GREATER`
|
||||
* - `GLFW_KEY_AT`
|
||||
* - `GLFW_KEY_A` to `GLFW_KEY_Z`
|
||||
* - `GLFW_KEY_LEFT_BRACKET`
|
||||
* - `GLFW_KEY_BACKSLASH`
|
||||
* - `GLFW_KEY_RIGHT_BRACKET`
|
||||
* - `GLFW_KEY_CIRCUMFLEX`
|
||||
* - `GLFW_KEY_UNDERSCORE`
|
||||
* - `GLFW_KEY_GRAVE_ACCENT`
|
||||
* - `GLFW_KEY_WORLD_1`
|
||||
* - `GLFW_KEY_WORLD_2`
|
||||
* - `GLFW_KEY_PARAGRAPH`
|
||||
* - `GLFW_KEY_MASCULINE`
|
||||
* - `GLFW_KEY_A_GRAVE`
|
||||
* - `GLFW_KEY_A_DIAERESIS`
|
||||
* - `GLFW_KEY_A_RING`
|
||||
* - `GLFW_KEY_AE`
|
||||
* - `GLFW_KEY_C_CEDILLA`
|
||||
* - `GLFW_KEY_E_GRAVE`
|
||||
* - `GLFW_KEY_E_ACUTE`
|
||||
* - `GLFW_KEY_I_GRAVE`
|
||||
* - `GLFW_KEY_N_TILDE`
|
||||
* - `GLFW_KEY_O_GRAVE`
|
||||
* - `GLFW_KEY_O_DIAERESIS`
|
||||
* - `GLFW_KEY_O_SLASH`
|
||||
* - `GLFW_KEY_U_GRAVE`
|
||||
* - `GLFW_KEY_U_DIAERESIS`
|
||||
* - `GLFW_KEY_S_SHARP`
|
||||
* - `GLFW_KEY_CYRILLIC_A`
|
||||
* - `GLFW_KEY_CYRILLIC_BE`
|
||||
* - `GLFW_KEY_CYRILLIC_VE`
|
||||
* - `GLFW_KEY_CYRILLIC_GHE`
|
||||
* - `GLFW_KEY_CYRILLIC_DE`
|
||||
* - `GLFW_KEY_CYRILLIC_IE`
|
||||
* - `GLFW_KEY_CYRILLIC_ZHE`
|
||||
* - `GLFW_KEY_CYRILLIC_ZE`
|
||||
* - `GLFW_KEY_CYRILLIC_I`
|
||||
* - `GLFW_KEY_CYRILLIC_SHORT_I`
|
||||
* - `GLFW_KEY_CYRILLIC_KA`
|
||||
* - `GLFW_KEY_CYRILLIC_EL`
|
||||
* - `GLFW_KEY_CYRILLIC_EM`
|
||||
* - `GLFW_KEY_CYRILLIC_EN`
|
||||
* - `GLFW_KEY_CYRILLIC_O`
|
||||
* - `GLFW_KEY_CYRILLIC_PE`
|
||||
* - `GLFW_KEY_CYRILLIC_ER`
|
||||
* - `GLFW_KEY_CYRILLIC_ES`
|
||||
* - `GLFW_KEY_CYRILLIC_TE`
|
||||
* - `GLFW_KEY_CYRILLIC_U`
|
||||
* - `GLFW_KEY_CYRILLIC_EF`
|
||||
* - `GLFW_KEY_CYRILLIC_HA`
|
||||
* - `GLFW_KEY_CYRILLIC_TSE`
|
||||
* - `GLFW_KEY_CYRILLIC_CHE`
|
||||
* - `GLFW_KEY_CYRILLIC_SHA`
|
||||
* - `GLFW_KEY_CYRILLIC_SHCHA`
|
||||
* - `GLFW_KEY_CYRILLIC_HARD_SIGN`
|
||||
* - `GLFW_KEY_CYRILLIC_YERU`
|
||||
* - `GLFW_KEY_CYRILLIC_SOFT_SIGN`
|
||||
* - `GLFW_KEY_CYRILLIC_E`
|
||||
* - `GLFW_KEY_CYRILLIC_YU`
|
||||
* - `GLFW_KEY_CYRILLIC_YA`
|
||||
* - `GLFW_KEY_CYRILLIC_IO`
|
||||
* - `GLFW_KEY_KP_0` to `GLFW_KEY_KP_9`
|
||||
* - `GLFW_KEY_KP_DECIMAL`
|
||||
* - `GLFW_KEY_KP_DIVIDE`
|
||||
* - `GLFW_KEY_KP_MULTIPLY`
|
||||
* - `GLFW_KEY_KP_SUBTRACT`
|
||||
* - `GLFW_KEY_KP_ADD`
|
||||
* - `GLFW_KEY_KP_EQUAL`
|
||||
*
|
||||
* Names for printable keys depend on keyboard layout, while names for
|
||||
* non-printable keys are the same across layouts but depend on the application
|
||||
* language and should be localized along with other user interface text.
|
||||
*
|
||||
* @param[in] key The key to query, or `GLFW_KEY_UNKNOWN`.
|
||||
* @param[in] key The key to query, or `0`.
|
||||
* @param[in] native_key The platform-specifc identifier of the key to query.
|
||||
* @return The UTF-8 encoded, layout-specific name of the key, or `NULL`.
|
||||
*
|
||||
@@ -4422,13 +4274,13 @@ GLFWAPI int glfwRawMouseMotionSupported(void);
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
GLFWAPI const char* glfwGetKeyName(int key, int native_key);
|
||||
GLFWAPI const char* glfwGetKeyName(uint32_t key, int native_key);
|
||||
|
||||
/*! @brief Returns the platform-specific identifier of the specified key.
|
||||
*
|
||||
* This function returns the platform-specific identifier of the specified key.
|
||||
*
|
||||
* If the key is `GLFW_KEY_UNKNOWN` or does not exist on the keyboard this
|
||||
* If the key is `0` or does not exist on the keyboard this
|
||||
* method will return `-1`.
|
||||
*
|
||||
* @param[in] key Any [named key](@ref keys).
|
||||
@@ -4446,7 +4298,7 @@ GLFWAPI const char* glfwGetKeyName(int key, int native_key);
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
GLFWAPI int glfwGetNativeKeyForKey(int key);
|
||||
GLFWAPI int glfwGetNativeKeyForKey(uint32_t key);
|
||||
|
||||
/*! @brief Returns the last reported state of a keyboard key for the specified
|
||||
* window.
|
||||
@@ -4470,7 +4322,7 @@ GLFWAPI int glfwGetNativeKeyForKey(int key);
|
||||
* __Do not use this function__ to implement [text input](@ref input_char).
|
||||
*
|
||||
* @param[in] window The desired window.
|
||||
* @param[in] key The desired [keyboard key](@ref keys). `GLFW_KEY_UNKNOWN` is
|
||||
* @param[in] key The desired [keyboard key](@ref keys). `0` is
|
||||
* not a valid key for this function.
|
||||
* @return One of `GLFW_PRESS` or `GLFW_RELEASE`.
|
||||
*
|
||||
@@ -4486,7 +4338,7 @@ GLFWAPI int glfwGetNativeKeyForKey(int key);
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
GLFWAPI int glfwGetKey(GLFWwindow* window, int key);
|
||||
GLFWAPI GLFWKeyAction glfwGetKey(GLFWwindow* window, uint32_t key);
|
||||
|
||||
/*! @brief Returns the last reported state of a mouse button for the specified
|
||||
* window.
|
||||
@@ -4722,16 +4574,12 @@ GLFWAPI GLFWkeyboardfun glfwSetKeyboardCallback(GLFWwindow* window, GLFWkeyboard
|
||||
* Used to notify the IME system of changes in state such as focus gained/lost
|
||||
* and text cursor position.
|
||||
*
|
||||
* @param which: What data to notify. 1 means focus and 2 means cursor position.
|
||||
* @param a, b, c, d: Interpreted based on the value of which. When which is 1
|
||||
* a is interpreted as a boolean indicating focus gained/lost. When which is 2
|
||||
* a, b, c, d are the cursor x, y, width and height values (in the window co-ordinate
|
||||
* system).
|
||||
* @param ev: What data to notify.
|
||||
*
|
||||
* @ingroup input
|
||||
* @since Added in version 4.0
|
||||
*/
|
||||
GLFWAPI void glfwUpdateIMEState(GLFWwindow* window, int which, int a, int b, int c, int d);
|
||||
GLFWAPI void glfwUpdateIMEState(GLFWwindow* window, const GLFWIMEUpdateEvent *ev);
|
||||
|
||||
|
||||
/*! @brief Sets the mouse button callback.
|
||||
|
||||
10
glfw/ibus_glfw.c
vendored
10
glfw/ibus_glfw.c
vendored
@@ -107,11 +107,10 @@ get_ibus_text_from_message(DBusMessage *msg) {
|
||||
}
|
||||
|
||||
static inline void
|
||||
send_text(const char *text, int ime_state) {
|
||||
send_text(const char *text, GLFWIMEState ime_state) {
|
||||
_GLFWwindow *w = _glfwFocusedWindow();
|
||||
if (w && w->callbacks.keyboard) {
|
||||
GLFWkeyevent fake_ev;
|
||||
_glfwInitializeKeyEvent(&fake_ev, GLFW_KEY_UNKNOWN, 0, GLFW_PRESS, 0);
|
||||
GLFWkeyevent fake_ev = {.action = GLFW_PRESS};
|
||||
fake_ev.text = text;
|
||||
fake_ev.ime_state = ime_state;
|
||||
w->callbacks.keyboard((GLFWwindow*) w, &fake_ev);
|
||||
@@ -131,11 +130,11 @@ message_handler(DBusConnection *conn UNUSED, DBusMessage *msg, void *user_data)
|
||||
case 0:
|
||||
text = get_ibus_text_from_message(msg);
|
||||
debug("IBUS: CommitText: '%s'\n", text ? text : "(nil)");
|
||||
send_text(text, 2);
|
||||
send_text(text, GLFW_IME_COMMIT_TEXT);
|
||||
break;
|
||||
case 1:
|
||||
text = get_ibus_text_from_message(msg);
|
||||
send_text(text, 1);
|
||||
send_text(text, GLFW_IME_PREEDIT_CHANGED);
|
||||
debug("IBUS: UpdatePreeditText: '%s'\n", text ? text : "(nil)");
|
||||
break;
|
||||
case 2:
|
||||
@@ -390,6 +389,7 @@ ibus_key_state(unsigned int glfw_modifiers, int action) {
|
||||
M(ALT, IBUS_MOD1_MASK);
|
||||
M(NUM_LOCK, IBUS_MOD2_MASK);
|
||||
M(SUPER, IBUS_MOD4_MASK);
|
||||
/* To do: figure out how to get super/hyper/meta */
|
||||
#undef M
|
||||
return ans;
|
||||
}
|
||||
|
||||
26
glfw/init.c
vendored
26
glfw/init.c
vendored
@@ -50,14 +50,14 @@ _GLFWlibrary _glfw = { false };
|
||||
//
|
||||
static _GLFWerror _glfwMainThreadError;
|
||||
static GLFWerrorfun _glfwErrorCallback;
|
||||
static _GLFWinitconfig _glfwInitHints =
|
||||
{
|
||||
true, // hat buttons
|
||||
GLFW_ANGLE_PLATFORM_TYPE_NONE, // ANGLE backend
|
||||
false, // debug keyboard
|
||||
{
|
||||
true, // macOS menu bar
|
||||
true // macOS bundle chdir
|
||||
static _GLFWinitconfig _glfwInitHints = {
|
||||
.hatButtons = true,
|
||||
.angleType = GLFW_ANGLE_PLATFORM_TYPE_NONE,
|
||||
.debugKeyboard = false,
|
||||
.debugRendering = false,
|
||||
.ns = {
|
||||
.menubar = true, // macOS menu bar
|
||||
.chdir = true // macOS bundle chdir
|
||||
}
|
||||
};
|
||||
|
||||
@@ -285,6 +285,9 @@ GLFWAPI void glfwInitHint(int hint, int value)
|
||||
case GLFW_DEBUG_KEYBOARD:
|
||||
_glfwInitHints.debugKeyboard = value;
|
||||
return;
|
||||
case GLFW_DEBUG_RENDERING:
|
||||
_glfwInitHints.debugRendering = value;
|
||||
return;
|
||||
case GLFW_COCOA_CHDIR_RESOURCES:
|
||||
_glfwInitHints.ns.chdir = value;
|
||||
return;
|
||||
@@ -375,3 +378,10 @@ GLFWAPI GLFWapplicationclosefun glfwSetApplicationCloseCallback(GLFWapplicationc
|
||||
_GLFW_SWAP_POINTERS(_glfw.callbacks.application_close, cbfun);
|
||||
return cbfun;
|
||||
}
|
||||
|
||||
GLFWAPI GLFWdrawtextfun glfwSetDrawTextFunction(GLFWdrawtextfun cbfun)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
_GLFW_SWAP_POINTERS(_glfw.callbacks.draw_text, cbfun);
|
||||
return cbfun;
|
||||
}
|
||||
|
||||
455
glfw/input.c
vendored
455
glfw/input.c
vendored
@@ -273,34 +273,62 @@ static bool parseMapping(_GLFWmapping* mapping, const char* string)
|
||||
////// GLFW event API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _glfwInitializeKeyEvent(GLFWkeyevent *ev, int key, int native_key, int action, int mods)
|
||||
{
|
||||
ev->key = key;
|
||||
ev->native_key = native_key;
|
||||
ev->action = action;
|
||||
ev->mods = mods;
|
||||
ev->text = NULL;
|
||||
ev->ime_state = 0;
|
||||
static void
|
||||
set_key_action(_GLFWwindow *window, uint32_t key, int val, int idx) {
|
||||
const unsigned sz = arraysz(window->activated_keys);
|
||||
if (idx < 0) {
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
if (window->activated_keys[i].key == 0) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (idx < 0) {
|
||||
idx = sz - 1;
|
||||
memmove(window->activated_keys, window->activated_keys + 1, sizeof(window->activated_keys[0]) * (sz - 1));
|
||||
window->activated_keys[sz - 1].key = key;
|
||||
}
|
||||
}
|
||||
if (val == GLFW_RELEASE) {
|
||||
memset(window->activated_keys + idx, 0, sizeof(window->activated_keys[0]));
|
||||
if (idx < (int)sz - 1) {
|
||||
memmove(window->activated_keys + idx, window->activated_keys + idx + 1, sizeof(window->activated_keys[0]) * (sz - 1 - idx));
|
||||
memset(window->activated_keys + sz - 1, 0, sizeof(window->activated_keys[0]));
|
||||
}
|
||||
} else {
|
||||
window->activated_keys[idx].key = key;
|
||||
window->activated_keys[idx].action = val;
|
||||
}
|
||||
}
|
||||
|
||||
// Notifies shared code of a physical key event
|
||||
//
|
||||
void _glfwInputKeyboard(_GLFWwindow* window, GLFWkeyevent* ev)
|
||||
{
|
||||
if (ev->key >= 0 && ev->key <= GLFW_KEY_LAST)
|
||||
if (ev->key > 0)
|
||||
{
|
||||
bool repeated = false;
|
||||
int idx = -1;
|
||||
int current_action = GLFW_RELEASE;
|
||||
const unsigned sz = arraysz(window->activated_keys);
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
if (window->activated_keys[i].key == ev->key) {
|
||||
idx = i;
|
||||
current_action = window->activated_keys[i].action;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ev->action == GLFW_RELEASE && window->keys[ev->key] == GLFW_RELEASE)
|
||||
if (ev->action == GLFW_RELEASE && current_action == GLFW_RELEASE)
|
||||
return;
|
||||
|
||||
if (ev->action == GLFW_PRESS && window->keys[ev->key] == GLFW_PRESS)
|
||||
if (ev->action == GLFW_PRESS && current_action == GLFW_PRESS)
|
||||
repeated = true;
|
||||
|
||||
if (ev->action == GLFW_RELEASE && window->stickyKeys)
|
||||
window->keys[ev->key] = _GLFW_STICK;
|
||||
set_key_action(window, ev->key, _GLFW_STICK, idx);
|
||||
else
|
||||
window->keys[ev->key] = (char) ev->action;
|
||||
set_key_action(window, ev->key, ev->action, idx);
|
||||
|
||||
if (repeated)
|
||||
ev->action = GLFW_REPEAT;
|
||||
@@ -463,200 +491,156 @@ void _glfwFreeJoystick(_GLFWjoystick* js)
|
||||
memset(js, 0, sizeof(_GLFWjoystick));
|
||||
}
|
||||
|
||||
const char* _glfwGetKeyName(int key)
|
||||
unsigned int
|
||||
encode_utf8(uint32_t ch, char* dest) {
|
||||
if (ch < 0x80) {
|
||||
dest[0] = (char)ch;
|
||||
return 1;
|
||||
}
|
||||
if (ch < 0x800) {
|
||||
dest[0] = (ch>>6) | 0xC0;
|
||||
dest[1] = (ch & 0x3F) | 0x80;
|
||||
return 2;
|
||||
}
|
||||
if (ch < 0x10000) {
|
||||
dest[0] = (ch>>12) | 0xE0;
|
||||
dest[1] = ((ch>>6) & 0x3F) | 0x80;
|
||||
dest[2] = (ch & 0x3F) | 0x80;
|
||||
return 3;
|
||||
}
|
||||
if (ch < 0x110000) {
|
||||
dest[0] = (ch>>18) | 0xF0;
|
||||
dest[1] = ((ch>>12) & 0x3F) | 0x80;
|
||||
dest[2] = ((ch>>6) & 0x3F) | 0x80;
|
||||
dest[3] = (ch & 0x3F) | 0x80;
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char*
|
||||
_glfwGetKeyName(int key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
// Printable keys
|
||||
case GLFW_KEY_SPACE: return "SPACE";
|
||||
case GLFW_KEY_EXCLAM: return "EXCLAM";
|
||||
case GLFW_KEY_DOUBLE_QUOTE: return "DOUBLE_QUOTE";
|
||||
case GLFW_KEY_NUMBER_SIGN: return "NUMBER_SIGN";
|
||||
case GLFW_KEY_DOLLAR: return "DOLLAR";
|
||||
case GLFW_KEY_AMPERSAND: return "AMPERSAND";
|
||||
case GLFW_KEY_APOSTROPHE: return "APOSTROPHE";
|
||||
case GLFW_KEY_PARENTHESIS_LEFT: return "PARENTHESIS_LEFT";
|
||||
case GLFW_KEY_PARENTHESIS_RIGHT: return "PARENTHESIS_RIGHT";
|
||||
case GLFW_KEY_PLUS: return "PLUS";
|
||||
case GLFW_KEY_COMMA: return "COMMA";
|
||||
case GLFW_KEY_MINUS: return "MINUS";
|
||||
case GLFW_KEY_PERIOD: return "PERIOD";
|
||||
case GLFW_KEY_SLASH: return "SLASH";
|
||||
case GLFW_KEY_0: return "0";
|
||||
case GLFW_KEY_1: return "1";
|
||||
case GLFW_KEY_2: return "2";
|
||||
case GLFW_KEY_3: return "3";
|
||||
case GLFW_KEY_4: return "4";
|
||||
case GLFW_KEY_5: return "5";
|
||||
case GLFW_KEY_6: return "6";
|
||||
case GLFW_KEY_7: return "7";
|
||||
case GLFW_KEY_8: return "8";
|
||||
case GLFW_KEY_9: return "9";
|
||||
case GLFW_KEY_COLON: return "COLON";
|
||||
case GLFW_KEY_SEMICOLON: return "SEMICOLON";
|
||||
case GLFW_KEY_LESS: return "LESS";
|
||||
case GLFW_KEY_EQUAL: return "EQUAL";
|
||||
case GLFW_KEY_GREATER: return "GREATER";
|
||||
case GLFW_KEY_AT: return "AT";
|
||||
case GLFW_KEY_A: return "A";
|
||||
case GLFW_KEY_B: return "B";
|
||||
case GLFW_KEY_C: return "C";
|
||||
case GLFW_KEY_D: return "D";
|
||||
case GLFW_KEY_E: return "E";
|
||||
case GLFW_KEY_F: return "F";
|
||||
case GLFW_KEY_G: return "G";
|
||||
case GLFW_KEY_H: return "H";
|
||||
case GLFW_KEY_I: return "I";
|
||||
case GLFW_KEY_J: return "J";
|
||||
case GLFW_KEY_K: return "K";
|
||||
case GLFW_KEY_L: return "L";
|
||||
case GLFW_KEY_M: return "M";
|
||||
case GLFW_KEY_N: return "N";
|
||||
case GLFW_KEY_O: return "O";
|
||||
case GLFW_KEY_P: return "P";
|
||||
case GLFW_KEY_Q: return "Q";
|
||||
case GLFW_KEY_R: return "R";
|
||||
case GLFW_KEY_S: return "S";
|
||||
case GLFW_KEY_T: return "T";
|
||||
case GLFW_KEY_U: return "U";
|
||||
case GLFW_KEY_V: return "V";
|
||||
case GLFW_KEY_W: return "W";
|
||||
case GLFW_KEY_X: return "X";
|
||||
case GLFW_KEY_Y: return "Y";
|
||||
case GLFW_KEY_Z: return "Z";
|
||||
case GLFW_KEY_LEFT_BRACKET: return "LEFT_BRACKET";
|
||||
case GLFW_KEY_BACKSLASH: return "BACKSLASH";
|
||||
case GLFW_KEY_RIGHT_BRACKET: return "RIGHT_BRACKET";
|
||||
case GLFW_KEY_CIRCUMFLEX: return "CIRCUMFLEX";
|
||||
case GLFW_KEY_UNDERSCORE: return "UNDERSCORE";
|
||||
case GLFW_KEY_GRAVE_ACCENT: return "GRAVE_ACCENT";
|
||||
case GLFW_KEY_WORLD_1: return "WORLD_1";
|
||||
case GLFW_KEY_WORLD_2: return "WORLD_2";
|
||||
case GLFW_KEY_PARAGRAPH: return "PARAGRAPH";
|
||||
case GLFW_KEY_MASCULINE: return "MASCULINE";
|
||||
case GLFW_KEY_A_GRAVE: return "A_GRAVE";
|
||||
case GLFW_KEY_A_DIAERESIS: return "A_DIAERESIS";
|
||||
case GLFW_KEY_A_RING: return "A_RING";
|
||||
case GLFW_KEY_AE: return "AE";
|
||||
case GLFW_KEY_C_CEDILLA: return "C_CEDILLA";
|
||||
case GLFW_KEY_E_GRAVE: return "E_GRAVE";
|
||||
case GLFW_KEY_E_ACUTE: return "E_ACUTE";
|
||||
case GLFW_KEY_I_GRAVE: return "I_GRAVE";
|
||||
case GLFW_KEY_N_TILDE: return "N_TILDE";
|
||||
case GLFW_KEY_O_GRAVE: return "O_GRAVE";
|
||||
case GLFW_KEY_O_DIAERESIS: return "O_DIAERESIS";
|
||||
case GLFW_KEY_O_SLASH: return "O_SLASH";
|
||||
case GLFW_KEY_U_GRAVE: return "U_GRAVE";
|
||||
case GLFW_KEY_U_DIAERESIS: return "U_DIAERESIS";
|
||||
case GLFW_KEY_S_SHARP: return "S_SHARP";
|
||||
case GLFW_KEY_CYRILLIC_A: return "CYRILLIC_A";
|
||||
case GLFW_KEY_CYRILLIC_BE: return "CYRILLIC_BE";
|
||||
case GLFW_KEY_CYRILLIC_VE: return "CYRILLIC_VE";
|
||||
case GLFW_KEY_CYRILLIC_GHE: return "CYRILLIC_GHE";
|
||||
case GLFW_KEY_CYRILLIC_DE: return "CYRILLIC_DE";
|
||||
case GLFW_KEY_CYRILLIC_IE: return "CYRILLIC_IE";
|
||||
case GLFW_KEY_CYRILLIC_ZHE: return "CYRILLIC_ZHE";
|
||||
case GLFW_KEY_CYRILLIC_ZE: return "CYRILLIC_ZE";
|
||||
case GLFW_KEY_CYRILLIC_I: return "CYRILLIC_I";
|
||||
case GLFW_KEY_CYRILLIC_SHORT_I: return "CYRILLIC_SHORT_I";
|
||||
case GLFW_KEY_CYRILLIC_KA: return "CYRILLIC_KA";
|
||||
case GLFW_KEY_CYRILLIC_EL: return "CYRILLIC_EL";
|
||||
case GLFW_KEY_CYRILLIC_EM: return "CYRILLIC_EM";
|
||||
case GLFW_KEY_CYRILLIC_EN: return "CYRILLIC_EN";
|
||||
case GLFW_KEY_CYRILLIC_O: return "CYRILLIC_O";
|
||||
case GLFW_KEY_CYRILLIC_PE: return "CYRILLIC_PE";
|
||||
case GLFW_KEY_CYRILLIC_ER: return "CYRILLIC_ER";
|
||||
case GLFW_KEY_CYRILLIC_ES: return "CYRILLIC_ES";
|
||||
case GLFW_KEY_CYRILLIC_TE: return "CYRILLIC_TE";
|
||||
case GLFW_KEY_CYRILLIC_U: return "CYRILLIC_U";
|
||||
case GLFW_KEY_CYRILLIC_EF: return "CYRILLIC_EF";
|
||||
case GLFW_KEY_CYRILLIC_HA: return "CYRILLIC_HA";
|
||||
case GLFW_KEY_CYRILLIC_TSE: return "CYRILLIC_TSE";
|
||||
case GLFW_KEY_CYRILLIC_CHE: return "CYRILLIC_CHE";
|
||||
case GLFW_KEY_CYRILLIC_SHA: return "CYRILLIC_SHA";
|
||||
case GLFW_KEY_CYRILLIC_SHCHA: return "CYRILLIC_SHCHA";
|
||||
case GLFW_KEY_CYRILLIC_HARD_SIGN: return "CYRILLIC_HARD_SIGN";
|
||||
case GLFW_KEY_CYRILLIC_YERU: return "CYRILLIC_YERU";
|
||||
case GLFW_KEY_CYRILLIC_SOFT_SIGN: return "CYRILLIC_SOFT_SIGN";
|
||||
case GLFW_KEY_CYRILLIC_E: return "CYRILLIC_E";
|
||||
case GLFW_KEY_CYRILLIC_YU: return "CYRILLIC_YU";
|
||||
case GLFW_KEY_CYRILLIC_YA: return "CYRILLIC_YA";
|
||||
case GLFW_KEY_CYRILLIC_IO: return "CYRILLIC_IO";
|
||||
|
||||
// Function keys
|
||||
case GLFW_KEY_ESCAPE: return "ESCAPE";
|
||||
case GLFW_KEY_F1: return "F1";
|
||||
case GLFW_KEY_F2: return "F2";
|
||||
case GLFW_KEY_F3: return "F3";
|
||||
case GLFW_KEY_F4: return "F4";
|
||||
case GLFW_KEY_F5: return "F5";
|
||||
case GLFW_KEY_F6: return "F6";
|
||||
case GLFW_KEY_F7: return "F7";
|
||||
case GLFW_KEY_F8: return "F8";
|
||||
case GLFW_KEY_F9: return "F9";
|
||||
case GLFW_KEY_F10: return "F10";
|
||||
case GLFW_KEY_F11: return "F11";
|
||||
case GLFW_KEY_F12: return "F12";
|
||||
case GLFW_KEY_F13: return "F13";
|
||||
case GLFW_KEY_F14: return "F14";
|
||||
case GLFW_KEY_F15: return "F15";
|
||||
case GLFW_KEY_F16: return "F16";
|
||||
case GLFW_KEY_F17: return "F17";
|
||||
case GLFW_KEY_F18: return "F18";
|
||||
case GLFW_KEY_F19: return "F19";
|
||||
case GLFW_KEY_F20: return "F20";
|
||||
case GLFW_KEY_F21: return "F21";
|
||||
case GLFW_KEY_F22: return "F22";
|
||||
case GLFW_KEY_F23: return "F23";
|
||||
case GLFW_KEY_F24: return "F24";
|
||||
case GLFW_KEY_F25: return "F25";
|
||||
case GLFW_KEY_UP: return "UP";
|
||||
case GLFW_KEY_DOWN: return "DOWN";
|
||||
case GLFW_KEY_LEFT: return "LEFT";
|
||||
case GLFW_KEY_RIGHT: return "RIGHT";
|
||||
case GLFW_KEY_LEFT_SHIFT: return "LEFT SHIFT";
|
||||
case GLFW_KEY_RIGHT_SHIFT: return "RIGHT SHIFT";
|
||||
case GLFW_KEY_LEFT_CONTROL: return "LEFT CONTROL";
|
||||
case GLFW_KEY_RIGHT_CONTROL: return "RIGHT CONTROL";
|
||||
case GLFW_KEY_LEFT_ALT: return "LEFT ALT";
|
||||
case GLFW_KEY_RIGHT_ALT: return "RIGHT ALT";
|
||||
case GLFW_KEY_TAB: return "TAB";
|
||||
case GLFW_KEY_ENTER: return "ENTER";
|
||||
case GLFW_KEY_BACKSPACE: return "BACKSPACE";
|
||||
case GLFW_KEY_INSERT: return "INSERT";
|
||||
case GLFW_KEY_DELETE: return "DELETE";
|
||||
case GLFW_KEY_PAGE_UP: return "PAGE UP";
|
||||
case GLFW_KEY_PAGE_DOWN: return "PAGE DOWN";
|
||||
case GLFW_KEY_HOME: return "HOME";
|
||||
case GLFW_KEY_END: return "END";
|
||||
case GLFW_KEY_KP_0: return "KEYPAD 0";
|
||||
case GLFW_KEY_KP_1: return "KEYPAD 1";
|
||||
case GLFW_KEY_KP_2: return "KEYPAD 2";
|
||||
case GLFW_KEY_KP_3: return "KEYPAD 3";
|
||||
case GLFW_KEY_KP_4: return "KEYPAD 4";
|
||||
case GLFW_KEY_KP_5: return "KEYPAD 5";
|
||||
case GLFW_KEY_KP_6: return "KEYPAD 6";
|
||||
case GLFW_KEY_KP_7: return "KEYPAD 7";
|
||||
case GLFW_KEY_KP_8: return "KEYPAD 8";
|
||||
case GLFW_KEY_KP_9: return "KEYPAD 9";
|
||||
case GLFW_KEY_KP_DIVIDE: return "KEYPAD DIVIDE";
|
||||
case GLFW_KEY_KP_MULTIPLY: return "KEYPAD MULTIPLY";
|
||||
case GLFW_KEY_KP_SUBTRACT: return "KEYPAD SUBTRACT";
|
||||
case GLFW_KEY_KP_ADD: return "KEYPAD ADD";
|
||||
case GLFW_KEY_KP_DECIMAL: return "KEYPAD DECIMAL";
|
||||
case GLFW_KEY_KP_EQUAL: return "KEYPAD EQUAL";
|
||||
case GLFW_KEY_KP_ENTER: return "KEYPAD ENTER";
|
||||
case GLFW_KEY_PRINT_SCREEN: return "PRINT SCREEN";
|
||||
case GLFW_KEY_NUM_LOCK: return "NUM LOCK";
|
||||
case GLFW_KEY_CAPS_LOCK: return "CAPS LOCK";
|
||||
case GLFW_KEY_SCROLL_LOCK: return "SCROLL LOCK";
|
||||
case GLFW_KEY_PAUSE: return "PAUSE";
|
||||
case GLFW_KEY_LEFT_SUPER: return "LEFT SUPER";
|
||||
case GLFW_KEY_RIGHT_SUPER: return "RIGHT SUPER";
|
||||
case GLFW_KEY_MENU: return "MENU";
|
||||
|
||||
default: return "UNKNOWN";
|
||||
/* start functional key names (auto generated by gen-key-constants.py do not edit) */
|
||||
case GLFW_FKEY_ESCAPE: return "ESCAPE";
|
||||
case GLFW_FKEY_ENTER: return "ENTER";
|
||||
case GLFW_FKEY_TAB: return "TAB";
|
||||
case GLFW_FKEY_BACKSPACE: return "BACKSPACE";
|
||||
case GLFW_FKEY_INSERT: return "INSERT";
|
||||
case GLFW_FKEY_DELETE: return "DELETE";
|
||||
case GLFW_FKEY_LEFT: return "LEFT";
|
||||
case GLFW_FKEY_RIGHT: return "RIGHT";
|
||||
case GLFW_FKEY_UP: return "UP";
|
||||
case GLFW_FKEY_DOWN: return "DOWN";
|
||||
case GLFW_FKEY_PAGE_UP: return "PAGE_UP";
|
||||
case GLFW_FKEY_PAGE_DOWN: return "PAGE_DOWN";
|
||||
case GLFW_FKEY_HOME: return "HOME";
|
||||
case GLFW_FKEY_END: return "END";
|
||||
case GLFW_FKEY_CAPS_LOCK: return "CAPS_LOCK";
|
||||
case GLFW_FKEY_SCROLL_LOCK: return "SCROLL_LOCK";
|
||||
case GLFW_FKEY_NUM_LOCK: return "NUM_LOCK";
|
||||
case GLFW_FKEY_PRINT_SCREEN: return "PRINT_SCREEN";
|
||||
case GLFW_FKEY_PAUSE: return "PAUSE";
|
||||
case GLFW_FKEY_MENU: return "MENU";
|
||||
case GLFW_FKEY_F1: return "F1";
|
||||
case GLFW_FKEY_F2: return "F2";
|
||||
case GLFW_FKEY_F3: return "F3";
|
||||
case GLFW_FKEY_F4: return "F4";
|
||||
case GLFW_FKEY_F5: return "F5";
|
||||
case GLFW_FKEY_F6: return "F6";
|
||||
case GLFW_FKEY_F7: return "F7";
|
||||
case GLFW_FKEY_F8: return "F8";
|
||||
case GLFW_FKEY_F9: return "F9";
|
||||
case GLFW_FKEY_F10: return "F10";
|
||||
case GLFW_FKEY_F11: return "F11";
|
||||
case GLFW_FKEY_F12: return "F12";
|
||||
case GLFW_FKEY_F13: return "F13";
|
||||
case GLFW_FKEY_F14: return "F14";
|
||||
case GLFW_FKEY_F15: return "F15";
|
||||
case GLFW_FKEY_F16: return "F16";
|
||||
case GLFW_FKEY_F17: return "F17";
|
||||
case GLFW_FKEY_F18: return "F18";
|
||||
case GLFW_FKEY_F19: return "F19";
|
||||
case GLFW_FKEY_F20: return "F20";
|
||||
case GLFW_FKEY_F21: return "F21";
|
||||
case GLFW_FKEY_F22: return "F22";
|
||||
case GLFW_FKEY_F23: return "F23";
|
||||
case GLFW_FKEY_F24: return "F24";
|
||||
case GLFW_FKEY_F25: return "F25";
|
||||
case GLFW_FKEY_F26: return "F26";
|
||||
case GLFW_FKEY_F27: return "F27";
|
||||
case GLFW_FKEY_F28: return "F28";
|
||||
case GLFW_FKEY_F29: return "F29";
|
||||
case GLFW_FKEY_F30: return "F30";
|
||||
case GLFW_FKEY_F31: return "F31";
|
||||
case GLFW_FKEY_F32: return "F32";
|
||||
case GLFW_FKEY_F33: return "F33";
|
||||
case GLFW_FKEY_F34: return "F34";
|
||||
case GLFW_FKEY_F35: return "F35";
|
||||
case GLFW_FKEY_KP_0: return "KP_0";
|
||||
case GLFW_FKEY_KP_1: return "KP_1";
|
||||
case GLFW_FKEY_KP_2: return "KP_2";
|
||||
case GLFW_FKEY_KP_3: return "KP_3";
|
||||
case GLFW_FKEY_KP_4: return "KP_4";
|
||||
case GLFW_FKEY_KP_5: return "KP_5";
|
||||
case GLFW_FKEY_KP_6: return "KP_6";
|
||||
case GLFW_FKEY_KP_7: return "KP_7";
|
||||
case GLFW_FKEY_KP_8: return "KP_8";
|
||||
case GLFW_FKEY_KP_9: return "KP_9";
|
||||
case GLFW_FKEY_KP_DECIMAL: return "KP_DECIMAL";
|
||||
case GLFW_FKEY_KP_DIVIDE: return "KP_DIVIDE";
|
||||
case GLFW_FKEY_KP_MULTIPLY: return "KP_MULTIPLY";
|
||||
case GLFW_FKEY_KP_SUBTRACT: return "KP_SUBTRACT";
|
||||
case GLFW_FKEY_KP_ADD: return "KP_ADD";
|
||||
case GLFW_FKEY_KP_ENTER: return "KP_ENTER";
|
||||
case GLFW_FKEY_KP_EQUAL: return "KP_EQUAL";
|
||||
case GLFW_FKEY_KP_SEPARATOR: return "KP_SEPARATOR";
|
||||
case GLFW_FKEY_KP_LEFT: return "KP_LEFT";
|
||||
case GLFW_FKEY_KP_RIGHT: return "KP_RIGHT";
|
||||
case GLFW_FKEY_KP_UP: return "KP_UP";
|
||||
case GLFW_FKEY_KP_DOWN: return "KP_DOWN";
|
||||
case GLFW_FKEY_KP_PAGE_UP: return "KP_PAGE_UP";
|
||||
case GLFW_FKEY_KP_PAGE_DOWN: return "KP_PAGE_DOWN";
|
||||
case GLFW_FKEY_KP_HOME: return "KP_HOME";
|
||||
case GLFW_FKEY_KP_END: return "KP_END";
|
||||
case GLFW_FKEY_KP_INSERT: return "KP_INSERT";
|
||||
case GLFW_FKEY_KP_DELETE: return "KP_DELETE";
|
||||
case GLFW_FKEY_KP_BEGIN: return "KP_BEGIN";
|
||||
case GLFW_FKEY_MEDIA_PLAY: return "MEDIA_PLAY";
|
||||
case GLFW_FKEY_MEDIA_PAUSE: return "MEDIA_PAUSE";
|
||||
case GLFW_FKEY_MEDIA_PLAY_PAUSE: return "MEDIA_PLAY_PAUSE";
|
||||
case GLFW_FKEY_MEDIA_REVERSE: return "MEDIA_REVERSE";
|
||||
case GLFW_FKEY_MEDIA_STOP: return "MEDIA_STOP";
|
||||
case GLFW_FKEY_MEDIA_FAST_FORWARD: return "MEDIA_FAST_FORWARD";
|
||||
case GLFW_FKEY_MEDIA_REWIND: return "MEDIA_REWIND";
|
||||
case GLFW_FKEY_MEDIA_TRACK_NEXT: return "MEDIA_TRACK_NEXT";
|
||||
case GLFW_FKEY_MEDIA_TRACK_PREVIOUS: return "MEDIA_TRACK_PREVIOUS";
|
||||
case GLFW_FKEY_MEDIA_RECORD: return "MEDIA_RECORD";
|
||||
case GLFW_FKEY_LOWER_VOLUME: return "LOWER_VOLUME";
|
||||
case GLFW_FKEY_RAISE_VOLUME: return "RAISE_VOLUME";
|
||||
case GLFW_FKEY_MUTE_VOLUME: return "MUTE_VOLUME";
|
||||
case GLFW_FKEY_LEFT_SHIFT: return "LEFT_SHIFT";
|
||||
case GLFW_FKEY_LEFT_CONTROL: return "LEFT_CONTROL";
|
||||
case GLFW_FKEY_LEFT_ALT: return "LEFT_ALT";
|
||||
case GLFW_FKEY_LEFT_SUPER: return "LEFT_SUPER";
|
||||
case GLFW_FKEY_LEFT_HYPER: return "LEFT_HYPER";
|
||||
case GLFW_FKEY_LEFT_META: return "LEFT_META";
|
||||
case GLFW_FKEY_RIGHT_SHIFT: return "RIGHT_SHIFT";
|
||||
case GLFW_FKEY_RIGHT_CONTROL: return "RIGHT_CONTROL";
|
||||
case GLFW_FKEY_RIGHT_ALT: return "RIGHT_ALT";
|
||||
case GLFW_FKEY_RIGHT_SUPER: return "RIGHT_SUPER";
|
||||
case GLFW_FKEY_RIGHT_HYPER: return "RIGHT_HYPER";
|
||||
case GLFW_FKEY_RIGHT_META: return "RIGHT_META";
|
||||
case GLFW_FKEY_ISO_LEVEL3_SHIFT: return "ISO_LEVEL3_SHIFT";
|
||||
case GLFW_FKEY_ISO_LEVEL5_SHIFT: return "ISO_LEVEL5_SHIFT";
|
||||
/* end functional key names */
|
||||
case 0: return "UNKNOWN";
|
||||
}
|
||||
static char buf[16];
|
||||
encode_utf8(key, buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
// Center the cursor in the content area of the specified window
|
||||
@@ -736,13 +720,15 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
|
||||
|
||||
if (!value)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Release all sticky keys
|
||||
for (i = 0; i <= GLFW_KEY_LAST; i++)
|
||||
for (unsigned i = arraysz(window->activated_keys) - 1; i-- > 0;)
|
||||
{
|
||||
if (window->keys[i] == _GLFW_STICK)
|
||||
window->keys[i] = GLFW_RELEASE;
|
||||
if (window->activated_keys[i].action == _GLFW_STICK) {
|
||||
if (i < arraysz(window->activated_keys) - 1) {
|
||||
memmove(window->activated_keys + i, window->activated_keys + i + 1, sizeof(window->activated_keys[0]) * (arraysz(window->activated_keys) - 1 - i));
|
||||
}
|
||||
memset(window->activated_keys + arraysz(window->activated_keys) - 1, 0, sizeof(window->activated_keys[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -798,59 +784,50 @@ GLFWAPI int glfwRawMouseMotionSupported(void)
|
||||
return _glfwPlatformRawMouseMotionSupported();
|
||||
}
|
||||
|
||||
GLFWAPI const char* glfwGetKeyName(int key, int native_key)
|
||||
GLFWAPI const char* glfwGetKeyName(uint32_t key, int native_key)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
if (key) return _glfwGetKeyName(key);
|
||||
|
||||
if (key != GLFW_KEY_UNKNOWN)
|
||||
{
|
||||
if (key != GLFW_KEY_KP_EQUAL &&
|
||||
(key < GLFW_KEY_KP_0 || key > GLFW_KEY_KP_ADD) &&
|
||||
(key < GLFW_KEY_APOSTROPHE || key > GLFW_KEY_LAST_PRINTABLE))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
native_key = _glfwPlatformGetNativeKeyForKey(key);
|
||||
}
|
||||
|
||||
native_key = _glfwPlatformGetNativeKeyForKey(key);
|
||||
return _glfwPlatformGetNativeKeyName(native_key);
|
||||
}
|
||||
|
||||
GLFWAPI int glfwGetNativeKeyForKey(int key)
|
||||
GLFWAPI int glfwGetNativeKeyForKey(uint32_t key)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(-1);
|
||||
|
||||
if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key);
|
||||
return GLFW_RELEASE;
|
||||
}
|
||||
|
||||
return _glfwPlatformGetNativeKeyForKey(key);
|
||||
}
|
||||
|
||||
GLFWAPI int glfwGetKey(GLFWwindow* handle, int key)
|
||||
GLFWAPI GLFWKeyAction glfwGetKey(GLFWwindow* handle, uint32_t key)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE);
|
||||
if (!key) return GLFW_RELEASE;
|
||||
|
||||
if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key);
|
||||
return GLFW_RELEASE;
|
||||
int current_action = GLFW_RELEASE;
|
||||
const unsigned sz = arraysz(window->activated_keys);
|
||||
int idx = -1;
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
if (window->activated_keys[i].key == key) {
|
||||
idx = i;
|
||||
current_action = window->activated_keys[i].action;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (window->keys[key] == _GLFW_STICK)
|
||||
|
||||
if (current_action == _GLFW_STICK)
|
||||
{
|
||||
// Sticky mode: release key now
|
||||
window->keys[key] = GLFW_RELEASE;
|
||||
return GLFW_PRESS;
|
||||
set_key_action(window, key, GLFW_RELEASE, idx);
|
||||
current_action = GLFW_PRESS;
|
||||
}
|
||||
|
||||
return (int) window->keys[key];
|
||||
return current_action;
|
||||
}
|
||||
|
||||
GLFWAPI int glfwGetMouseButton(GLFWwindow* handle, int button)
|
||||
@@ -1036,13 +1013,13 @@ GLFWAPI GLFWkeyboardfun glfwSetKeyboardCallback(GLFWwindow* handle, GLFWkeyboard
|
||||
return cbfun;
|
||||
}
|
||||
|
||||
GLFWAPI void glfwUpdateIMEState(GLFWwindow* handle, int which, int a, int b, int c, int d) {
|
||||
GLFWAPI void glfwUpdateIMEState(GLFWwindow* handle, const GLFWIMEUpdateEvent *ev) {
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
#if defined(_GLFW_X11) || defined(_GLFW_WAYLAND) || defined(_GLFW_COCOA)
|
||||
_glfwPlatformUpdateIMEState(window, which, a, b, c, d);
|
||||
_glfwPlatformUpdateIMEState(window, ev);
|
||||
#else
|
||||
(void)window; (void)which; (void)a; (void)b; (void)c; (void)d;
|
||||
#endif
|
||||
|
||||
15
glfw/internal.h
vendored
15
glfw/internal.h
vendored
@@ -276,6 +276,7 @@ struct _GLFWinitconfig
|
||||
bool hatButtons;
|
||||
int angleType;
|
||||
bool debugKeyboard;
|
||||
bool debugRendering;
|
||||
struct {
|
||||
bool menubar;
|
||||
bool chdir;
|
||||
@@ -401,6 +402,11 @@ struct _GLFWcontext
|
||||
_GLFWcontextOSMesa osmesa;
|
||||
};
|
||||
|
||||
typedef struct GLFWKeyState {
|
||||
uint32_t key;
|
||||
char action;
|
||||
} GLFWKeyState;
|
||||
|
||||
// Window and context structure
|
||||
//
|
||||
struct _GLFWwindow
|
||||
@@ -431,7 +437,7 @@ struct _GLFWwindow
|
||||
bool lockKeyMods;
|
||||
int cursorMode;
|
||||
char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1];
|
||||
char keys[GLFW_KEY_LAST + 1];
|
||||
GLFWKeyState activated_keys[16];
|
||||
// Virtual cursor position when cursor is disabled
|
||||
double virtualCursorPosX, virtualCursorPosY;
|
||||
bool rawMouseMotion;
|
||||
@@ -609,6 +615,7 @@ struct _GLFWlibrary
|
||||
GLFWmonitorfun monitor;
|
||||
GLFWjoystickfun joystick;
|
||||
GLFWapplicationclosefun application_close;
|
||||
GLFWdrawtextfun draw_text;
|
||||
} callbacks;
|
||||
|
||||
|
||||
@@ -649,7 +656,7 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor);
|
||||
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor);
|
||||
|
||||
const char* _glfwPlatformGetNativeKeyName(int native_key);
|
||||
int _glfwPlatformGetNativeKeyForKey(int key);
|
||||
int _glfwPlatformGetNativeKeyForKey(uint32_t key);
|
||||
|
||||
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor);
|
||||
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos);
|
||||
@@ -723,7 +730,8 @@ void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, bool enabled);
|
||||
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, bool enabled);
|
||||
void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, bool enabled);
|
||||
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity);
|
||||
void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c, int d);
|
||||
void _glfwPlatformUpdateIMEState(_GLFWwindow *w, const GLFWIMEUpdateEvent *ev);
|
||||
void _glfwPlatformChangeCursorTheme(void);
|
||||
|
||||
void _glfwPlatformPollEvents(void);
|
||||
void _glfwPlatformWaitEvents(void);
|
||||
@@ -771,7 +779,6 @@ void _glfwInputWindowDamage(_GLFWwindow* window);
|
||||
void _glfwInputWindowCloseRequest(_GLFWwindow* window);
|
||||
void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor);
|
||||
|
||||
void _glfwInitializeKeyEvent(GLFWkeyevent *ev, int key, int native_key, int action, int mods);
|
||||
void _glfwInputKeyboard(_GLFWwindow *window, GLFWkeyevent *ev);
|
||||
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags, int mods);
|
||||
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
|
||||
|
||||
109
glfw/linux_desktop_settings.c
vendored
Normal file
109
glfw/linux_desktop_settings.c
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* linux_cursor_settings.c
|
||||
* Copyright (C) 2021 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#include "linux_desktop_settings.h"
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char *DESKTOP_SERVICE = "org.freedesktop.portal.Desktop";
|
||||
static const char *DESKTOP_PATH = "/org/freedesktop/portal/desktop";
|
||||
static const char *DESKTOP_INTERFACE = "org.freedesktop.portal.Settings";
|
||||
static const char *GNOME_DESKTOP_NAMESPACE = "org.gnome.desktop.interface";
|
||||
|
||||
|
||||
static char theme_name[64] = {0};
|
||||
static int theme_size = -1;
|
||||
static bool gnome_cursor_theme_read = false, gnome_cursor_size_read = false;
|
||||
|
||||
static bool
|
||||
parse_dbus_message_for_type(DBusMessage *const reply, const char *errmsg, const int type, void *value) {
|
||||
DBusMessageIter iter[3];
|
||||
dbus_message_iter_init(reply, &iter[0]);
|
||||
#define FAIL { _glfwInputError(GLFW_PLATFORM_ERROR, "%s", errmsg); return false; }
|
||||
if (dbus_message_iter_get_arg_type(&iter[0]) != DBUS_TYPE_VARIANT) FAIL;
|
||||
dbus_message_iter_recurse(&iter[0], &iter[1]);
|
||||
if (dbus_message_iter_get_arg_type(&iter[1]) != DBUS_TYPE_VARIANT) FAIL;
|
||||
dbus_message_iter_recurse(&iter[1], &iter[2]);
|
||||
if (dbus_message_iter_get_arg_type(&iter[2]) != type) FAIL;
|
||||
dbus_message_iter_get_basic(&iter[2], value);
|
||||
return true;
|
||||
#undef FAIL
|
||||
}
|
||||
|
||||
#define HANDLER(name) void name(DBusMessage *msg, const char* errmsg, void *data) { \
|
||||
(void)data; \
|
||||
if (errmsg) { \
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "%s: failed with error: %s", #name, errmsg); \
|
||||
return; \
|
||||
}
|
||||
|
||||
HANDLER(on_gnome_cursor_theme_read)
|
||||
const char *name;
|
||||
if (!parse_dbus_message_for_type(msg, "Failed to get cursor theme name from reply", DBUS_TYPE_STRING, &name)) return;
|
||||
if (name && name[0]) {
|
||||
gnome_cursor_theme_read = true;
|
||||
strncpy(theme_name, name, sizeof(theme_name) - 1);
|
||||
if (gnome_cursor_size_read) _glfwPlatformChangeCursorTheme();
|
||||
}
|
||||
}
|
||||
|
||||
HANDLER(on_gnome_cursor_size_read)
|
||||
int32_t sz;
|
||||
if (!parse_dbus_message_for_type(msg, "Failed to get cursor theme size from reply", DBUS_TYPE_INT32, &sz)) return;
|
||||
gnome_cursor_size_read = true;
|
||||
theme_size = sz;
|
||||
if (gnome_cursor_theme_read) _glfwPlatformChangeCursorTheme();
|
||||
}
|
||||
#undef HANDLER
|
||||
|
||||
|
||||
static bool
|
||||
call_read(DBusConnection *session_bus, dbus_pending_callback callback, const char *namespace, const char *key) {
|
||||
return glfw_dbus_call_method_with_reply(
|
||||
session_bus, DESKTOP_SERVICE, DESKTOP_PATH, DESKTOP_INTERFACE, "Read", DBUS_TIMEOUT_USE_DEFAULT,
|
||||
callback, NULL, DBUS_TYPE_STRING, &namespace, DBUS_TYPE_STRING, &key, DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
static void
|
||||
get_from_gnome(void) {
|
||||
theme_size = 32;
|
||||
DBusConnection *session_bus = glfw_dbus_session_bus();
|
||||
if (session_bus) {
|
||||
const char *theme_key = "cursor-theme";
|
||||
call_read(session_bus, on_gnome_cursor_theme_read, GNOME_DESKTOP_NAMESPACE, theme_key);
|
||||
const char *size_key = "cursor-size";
|
||||
call_read(session_bus, on_gnome_cursor_size_read, GNOME_DESKTOP_NAMESPACE, size_key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
glfw_current_cursor_theme(const char **theme, int *size) {
|
||||
*theme = theme_name[0] ? theme_name : NULL;
|
||||
*size = (theme_size > 0 && theme_size < 2048) ? theme_size : 32;
|
||||
}
|
||||
|
||||
static void
|
||||
get_cursor_theme_from_env(void) {
|
||||
const char *q = getenv("XCURSOR_THEME");
|
||||
if (q) strncpy(theme_name, q, sizeof(theme_name)-1);
|
||||
const char *env = getenv("XCURSOR_SIZE");
|
||||
theme_size = 32;
|
||||
if (env) {
|
||||
const int retval = atoi(env);
|
||||
if (retval > 0 && retval < 2048) theme_size = retval;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
glfw_initialize_desktop_settings(void) {
|
||||
get_cursor_theme_from_env();
|
||||
const char *desktop = getenv("XDG_CURRENT_DESKTOP");
|
||||
bool is_gnome = desktop && strncasecmp(desktop, "GNOME", sizeof("GNOME") - 1) == 0;
|
||||
if (is_gnome) get_from_gnome();
|
||||
}
|
||||
14
glfw/linux_desktop_settings.h
vendored
Normal file
14
glfw/linux_desktop_settings.h
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "dbus_glfw.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
void glfw_initialize_desktop_settings(void);
|
||||
void glfw_current_cursor_theme(const char **theme, int *size);
|
||||
3
glfw/memfd.h
vendored
3
glfw/memfd.h
vendored
@@ -39,8 +39,7 @@ static inline int memfd_create(const char *name, unsigned int flags) {
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static inline int
|
||||
createTmpfileCloexec(char* tmpname)
|
||||
static inline int createTmpfileCloexec(char* tmpname)
|
||||
{
|
||||
int fd;
|
||||
|
||||
|
||||
6
glfw/null_monitor.c
vendored
6
glfw/null_monitor.c
vendored
@@ -70,8 +70,12 @@ void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
|
||||
_glfwFreeGammaArrays(&monitor->null.ramp);
|
||||
}
|
||||
|
||||
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor UNUSED, int* xpos UNUSED, int* ypos UNUSED)
|
||||
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor UNUSED, int* xpos, int* ypos)
|
||||
{
|
||||
if (xpos)
|
||||
*xpos = 0;
|
||||
if (ypos)
|
||||
*ypos = 0;
|
||||
}
|
||||
|
||||
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor UNUSED,
|
||||
|
||||
23
glfw/null_window.c
vendored
23
glfw/null_window.c
vendored
@@ -274,10 +274,25 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||
{
|
||||
if (window->null.decorated && !window->monitor)
|
||||
{
|
||||
*left = 1;
|
||||
*top = 10;
|
||||
*right = 1;
|
||||
*bottom = 1;
|
||||
if (left)
|
||||
*left = 1;
|
||||
if (top)
|
||||
*top = 10;
|
||||
if (right)
|
||||
*right = 1;
|
||||
if (bottom)
|
||||
*bottom = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (left)
|
||||
*left = 0;
|
||||
if (top)
|
||||
*top = 0;
|
||||
if (right)
|
||||
*right = 0;
|
||||
if (bottom)
|
||||
*bottom = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
"wl_platform.h",
|
||||
"posix_thread.h",
|
||||
"wl_cursors.h",
|
||||
"wl_text_input.h",
|
||||
"xkb_glfw.h",
|
||||
"dbus_glfw.h",
|
||||
"ibus_glfw.h",
|
||||
@@ -64,6 +65,8 @@
|
||||
"linux_joystick.h",
|
||||
"null_joystick.h",
|
||||
"linux_notify.h",
|
||||
"linux_desktop_settings.h",
|
||||
"wl_client_side_decorations.h",
|
||||
"main_loop.h"
|
||||
],
|
||||
"protocols": [
|
||||
@@ -73,13 +76,16 @@
|
||||
"unstable/pointer-constraints/pointer-constraints-unstable-v1.xml",
|
||||
"unstable/idle-inhibit/idle-inhibit-unstable-v1.xml",
|
||||
"unstable/xdg-decoration/xdg-decoration-unstable-v1.xml",
|
||||
"unstable/primary-selection/primary-selection-unstable-v1.xml"
|
||||
"unstable/primary-selection/primary-selection-unstable-v1.xml",
|
||||
"unstable/text-input/text-input-unstable-v3.xml"
|
||||
],
|
||||
"sources": [
|
||||
"wl_init.c",
|
||||
"wl_monitor.c",
|
||||
"wl_window.c",
|
||||
"wl_cursors.c",
|
||||
"wl_text_input.c",
|
||||
"wl_client_side_decorations.c",
|
||||
"posix_thread.c",
|
||||
"xkb_glfw.c",
|
||||
"dbus_glfw.c",
|
||||
@@ -88,6 +94,7 @@
|
||||
"osmesa_context.c",
|
||||
"backend_utils.c",
|
||||
"linux_joystick.c",
|
||||
"linux_desktop_settings.c",
|
||||
"null_joystick.c",
|
||||
"linux_notify.c"
|
||||
]
|
||||
|
||||
16
glfw/window.c
vendored
16
glfw/window.c
vendored
@@ -50,21 +50,19 @@ void _glfwInputWindowFocus(_GLFWwindow* window, bool focused)
|
||||
|
||||
if (!focused)
|
||||
{
|
||||
int key, button;
|
||||
_glfw.focusedWindowId = 0;
|
||||
|
||||
for (key = 0; key <= GLFW_KEY_LAST; key++)
|
||||
for (unsigned i = 0; i < arraysz(window->activated_keys); i++)
|
||||
{
|
||||
if (window->keys[key] == GLFW_PRESS)
|
||||
if (window->activated_keys[i].key > 0 && window->activated_keys[i].action == GLFW_PRESS)
|
||||
{
|
||||
const int native_key = _glfwPlatformGetNativeKeyForKey(key);
|
||||
GLFWkeyevent ev;
|
||||
_glfwInitializeKeyEvent(&ev, key, native_key, GLFW_RELEASE, 0);
|
||||
const int native_key = _glfwPlatformGetNativeKeyForKey(window->activated_keys[i].key);
|
||||
GLFWkeyevent ev = {.key = window->activated_keys[i].key, .native_key = native_key, .action = GLFW_RELEASE};
|
||||
_glfwInputKeyboard(window, &ev);
|
||||
}
|
||||
}
|
||||
|
||||
for (button = 0; button <= GLFW_MOUSE_BUTTON_LAST; button++)
|
||||
for (int button = 0; button <= GLFW_MOUSE_BUTTON_LAST; button++)
|
||||
{
|
||||
if (window->mouseButtons[button] == GLFW_PRESS)
|
||||
_glfwInputMouseClick(window, button, GLFW_RELEASE, 0);
|
||||
@@ -703,8 +701,8 @@ GLFWAPI void glfwSetWindowSizeIncrements(GLFWwindow* handle, int widthincr, int
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
assert(widthincr >= 0);
|
||||
assert(heightincr >= 0);
|
||||
assert(widthincr >= 0 || widthincr == GLFW_DONT_CARE);
|
||||
assert(heightincr >= 0 || heightincr == GLFW_DONT_CARE);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
|
||||
438
glfw/wl_client_side_decorations.c
vendored
Normal file
438
glfw/wl_client_side_decorations.c
vendored
Normal file
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
* wl_client_side_decorations.c
|
||||
* Copyright (C) 2021 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#include "wl_client_side_decorations.h"
|
||||
|
||||
#include "backend_utils.h"
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define debug(...) if (_glfw.hints.init.debugRendering) fprintf(stderr, __VA_ARGS__);
|
||||
#define decs window->wl.decorations
|
||||
|
||||
#define ARGB(a, r, g, b) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
|
||||
#define A(x) (((x) >> 24) & 0xff)
|
||||
#define R(x) (((x) >> 16) & 0xff)
|
||||
#define G(x) (((x) >> 8) & 0xff)
|
||||
#define B(x) ((x) & 0xff)
|
||||
#define SWAP(x, y) do { __typeof__(x) SWAP = x; x = y; y = SWAP; } while (0)
|
||||
|
||||
static const uint32_t passive_bg_color = 0xffeeeeee;
|
||||
static const uint32_t active_bg_color = 0xffdddad6;
|
||||
typedef float kernel_type;
|
||||
|
||||
static void
|
||||
build_blur_kernel(kernel_type *blur_kernel, const size_t size, kernel_type sigma) {
|
||||
// 1D Normalized Gaussian
|
||||
const kernel_type half = size / (kernel_type)2;
|
||||
kernel_type sum = 0;
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
kernel_type f = (i - half);
|
||||
blur_kernel[i] = (kernel_type)exp(- f * f / sigma);
|
||||
sum += blur_kernel[i];
|
||||
}
|
||||
for (size_t i = 0; i < size; i++) blur_kernel[i] /= sum;
|
||||
}
|
||||
|
||||
static void
|
||||
blur_mask(kernel_type *image_data, ssize_t width, ssize_t height, ssize_t kernel_size, kernel_type sigma, kernel_type *scratch, kernel_type *blur_kernel, ssize_t margin) {
|
||||
(void)margin;
|
||||
build_blur_kernel(blur_kernel, kernel_size, sigma);
|
||||
const size_t half = kernel_size / 2;
|
||||
|
||||
for (ssize_t y = 0; y < height; y++) {
|
||||
kernel_type *s = image_data + y * width, *d = scratch + y * width;
|
||||
for (ssize_t x = 0; x < width; x++) {
|
||||
kernel_type a = 0;
|
||||
for (ssize_t k = 0; k < kernel_size; k++) {
|
||||
const ssize_t px = x + k - half;
|
||||
if (0 <= px && px < width) a += s[px] * blur_kernel[k];
|
||||
}
|
||||
d[x] = a;
|
||||
}
|
||||
}
|
||||
|
||||
for (ssize_t y = 0; y < height; y++) {
|
||||
kernel_type *d = image_data + y * width;
|
||||
for (ssize_t x = 0; x < width; x++) {
|
||||
kernel_type a = 0;
|
||||
for (ssize_t k = 0; k < kernel_size; k++) {
|
||||
const ssize_t py = y + k - half;
|
||||
if (0 <= py && py < height) {
|
||||
kernel_type *s = scratch + py * width;
|
||||
a += s[x] * blur_kernel[k];
|
||||
}
|
||||
}
|
||||
d[x] = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static kernel_type*
|
||||
create_shadow_mask(size_t width, size_t height, size_t margin, size_t kernel_size, kernel_type base_alpha, kernel_type sigma) {
|
||||
kernel_type *mask = calloc(sizeof(kernel_type), 2 * width * height + kernel_size);
|
||||
if (!mask) return NULL;
|
||||
for (size_t y = margin; y < height - margin; y++) {
|
||||
kernel_type *row = mask + y * width;
|
||||
for (size_t x = margin; x < width - margin; x++) row[x] = base_alpha;
|
||||
}
|
||||
blur_mask(mask, width, height, kernel_size, sigma, mask + width * height, (kernel_type*)(mask + 2 * width * height), margin);
|
||||
return mask;
|
||||
}
|
||||
|
||||
static void
|
||||
swap_buffers(_GLFWWaylandBufferPair *pair) {
|
||||
SWAP(pair->front, pair->back);
|
||||
SWAP(pair->data.front, pair->data.back);
|
||||
}
|
||||
|
||||
static size_t
|
||||
init_buffer_pair(_GLFWWaylandBufferPair *pair, size_t width, size_t height, unsigned scale) {
|
||||
memset(pair, 0, sizeof(_GLFWWaylandBufferPair));
|
||||
pair->width = width * scale;
|
||||
pair->height = height * scale;
|
||||
pair->stride = 4 * pair->width;
|
||||
pair->size_in_bytes = pair->stride * pair->height;
|
||||
return 2 * pair->size_in_bytes;
|
||||
}
|
||||
|
||||
static void
|
||||
alloc_buffer_pair(_GLFWWaylandBufferPair *pair, struct wl_shm_pool *pool, uint8_t *data, size_t *offset) {
|
||||
pair->data.a = data + *offset;
|
||||
pair->a = wl_shm_pool_create_buffer(pool, *offset, pair->width, pair->height, pair->stride, WL_SHM_FORMAT_ARGB8888);
|
||||
*offset += pair->size_in_bytes;
|
||||
pair->data.b = data + *offset;
|
||||
pair->b = wl_shm_pool_create_buffer(pool, *offset, pair->width, pair->height, pair->stride, WL_SHM_FORMAT_ARGB8888);
|
||||
*offset += pair->size_in_bytes;
|
||||
pair->front = pair->a; pair->back = pair->b;
|
||||
pair->data.front = pair->data.a; pair->data.back = pair->data.b;
|
||||
}
|
||||
|
||||
#define st decs.shadow_tile
|
||||
|
||||
void
|
||||
initialize_csd_metrics(_GLFWwindow *window) {
|
||||
decs.metrics.width = 12;
|
||||
decs.metrics.top = 36;
|
||||
decs.metrics.visible_titlebar_height = window->wl.decorations.metrics.top - window->wl.decorations.metrics.width;
|
||||
decs.metrics.horizontal = 2 * window->wl.decorations.metrics.width;
|
||||
decs.metrics.vertical = window->wl.decorations.metrics.width + window->wl.decorations.metrics.top;
|
||||
}
|
||||
|
||||
static size_t
|
||||
create_shadow_tile(_GLFWwindow *window) {
|
||||
const size_t margin = decs.bottom.buffer.height;
|
||||
if (st.data && st.for_decoration_size == margin) return margin;
|
||||
st.for_decoration_size = margin;
|
||||
free(st.data);
|
||||
st.segments = 7;
|
||||
st.stride = st.segments * margin;
|
||||
st.corner_size = margin * (st.segments - 1) / 2;
|
||||
kernel_type* mask = create_shadow_mask(st.stride, st.stride, margin, 2 * margin + 1, (kernel_type)0.7, 32 * margin);
|
||||
st.data = malloc(sizeof(uint32_t) * st.stride * st.stride);
|
||||
if (st.data) for (size_t i = 0; i < st.stride * st.stride; i++) st.data[i] = ((uint8_t)(mask[i] * 255)) << 24;
|
||||
free(mask);
|
||||
return margin;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
render_title_bar(_GLFWwindow *window, bool to_front_buffer) {
|
||||
const bool is_focused = window->id == _glfw.focusedWindowId;
|
||||
uint32_t bg_color = is_focused ? active_bg_color : passive_bg_color;
|
||||
uint32_t fg_color = is_focused ? 0xff444444 : 0xff888888;
|
||||
if (decs.use_custom_titlebar_color) {
|
||||
bg_color = 0xff000000 | (decs.titlebar_color & 0xffffff);
|
||||
double red = ((bg_color >> 16) & 0xFF) / 255.0;
|
||||
double green = ((bg_color >> 8) & 0xFF) / 255.0;
|
||||
double blue = (bg_color & 0xFF) / 255.0;
|
||||
double luma = 0.2126 * red + 0.7152 * green + 0.0722 * blue;
|
||||
if (luma < 0.5) {
|
||||
fg_color = is_focused ? 0xffeeeeee : 0xff888888;
|
||||
}
|
||||
}
|
||||
uint8_t *output = to_front_buffer ? decs.top.buffer.data.front : decs.top.buffer.data.back;
|
||||
|
||||
// render shadow part
|
||||
const size_t margin = create_shadow_tile(window);
|
||||
const size_t edge_segment_size = st.corner_size - margin;
|
||||
const uint8_t divisor = is_focused ? 1 : 2;
|
||||
for (size_t y = 0; y < margin; y++) {
|
||||
// left segment
|
||||
uint32_t *s = st.data + y * st.stride + margin;
|
||||
uint32_t *d = (uint32_t*)(output + y * decs.top.buffer.stride);
|
||||
for (size_t x = 0; x < edge_segment_size; x++) d[x] = (A(s[x]) / divisor) << 24;
|
||||
// middle segment
|
||||
s += edge_segment_size;
|
||||
size_t limit = decs.top.buffer.width > edge_segment_size ? decs.top.buffer.width - edge_segment_size : 0;
|
||||
for (size_t x = edge_segment_size, sx = 0; x < limit; x++, sx = (sx + 1) % margin) d[x] = (A(s[sx]) / divisor) << 24;
|
||||
// right segment
|
||||
s += margin;
|
||||
for (size_t x = limit; x < decs.top.buffer.width; x++, s++) d[x] = (A(*s) / divisor) << 24;
|
||||
}
|
||||
|
||||
// render text part
|
||||
output += decs.top.buffer.stride * margin;
|
||||
if (window->wl.title && window->wl.title[0] && _glfw.callbacks.draw_text) {
|
||||
if (_glfw.callbacks.draw_text((GLFWwindow*)window, window->wl.title, fg_color, bg_color, output, decs.top.buffer.width, decs.top.buffer.height - margin, 0, 0, 0)) return;
|
||||
}
|
||||
for (uint32_t *px = (uint32_t*)output, *end = (uint32_t*)(output + decs.top.buffer.size_in_bytes); px < end; px++) {
|
||||
*px = bg_color;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
update_title_bar(_GLFWwindow *window) {
|
||||
render_title_bar(window, false);
|
||||
swap_buffers(&decs.top.buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
render_edges(_GLFWwindow *window) {
|
||||
const size_t margin = create_shadow_tile(window);
|
||||
if (!st.data) return; // out of memory
|
||||
|
||||
// bottom edge
|
||||
uint32_t *src = st.data + (st.segments - 1) * margin * st.stride;
|
||||
for (size_t y = 0; y < margin; y++) {
|
||||
uint32_t *d = (uint32_t*)(decs.bottom.buffer.data.front + y * decs.bottom.buffer.stride);
|
||||
uint32_t *s = src + st.stride * y;
|
||||
// left corner
|
||||
for (size_t x = 0; x < st.corner_size && x < decs.bottom.buffer.width; x++) d[x] = s[x];
|
||||
// middle
|
||||
size_t pos = st.corner_size, limit = decs.bottom.buffer.width > st.corner_size ? decs.bottom.buffer.width - st.corner_size : 0;
|
||||
s += st.corner_size;
|
||||
while (pos < limit) {
|
||||
uint32_t *p = d + pos;
|
||||
for (size_t x = 0; x < margin && pos + x < limit; x++) p[x] = s[x];
|
||||
pos += margin;
|
||||
}
|
||||
// right corner
|
||||
s += margin;
|
||||
for (size_t x = 0; x < st.corner_size && limit + x < decs.bottom.buffer.width; x++) d[limit + x] = s[x];
|
||||
}
|
||||
|
||||
// upper corners
|
||||
for (size_t y = 0; y < st.corner_size && y < decs.left.buffer.height; y++) {
|
||||
uint32_t *left_src = st.data + st.stride * y;
|
||||
uint32_t *left_dest = (uint32_t*)(decs.left.buffer.data.front + y * decs.left.buffer.stride);
|
||||
memcpy(left_dest, left_src, margin * sizeof(uint32_t));
|
||||
uint32_t *right_src = left_src + 2 * st.corner_size;
|
||||
uint32_t *right_dest = (uint32_t*)(decs.right.buffer.data.front + y * decs.right.buffer.stride);
|
||||
memcpy(right_dest, right_src, margin * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// lower corners
|
||||
size_t src_height = st.corner_size - margin;
|
||||
size_t dest_top = decs.left.buffer.height > src_height ? decs.left.buffer.height - src_height : 0;
|
||||
size_t src_top = st.corner_size + margin;
|
||||
for (size_t src_y = src_top, dest_y = dest_top; src_y < src_top + src_height && dest_y < decs.left.buffer.height; src_y++, dest_y++) {
|
||||
uint32_t *s = st.data + st.stride * src_y;
|
||||
uint32_t *d = (uint32_t*)(decs.left.buffer.data.front + dest_y * decs.left.buffer.stride);
|
||||
memcpy(d, s, margin * sizeof(uint32_t));
|
||||
s += 2 * st.corner_size;
|
||||
d = (uint32_t*)(decs.right.buffer.data.front + dest_y * decs.left.buffer.stride);
|
||||
memcpy(d, s, margin * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// sides
|
||||
size_t limit = decs.left.buffer.height > src_height ? decs.left.buffer.height - src_height : 0;
|
||||
for (size_t dest_y = st.corner_size, src_y = 0; dest_y < limit; dest_y++, src_y = (src_y + 1) % margin) {
|
||||
uint32_t *src = st.data + (st.corner_size + src_y) * st.stride;
|
||||
uint32_t *left_dest = (uint32_t*)(decs.left.buffer.data.front + dest_y * decs.left.buffer.stride);
|
||||
memcpy(left_dest, src, margin * sizeof(uint32_t));
|
||||
src += 2 * st.corner_size;
|
||||
uint32_t *right_dest = (uint32_t*)(decs.right.buffer.data.front + dest_y * decs.right.buffer.stride);
|
||||
memcpy(right_dest, src, margin * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
#define copy(which) for (uint32_t *src = (uint32_t*)decs.which.buffer.data.front, *dest = (uint32_t*)decs.which.buffer.data.back; src < (uint32_t*)(decs.which.buffer.data.front + decs.which.buffer.size_in_bytes); src++, dest++) *dest = (A(*src) / 2 ) << 24;
|
||||
copy(left); copy(bottom); copy(right);
|
||||
#undef copy
|
||||
|
||||
}
|
||||
#undef st
|
||||
|
||||
static bool
|
||||
create_shm_buffers(_GLFWwindow* window) {
|
||||
const unsigned scale = window->wl.scale >= 1 ? window->wl.scale : 1;
|
||||
|
||||
const size_t vertical_width = decs.metrics.width, vertical_height = window->wl.height + decs.metrics.top;
|
||||
const size_t horizontal_height = decs.metrics.width, horizontal_width = window->wl.width + 2 * decs.metrics.width;
|
||||
|
||||
decs.mapping.size = 0;
|
||||
decs.mapping.size += init_buffer_pair(&decs.top.buffer, window->wl.width, decs.metrics.top, scale);
|
||||
decs.mapping.size += init_buffer_pair(&decs.left.buffer, vertical_width, vertical_height, scale);
|
||||
decs.mapping.size += init_buffer_pair(&decs.bottom.buffer, horizontal_width, horizontal_height, scale);
|
||||
decs.mapping.size += init_buffer_pair(&decs.right.buffer, vertical_width, vertical_height, scale);
|
||||
|
||||
int fd = createAnonymousFile(decs.mapping.size);
|
||||
if (fd < 0) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Creating a buffer file for %zu B failed: %s",
|
||||
decs.mapping.size, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
decs.mapping.data = mmap(NULL, decs.mapping.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (decs.mapping.data == MAP_FAILED) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: mmap failed: %s", strerror(errno));
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
struct wl_shm_pool* pool = wl_shm_create_pool(_glfw.wl.shm, fd, decs.mapping.size);
|
||||
close(fd);
|
||||
size_t offset = 0;
|
||||
#define a(which) alloc_buffer_pair(&decs.which.buffer, pool, decs.mapping.data, &offset)
|
||||
a(top); a(left); a(bottom); a(right);
|
||||
#undef a
|
||||
wl_shm_pool_destroy(pool);
|
||||
create_shadow_tile(window);
|
||||
render_title_bar(window, true);
|
||||
render_edges(window);
|
||||
debug("Created decoration buffers at scale: %u vertical_height: %zu horizontal_width: %zu\n", scale, vertical_height, horizontal_width);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
free_csd_surfaces(_GLFWwindow *window) {
|
||||
#define d(which) {\
|
||||
if (decs.which.subsurface) wl_subsurface_destroy(decs.which.subsurface); \
|
||||
decs.which.subsurface = NULL; \
|
||||
if (decs.which.surface) wl_surface_destroy(decs.which.surface); \
|
||||
decs.which.surface = NULL; \
|
||||
}
|
||||
d(left); d(top); d(right); d(bottom);
|
||||
#undef d
|
||||
}
|
||||
|
||||
static void
|
||||
free_csd_buffers(_GLFWwindow *window) {
|
||||
#define d(which) { \
|
||||
if (decs.which.buffer.a) wl_buffer_destroy(decs.which.buffer.a); \
|
||||
if (decs.which.buffer.b) wl_buffer_destroy(decs.which.buffer.b); \
|
||||
memset(&decs.which.buffer, 0, sizeof(_GLFWWaylandBufferPair)); \
|
||||
}
|
||||
d(left); d(top); d(right); d(bottom);
|
||||
#undef d
|
||||
if (decs.mapping.data) munmap(decs.mapping.data, decs.mapping.size);
|
||||
decs.mapping.data = NULL; decs.mapping.size = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
position_csd_surface(_GLFWWaylandCSDEdge *s, int x, int y, int scale) {
|
||||
wl_surface_set_buffer_scale(s->surface, scale);
|
||||
s->x = x; s->y = y;
|
||||
wl_subsurface_set_position(s->subsurface, s->x, s->y);
|
||||
}
|
||||
|
||||
static void
|
||||
create_csd_surfaces(_GLFWwindow *window, _GLFWWaylandCSDEdge *s) {
|
||||
s->surface = wl_compositor_create_surface(_glfw.wl.compositor);
|
||||
s->subsurface = wl_subcompositor_get_subsurface(_glfw.wl.subcompositor, s->surface, window->wl.surface);
|
||||
}
|
||||
|
||||
#define damage_csd(which, xbuffer) \
|
||||
wl_surface_attach(decs.which.surface, xbuffer, 0, 0); \
|
||||
wl_surface_damage(decs.which.surface, 0, 0, decs.which.buffer.width, decs.which.buffer.height); \
|
||||
wl_surface_commit(decs.which.surface)
|
||||
|
||||
bool
|
||||
ensure_csd_resources(_GLFWwindow *window) {
|
||||
if (!window->decorated || window->wl.decorations.serverSide) return false;
|
||||
const bool is_focused = window->id == _glfw.focusedWindowId;
|
||||
const bool focus_changed = is_focused != decs.for_window_state.focused;
|
||||
const bool size_changed = (
|
||||
decs.for_window_state.width != window->wl.width ||
|
||||
decs.for_window_state.height != window->wl.height ||
|
||||
decs.for_window_state.scale != window->wl.scale ||
|
||||
!decs.mapping.data
|
||||
);
|
||||
const bool needs_update = focus_changed || size_changed || !decs.left.surface;
|
||||
if (!needs_update) return false;
|
||||
if (size_changed) {
|
||||
free_csd_buffers(window);
|
||||
if (!create_shm_buffers(window)) return false;
|
||||
}
|
||||
|
||||
int32_t x, y, scale = window->wl.scale < 1 ? 1 : window->wl.scale;
|
||||
x = 0; y = -decs.metrics.top;
|
||||
if (!decs.top.surface) create_csd_surfaces(window, &decs.top);
|
||||
position_csd_surface(&decs.top, x, y, scale);
|
||||
|
||||
x = -decs.metrics.width; y = -decs.metrics.top;
|
||||
if (!decs.left.surface) create_csd_surfaces(window, &decs.left);
|
||||
position_csd_surface(&decs.left, x, y, scale);
|
||||
|
||||
x = -decs.metrics.width; y = window->wl.height;
|
||||
if (!decs.bottom.surface) create_csd_surfaces(window, &decs.bottom);
|
||||
position_csd_surface(&decs.bottom, x, y, scale);
|
||||
|
||||
x = window->wl.width; y = -decs.metrics.top;
|
||||
if (!decs.right.surface) create_csd_surfaces(window, &decs.right);
|
||||
position_csd_surface(&decs.right, x, y, scale);
|
||||
|
||||
if (focus_changed) update_title_bar(window);
|
||||
damage_csd(top, decs.top.buffer.front);
|
||||
damage_csd(left, is_focused ? decs.left.buffer.front : decs.left.buffer.back);
|
||||
damage_csd(bottom, is_focused ? decs.bottom.buffer.front : decs.bottom.buffer.back);
|
||||
damage_csd(right, is_focused ? decs.right.buffer.front : decs.right.buffer.back);
|
||||
|
||||
decs.for_window_state.width = window->wl.width;
|
||||
decs.for_window_state.height = window->wl.height;
|
||||
decs.for_window_state.scale = window->wl.scale;
|
||||
decs.for_window_state.focused = is_focused;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
free_all_csd_resources(_GLFWwindow *window) {
|
||||
free_csd_surfaces(window);
|
||||
free_csd_buffers(window);
|
||||
if (decs.shadow_tile.data) free(decs.shadow_tile.data);
|
||||
decs.shadow_tile.data = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
change_csd_title(_GLFWwindow *window) {
|
||||
if (!window->decorated || window->wl.decorations.serverSide) return;
|
||||
if (ensure_csd_resources(window)) return; // CSD were re-rendered for other reasons
|
||||
if (decs.top.surface) {
|
||||
update_title_bar(window);
|
||||
damage_csd(top, decs.top.buffer.front);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
set_csd_window_geometry(_GLFWwindow *window, int32_t *width, int32_t *height) {
|
||||
bool has_csd = window->decorated && !window->wl.decorations.serverSide && window->wl.decorations.left.surface && !(window->wl.toplevel_states & TOPLEVEL_STATE_FULLSCREEN);
|
||||
bool size_specified_by_compositor = *width > 0 && *height > 0;
|
||||
if (!size_specified_by_compositor) {
|
||||
*width = window->wl.user_requested_content_size.width;
|
||||
*height = window->wl.user_requested_content_size.height;
|
||||
if (has_csd) *height += decs.metrics.visible_titlebar_height;
|
||||
}
|
||||
decs.geometry.x = 0; decs.geometry.y = 0;
|
||||
decs.geometry.width = *width; decs.geometry.height = *height;
|
||||
if (has_csd) {
|
||||
decs.geometry.y = -decs.metrics.visible_titlebar_height;
|
||||
*height -= decs.metrics.visible_titlebar_height;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
set_titlebar_color(_GLFWwindow *window, uint32_t color, bool use_system_color) {
|
||||
bool use_custom_color = !use_system_color;
|
||||
if (use_custom_color != decs.use_custom_titlebar_color || color != decs.titlebar_color) {
|
||||
decs.use_custom_titlebar_color = use_custom_color;
|
||||
decs.titlebar_color = color;
|
||||
}
|
||||
if (window->decorated && decs.top.surface) {
|
||||
update_title_bar(window);
|
||||
damage_csd(top, decs.top.buffer.front);
|
||||
}
|
||||
}
|
||||
17
glfw/wl_client_side_decorations.h
vendored
Normal file
17
glfw/wl_client_side_decorations.h
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
void initialize_csd_metrics(_GLFWwindow *window);
|
||||
void free_all_csd_resources(_GLFWwindow *window);
|
||||
void free_csd_surfaces(_GLFWwindow *window);
|
||||
void change_csd_title(_GLFWwindow *window);
|
||||
bool ensure_csd_resources(_GLFWwindow *window);
|
||||
void set_csd_window_geometry(_GLFWwindow *window, int32_t *width, int32_t *height);
|
||||
void set_titlebar_color(_GLFWwindow *window, uint32_t color, bool use_system_color);
|
||||
46
glfw/wl_cursors.c
vendored
46
glfw/wl_cursors.c
vendored
@@ -1,6 +1,7 @@
|
||||
// Future devs supporting whatever Wayland protocol stabilizes for cursor selection: see _themeAdd.
|
||||
|
||||
#include "internal.h"
|
||||
#include "linux_desktop_settings.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
@@ -8,38 +9,35 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static GLFWWLCursorThemes cursor_themes;
|
||||
|
||||
static int
|
||||
pixels_from_scale(int scale) {
|
||||
static bool queried_env = false;
|
||||
static int factor = 32;
|
||||
if (!queried_env) {
|
||||
const char *env = getenv("XCURSOR_SIZE");
|
||||
if (env) {
|
||||
const int retval = atoi(env);
|
||||
if (retval > 0 && retval < 2048) factor = retval;
|
||||
}
|
||||
queried_env = true;
|
||||
}
|
||||
int factor;
|
||||
const char* name;
|
||||
glfw_current_cursor_theme(&name, &factor);
|
||||
return factor * scale;
|
||||
}
|
||||
|
||||
|
||||
struct wl_cursor_theme*
|
||||
glfw_wlc_theme_for_scale(int scale) {
|
||||
GLFWWLCursorThemes *t = &_glfw.wl.cursor_themes;
|
||||
for (size_t i = 0; i < t->count; i++) {
|
||||
if (t->themes[i].scale == scale) return t->themes[i].theme;
|
||||
for (size_t i = 0; i < cursor_themes.count; i++) {
|
||||
if (cursor_themes.themes[i].scale == scale) return cursor_themes.themes[i].theme;
|
||||
}
|
||||
|
||||
if (t->count >= t->capacity) {
|
||||
t->themes = realloc(t->themes, sizeof(GLFWWLCursorTheme) * (t->count + 16));
|
||||
if (!t->themes) {
|
||||
if (cursor_themes.count >= cursor_themes.capacity) {
|
||||
cursor_themes.themes = realloc(cursor_themes.themes, sizeof(GLFWWLCursorTheme) * (cursor_themes.count + 16));
|
||||
if (!cursor_themes.themes) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Out of memory allocating space for cursor themes");
|
||||
return NULL;
|
||||
}
|
||||
t->capacity = t->count + 16;
|
||||
cursor_themes.capacity = cursor_themes.count + 16;
|
||||
}
|
||||
struct wl_cursor_theme *ans = wl_cursor_theme_load(getenv("XCURSOR_THEME"), pixels_from_scale(scale), _glfw.wl.shm);
|
||||
int factor;
|
||||
const char* name;
|
||||
glfw_current_cursor_theme(&name, &factor);
|
||||
struct wl_cursor_theme *ans = wl_cursor_theme_load(name, pixels_from_scale(scale), _glfw.wl.shm);
|
||||
if (!ans) {
|
||||
_glfwInputError(
|
||||
GLFW_PLATFORM_ERROR, "Wayland: wl_cursor_theme_load failed at scale: %d pixels: %d",
|
||||
@@ -47,7 +45,7 @@ glfw_wlc_theme_for_scale(int scale) {
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
GLFWWLCursorTheme *theme = t->themes + t->count++;
|
||||
GLFWWLCursorTheme *theme = cursor_themes.themes + cursor_themes.count++;
|
||||
theme->scale = scale;
|
||||
theme->theme = ans;
|
||||
return ans;
|
||||
@@ -55,11 +53,9 @@ glfw_wlc_theme_for_scale(int scale) {
|
||||
|
||||
void
|
||||
glfw_wlc_destroy(void) {
|
||||
GLFWWLCursorThemes *t = &_glfw.wl.cursor_themes;
|
||||
|
||||
for (size_t i = 0; i < t->count; i++) {
|
||||
wl_cursor_theme_destroy(t->themes[i].theme);
|
||||
for (size_t i = 0; i < cursor_themes.count; i++) {
|
||||
wl_cursor_theme_destroy(cursor_themes.themes[i].theme);
|
||||
}
|
||||
free(t->themes);
|
||||
t->themes = NULL; t->capacity = 0; t->count = 0;
|
||||
free(cursor_themes.themes);
|
||||
cursor_themes.themes = NULL; cursor_themes.capacity = 0; cursor_themes.count = 0;
|
||||
}
|
||||
|
||||
168
glfw/wl_init.c
vendored
168
glfw/wl_init.c
vendored
@@ -29,6 +29,8 @@
|
||||
#define _GNU_SOURCE
|
||||
#include "internal.h"
|
||||
#include "backend_utils.h"
|
||||
#include "wl_client_side_decorations.h"
|
||||
#include "linux_desktop_settings.h"
|
||||
#include "../kitty/monotonic.h"
|
||||
|
||||
#include <assert.h>
|
||||
@@ -58,37 +60,21 @@ static inline int min(int n1, int n2)
|
||||
return n1 < n2 ? n1 : n2;
|
||||
}
|
||||
|
||||
static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface,
|
||||
int* which)
|
||||
static _GLFWwindow*
|
||||
findWindowFromDecorationSurface(struct wl_surface* surface, _GLFWdecorationSideWayland* which)
|
||||
{
|
||||
int focus;
|
||||
_GLFWdecorationSideWayland focus;
|
||||
if (!which) which = &focus;
|
||||
_GLFWwindow* window = _glfw.windowListHead;
|
||||
if (!which)
|
||||
which = &focus;
|
||||
while (window)
|
||||
{
|
||||
if (surface == window->wl.decorations.top.surface)
|
||||
{
|
||||
*which = topDecoration;
|
||||
break;
|
||||
}
|
||||
if (surface == window->wl.decorations.left.surface)
|
||||
{
|
||||
*which = leftDecoration;
|
||||
break;
|
||||
}
|
||||
if (surface == window->wl.decorations.right.surface)
|
||||
{
|
||||
*which = rightDecoration;
|
||||
break;
|
||||
}
|
||||
if (surface == window->wl.decorations.bottom.surface)
|
||||
{
|
||||
*which = bottomDecoration;
|
||||
break;
|
||||
}
|
||||
#define q(edge, result) if (surface == window->wl.decorations.edge.surface) { *which = result; break; }
|
||||
while (window) {
|
||||
q(top, TOP_DECORATION);
|
||||
q(left, LEFT_DECORATION);
|
||||
q(right, RIGHT_DECORATION);
|
||||
q(bottom, BOTTOM_DECORATION);
|
||||
window = window->next;
|
||||
}
|
||||
#undef q
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -103,7 +89,7 @@ static void pointerHandleEnter(void* data UNUSED,
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
int focus = 0;
|
||||
_GLFWdecorationSideWayland focus = CENTRAL_WINDOW;
|
||||
_GLFWwindow* window = wl_surface_get_user_data(surface);
|
||||
if (!window)
|
||||
{
|
||||
@@ -173,6 +159,8 @@ static void setCursor(GLFWCursorShape shape, _GLFWwindow* window)
|
||||
_glfw.wl.cursorPreviousShape = shape;
|
||||
}
|
||||
|
||||
#define x window->wl.allCursorPosX
|
||||
#define y window->wl.allCursorPosY
|
||||
static void pointerHandleMotion(void* data UNUSED,
|
||||
struct wl_pointer* pointer UNUSED,
|
||||
uint32_t time UNUSED,
|
||||
@@ -181,46 +169,45 @@ static void pointerHandleMotion(void* data UNUSED,
|
||||
{
|
||||
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||
GLFWCursorShape cursorShape = GLFW_ARROW_CURSOR;
|
||||
double x, y;
|
||||
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
return;
|
||||
x = wl_fixed_to_double(sx);
|
||||
y = wl_fixed_to_double(sy);
|
||||
window->wl.allCursorPosX = wl_fixed_to_double(sx);
|
||||
window->wl.allCursorPosY = wl_fixed_to_double(sy);
|
||||
|
||||
switch (window->wl.decorations.focus)
|
||||
{
|
||||
case mainWindow:
|
||||
case CENTRAL_WINDOW:
|
||||
window->wl.cursorPosX = x;
|
||||
window->wl.cursorPosY = y;
|
||||
_glfwInputCursorPos(window, x, y);
|
||||
_glfw.wl.cursorPreviousShape = GLFW_INVALID_CURSOR;
|
||||
return;
|
||||
case topDecoration:
|
||||
if (y < _GLFW_DECORATION_WIDTH)
|
||||
case TOP_DECORATION:
|
||||
if (y < window->wl.decorations.metrics.width)
|
||||
cursorShape = GLFW_VRESIZE_CURSOR;
|
||||
else
|
||||
cursorShape = GLFW_ARROW_CURSOR;
|
||||
break;
|
||||
case leftDecoration:
|
||||
if (y < _GLFW_DECORATION_WIDTH)
|
||||
case LEFT_DECORATION:
|
||||
if (y < window->wl.decorations.metrics.width)
|
||||
cursorShape = GLFW_NW_RESIZE_CURSOR;
|
||||
else
|
||||
cursorShape = GLFW_HRESIZE_CURSOR;
|
||||
break;
|
||||
case rightDecoration:
|
||||
if (y < _GLFW_DECORATION_WIDTH)
|
||||
case RIGHT_DECORATION:
|
||||
if (y < window->wl.decorations.metrics.width)
|
||||
cursorShape = GLFW_NE_RESIZE_CURSOR;
|
||||
else
|
||||
cursorShape = GLFW_HRESIZE_CURSOR;
|
||||
break;
|
||||
case bottomDecoration:
|
||||
if (x < _GLFW_DECORATION_WIDTH)
|
||||
case BOTTOM_DECORATION:
|
||||
if (x < window->wl.decorations.metrics.width)
|
||||
cursorShape = GLFW_SW_RESIZE_CURSOR;
|
||||
else if (x > window->wl.width + _GLFW_DECORATION_WIDTH)
|
||||
else if (x > window->wl.width + window->wl.decorations.metrics.width)
|
||||
cursorShape = GLFW_SE_RESIZE_CURSOR;
|
||||
else
|
||||
cursorShape = GLFW_VRESIZE_CURSOR;
|
||||
@@ -249,33 +236,46 @@ static void pointerHandleButton(void* data UNUSED,
|
||||
{
|
||||
switch (window->wl.decorations.focus)
|
||||
{
|
||||
case mainWindow:
|
||||
case CENTRAL_WINDOW:
|
||||
break;
|
||||
case topDecoration:
|
||||
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
||||
case TOP_DECORATION:
|
||||
if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||
monotonic_t last_click_at = window->wl.decorations.last_click_on_top_decoration_at;
|
||||
window->wl.decorations.last_click_on_top_decoration_at = monotonic();
|
||||
if (window->wl.decorations.last_click_on_top_decoration_at - last_click_at <= _glfwPlatformGetDoubleClickInterval(window)) {
|
||||
window->wl.decorations.last_click_on_top_decoration_at = 0;
|
||||
if (window->wl.toplevel_states & TOPLEVEL_STATE_MAXIMIZED)
|
||||
xdg_toplevel_unset_maximized(window->wl.xdg.toplevel);
|
||||
else
|
||||
xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (y < window->wl.decorations.metrics.width)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
|
||||
else
|
||||
{
|
||||
if (window->wl.xdg.toplevel)
|
||||
xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);
|
||||
}
|
||||
|
||||
break;
|
||||
case leftDecoration:
|
||||
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
||||
case LEFT_DECORATION:
|
||||
if (y < window->wl.decorations.metrics.width)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
|
||||
else
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
|
||||
break;
|
||||
case rightDecoration:
|
||||
if (window->wl.cursorPosY < _GLFW_DECORATION_WIDTH)
|
||||
case RIGHT_DECORATION:
|
||||
if (y < window->wl.decorations.metrics.width)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
|
||||
else
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
|
||||
break;
|
||||
case bottomDecoration:
|
||||
if (window->wl.cursorPosX < _GLFW_DECORATION_WIDTH)
|
||||
case BOTTOM_DECORATION:
|
||||
if (x < window->wl.decorations.metrics.width)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
|
||||
else if (window->wl.cursorPosX > window->wl.width + _GLFW_DECORATION_WIDTH)
|
||||
else if (x > window->wl.width + window->wl.decorations.metrics.width)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
|
||||
else
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
|
||||
@@ -291,18 +291,15 @@ static void pointerHandleButton(void* data UNUSED,
|
||||
}
|
||||
else if (button == BTN_RIGHT)
|
||||
{
|
||||
if (window->wl.decorations.focus != mainWindow && window->wl.xdg.toplevel)
|
||||
if (window->wl.decorations.focus != CENTRAL_WINDOW && window->wl.xdg.toplevel)
|
||||
{
|
||||
xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
|
||||
_glfw.wl.seat, serial,
|
||||
(int32_t)window->wl.cursorPosX,
|
||||
(int32_t)window->wl.cursorPosY);
|
||||
xdg_toplevel_show_window_menu(window->wl.xdg.toplevel, _glfw.wl.seat, serial, (int32_t)x, (int32_t)y - window->wl.decorations.metrics.top);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Don’t pass the button to the user if it was related to a decoration.
|
||||
if (window->wl.decorations.focus != mainWindow)
|
||||
if (window->wl.decorations.focus != CENTRAL_WINDOW)
|
||||
return;
|
||||
|
||||
_glfw.wl.serial = serial;
|
||||
@@ -318,6 +315,8 @@ static void pointerHandleButton(void* data UNUSED,
|
||||
: GLFW_RELEASE,
|
||||
_glfw.wl.xkb.states.modifiers);
|
||||
}
|
||||
#undef x
|
||||
#undef y
|
||||
|
||||
static void pointerHandleAxis(void* data UNUSED,
|
||||
struct wl_pointer* pointer UNUSED,
|
||||
@@ -393,7 +392,7 @@ static void keyboardHandleEnter(void* data UNUSED,
|
||||
}
|
||||
|
||||
_glfw.wl.serial = serial;
|
||||
_glfw.wl.keyboardFocus = window;
|
||||
_glfw.wl.keyboardFocusId = window->id;
|
||||
_glfwInputWindowFocus(window, true);
|
||||
uint32_t* key;
|
||||
if (keys && _glfw.wl.keyRepeatInfo.key) {
|
||||
@@ -411,21 +410,23 @@ static void keyboardHandleLeave(void* data UNUSED,
|
||||
uint32_t serial,
|
||||
struct wl_surface* surface UNUSED)
|
||||
{
|
||||
_GLFWwindow* window = _glfw.wl.keyboardFocus;
|
||||
_GLFWwindow* window = _glfwWindowForId(_glfw.wl.keyboardFocusId);
|
||||
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
_glfw.wl.serial = serial;
|
||||
_glfw.wl.keyboardFocus = NULL;
|
||||
_glfw.wl.keyboardFocusId = 0;
|
||||
_glfwInputWindowFocus(window, false);
|
||||
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
dispatchPendingKeyRepeats(id_type timer_id UNUSED, void *data UNUSED) {
|
||||
if (_glfw.wl.keyRepeatInfo.keyboardFocus != _glfw.wl.keyboardFocus || _glfw.wl.keyboardRepeatRate == 0) return;
|
||||
glfw_xkb_handle_key_event(_glfw.wl.keyRepeatInfo.keyboardFocus, &_glfw.wl.xkb, _glfw.wl.keyRepeatInfo.key, GLFW_REPEAT);
|
||||
if (_glfw.wl.keyRepeatInfo.keyboardFocusId != _glfw.wl.keyboardFocusId || _glfw.wl.keyboardRepeatRate == 0) return;
|
||||
_GLFWwindow* window = _glfwWindowForId(_glfw.wl.keyboardFocusId);
|
||||
if (!window) return;
|
||||
glfw_xkb_handle_key_event(window, &_glfw.wl.xkb, _glfw.wl.keyRepeatInfo.key, GLFW_REPEAT);
|
||||
changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, (s_to_monotonic_t(1ll) / (monotonic_t)_glfw.wl.keyboardRepeatRate));
|
||||
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 1);
|
||||
}
|
||||
@@ -438,26 +439,24 @@ static void keyboardHandleKey(void* data UNUSED,
|
||||
uint32_t key,
|
||||
uint32_t state)
|
||||
{
|
||||
_GLFWwindow* window = _glfw.wl.keyboardFocus;
|
||||
_GLFWwindow* window = _glfwWindowForId(_glfw.wl.keyboardFocusId);
|
||||
if (!window)
|
||||
return;
|
||||
int action = state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE;
|
||||
|
||||
_glfw.wl.serial = serial;
|
||||
glfw_xkb_handle_key_event(window, &_glfw.wl.xkb, key, action);
|
||||
bool repeatable = false;
|
||||
_glfw.wl.keyRepeatInfo.key = 0;
|
||||
|
||||
if (action == GLFW_PRESS && _glfw.wl.keyboardRepeatRate > 0 && glfw_xkb_should_repeat(&_glfw.wl.xkb, key))
|
||||
{
|
||||
_glfw.wl.keyRepeatInfo.key = key;
|
||||
repeatable = true;
|
||||
_glfw.wl.keyRepeatInfo.keyboardFocus = window;
|
||||
}
|
||||
if (repeatable) {
|
||||
_glfw.wl.keyRepeatInfo.keyboardFocusId = window->id;
|
||||
changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, _glfw.wl.keyboardRepeatDelay);
|
||||
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 1);
|
||||
} else if (action == GLFW_RELEASE && key == _glfw.wl.keyRepeatInfo.key) {
|
||||
_glfw.wl.keyRepeatInfo.key = 0;
|
||||
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 0);
|
||||
}
|
||||
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, repeatable ? 1 : 0);
|
||||
}
|
||||
|
||||
static void keyboardHandleModifiers(void* data UNUSED,
|
||||
@@ -584,6 +583,7 @@ static void registryHandleGlobal(void* data UNUSED,
|
||||
if (_glfw.wl.primarySelectionDeviceManager && !_glfw.wl.primarySelectionDevice) {
|
||||
_glfwSetupWaylandPrimarySelectionDevice();
|
||||
}
|
||||
_glfwWaylandInitTextInput();
|
||||
}
|
||||
}
|
||||
else if (strcmp(interface, "xdg_wm_base") == 0)
|
||||
@@ -598,11 +598,6 @@ static void registryHandleGlobal(void* data UNUSED,
|
||||
wl_registry_bind(registry, name,
|
||||
&zxdg_decoration_manager_v1_interface, 1);
|
||||
}
|
||||
else if (strcmp(interface, "wp_viewporter") == 0)
|
||||
{
|
||||
_glfw.wl.viewporter =
|
||||
wl_registry_bind(registry, name, &wp_viewporter_interface, 1);
|
||||
}
|
||||
else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0)
|
||||
{
|
||||
_glfw.wl.relativePointerManager =
|
||||
@@ -617,6 +612,11 @@ static void registryHandleGlobal(void* data UNUSED,
|
||||
&zwp_pointer_constraints_v1_interface,
|
||||
1);
|
||||
}
|
||||
else if (strcmp(interface, GLFW_WAYLAND_TEXT_INPUT_INTERFACE_NAME) == 0)
|
||||
{
|
||||
_glfwWaylandBindTextInput(registry, name);
|
||||
_glfwWaylandInitTextInput();
|
||||
}
|
||||
else if (strcmp(interface, "zwp_idle_inhibit_manager_v1") == 0)
|
||||
{
|
||||
_glfw.wl.idleInhibitManager =
|
||||
@@ -717,6 +717,9 @@ glfwWaylandCheckForServerSideDecorations(void) {
|
||||
|
||||
int _glfwPlatformInit(void)
|
||||
{
|
||||
int i;
|
||||
_GLFWmonitor* monitor;
|
||||
|
||||
_glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0");
|
||||
if (!_glfw.wl.cursor.handle)
|
||||
{
|
||||
@@ -754,6 +757,7 @@ int _glfwPlatformInit(void)
|
||||
"Wayland: Failed to initialize event loop data");
|
||||
}
|
||||
glfw_dbus_init(&_glfw.wl.dbus, &_glfw.wl.eventLoopData);
|
||||
glfw_initialize_desktop_settings();
|
||||
_glfw.wl.keyRepeatInfo.keyRepeatTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-key-repeat", ms_to_monotonic_t(500ll), 0, true, dispatchPendingKeyRepeats, NULL, NULL);
|
||||
_glfw.wl.cursorAnimationTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-cursor-animation", ms_to_monotonic_t(500ll), 0, true, animateCursorImage, NULL, NULL);
|
||||
|
||||
@@ -768,6 +772,17 @@ int _glfwPlatformInit(void)
|
||||
// Sync so we got all initial output events
|
||||
wl_display_roundtrip(_glfw.wl.display);
|
||||
|
||||
for (i = 0; i < _glfw.monitorCount; ++i)
|
||||
{
|
||||
monitor = _glfw.monitors[i];
|
||||
if (monitor->widthMM <= 0 || monitor->heightMM <= 0)
|
||||
{
|
||||
// If Wayland does not provide a physical size, assume the default 96 DPI
|
||||
monitor->widthMM = (int) (monitor->modes[monitor->wl.currentMode].width * 25.4f / 96.f);
|
||||
monitor->heightMM = (int) (monitor->modes[monitor->wl.currentMode].height * 25.4f / 96.f);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_glfw.wl.wmBase)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
@@ -817,8 +832,6 @@ void _glfwPlatformTerminate(void)
|
||||
wl_compositor_destroy(_glfw.wl.compositor);
|
||||
if (_glfw.wl.shm)
|
||||
wl_shm_destroy(_glfw.wl.shm);
|
||||
if (_glfw.wl.viewporter)
|
||||
wp_viewporter_destroy(_glfw.wl.viewporter);
|
||||
if (_glfw.wl.decorationManager)
|
||||
zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager);
|
||||
if (_glfw.wl.wmBase)
|
||||
@@ -833,6 +846,7 @@ void _glfwPlatformTerminate(void)
|
||||
zwp_relative_pointer_manager_v1_destroy(_glfw.wl.relativePointerManager);
|
||||
if (_glfw.wl.pointerConstraints)
|
||||
zwp_pointer_constraints_v1_destroy(_glfw.wl.pointerConstraints);
|
||||
_glfwWaylandDestroyTextInput();
|
||||
if (_glfw.wl.idleInhibitManager)
|
||||
zwp_idle_inhibit_manager_v1_destroy(_glfw.wl.idleInhibitManager);
|
||||
if (_glfw.wl.dataSourceForClipboard)
|
||||
|
||||
112
glfw/wl_platform.h
vendored
112
glfw/wl_platform.h
vendored
@@ -53,12 +53,12 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
|
||||
#include "wl_cursors.h"
|
||||
|
||||
#include "wayland-xdg-shell-client-protocol.h"
|
||||
#include "wayland-viewporter-client-protocol.h"
|
||||
#include "wayland-xdg-decoration-unstable-v1-client-protocol.h"
|
||||
#include "wayland-relative-pointer-unstable-v1-client-protocol.h"
|
||||
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
|
||||
#include "wayland-idle-inhibit-unstable-v1-client-protocol.h"
|
||||
#include "wayland-primary-selection-unstable-v1-client-protocol.h"
|
||||
#include "wl_text_input.h"
|
||||
|
||||
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
|
||||
#define _glfw_dlclose(handle) dlclose(handle)
|
||||
@@ -88,28 +88,45 @@ typedef void (* PFN_wl_egl_window_resize)(struct wl_egl_window*, int, int, int,
|
||||
#define wl_egl_window_destroy _glfw.wl.egl.window_destroy
|
||||
#define wl_egl_window_resize _glfw.wl.egl.window_resize
|
||||
|
||||
#define _GLFW_DECORATION_WIDTH 4
|
||||
#define _GLFW_DECORATION_TOP 24
|
||||
#define _GLFW_DECORATION_VERTICAL (_GLFW_DECORATION_TOP + _GLFW_DECORATION_WIDTH)
|
||||
#define _GLFW_DECORATION_HORIZONTAL (2 * _GLFW_DECORATION_WIDTH)
|
||||
|
||||
typedef enum _GLFWdecorationSideWayland
|
||||
{
|
||||
mainWindow,
|
||||
topDecoration,
|
||||
leftDecoration,
|
||||
rightDecoration,
|
||||
bottomDecoration,
|
||||
|
||||
CENTRAL_WINDOW,
|
||||
TOP_DECORATION,
|
||||
LEFT_DECORATION,
|
||||
RIGHT_DECORATION,
|
||||
BOTTOM_DECORATION,
|
||||
} _GLFWdecorationSideWayland;
|
||||
|
||||
typedef struct _GLFWdecorationWayland
|
||||
{
|
||||
struct wl_surface* surface;
|
||||
struct wl_subsurface* subsurface;
|
||||
struct wp_viewport* viewport;
|
||||
typedef struct _GLFWWaylandBufferPair {
|
||||
struct wl_buffer *a, *b, *front, *back;
|
||||
struct { uint8_t *a, *b, *front, *back; } data;
|
||||
bool has_pending_update;
|
||||
size_t size_in_bytes, width, height, stride;
|
||||
} _GLFWWaylandBufferPair;
|
||||
|
||||
typedef struct _GLFWWaylandCSDEdge {
|
||||
struct wl_surface *surface;
|
||||
struct wl_subsurface *subsurface;
|
||||
_GLFWWaylandBufferPair buffer;
|
||||
int x, y;
|
||||
} _GLFWWaylandCSDEdge;
|
||||
|
||||
typedef enum WaylandWindowState {
|
||||
|
||||
TOPLEVEL_STATE_NONE = 0,
|
||||
TOPLEVEL_STATE_MAXIMIZED = 1,
|
||||
TOPLEVEL_STATE_FULLSCREEN = 2,
|
||||
TOPLEVEL_STATE_RESIZING = 4,
|
||||
TOPLEVEL_STATE_ACTIVATED = 8,
|
||||
TOPLEVEL_STATE_TILED_LEFT = 16,
|
||||
TOPLEVEL_STATE_TILED_RIGHT = 32,
|
||||
TOPLEVEL_STATE_TILED_TOP = 64,
|
||||
TOPLEVEL_STATE_TILED_BOTTOM = 128,
|
||||
} WaylandWindowState;
|
||||
|
||||
|
||||
static const WaylandWindowState TOPLEVEL_STATE_DOCKED = TOPLEVEL_STATE_MAXIMIZED | TOPLEVEL_STATE_FULLSCREEN | TOPLEVEL_STATE_TILED_TOP | TOPLEVEL_STATE_TILED_LEFT | TOPLEVEL_STATE_TILED_RIGHT | TOPLEVEL_STATE_TILED_BOTTOM;
|
||||
|
||||
} _GLFWdecorationWayland;
|
||||
|
||||
// Wayland-specific per-window data
|
||||
//
|
||||
@@ -117,7 +134,6 @@ typedef struct _GLFWwindowWayland
|
||||
{
|
||||
int width, height;
|
||||
bool visible;
|
||||
bool maximized;
|
||||
bool hovered;
|
||||
bool transparent;
|
||||
struct wl_surface* surface;
|
||||
@@ -131,7 +147,7 @@ typedef struct _GLFWwindowWayland
|
||||
} xdg;
|
||||
|
||||
_GLFWcursor* currentCursor;
|
||||
double cursorPosX, cursorPosY;
|
||||
double cursorPosX, cursorPosY, allCursorPosX, allCursorPosY;
|
||||
|
||||
char* title;
|
||||
char appId[256];
|
||||
@@ -151,13 +167,37 @@ typedef struct _GLFWwindowWayland
|
||||
|
||||
struct zwp_idle_inhibitor_v1* idleInhibitor;
|
||||
|
||||
bool fullscreened;
|
||||
|
||||
struct {
|
||||
bool serverSide;
|
||||
struct wl_buffer* buffer;
|
||||
_GLFWdecorationWayland top, left, right, bottom;
|
||||
int focus;
|
||||
bool serverSide;
|
||||
_GLFWdecorationSideWayland focus;
|
||||
_GLFWWaylandCSDEdge top, left, right, bottom;
|
||||
|
||||
struct {
|
||||
uint8_t *data;
|
||||
size_t size;
|
||||
} mapping;
|
||||
|
||||
struct {
|
||||
int width, height, scale;
|
||||
bool focused;
|
||||
} for_window_state;
|
||||
|
||||
struct {
|
||||
unsigned int width, top, horizontal, vertical, visible_titlebar_height;
|
||||
} metrics;
|
||||
|
||||
struct {
|
||||
int32_t x, y, width, height;
|
||||
} geometry;
|
||||
|
||||
struct {
|
||||
uint32_t *data;
|
||||
size_t for_decoration_size, stride, segments, corner_size;
|
||||
} shadow_tile;
|
||||
monotonic_t last_click_on_top_decoration_at;
|
||||
|
||||
uint32_t titlebar_color;
|
||||
bool use_custom_titlebar_color;
|
||||
} decorations;
|
||||
|
||||
struct {
|
||||
@@ -166,6 +206,12 @@ typedef struct _GLFWwindowWayland
|
||||
struct wl_callback *current_wl_callback;
|
||||
} frameCallbackData;
|
||||
|
||||
struct {
|
||||
int32_t width, height;
|
||||
} user_requested_content_size;
|
||||
|
||||
uint32_t toplevel_states;
|
||||
bool maximize_on_first_show;
|
||||
|
||||
} _GLFWwindowWayland;
|
||||
|
||||
@@ -204,14 +250,13 @@ typedef struct _GLFWlibraryWayland
|
||||
struct wl_seat* seat;
|
||||
struct wl_pointer* pointer;
|
||||
struct wl_keyboard* keyboard;
|
||||
struct wl_data_device_manager* dataDeviceManager;
|
||||
struct wl_data_device* dataDevice;
|
||||
struct xdg_wm_base* wmBase;
|
||||
struct zxdg_decoration_manager_v1* decorationManager;
|
||||
struct wp_viewporter* viewporter;
|
||||
struct zwp_relative_pointer_manager_v1* relativePointerManager;
|
||||
struct zwp_pointer_constraints_v1* pointerConstraints;
|
||||
struct zwp_idle_inhibit_manager_v1* idleInhibitManager;
|
||||
struct wl_data_device_manager* dataDeviceManager;
|
||||
struct wl_data_device* dataDevice;
|
||||
struct wl_data_source* dataSourceForClipboard;
|
||||
struct zwp_primary_selection_device_manager_v1* primarySelectionDeviceManager;
|
||||
struct zwp_primary_selection_device_v1* primarySelectionDevice;
|
||||
@@ -226,17 +271,18 @@ typedef struct _GLFWlibraryWayland
|
||||
|
||||
int32_t keyboardRepeatRate;
|
||||
monotonic_t keyboardRepeatDelay;
|
||||
|
||||
struct {
|
||||
uint32_t key;
|
||||
id_type keyRepeatTimer;
|
||||
_GLFWwindow* keyboardFocus;
|
||||
GLFWid keyboardFocusId;
|
||||
} keyRepeatInfo;
|
||||
id_type cursorAnimationTimer;
|
||||
_GLFWXKBData xkb;
|
||||
_GLFWDBUSData dbus;
|
||||
|
||||
_GLFWwindow* pointerFocus;
|
||||
_GLFWwindow* keyboardFocus;
|
||||
GLFWid keyboardFocusId;
|
||||
|
||||
struct {
|
||||
void* handle;
|
||||
@@ -261,7 +307,6 @@ typedef struct _GLFWlibraryWayland
|
||||
size_t dataOffersCounter;
|
||||
_GLFWWaylandDataOffer dataOffers[8];
|
||||
char* primarySelectionString;
|
||||
GLFWWLCursorThemes cursor_themes;
|
||||
} _GLFWlibraryWayland;
|
||||
|
||||
// Wayland-specific per-monitor data
|
||||
@@ -275,7 +320,8 @@ typedef struct _GLFWmonitorWayland
|
||||
int x;
|
||||
int y;
|
||||
int scale;
|
||||
} _GLFWmonitorWayland;
|
||||
|
||||
} _GLFWmonitorWayland;
|
||||
|
||||
// Wayland-specific per-cursor data
|
||||
//
|
||||
|
||||
154
glfw/wl_text_input.c
vendored
Normal file
154
glfw/wl_text_input.c
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* wl_text_input.c
|
||||
* Copyright (C) 2021 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#include "wl_text_input.h"
|
||||
#include "internal.h"
|
||||
#include "wayland-text-input-unstable-v3-client-protocol.h"
|
||||
#include <stdlib.h>
|
||||
#define debug(...) if (_glfw.hints.init.debugKeyboard) printf(__VA_ARGS__);
|
||||
|
||||
static struct zwp_text_input_v3* text_input;
|
||||
static struct zwp_text_input_manager_v3* text_input_manager;
|
||||
static char *pending_pre_edit = NULL;
|
||||
static char *pending_commit = NULL;
|
||||
uint32_t commit_serial = 0;
|
||||
|
||||
static void commit(void) {
|
||||
if (text_input) {
|
||||
zwp_text_input_v3_commit (text_input);
|
||||
commit_serial++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
text_input_enter(void *data UNUSED, struct zwp_text_input_v3 *text_input UNUSED, struct wl_surface *surface UNUSED) {
|
||||
debug("text-input: enter event\n");
|
||||
if (text_input) {
|
||||
zwp_text_input_v3_enable(text_input);
|
||||
zwp_text_input_v3_set_content_type(text_input, ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE, ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TERMINAL);
|
||||
commit();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
text_input_leave(void *data UNUSED, struct zwp_text_input_v3 *text_input UNUSED, struct wl_surface *surface UNUSED) {
|
||||
debug("text-input: leave event\n");
|
||||
if (text_input) {
|
||||
zwp_text_input_v3_disable(text_input);
|
||||
commit();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
send_text(const char *text, GLFWIMEState ime_state) {
|
||||
_GLFWwindow *w = _glfwFocusedWindow();
|
||||
if (w && w->callbacks.keyboard) {
|
||||
GLFWkeyevent fake_ev = {.action = GLFW_PRESS};
|
||||
fake_ev.text = text;
|
||||
fake_ev.ime_state = ime_state;
|
||||
w->callbacks.keyboard((GLFWwindow*) w, &fake_ev);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
text_input_preedit_string(
|
||||
void *data UNUSED,
|
||||
struct zwp_text_input_v3 *text_input UNUSED,
|
||||
const char *text,
|
||||
int32_t cursor_begin,
|
||||
int32_t cursor_end
|
||||
) {
|
||||
debug("text-input: preedit_string event: text: %s cursor_begin: %d cursor_end: %d\n", text, cursor_begin, cursor_end);
|
||||
free(pending_pre_edit);
|
||||
pending_pre_edit = text ? _glfw_strdup(text) : NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
text_input_commit_string(void *data UNUSED, struct zwp_text_input_v3 *text_input UNUSED, const char *text) {
|
||||
debug("text-input: commit_string event: text: %s\n", text);
|
||||
free(pending_commit);
|
||||
pending_commit = text ? _glfw_strdup(text) : NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
text_input_delete_surrounding_text(
|
||||
void *data UNUSED,
|
||||
struct zwp_text_input_v3 *zwp_text_input_v3 UNUSED,
|
||||
uint32_t before_length,
|
||||
uint32_t after_length) {
|
||||
debug("text-input: delete_surrounding_text event: before_length: %u after_length: %u\n", before_length, after_length);
|
||||
}
|
||||
|
||||
static void
|
||||
text_input_done(void *data UNUSED, struct zwp_text_input_v3 *zwp_text_input_v3 UNUSED, uint32_t serial UNUSED) {
|
||||
debug("text-input: done event: serial: %u current_commit_serial: %u\n", serial, commit_serial);
|
||||
if (serial != commit_serial) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: text_input_done serial mismatch, expected=%u got=%u\n", commit_serial, serial);
|
||||
return;
|
||||
}
|
||||
if (pending_pre_edit) {
|
||||
send_text(pending_pre_edit, GLFW_IME_PREEDIT_CHANGED);
|
||||
free(pending_pre_edit); pending_pre_edit = NULL;
|
||||
}
|
||||
if (pending_commit) {
|
||||
send_text(pending_commit, GLFW_IME_COMMIT_TEXT);
|
||||
free(pending_commit); pending_commit = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_glfwWaylandBindTextInput(struct wl_registry* registry, uint32_t name) {
|
||||
if (!text_input_manager) text_input_manager = wl_registry_bind(registry, name, &zwp_text_input_manager_v3_interface, 1);
|
||||
}
|
||||
|
||||
void
|
||||
_glfwWaylandInitTextInput(void) {
|
||||
static const struct zwp_text_input_v3_listener text_input_listener = {
|
||||
.enter = text_input_enter,
|
||||
.leave = text_input_leave,
|
||||
.preedit_string = text_input_preedit_string,
|
||||
.commit_string = text_input_commit_string,
|
||||
.delete_surrounding_text = text_input_delete_surrounding_text,
|
||||
.done = text_input_done,
|
||||
};
|
||||
if (!text_input) {
|
||||
if (text_input_manager && _glfw.wl.seat) {
|
||||
text_input = zwp_text_input_manager_v3_get_text_input(
|
||||
text_input_manager, _glfw.wl.seat);
|
||||
if (text_input) zwp_text_input_v3_add_listener(text_input, &text_input_listener, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_glfwWaylandDestroyTextInput(void) {
|
||||
if (text_input) zwp_text_input_v3_destroy(text_input);
|
||||
if (text_input_manager) zwp_text_input_manager_v3_destroy(text_input_manager);
|
||||
text_input = NULL; text_input_manager = NULL;
|
||||
free(pending_pre_edit); pending_pre_edit = NULL;
|
||||
free(pending_commit); pending_commit = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
_glfwPlatformUpdateIMEState(_GLFWwindow *w, const GLFWIMEUpdateEvent *ev) {
|
||||
if (!text_input) return;
|
||||
switch(ev->type) {
|
||||
case GLFW_IME_UPDATE_FOCUS:
|
||||
debug("\ntext-input: updating IME focus state, focused: %d\n", ev->focused);
|
||||
if (ev->focused) zwp_text_input_v3_enable(text_input); else zwp_text_input_v3_disable(text_input);
|
||||
commit();
|
||||
break;
|
||||
case GLFW_IME_UPDATE_CURSOR_POSITION: {
|
||||
const int scale = w->wl.scale;
|
||||
const int left = ev->cursor.left / scale, top = ev->cursor.top / scale, width = ev->cursor.width / scale, height = ev->cursor.height / scale;
|
||||
debug("\ntext-input: updating cursor position: left=%d top=%d width=%d height=%d\n", left, top, width, height);
|
||||
zwp_text_input_v3_set_cursor_rectangle(text_input, left, top, width, height);
|
||||
commit();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
14
glfw/wl_text_input.h
vendored
Normal file
14
glfw/wl_text_input.h
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <wayland-client.h>
|
||||
|
||||
#define GLFW_WAYLAND_TEXT_INPUT_INTERFACE_NAME "zwp_text_input_manager_v3"
|
||||
|
||||
void _glfwWaylandBindTextInput(struct wl_registry* registry, uint32_t name);
|
||||
void _glfwWaylandInitTextInput(void);
|
||||
void _glfwWaylandDestroyTextInput(void);
|
||||
510
glfw/wl_window.c
vendored
510
glfw/wl_window.c
vendored
@@ -32,6 +32,7 @@
|
||||
#include "backend_utils.h"
|
||||
#include "memfd.h"
|
||||
#include "linux_notify.h"
|
||||
#include "wl_client_side_decorations.h"
|
||||
#include "../kitty/monotonic.h"
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -41,10 +42,65 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define debug(...) if (_glfw.hints.init.debugRendering) fprintf(stderr, __VA_ARGS__);
|
||||
|
||||
static struct wl_buffer* createShmBuffer(const GLFWimage* image, bool is_opaque, bool init_data)
|
||||
{
|
||||
struct wl_shm_pool* pool;
|
||||
struct wl_buffer* buffer;
|
||||
int stride = image->width * 4;
|
||||
int length = image->width * image->height * 4;
|
||||
void* data;
|
||||
int fd, i;
|
||||
|
||||
fd = createAnonymousFile(length);
|
||||
if (fd < 0)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Creating a buffer file for %d B failed: %s",
|
||||
length, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (data == MAP_FAILED)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: mmap failed: %s", strerror(errno));
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pool = wl_shm_create_pool(_glfw.wl.shm, fd, length);
|
||||
|
||||
close(fd);
|
||||
if (init_data) {
|
||||
unsigned char* source = (unsigned char*) image->pixels;
|
||||
unsigned char* target = data;
|
||||
for (i = 0; i < image->width * image->height; i++, source += 4)
|
||||
{
|
||||
unsigned int alpha = source[3];
|
||||
|
||||
*target++ = (unsigned char) ((source[2] * alpha) / 255);
|
||||
*target++ = (unsigned char) ((source[1] * alpha) / 255);
|
||||
*target++ = (unsigned char) ((source[0] * alpha) / 255);
|
||||
*target++ = (unsigned char) alpha;
|
||||
}
|
||||
}
|
||||
|
||||
buffer =
|
||||
wl_shm_pool_create_buffer(pool, 0,
|
||||
image->width,
|
||||
image->height,
|
||||
stride, is_opaque ? WL_SHM_FORMAT_XRGB8888 : WL_SHM_FORMAT_ARGB8888);
|
||||
munmap(data, length);
|
||||
wl_shm_pool_destroy(pool);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void
|
||||
setCursorImage(_GLFWwindow* window)
|
||||
{
|
||||
setCursorImage(_GLFWwindow* window, bool on_theme_change) {
|
||||
_GLFWcursorWayland defaultCursor = {.shape = GLFW_ARROW_CURSOR};
|
||||
_GLFWcursorWayland* cursorWayland = window->cursor ? &window->cursor->wl : &defaultCursor;
|
||||
struct wl_cursor_image* image = NULL;
|
||||
@@ -55,9 +111,8 @@ setCursorImage(_GLFWwindow* window)
|
||||
if (cursorWayland->scale < 0) {
|
||||
buffer = cursorWayland->buffer;
|
||||
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 0);
|
||||
} else
|
||||
{
|
||||
if (cursorWayland->scale != scale) {
|
||||
} else {
|
||||
if (on_theme_change || cursorWayland->scale != scale) {
|
||||
struct wl_cursor *newCursor = NULL;
|
||||
struct wl_cursor_theme *theme = glfw_wlc_theme_for_scale(scale);
|
||||
if (theme) newCursor = _glfwLoadCursor(cursorWayland->shape, theme);
|
||||
@@ -132,7 +187,7 @@ static bool checkScaleChange(_GLFWwindow* window)
|
||||
{
|
||||
window->wl.scale = scale;
|
||||
wl_surface_set_buffer_scale(window->wl.surface, scale);
|
||||
setCursorImage(window);
|
||||
setCursorImage(window, false);
|
||||
return true;
|
||||
}
|
||||
if (window->wl.monitorsCount > 0 && !window->wl.initial_scale_notified) {
|
||||
@@ -158,42 +213,15 @@ static void setOpaqueRegion(_GLFWwindow* window)
|
||||
}
|
||||
|
||||
|
||||
static void resizeFramebuffer(_GLFWwindow* window)
|
||||
{
|
||||
static void
|
||||
resizeFramebuffer(_GLFWwindow* window) {
|
||||
int scale = window->wl.scale;
|
||||
int scaledWidth = window->wl.width * scale;
|
||||
int scaledHeight = window->wl.height * scale;
|
||||
debug("Resizing framebuffer to: %dx%d at scale: %d\n", window->wl.width, window->wl.height, scale);
|
||||
wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0);
|
||||
if (!window->wl.transparent)
|
||||
setOpaqueRegion(window);
|
||||
if (!window->wl.transparent) setOpaqueRegion(window);
|
||||
_glfwInputFramebufferSize(window, scaledWidth, scaledHeight);
|
||||
|
||||
if (!window->wl.decorations.top.surface)
|
||||
return;
|
||||
|
||||
// Top decoration.
|
||||
wp_viewport_set_destination(window->wl.decorations.top.viewport,
|
||||
window->wl.width, _GLFW_DECORATION_TOP);
|
||||
wl_surface_commit(window->wl.decorations.top.surface);
|
||||
|
||||
// Left decoration.
|
||||
wp_viewport_set_destination(window->wl.decorations.left.viewport,
|
||||
_GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);
|
||||
wl_surface_commit(window->wl.decorations.left.surface);
|
||||
|
||||
// Right decoration.
|
||||
wl_subsurface_set_position(window->wl.decorations.right.subsurface,
|
||||
window->wl.width, -_GLFW_DECORATION_TOP);
|
||||
wp_viewport_set_destination(window->wl.decorations.right.viewport,
|
||||
_GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);
|
||||
wl_surface_commit(window->wl.decorations.right.surface);
|
||||
|
||||
// Bottom decoration.
|
||||
wl_subsurface_set_position(window->wl.decorations.bottom.subsurface,
|
||||
-_GLFW_DECORATION_WIDTH, window->wl.height);
|
||||
wp_viewport_set_destination(window->wl.decorations.bottom.viewport,
|
||||
window->wl.width + _GLFW_DECORATION_HORIZONTAL, _GLFW_DECORATION_WIDTH);
|
||||
wl_surface_commit(window->wl.decorations.bottom.surface);
|
||||
}
|
||||
|
||||
|
||||
@@ -206,15 +234,15 @@ clipboard_mime(void) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void dispatchChangesAfterConfigure(_GLFWwindow *window, int32_t width, int32_t height) {
|
||||
if (width <= 0) width = window->wl.width;
|
||||
if (height <= 0) height = window->wl.height;
|
||||
static void
|
||||
dispatchChangesAfterConfigure(_GLFWwindow *window, int32_t width, int32_t height) {
|
||||
bool size_changed = width != window->wl.width || height != window->wl.height;
|
||||
bool scale_changed = checkScaleChange(window);
|
||||
|
||||
if (size_changed) {
|
||||
_glfwInputWindowSize(window, width, height);
|
||||
_glfwPlatformSetWindowSize(window, width, height);
|
||||
window->wl.width = width; window->wl.height = height;
|
||||
resizeFramebuffer(window);
|
||||
}
|
||||
|
||||
if (scale_changed) {
|
||||
@@ -227,221 +255,14 @@ static void dispatchChangesAfterConfigure(_GLFWwindow *window, int32_t width, in
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create a new, unique, anonymous file of the given size, and
|
||||
* return the file descriptor for it. The file descriptor is set
|
||||
* CLOEXEC. The file is immediately suitable for mmap()'ing
|
||||
* the given size at offset zero.
|
||||
*
|
||||
* The file should not have a permanent backing store like a disk,
|
||||
* but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
|
||||
*
|
||||
* The file name is deleted from the file system.
|
||||
*
|
||||
* The file is suitable for buffer sharing between processes by
|
||||
* transmitting the file descriptor over Unix sockets using the
|
||||
* SCM_RIGHTS methods.
|
||||
*
|
||||
* posix_fallocate() is used to guarantee that disk space is available
|
||||
* for the file at the given size. If disk space is insufficient, errno
|
||||
* is set to ENOSPC. If posix_fallocate() is not supported, program may
|
||||
* receive SIGBUS on accessing mmap()'ed file contents instead.
|
||||
*/
|
||||
static int
|
||||
createAnonymousFile(off_t size)
|
||||
{
|
||||
int ret, fd = -1, shm_anon = 0;
|
||||
#ifdef HAS_MEMFD_CREATE
|
||||
fd = memfd_create("glfw-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING);
|
||||
if (fd < 0) return -1;
|
||||
// We can add this seal before calling posix_fallocate(), as the file
|
||||
// is currently zero-sized anyway.
|
||||
//
|
||||
// There is also no need to check for the return value, we couldn’t do
|
||||
// anything with it anyway.
|
||||
fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
|
||||
#elif defined(SHM_ANON)
|
||||
fd = shm_open(SHM_ANON, O_RDWR | O_CLOEXEC, 0600);
|
||||
if (fd < 0) return -1;
|
||||
shm_anon = 1;
|
||||
#else
|
||||
static const char template[] = "/glfw-shared-XXXXXX";
|
||||
const char* path;
|
||||
char* name;
|
||||
|
||||
path = getenv("XDG_RUNTIME_DIR");
|
||||
if (!path)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
name = calloc(strlen(path) + sizeof(template), 1);
|
||||
strcpy(name, path);
|
||||
strcat(name, template);
|
||||
|
||||
fd = createTmpfileCloexec(name);
|
||||
|
||||
free(name);
|
||||
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
#endif
|
||||
// posix_fallocate does not work on SHM descriptors
|
||||
ret = shm_anon ? ftruncate(fd, size) : posix_fallocate(fd, 0, size);
|
||||
if (ret != 0)
|
||||
{
|
||||
close(fd);
|
||||
errno = ret;
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
static struct wl_buffer* createShmBuffer(const GLFWimage* image)
|
||||
{
|
||||
struct wl_shm_pool* pool;
|
||||
struct wl_buffer* buffer;
|
||||
int stride = image->width * 4;
|
||||
int length = image->width * image->height * 4;
|
||||
void* data;
|
||||
int fd, i;
|
||||
|
||||
fd = createAnonymousFile(length);
|
||||
if (fd < 0)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Creating a buffer file for %d B failed: %s",
|
||||
length, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (data == MAP_FAILED)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: mmap failed: %s", strerror(errno));
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pool = wl_shm_create_pool(_glfw.wl.shm, fd, length);
|
||||
|
||||
close(fd);
|
||||
unsigned char* source = (unsigned char*) image->pixels;
|
||||
unsigned char* target = data;
|
||||
for (i = 0; i < image->width * image->height; i++, source += 4)
|
||||
{
|
||||
unsigned int alpha = source[3];
|
||||
|
||||
*target++ = (unsigned char) ((source[2] * alpha) / 255);
|
||||
*target++ = (unsigned char) ((source[1] * alpha) / 255);
|
||||
*target++ = (unsigned char) ((source[0] * alpha) / 255);
|
||||
*target++ = (unsigned char) alpha;
|
||||
}
|
||||
|
||||
buffer =
|
||||
wl_shm_pool_create_buffer(pool, 0,
|
||||
image->width,
|
||||
image->height,
|
||||
stride, WL_SHM_FORMAT_ARGB8888);
|
||||
munmap(data, length);
|
||||
wl_shm_pool_destroy(pool);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void createDecoration(_GLFWdecorationWayland* decoration,
|
||||
struct wl_surface* parent,
|
||||
struct wl_buffer* buffer, bool opaque,
|
||||
int x, int y,
|
||||
int width, int height)
|
||||
{
|
||||
struct wl_region* region;
|
||||
|
||||
decoration->surface = wl_compositor_create_surface(_glfw.wl.compositor);
|
||||
decoration->subsurface =
|
||||
wl_subcompositor_get_subsurface(_glfw.wl.subcompositor,
|
||||
decoration->surface, parent);
|
||||
wl_subsurface_set_position(decoration->subsurface, x, y);
|
||||
decoration->viewport = wp_viewporter_get_viewport(_glfw.wl.viewporter,
|
||||
decoration->surface);
|
||||
wp_viewport_set_destination(decoration->viewport, width, height);
|
||||
wl_surface_attach(decoration->surface, buffer, 0, 0);
|
||||
|
||||
if (opaque)
|
||||
{
|
||||
region = wl_compositor_create_region(_glfw.wl.compositor);
|
||||
wl_region_add(region, 0, 0, width, height);
|
||||
wl_surface_set_opaque_region(decoration->surface, region);
|
||||
wl_surface_commit(decoration->surface);
|
||||
wl_region_destroy(region);
|
||||
}
|
||||
else
|
||||
wl_surface_commit(decoration->surface);
|
||||
}
|
||||
|
||||
static void createDecorations(_GLFWwindow* window)
|
||||
{
|
||||
unsigned char data[] = { 224, 224, 224, 255 };
|
||||
const GLFWimage image = { 1, 1, data };
|
||||
bool opaque = (data[3] == 255);
|
||||
|
||||
if (!_glfw.wl.viewporter || !window->decorated || window->wl.decorations.serverSide)
|
||||
return;
|
||||
|
||||
if (!window->wl.decorations.buffer)
|
||||
window->wl.decorations.buffer = createShmBuffer(&image);
|
||||
if (!window->wl.decorations.buffer)
|
||||
return;
|
||||
|
||||
createDecoration(&window->wl.decorations.top, window->wl.surface,
|
||||
window->wl.decorations.buffer, opaque,
|
||||
0, -_GLFW_DECORATION_TOP,
|
||||
window->wl.width, _GLFW_DECORATION_TOP);
|
||||
createDecoration(&window->wl.decorations.left, window->wl.surface,
|
||||
window->wl.decorations.buffer, opaque,
|
||||
-_GLFW_DECORATION_WIDTH, -_GLFW_DECORATION_TOP,
|
||||
_GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);
|
||||
createDecoration(&window->wl.decorations.right, window->wl.surface,
|
||||
window->wl.decorations.buffer, opaque,
|
||||
window->wl.width, -_GLFW_DECORATION_TOP,
|
||||
_GLFW_DECORATION_WIDTH, window->wl.height + _GLFW_DECORATION_TOP);
|
||||
createDecoration(&window->wl.decorations.bottom, window->wl.surface,
|
||||
window->wl.decorations.buffer, opaque,
|
||||
-_GLFW_DECORATION_WIDTH, window->wl.height,
|
||||
window->wl.width + _GLFW_DECORATION_HORIZONTAL, _GLFW_DECORATION_WIDTH);
|
||||
}
|
||||
|
||||
static void destroyDecoration(_GLFWdecorationWayland* decoration)
|
||||
{
|
||||
if (decoration->surface)
|
||||
wl_surface_destroy(decoration->surface);
|
||||
if (decoration->subsurface)
|
||||
wl_subsurface_destroy(decoration->subsurface);
|
||||
if (decoration->viewport)
|
||||
wp_viewport_destroy(decoration->viewport);
|
||||
decoration->surface = NULL;
|
||||
decoration->subsurface = NULL;
|
||||
decoration->viewport = NULL;
|
||||
}
|
||||
|
||||
static void destroyDecorations(_GLFWwindow* window)
|
||||
{
|
||||
destroyDecoration(&window->wl.decorations.top);
|
||||
destroyDecoration(&window->wl.decorations.left);
|
||||
destroyDecoration(&window->wl.decorations.right);
|
||||
destroyDecoration(&window->wl.decorations.bottom);
|
||||
}
|
||||
|
||||
static void xdgDecorationHandleConfigure(void* data,
|
||||
struct zxdg_toplevel_decoration_v1* decoration UNUSED,
|
||||
uint32_t mode)
|
||||
{
|
||||
_GLFWwindow* window = data;
|
||||
|
||||
window->wl.decorations.serverSide = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
|
||||
if (!window->wl.decorations.serverSide)
|
||||
createDecorations(window);
|
||||
ensure_csd_resources(window);
|
||||
}
|
||||
|
||||
static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener = {
|
||||
@@ -468,6 +289,7 @@ static void surfaceHandleEnter(void *data,
|
||||
if (checkScaleChange(window)) {
|
||||
resizeFramebuffer(window);
|
||||
_glfwInputWindowContentScale(window, window->wl.scale, window->wl.scale);
|
||||
ensure_csd_resources(window);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,6 +314,7 @@ static void surfaceHandleLeave(void *data,
|
||||
if (checkScaleChange(window)) {
|
||||
resizeFramebuffer(window);
|
||||
_glfwInputWindowContentScale(window, window->wl.scale, window->wl.scale);
|
||||
ensure_csd_resources(window);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,6 +362,8 @@ static bool createSurface(_GLFWwindow* window,
|
||||
|
||||
window->wl.width = wndconfig->width;
|
||||
window->wl.height = wndconfig->height;
|
||||
window->wl.user_requested_content_size.width = wndconfig->width;
|
||||
window->wl.user_requested_content_size.height = wndconfig->height;
|
||||
window->wl.scale = 1;
|
||||
|
||||
if (!window->wl.transparent)
|
||||
@@ -547,8 +372,7 @@ static bool createSurface(_GLFWwindow* window,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, bool on)
|
||||
static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, bool on)
|
||||
{
|
||||
if (window->wl.xdg.toplevel)
|
||||
{
|
||||
@@ -556,12 +380,10 @@ setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, bool on)
|
||||
xdg_toplevel_set_fullscreen(
|
||||
window->wl.xdg.toplevel,
|
||||
monitor ? monitor->wl.output : NULL);
|
||||
if (!window->wl.decorations.serverSide)
|
||||
destroyDecorations(window);
|
||||
if (!window->wl.decorations.serverSide) free_csd_surfaces(window);
|
||||
} else {
|
||||
xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);
|
||||
if (!_glfw.wl.decorationManager)
|
||||
createDecorations(window);
|
||||
ensure_csd_resources(window);
|
||||
}
|
||||
}
|
||||
setIdleInhibitor(window, on);
|
||||
@@ -569,7 +391,7 @@ setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, bool on)
|
||||
|
||||
bool
|
||||
_glfwPlatformToggleFullscreen(_GLFWwindow *window, unsigned int flags UNUSED) {
|
||||
bool already_fullscreen = window->wl.fullscreened;
|
||||
bool already_fullscreen = window->wl.toplevel_states & TOPLEVEL_STATE_FULLSCREEN;
|
||||
setFullscreen(window, NULL, !already_fullscreen);
|
||||
return !already_fullscreen;
|
||||
}
|
||||
@@ -583,32 +405,33 @@ static void xdgToplevelHandleConfigure(void* data,
|
||||
_GLFWwindow* window = data;
|
||||
float aspectRatio;
|
||||
float targetRatio;
|
||||
uint32_t* state;
|
||||
bool maximized = false;
|
||||
bool fullscreen = false;
|
||||
bool activated = false;
|
||||
enum xdg_toplevel_state* state;
|
||||
uint32_t new_states = 0;
|
||||
debug("top-level configure event: size: %dx%d states: ", width, height);
|
||||
|
||||
wl_array_for_each(state, states)
|
||||
{
|
||||
switch (*state)
|
||||
{
|
||||
case XDG_TOPLEVEL_STATE_MAXIMIZED:
|
||||
maximized = true;
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_FULLSCREEN:
|
||||
fullscreen = true;
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_RESIZING:
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_ACTIVATED:
|
||||
activated = true;
|
||||
break;
|
||||
wl_array_for_each(state, states) {
|
||||
switch (*state) {
|
||||
#define C(x) case XDG_##x: new_states |= x; debug("%s ", #x); break
|
||||
C(TOPLEVEL_STATE_RESIZING);
|
||||
C(TOPLEVEL_STATE_MAXIMIZED);
|
||||
C(TOPLEVEL_STATE_FULLSCREEN);
|
||||
C(TOPLEVEL_STATE_ACTIVATED);
|
||||
C(TOPLEVEL_STATE_TILED_LEFT);
|
||||
C(TOPLEVEL_STATE_TILED_RIGHT);
|
||||
C(TOPLEVEL_STATE_TILED_TOP);
|
||||
C(TOPLEVEL_STATE_TILED_BOTTOM);
|
||||
#undef C
|
||||
}
|
||||
}
|
||||
|
||||
debug("\n");
|
||||
if (new_states & TOPLEVEL_STATE_RESIZING) {
|
||||
if (width) window->wl.user_requested_content_size.width = width;
|
||||
if (height) window->wl.user_requested_content_size.height = height;
|
||||
if (!(window->wl.toplevel_states & TOPLEVEL_STATE_RESIZING)) _glfwInputLiveResize(window, true);
|
||||
}
|
||||
if (width != 0 && height != 0)
|
||||
{
|
||||
if (!maximized && !fullscreen)
|
||||
if (!(new_states & TOPLEVEL_STATE_DOCKED))
|
||||
{
|
||||
if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)
|
||||
{
|
||||
@@ -621,15 +444,19 @@ static void xdgToplevelHandleConfigure(void* data,
|
||||
}
|
||||
}
|
||||
}
|
||||
window->wl.fullscreened = fullscreen;
|
||||
if (!fullscreen) {
|
||||
if (window->decorated && !window->wl.decorations.serverSide && window->wl.decorations.buffer) {
|
||||
width -= _GLFW_DECORATION_HORIZONTAL;
|
||||
height -= _GLFW_DECORATION_VERTICAL;
|
||||
}
|
||||
}
|
||||
bool live_resize_done = !(new_states & TOPLEVEL_STATE_RESIZING) && (window->wl.toplevel_states & TOPLEVEL_STATE_RESIZING);
|
||||
window->wl.toplevel_states = new_states;
|
||||
set_csd_window_geometry(window, &width, &height);
|
||||
dispatchChangesAfterConfigure(window, width, height);
|
||||
_glfwInputWindowFocus(window, activated);
|
||||
debug("final window content size: %dx%d\n", window->wl.width, window->wl.height);
|
||||
_glfwInputWindowFocus(window, window->wl.toplevel_states & TOPLEVEL_STATE_ACTIVATED);
|
||||
ensure_csd_resources(window);
|
||||
wl_surface_commit(window->wl.surface);
|
||||
#define geometry window->wl.decorations.geometry
|
||||
debug("Setting window geometry: x=%d y=%d %dx%d\n", geometry.x, geometry.y, geometry.width, geometry.height);
|
||||
xdg_surface_set_window_geometry(window->wl.xdg.surface, geometry.x, geometry.y, geometry.width, geometry.height);
|
||||
#undef geometry
|
||||
if (live_resize_done) _glfwInputLiveResize(window, false);
|
||||
}
|
||||
|
||||
static void xdgToplevelHandleClose(void* data,
|
||||
@@ -659,6 +486,7 @@ static void setXdgDecorations(_GLFWwindow* window)
|
||||
{
|
||||
if (_glfw.wl.decorationManager)
|
||||
{
|
||||
window->wl.decorations.serverSide = true;
|
||||
window->wl.xdg.decoration =
|
||||
zxdg_decoration_manager_v1_get_toplevel_decoration(
|
||||
_glfw.wl.decorationManager, window->wl.xdg.toplevel);
|
||||
@@ -672,7 +500,7 @@ static void setXdgDecorations(_GLFWwindow* window)
|
||||
else
|
||||
{
|
||||
window->wl.decorations.serverSide = false;
|
||||
createDecorations(window);
|
||||
ensure_csd_resources(window);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -719,8 +547,9 @@ static bool createXdgSurface(_GLFWwindow* window)
|
||||
window->monitor->wl.output);
|
||||
setIdleInhibitor(window, true);
|
||||
}
|
||||
else if (window->wl.maximized)
|
||||
else if (window->wl.maximize_on_first_show)
|
||||
{
|
||||
window->wl.maximize_on_first_show = false;
|
||||
xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
|
||||
setIdleInhibitor(window, false);
|
||||
setXdgDecorations(window);
|
||||
@@ -739,16 +568,15 @@ static bool createXdgSurface(_GLFWwindow* window)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
incrementCursorImage(_GLFWwindow* window)
|
||||
static void incrementCursorImage(_GLFWwindow* window)
|
||||
{
|
||||
if (window && window->wl.decorations.focus == mainWindow && window->cursorMode != GLFW_CURSOR_HIDDEN) {
|
||||
if (window && window->wl.decorations.focus == CENTRAL_WINDOW && window->cursorMode != GLFW_CURSOR_HIDDEN) {
|
||||
_GLFWcursor* cursor = window->wl.currentCursor;
|
||||
if (cursor && cursor->wl.cursor)
|
||||
{
|
||||
cursor->wl.currentImage += 1;
|
||||
cursor->wl.currentImage %= cursor->wl.cursor->image_count;
|
||||
setCursorImage(window);
|
||||
setCursorImage(window, false);
|
||||
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, cursor->wl.cursor->image_count > 1);
|
||||
return;
|
||||
}
|
||||
@@ -788,8 +616,7 @@ wayland_read_events(int poll_result, int events, void *data UNUSED) {
|
||||
else wl_display_cancel_read(_glfw.wl.display);
|
||||
}
|
||||
|
||||
static void
|
||||
handleEvents(monotonic_t timeout)
|
||||
static void handleEvents(monotonic_t timeout)
|
||||
{
|
||||
struct wl_display* display = _glfw.wl.display;
|
||||
errno = 0;
|
||||
@@ -886,6 +713,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
{
|
||||
initialize_csd_metrics(window);
|
||||
window->wl.transparent = fbconfig->transparent;
|
||||
strncpy(window->wl.appId, wndconfig->wl.appId, sizeof(window->wl.appId));
|
||||
|
||||
@@ -913,6 +741,8 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
||||
|
||||
if (wndconfig->title)
|
||||
window->wl.title = _glfw_strdup(wndconfig->title);
|
||||
if (wndconfig->maximized)
|
||||
window->wl.maximize_on_first_show = true;
|
||||
|
||||
if (wndconfig->visible)
|
||||
{
|
||||
@@ -945,11 +775,14 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
||||
_glfw.wl.pointerFocus = NULL;
|
||||
_glfwInputCursorEnter(window, false);
|
||||
}
|
||||
if (window == _glfw.wl.keyboardFocus)
|
||||
if (window->id == _glfw.wl.keyboardFocusId)
|
||||
{
|
||||
_glfw.wl.keyboardFocus = NULL;
|
||||
_glfw.wl.keyboardFocusId = 0;
|
||||
_glfwInputWindowFocus(window, false);
|
||||
}
|
||||
if (window->id == _glfw.wl.keyRepeatInfo.keyboardFocusId) {
|
||||
_glfw.wl.keyRepeatInfo.keyboardFocusId = 0;
|
||||
}
|
||||
|
||||
if (window->wl.idleInhibitor)
|
||||
zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor);
|
||||
@@ -957,14 +790,10 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
||||
if (window->context.destroy)
|
||||
window->context.destroy(window);
|
||||
|
||||
destroyDecorations(window);
|
||||
|
||||
free_all_csd_resources(window);
|
||||
if (window->wl.xdg.decoration)
|
||||
zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration);
|
||||
|
||||
if (window->wl.decorations.buffer)
|
||||
wl_buffer_destroy(window->wl.decorations.buffer);
|
||||
|
||||
if (window->wl.native)
|
||||
wl_egl_window_destroy(window->wl.native);
|
||||
|
||||
@@ -985,14 +814,16 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
||||
|
||||
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
|
||||
{
|
||||
if (window->wl.title)
|
||||
if (window->wl.title) {
|
||||
if (title && strcmp(title, window->wl.title) == 0) return;
|
||||
free(window->wl.title);
|
||||
} else if (!title) return;
|
||||
// Wayland cannot handle requests larger than ~8200 bytes. Sending
|
||||
// one causes an abort(). Since titles this large are meaningless anyway
|
||||
// ensure they do not happen.
|
||||
window->wl.title = utf_8_strndup(title, 2048);
|
||||
if (window->wl.xdg.toplevel)
|
||||
xdg_toplevel_set_title(window->wl.xdg.toplevel, window->wl.title);
|
||||
if (window->wl.xdg.toplevel) xdg_toplevel_set_title(window->wl.xdg.toplevel, window->wl.title);
|
||||
change_csd_title(window);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window UNUSED,
|
||||
@@ -1006,9 +837,12 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window UNUSED, int* xpos UNUSED, int
|
||||
{
|
||||
// A Wayland client is not aware of its position, so just warn and leave it
|
||||
// as (0, 0)
|
||||
|
||||
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
||||
"Wayland: The platform does not provide the window position");
|
||||
static bool warned_once = false;
|
||||
if (!warned_once) {
|
||||
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
||||
"Wayland: The platform does not provide the window position");
|
||||
warned_once = true;
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowPos(_GLFWwindow* window UNUSED, int xpos UNUSED, int ypos UNUSED)
|
||||
@@ -1030,9 +864,14 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
|
||||
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
|
||||
{
|
||||
if (width != window->wl.width || height != window->wl.height) {
|
||||
window->wl.width = width;
|
||||
window->wl.height = height;
|
||||
window->wl.user_requested_content_size.width = width;
|
||||
window->wl.user_requested_content_size.height = height;
|
||||
int32_t width = 0, height = 0;
|
||||
set_csd_window_geometry(window, &width, &height);
|
||||
window->wl.width = width; window->wl.height = height;
|
||||
resizeFramebuffer(window);
|
||||
ensure_csd_resources(window);
|
||||
wl_surface_commit(window->wl.surface);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1085,13 +924,13 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||
if (window->decorated && !window->monitor && !window->wl.decorations.serverSide)
|
||||
{
|
||||
if (top)
|
||||
*top = _GLFW_DECORATION_TOP;
|
||||
*top = window->wl.decorations.metrics.top;
|
||||
if (left)
|
||||
*left = _GLFW_DECORATION_WIDTH;
|
||||
*left = window->wl.decorations.metrics.width;
|
||||
if (right)
|
||||
*right = _GLFW_DECORATION_WIDTH;
|
||||
*right = window->wl.decorations.metrics.width;
|
||||
if (bottom)
|
||||
*bottom = _GLFW_DECORATION_WIDTH;
|
||||
*bottom = window->wl.decorations.metrics.width;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1121,13 +960,12 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window)
|
||||
{
|
||||
if (window->monitor)
|
||||
xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);
|
||||
if (window->wl.maximized)
|
||||
if (window->wl.toplevel_states & TOPLEVEL_STATE_MAXIMIZED)
|
||||
xdg_toplevel_unset_maximized(window->wl.xdg.toplevel);
|
||||
// There is no way to unset minimized, or even to know if we are
|
||||
// minimized, so there is nothing to do in this case.
|
||||
}
|
||||
_glfwInputWindowMonitor(window, NULL);
|
||||
window->wl.maximized = false;
|
||||
}
|
||||
|
||||
void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
|
||||
@@ -1136,7 +974,6 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
|
||||
{
|
||||
xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
|
||||
}
|
||||
window->wl.maximized = true;
|
||||
}
|
||||
|
||||
void _glfwPlatformShowWindow(_GLFWwindow* window)
|
||||
@@ -1202,7 +1039,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
||||
|
||||
int _glfwPlatformWindowFocused(_GLFWwindow* window)
|
||||
{
|
||||
return _glfw.wl.keyboardFocus == window;
|
||||
return _glfw.wl.keyboardFocusId = window ? window->id : 0;
|
||||
}
|
||||
|
||||
int _glfwPlatformWindowOccluded(_GLFWwindow* window UNUSED)
|
||||
@@ -1224,7 +1061,7 @@ int _glfwPlatformWindowVisible(_GLFWwindow* window)
|
||||
|
||||
int _glfwPlatformWindowMaximized(_GLFWwindow* window)
|
||||
{
|
||||
return window->wl.maximized;
|
||||
return window->wl.toplevel_states & TOPLEVEL_STATE_MAXIMIZED;
|
||||
}
|
||||
|
||||
int _glfwPlatformWindowHovered(_GLFWwindow* window)
|
||||
@@ -1249,9 +1086,9 @@ void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, bool enabled)
|
||||
if (!window->monitor)
|
||||
{
|
||||
if (enabled)
|
||||
createDecorations(window);
|
||||
ensure_csd_resources(window);
|
||||
else
|
||||
destroyDecorations(window);
|
||||
free_csd_surfaces(window);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1350,7 +1187,7 @@ const char* _glfwPlatformGetNativeKeyName(int native_key)
|
||||
return glfw_xkb_keysym_name(native_key);
|
||||
}
|
||||
|
||||
int _glfwPlatformGetNativeKeyForKey(int key)
|
||||
int _glfwPlatformGetNativeKeyForKey(uint32_t key)
|
||||
{
|
||||
return glfw_xkb_sym_for_key(key);
|
||||
}
|
||||
@@ -1359,9 +1196,10 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
const GLFWimage* image,
|
||||
int xhot, int yhot, int count UNUSED)
|
||||
{
|
||||
cursor->wl.buffer = createShmBuffer(image);
|
||||
cursor->wl.buffer = createShmBuffer(image, false, true);
|
||||
if (!cursor->wl.buffer)
|
||||
return false;
|
||||
|
||||
cursor->wl.width = image->width;
|
||||
cursor->wl.height = image->height;
|
||||
cursor->wl.xhot = xhot;
|
||||
@@ -1509,7 +1347,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
|
||||
// If we're not in the correct window just save the cursor
|
||||
// the next time the pointer enters the window the cursor will change
|
||||
if (window != _glfw.wl.pointerFocus || window->wl.decorations.focus != mainWindow)
|
||||
if (window != _glfw.wl.pointerFocus || window->wl.decorations.focus != CENTRAL_WINDOW)
|
||||
return;
|
||||
|
||||
// Unlock possible pointer lock if no longer disabled.
|
||||
@@ -1518,7 +1356,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_NORMAL)
|
||||
{
|
||||
setCursorImage(window);
|
||||
setCursorImage(window, false);
|
||||
}
|
||||
else if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
{
|
||||
@@ -2101,11 +1939,6 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
|
||||
return err;
|
||||
}
|
||||
|
||||
void
|
||||
_glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c, int d) {
|
||||
glfw_xkb_update_ime_state(w, &_glfw.wl.xkb, which, a, b, c, d);
|
||||
}
|
||||
|
||||
static void
|
||||
frame_handle_redraw(void *data, struct wl_callback *callback, uint32_t time UNUSED) {
|
||||
_GLFWwindow* window = (_GLFWwindow*) data;
|
||||
@@ -2116,6 +1949,16 @@ frame_handle_redraw(void *data, struct wl_callback *callback, uint32_t time UNUS
|
||||
wl_callback_destroy(callback);
|
||||
}
|
||||
|
||||
void
|
||||
_glfwPlatformChangeCursorTheme(void) {
|
||||
glfw_wlc_destroy();
|
||||
_GLFWwindow *w = _glfw.windowListHead;
|
||||
while (w) {
|
||||
setCursorImage(w, true);
|
||||
w = w->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW native API //////
|
||||
@@ -2158,3 +2001,12 @@ GLFWAPI unsigned long long glfwDBusUserNotify(const char *app_name, const char*
|
||||
GLFWAPI void glfwDBusSetUserNotificationHandler(GLFWDBusnotificationactivatedfun handler) {
|
||||
glfw_dbus_set_user_notification_activated_handler(handler);
|
||||
}
|
||||
|
||||
GLFWAPI bool glfwWaylandSetTitlebarColor(GLFWwindow *handle, uint32_t color, bool use_system_color) {
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
if (!window->wl.decorations.serverSide) {
|
||||
set_titlebar_color(window, color, use_system_color);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
48
glfw/x11_window.c
vendored
48
glfw/x11_window.c
vendored
@@ -185,6 +185,7 @@ static int translateState(int state)
|
||||
{
|
||||
int mods = 0;
|
||||
|
||||
/* Need some way to expose hyper and meta without xkbcommon-x11 */
|
||||
if (state & ShiftMask)
|
||||
mods |= GLFW_MOD_SHIFT;
|
||||
if (state & ControlMask)
|
||||
@@ -224,7 +225,8 @@ static void sendEventToWM(_GLFWwindow* window, Atom type,
|
||||
|
||||
// Updates the normal hints according to the window settings
|
||||
//
|
||||
static void updateNormalHints(_GLFWwindow* window, int width, int height)
|
||||
static void
|
||||
updateNormalHints(_GLFWwindow* window, int width, int height)
|
||||
{
|
||||
XSizeHints* hints = XAllocSizeHints();
|
||||
|
||||
@@ -257,7 +259,7 @@ static void updateNormalHints(_GLFWwindow* window, int width, int height)
|
||||
}
|
||||
|
||||
if (window->widthincr != GLFW_DONT_CARE &&
|
||||
window->heightincr != GLFW_DONT_CARE)
|
||||
window->heightincr != GLFW_DONT_CARE && !window->x11.maximized)
|
||||
{
|
||||
hints->flags |= PResizeInc;
|
||||
hints->width_inc = window->widthincr;
|
||||
@@ -422,14 +424,18 @@ static char* convertLatin1toUTF8(const char* source)
|
||||
size_t size = 1;
|
||||
const char* sp;
|
||||
|
||||
for (sp = source; *sp; sp++)
|
||||
size += (*sp & 0x80) ? 2 : 1;
|
||||
if (source) {
|
||||
for (sp = source; *sp; sp++)
|
||||
size += (*sp & 0x80) ? 2 : 1;
|
||||
}
|
||||
|
||||
char* target = calloc(size, 1);
|
||||
char* tp = target;
|
||||
|
||||
for (sp = source; *sp; sp++)
|
||||
tp += encodeUTF8(tp, *sp);
|
||||
if (source) {
|
||||
for (sp = source; *sp; sp++)
|
||||
tp += encodeUTF8(tp, *sp);
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
@@ -771,7 +777,7 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request)
|
||||
|
||||
if (j < formatCount)
|
||||
{
|
||||
XChangeProperty(_glfw.x11.display,
|
||||
if (selectionString) XChangeProperty(_glfw.x11.display,
|
||||
request->requestor,
|
||||
targets[i + 1],
|
||||
targets[i],
|
||||
@@ -823,7 +829,7 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request)
|
||||
{
|
||||
// The requested target is one we support
|
||||
|
||||
XChangeProperty(_glfw.x11.display,
|
||||
if (selectionString) XChangeProperty(_glfw.x11.display,
|
||||
request->requestor,
|
||||
request->property,
|
||||
request->target,
|
||||
@@ -954,8 +960,10 @@ static const char* getSelectionString(Atom selection)
|
||||
(XPointer) ¬ification))
|
||||
{
|
||||
monotonic_t time = glfwGetTime();
|
||||
if (time - start > s_to_monotonic_t(2ll))
|
||||
if (time - start > s_to_monotonic_t(2ll)) {
|
||||
free(string);
|
||||
return "";
|
||||
}
|
||||
waitForX11Event(s_to_monotonic_t(2ll) - (time - start));
|
||||
}
|
||||
|
||||
@@ -1518,7 +1526,7 @@ static void processEvent(XEvent *event)
|
||||
count = 3;
|
||||
formats = (Atom*) event->xclient.data.l + 2;
|
||||
}
|
||||
char **atom_names = calloc(count, sizeof(char**));
|
||||
char **atom_names = calloc(count, sizeof(char*));
|
||||
if (atom_names) {
|
||||
get_atom_names(formats, count, atom_names);
|
||||
|
||||
@@ -1737,6 +1745,9 @@ static void processEvent(XEvent *event)
|
||||
if (window->x11.maximized != maximized)
|
||||
{
|
||||
window->x11.maximized = maximized;
|
||||
int width, height;
|
||||
_glfwPlatformGetWindowSize(window, &width, &height);
|
||||
updateNormalHints(window, width, height);
|
||||
_glfwInputWindowMaximize(window, maximized);
|
||||
}
|
||||
}
|
||||
@@ -1984,8 +1995,8 @@ void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
|
||||
for (i = 0; i < count; i++)
|
||||
longCount += 2 + images[i].width * images[i].height;
|
||||
|
||||
long* icon = calloc(longCount, sizeof(long));
|
||||
long* target = icon;
|
||||
unsigned long* icon = calloc(longCount, sizeof(unsigned long));
|
||||
unsigned long* target = icon;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
@@ -1994,10 +2005,9 @@ void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
|
||||
|
||||
for (j = 0; j < images[i].width * images[i].height; j++)
|
||||
{
|
||||
*target++ = (images[i].pixels[j * 4 + 0] << 16) |
|
||||
(images[i].pixels[j * 4 + 1] << 8) |
|
||||
(images[i].pixels[j * 4 + 2] << 0) |
|
||||
(images[i].pixels[j * 4 + 3] << 24);
|
||||
unsigned char *p = images->pixels + j * 4;
|
||||
const unsigned char r = *p++, g = *p++, b = *p++, a = *p++;
|
||||
*target++ = a << 24 | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2772,7 +2782,7 @@ const char* _glfwPlatformGetNativeKeyName(int native_key)
|
||||
return glfw_xkb_keysym_name(native_key);
|
||||
}
|
||||
|
||||
int _glfwPlatformGetNativeKeyForKey(int key)
|
||||
int _glfwPlatformGetNativeKeyForKey(uint32_t key)
|
||||
{
|
||||
return glfw_xkb_sym_for_key(key);
|
||||
}
|
||||
@@ -3080,8 +3090,8 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
|
||||
}
|
||||
|
||||
void
|
||||
_glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c, int d) {
|
||||
glfw_xkb_update_ime_state(w, &_glfw.x11.xkb, which, a, b, c, d);
|
||||
_glfwPlatformUpdateIMEState(_GLFWwindow *w, const GLFWIMEUpdateEvent *ev) {
|
||||
glfw_xkb_update_ime_state(w, &_glfw.x11.xkb, ev);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
838
glfw/xkb-compat-shim.h
vendored
Normal file
838
glfw/xkb-compat-shim.h
vendored
Normal file
@@ -0,0 +1,838 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
// needed for xkbcommon < 1.0
|
||||
|
||||
|
||||
/* We don't use the uint32_t types here, to save some space. */
|
||||
struct codepair {
|
||||
uint16_t keysym;
|
||||
uint16_t ucs;
|
||||
};
|
||||
|
||||
static const struct codepair keysymtab[] = {
|
||||
{ 0x01a1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */
|
||||
{ 0x01a2, 0x02d8 }, /* breve ˘ BREVE */
|
||||
{ 0x01a3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */
|
||||
{ 0x01a5, 0x013d }, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */
|
||||
{ 0x01a6, 0x015a }, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */
|
||||
{ 0x01a9, 0x0160 }, /* Scaron Š LATIN CAPITAL LETTER S WITH CARON */
|
||||
{ 0x01aa, 0x015e }, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */
|
||||
{ 0x01ab, 0x0164 }, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */
|
||||
{ 0x01ac, 0x0179 }, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */
|
||||
{ 0x01ae, 0x017d }, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */
|
||||
{ 0x01af, 0x017b }, /* Zabovedot Ż LATIN CAPITAL LETTER Z WITH DOT ABOVE */
|
||||
{ 0x01b1, 0x0105 }, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */
|
||||
{ 0x01b2, 0x02db }, /* ogonek ˛ OGONEK */
|
||||
{ 0x01b3, 0x0142 }, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */
|
||||
{ 0x01b5, 0x013e }, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */
|
||||
{ 0x01b6, 0x015b }, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */
|
||||
{ 0x01b7, 0x02c7 }, /* caron ˇ CARON */
|
||||
{ 0x01b9, 0x0161 }, /* scaron š LATIN SMALL LETTER S WITH CARON */
|
||||
{ 0x01ba, 0x015f }, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */
|
||||
{ 0x01bb, 0x0165 }, /* tcaron ť LATIN SMALL LETTER T WITH CARON */
|
||||
{ 0x01bc, 0x017a }, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */
|
||||
{ 0x01bd, 0x02dd }, /* doubleacute ˝ DOUBLE ACUTE ACCENT */
|
||||
{ 0x01be, 0x017e }, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */
|
||||
{ 0x01bf, 0x017c }, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */
|
||||
{ 0x01c0, 0x0154 }, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */
|
||||
{ 0x01c3, 0x0102 }, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */
|
||||
{ 0x01c5, 0x0139 }, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */
|
||||
{ 0x01c6, 0x0106 }, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */
|
||||
{ 0x01c8, 0x010c }, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */
|
||||
{ 0x01ca, 0x0118 }, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */
|
||||
{ 0x01cc, 0x011a }, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */
|
||||
{ 0x01cf, 0x010e }, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */
|
||||
{ 0x01d0, 0x0110 }, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */
|
||||
{ 0x01d1, 0x0143 }, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */
|
||||
{ 0x01d2, 0x0147 }, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */
|
||||
{ 0x01d5, 0x0150 }, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */
|
||||
{ 0x01d8, 0x0158 }, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */
|
||||
{ 0x01d9, 0x016e }, /* Uring Ů LATIN CAPITAL LETTER U WITH RING ABOVE */
|
||||
{ 0x01db, 0x0170 }, /* Udoubleacute Ű LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */
|
||||
{ 0x01de, 0x0162 }, /* Tcedilla Ţ LATIN CAPITAL LETTER T WITH CEDILLA */
|
||||
{ 0x01e0, 0x0155 }, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */
|
||||
{ 0x01e3, 0x0103 }, /* abreve ă LATIN SMALL LETTER A WITH BREVE */
|
||||
{ 0x01e5, 0x013a }, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */
|
||||
{ 0x01e6, 0x0107 }, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */
|
||||
{ 0x01e8, 0x010d }, /* ccaron č LATIN SMALL LETTER C WITH CARON */
|
||||
{ 0x01ea, 0x0119 }, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */
|
||||
{ 0x01ec, 0x011b }, /* ecaron ě LATIN SMALL LETTER E WITH CARON */
|
||||
{ 0x01ef, 0x010f }, /* dcaron ď LATIN SMALL LETTER D WITH CARON */
|
||||
{ 0x01f0, 0x0111 }, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */
|
||||
{ 0x01f1, 0x0144 }, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */
|
||||
{ 0x01f2, 0x0148 }, /* ncaron ň LATIN SMALL LETTER N WITH CARON */
|
||||
{ 0x01f5, 0x0151 }, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */
|
||||
{ 0x01f8, 0x0159 }, /* rcaron ř LATIN SMALL LETTER R WITH CARON */
|
||||
{ 0x01f9, 0x016f }, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */
|
||||
{ 0x01fb, 0x0171 }, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */
|
||||
{ 0x01fe, 0x0163 }, /* tcedilla ţ LATIN SMALL LETTER T WITH CEDILLA */
|
||||
{ 0x01ff, 0x02d9 }, /* abovedot ˙ DOT ABOVE */
|
||||
{ 0x02a1, 0x0126 }, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */
|
||||
{ 0x02a6, 0x0124 }, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */
|
||||
{ 0x02a9, 0x0130 }, /* Iabovedot İ LATIN CAPITAL LETTER I WITH DOT ABOVE */
|
||||
{ 0x02ab, 0x011e }, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */
|
||||
{ 0x02ac, 0x0134 }, /* Jcircumflex Ĵ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */
|
||||
{ 0x02b1, 0x0127 }, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */
|
||||
{ 0x02b6, 0x0125 }, /* hcircumflex ĥ LATIN SMALL LETTER H WITH CIRCUMFLEX */
|
||||
{ 0x02b9, 0x0131 }, /* idotless ı LATIN SMALL LETTER DOTLESS I */
|
||||
{ 0x02bb, 0x011f }, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */
|
||||
{ 0x02bc, 0x0135 }, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */
|
||||
{ 0x02c5, 0x010a }, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */
|
||||
{ 0x02c6, 0x0108 }, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */
|
||||
{ 0x02d5, 0x0120 }, /* Gabovedot Ġ LATIN CAPITAL LETTER G WITH DOT ABOVE */
|
||||
{ 0x02d8, 0x011c }, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */
|
||||
{ 0x02dd, 0x016c }, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */
|
||||
{ 0x02de, 0x015c }, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */
|
||||
{ 0x02e5, 0x010b }, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */
|
||||
{ 0x02e6, 0x0109 }, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */
|
||||
{ 0x02f5, 0x0121 }, /* gabovedot ġ LATIN SMALL LETTER G WITH DOT ABOVE */
|
||||
{ 0x02f8, 0x011d }, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */
|
||||
{ 0x02fd, 0x016d }, /* ubreve ŭ LATIN SMALL LETTER U WITH BREVE */
|
||||
{ 0x02fe, 0x015d }, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */
|
||||
{ 0x03a2, 0x0138 }, /* kra ĸ LATIN SMALL LETTER KRA */
|
||||
{ 0x03a3, 0x0156 }, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */
|
||||
{ 0x03a5, 0x0128 }, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */
|
||||
{ 0x03a6, 0x013b }, /* Lcedilla Ļ LATIN CAPITAL LETTER L WITH CEDILLA */
|
||||
{ 0x03aa, 0x0112 }, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */
|
||||
{ 0x03ab, 0x0122 }, /* Gcedilla Ģ LATIN CAPITAL LETTER G WITH CEDILLA */
|
||||
{ 0x03ac, 0x0166 }, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */
|
||||
{ 0x03b3, 0x0157 }, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */
|
||||
{ 0x03b5, 0x0129 }, /* itilde ĩ LATIN SMALL LETTER I WITH TILDE */
|
||||
{ 0x03b6, 0x013c }, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */
|
||||
{ 0x03ba, 0x0113 }, /* emacron ē LATIN SMALL LETTER E WITH MACRON */
|
||||
{ 0x03bb, 0x0123 }, /* gcedilla ģ LATIN SMALL LETTER G WITH CEDILLA */
|
||||
{ 0x03bc, 0x0167 }, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */
|
||||
{ 0x03bd, 0x014a }, /* ENG Ŋ LATIN CAPITAL LETTER ENG */
|
||||
{ 0x03bf, 0x014b }, /* eng ŋ LATIN SMALL LETTER ENG */
|
||||
{ 0x03c0, 0x0100 }, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */
|
||||
{ 0x03c7, 0x012e }, /* Iogonek Į LATIN CAPITAL LETTER I WITH OGONEK */
|
||||
{ 0x03cc, 0x0116 }, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */
|
||||
{ 0x03cf, 0x012a }, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */
|
||||
{ 0x03d1, 0x0145 }, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */
|
||||
{ 0x03d2, 0x014c }, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */
|
||||
{ 0x03d3, 0x0136 }, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */
|
||||
{ 0x03d9, 0x0172 }, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */
|
||||
{ 0x03dd, 0x0168 }, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */
|
||||
{ 0x03de, 0x016a }, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */
|
||||
{ 0x03e0, 0x0101 }, /* amacron ā LATIN SMALL LETTER A WITH MACRON */
|
||||
{ 0x03e7, 0x012f }, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */
|
||||
{ 0x03ec, 0x0117 }, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */
|
||||
{ 0x03ef, 0x012b }, /* imacron ī LATIN SMALL LETTER I WITH MACRON */
|
||||
{ 0x03f1, 0x0146 }, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */
|
||||
{ 0x03f2, 0x014d }, /* omacron ō LATIN SMALL LETTER O WITH MACRON */
|
||||
{ 0x03f3, 0x0137 }, /* kcedilla ķ LATIN SMALL LETTER K WITH CEDILLA */
|
||||
{ 0x03f9, 0x0173 }, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */
|
||||
{ 0x03fd, 0x0169 }, /* utilde ũ LATIN SMALL LETTER U WITH TILDE */
|
||||
{ 0x03fe, 0x016b }, /* umacron ū LATIN SMALL LETTER U WITH MACRON */
|
||||
{ 0x047e, 0x203e }, /* overline ‾ OVERLINE */
|
||||
{ 0x04a1, 0x3002 }, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */
|
||||
{ 0x04a2, 0x300c }, /* kana_openingbracket 「 LEFT CORNER BRACKET */
|
||||
{ 0x04a3, 0x300d }, /* kana_closingbracket 」 RIGHT CORNER BRACKET */
|
||||
{ 0x04a4, 0x3001 }, /* kana_comma 、 IDEOGRAPHIC COMMA */
|
||||
{ 0x04a5, 0x30fb }, /* kana_conjunctive ・ KATAKANA MIDDLE DOT */
|
||||
{ 0x04a6, 0x30f2 }, /* kana_WO ヲ KATAKANA LETTER WO */
|
||||
{ 0x04a7, 0x30a1 }, /* kana_a ァ KATAKANA LETTER SMALL A */
|
||||
{ 0x04a8, 0x30a3 }, /* kana_i ィ KATAKANA LETTER SMALL I */
|
||||
{ 0x04a9, 0x30a5 }, /* kana_u ゥ KATAKANA LETTER SMALL U */
|
||||
{ 0x04aa, 0x30a7 }, /* kana_e ェ KATAKANA LETTER SMALL E */
|
||||
{ 0x04ab, 0x30a9 }, /* kana_o ォ KATAKANA LETTER SMALL O */
|
||||
{ 0x04ac, 0x30e3 }, /* kana_ya ャ KATAKANA LETTER SMALL YA */
|
||||
{ 0x04ad, 0x30e5 }, /* kana_yu ュ KATAKANA LETTER SMALL YU */
|
||||
{ 0x04ae, 0x30e7 }, /* kana_yo ョ KATAKANA LETTER SMALL YO */
|
||||
{ 0x04af, 0x30c3 }, /* kana_tsu ッ KATAKANA LETTER SMALL TU */
|
||||
{ 0x04b0, 0x30fc }, /* prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */
|
||||
{ 0x04b1, 0x30a2 }, /* kana_A ア KATAKANA LETTER A */
|
||||
{ 0x04b2, 0x30a4 }, /* kana_I イ KATAKANA LETTER I */
|
||||
{ 0x04b3, 0x30a6 }, /* kana_U ウ KATAKANA LETTER U */
|
||||
{ 0x04b4, 0x30a8 }, /* kana_E エ KATAKANA LETTER E */
|
||||
{ 0x04b5, 0x30aa }, /* kana_O オ KATAKANA LETTER O */
|
||||
{ 0x04b6, 0x30ab }, /* kana_KA カ KATAKANA LETTER KA */
|
||||
{ 0x04b7, 0x30ad }, /* kana_KI キ KATAKANA LETTER KI */
|
||||
{ 0x04b8, 0x30af }, /* kana_KU ク KATAKANA LETTER KU */
|
||||
{ 0x04b9, 0x30b1 }, /* kana_KE ケ KATAKANA LETTER KE */
|
||||
{ 0x04ba, 0x30b3 }, /* kana_KO コ KATAKANA LETTER KO */
|
||||
{ 0x04bb, 0x30b5 }, /* kana_SA サ KATAKANA LETTER SA */
|
||||
{ 0x04bc, 0x30b7 }, /* kana_SHI シ KATAKANA LETTER SI */
|
||||
{ 0x04bd, 0x30b9 }, /* kana_SU ス KATAKANA LETTER SU */
|
||||
{ 0x04be, 0x30bb }, /* kana_SE セ KATAKANA LETTER SE */
|
||||
{ 0x04bf, 0x30bd }, /* kana_SO ソ KATAKANA LETTER SO */
|
||||
{ 0x04c0, 0x30bf }, /* kana_TA タ KATAKANA LETTER TA */
|
||||
{ 0x04c1, 0x30c1 }, /* kana_CHI チ KATAKANA LETTER TI */
|
||||
{ 0x04c2, 0x30c4 }, /* kana_TSU ツ KATAKANA LETTER TU */
|
||||
{ 0x04c3, 0x30c6 }, /* kana_TE テ KATAKANA LETTER TE */
|
||||
{ 0x04c4, 0x30c8 }, /* kana_TO ト KATAKANA LETTER TO */
|
||||
{ 0x04c5, 0x30ca }, /* kana_NA ナ KATAKANA LETTER NA */
|
||||
{ 0x04c6, 0x30cb }, /* kana_NI ニ KATAKANA LETTER NI */
|
||||
{ 0x04c7, 0x30cc }, /* kana_NU ヌ KATAKANA LETTER NU */
|
||||
{ 0x04c8, 0x30cd }, /* kana_NE ネ KATAKANA LETTER NE */
|
||||
{ 0x04c9, 0x30ce }, /* kana_NO ノ KATAKANA LETTER NO */
|
||||
{ 0x04ca, 0x30cf }, /* kana_HA ハ KATAKANA LETTER HA */
|
||||
{ 0x04cb, 0x30d2 }, /* kana_HI ヒ KATAKANA LETTER HI */
|
||||
{ 0x04cc, 0x30d5 }, /* kana_FU フ KATAKANA LETTER HU */
|
||||
{ 0x04cd, 0x30d8 }, /* kana_HE ヘ KATAKANA LETTER HE */
|
||||
{ 0x04ce, 0x30db }, /* kana_HO ホ KATAKANA LETTER HO */
|
||||
{ 0x04cf, 0x30de }, /* kana_MA マ KATAKANA LETTER MA */
|
||||
{ 0x04d0, 0x30df }, /* kana_MI ミ KATAKANA LETTER MI */
|
||||
{ 0x04d1, 0x30e0 }, /* kana_MU ム KATAKANA LETTER MU */
|
||||
{ 0x04d2, 0x30e1 }, /* kana_ME メ KATAKANA LETTER ME */
|
||||
{ 0x04d3, 0x30e2 }, /* kana_MO モ KATAKANA LETTER MO */
|
||||
{ 0x04d4, 0x30e4 }, /* kana_YA ヤ KATAKANA LETTER YA */
|
||||
{ 0x04d5, 0x30e6 }, /* kana_YU ユ KATAKANA LETTER YU */
|
||||
{ 0x04d6, 0x30e8 }, /* kana_YO ヨ KATAKANA LETTER YO */
|
||||
{ 0x04d7, 0x30e9 }, /* kana_RA ラ KATAKANA LETTER RA */
|
||||
{ 0x04d8, 0x30ea }, /* kana_RI リ KATAKANA LETTER RI */
|
||||
{ 0x04d9, 0x30eb }, /* kana_RU ル KATAKANA LETTER RU */
|
||||
{ 0x04da, 0x30ec }, /* kana_RE レ KATAKANA LETTER RE */
|
||||
{ 0x04db, 0x30ed }, /* kana_RO ロ KATAKANA LETTER RO */
|
||||
{ 0x04dc, 0x30ef }, /* kana_WA ワ KATAKANA LETTER WA */
|
||||
{ 0x04dd, 0x30f3 }, /* kana_N ン KATAKANA LETTER N */
|
||||
{ 0x04de, 0x309b }, /* voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */
|
||||
{ 0x04df, 0x309c }, /* semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */
|
||||
{ 0x05ac, 0x060c }, /* Arabic_comma ، ARABIC COMMA */
|
||||
{ 0x05bb, 0x061b }, /* Arabic_semicolon ؛ ARABIC SEMICOLON */
|
||||
{ 0x05bf, 0x061f }, /* Arabic_question_mark ؟ ARABIC QUESTION MARK */
|
||||
{ 0x05c1, 0x0621 }, /* Arabic_hamza ء ARABIC LETTER HAMZA */
|
||||
{ 0x05c2, 0x0622 }, /* Arabic_maddaonalef آ ARABIC LETTER ALEF WITH MADDA ABOVE */
|
||||
{ 0x05c3, 0x0623 }, /* Arabic_hamzaonalef أ ARABIC LETTER ALEF WITH HAMZA ABOVE */
|
||||
{ 0x05c4, 0x0624 }, /* Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */
|
||||
{ 0x05c5, 0x0625 }, /* Arabic_hamzaunderalef إ ARABIC LETTER ALEF WITH HAMZA BELOW */
|
||||
{ 0x05c6, 0x0626 }, /* Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */
|
||||
{ 0x05c7, 0x0627 }, /* Arabic_alef ا ARABIC LETTER ALEF */
|
||||
{ 0x05c8, 0x0628 }, /* Arabic_beh ب ARABIC LETTER BEH */
|
||||
{ 0x05c9, 0x0629 }, /* Arabic_tehmarbuta ة ARABIC LETTER TEH MARBUTA */
|
||||
{ 0x05ca, 0x062a }, /* Arabic_teh ت ARABIC LETTER TEH */
|
||||
{ 0x05cb, 0x062b }, /* Arabic_theh ث ARABIC LETTER THEH */
|
||||
{ 0x05cc, 0x062c }, /* Arabic_jeem ج ARABIC LETTER JEEM */
|
||||
{ 0x05cd, 0x062d }, /* Arabic_hah ح ARABIC LETTER HAH */
|
||||
{ 0x05ce, 0x062e }, /* Arabic_khah خ ARABIC LETTER KHAH */
|
||||
{ 0x05cf, 0x062f }, /* Arabic_dal د ARABIC LETTER DAL */
|
||||
{ 0x05d0, 0x0630 }, /* Arabic_thal ذ ARABIC LETTER THAL */
|
||||
{ 0x05d1, 0x0631 }, /* Arabic_ra ر ARABIC LETTER REH */
|
||||
{ 0x05d2, 0x0632 }, /* Arabic_zain ز ARABIC LETTER ZAIN */
|
||||
{ 0x05d3, 0x0633 }, /* Arabic_seen س ARABIC LETTER SEEN */
|
||||
{ 0x05d4, 0x0634 }, /* Arabic_sheen ش ARABIC LETTER SHEEN */
|
||||
{ 0x05d5, 0x0635 }, /* Arabic_sad ص ARABIC LETTER SAD */
|
||||
{ 0x05d6, 0x0636 }, /* Arabic_dad ض ARABIC LETTER DAD */
|
||||
{ 0x05d7, 0x0637 }, /* Arabic_tah ط ARABIC LETTER TAH */
|
||||
{ 0x05d8, 0x0638 }, /* Arabic_zah ظ ARABIC LETTER ZAH */
|
||||
{ 0x05d9, 0x0639 }, /* Arabic_ain ع ARABIC LETTER AIN */
|
||||
{ 0x05da, 0x063a }, /* Arabic_ghain غ ARABIC LETTER GHAIN */
|
||||
{ 0x05e0, 0x0640 }, /* Arabic_tatweel ـ ARABIC TATWEEL */
|
||||
{ 0x05e1, 0x0641 }, /* Arabic_feh ف ARABIC LETTER FEH */
|
||||
{ 0x05e2, 0x0642 }, /* Arabic_qaf ق ARABIC LETTER QAF */
|
||||
{ 0x05e3, 0x0643 }, /* Arabic_kaf ك ARABIC LETTER KAF */
|
||||
{ 0x05e4, 0x0644 }, /* Arabic_lam ل ARABIC LETTER LAM */
|
||||
{ 0x05e5, 0x0645 }, /* Arabic_meem م ARABIC LETTER MEEM */
|
||||
{ 0x05e6, 0x0646 }, /* Arabic_noon ن ARABIC LETTER NOON */
|
||||
{ 0x05e7, 0x0647 }, /* Arabic_ha ه ARABIC LETTER HEH */
|
||||
{ 0x05e8, 0x0648 }, /* Arabic_waw و ARABIC LETTER WAW */
|
||||
{ 0x05e9, 0x0649 }, /* Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */
|
||||
{ 0x05ea, 0x064a }, /* Arabic_yeh ي ARABIC LETTER YEH */
|
||||
{ 0x05eb, 0x064b }, /* Arabic_fathatan ً ARABIC FATHATAN */
|
||||
{ 0x05ec, 0x064c }, /* Arabic_dammatan ٌ ARABIC DAMMATAN */
|
||||
{ 0x05ed, 0x064d }, /* Arabic_kasratan ٍ ARABIC KASRATAN */
|
||||
{ 0x05ee, 0x064e }, /* Arabic_fatha َ ARABIC FATHA */
|
||||
{ 0x05ef, 0x064f }, /* Arabic_damma ُ ARABIC DAMMA */
|
||||
{ 0x05f0, 0x0650 }, /* Arabic_kasra ِ ARABIC KASRA */
|
||||
{ 0x05f1, 0x0651 }, /* Arabic_shadda ّ ARABIC SHADDA */
|
||||
{ 0x05f2, 0x0652 }, /* Arabic_sukun ْ ARABIC SUKUN */
|
||||
{ 0x06a1, 0x0452 }, /* Serbian_dje ђ CYRILLIC SMALL LETTER DJE */
|
||||
{ 0x06a2, 0x0453 }, /* Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */
|
||||
{ 0x06a3, 0x0451 }, /* Cyrillic_io ё CYRILLIC SMALL LETTER IO */
|
||||
{ 0x06a4, 0x0454 }, /* Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */
|
||||
{ 0x06a5, 0x0455 }, /* Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */
|
||||
{ 0x06a6, 0x0456 }, /* Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */
|
||||
{ 0x06a7, 0x0457 }, /* Ukrainian_yi ї CYRILLIC SMALL LETTER YI */
|
||||
{ 0x06a8, 0x0458 }, /* Cyrillic_je ј CYRILLIC SMALL LETTER JE */
|
||||
{ 0x06a9, 0x0459 }, /* Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */
|
||||
{ 0x06aa, 0x045a }, /* Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */
|
||||
{ 0x06ab, 0x045b }, /* Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */
|
||||
{ 0x06ac, 0x045c }, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */
|
||||
{ 0x06ad, 0x0491 }, /* Ukrainian_ghe_with_upturn ґ CYRILLIC SMALL LETTER GHE WITH UPTURN */
|
||||
{ 0x06ae, 0x045e }, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */
|
||||
{ 0x06af, 0x045f }, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */
|
||||
{ 0x06b0, 0x2116 }, /* numerosign № NUMERO SIGN */
|
||||
{ 0x06b1, 0x0402 }, /* Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */
|
||||
{ 0x06b2, 0x0403 }, /* Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */
|
||||
{ 0x06b3, 0x0401 }, /* Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */
|
||||
{ 0x06b4, 0x0404 }, /* Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */
|
||||
{ 0x06b5, 0x0405 }, /* Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */
|
||||
{ 0x06b6, 0x0406 }, /* Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */
|
||||
{ 0x06b7, 0x0407 }, /* Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */
|
||||
{ 0x06b8, 0x0408 }, /* Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */
|
||||
{ 0x06b9, 0x0409 }, /* Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */
|
||||
{ 0x06ba, 0x040a }, /* Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */
|
||||
{ 0x06bb, 0x040b }, /* Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */
|
||||
{ 0x06bc, 0x040c }, /* Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */
|
||||
{ 0x06bd, 0x0490 }, /* Ukrainian_GHE_WITH_UPTURN Ґ CYRILLIC CAPITAL LETTER GHE WITH UPTURN */
|
||||
{ 0x06be, 0x040e }, /* Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */
|
||||
{ 0x06bf, 0x040f }, /* Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */
|
||||
{ 0x06c0, 0x044e }, /* Cyrillic_yu ю CYRILLIC SMALL LETTER YU */
|
||||
{ 0x06c1, 0x0430 }, /* Cyrillic_a а CYRILLIC SMALL LETTER A */
|
||||
{ 0x06c2, 0x0431 }, /* Cyrillic_be б CYRILLIC SMALL LETTER BE */
|
||||
{ 0x06c3, 0x0446 }, /* Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */
|
||||
{ 0x06c4, 0x0434 }, /* Cyrillic_de д CYRILLIC SMALL LETTER DE */
|
||||
{ 0x06c5, 0x0435 }, /* Cyrillic_ie е CYRILLIC SMALL LETTER IE */
|
||||
{ 0x06c6, 0x0444 }, /* Cyrillic_ef ф CYRILLIC SMALL LETTER EF */
|
||||
{ 0x06c7, 0x0433 }, /* Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */
|
||||
{ 0x06c8, 0x0445 }, /* Cyrillic_ha х CYRILLIC SMALL LETTER HA */
|
||||
{ 0x06c9, 0x0438 }, /* Cyrillic_i и CYRILLIC SMALL LETTER I */
|
||||
{ 0x06ca, 0x0439 }, /* Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */
|
||||
{ 0x06cb, 0x043a }, /* Cyrillic_ka к CYRILLIC SMALL LETTER KA */
|
||||
{ 0x06cc, 0x043b }, /* Cyrillic_el л CYRILLIC SMALL LETTER EL */
|
||||
{ 0x06cd, 0x043c }, /* Cyrillic_em м CYRILLIC SMALL LETTER EM */
|
||||
{ 0x06ce, 0x043d }, /* Cyrillic_en н CYRILLIC SMALL LETTER EN */
|
||||
{ 0x06cf, 0x043e }, /* Cyrillic_o о CYRILLIC SMALL LETTER O */
|
||||
{ 0x06d0, 0x043f }, /* Cyrillic_pe п CYRILLIC SMALL LETTER PE */
|
||||
{ 0x06d1, 0x044f }, /* Cyrillic_ya я CYRILLIC SMALL LETTER YA */
|
||||
{ 0x06d2, 0x0440 }, /* Cyrillic_er р CYRILLIC SMALL LETTER ER */
|
||||
{ 0x06d3, 0x0441 }, /* Cyrillic_es с CYRILLIC SMALL LETTER ES */
|
||||
{ 0x06d4, 0x0442 }, /* Cyrillic_te т CYRILLIC SMALL LETTER TE */
|
||||
{ 0x06d5, 0x0443 }, /* Cyrillic_u у CYRILLIC SMALL LETTER U */
|
||||
{ 0x06d6, 0x0436 }, /* Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */
|
||||
{ 0x06d7, 0x0432 }, /* Cyrillic_ve в CYRILLIC SMALL LETTER VE */
|
||||
{ 0x06d8, 0x044c }, /* Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */
|
||||
{ 0x06d9, 0x044b }, /* Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */
|
||||
{ 0x06da, 0x0437 }, /* Cyrillic_ze з CYRILLIC SMALL LETTER ZE */
|
||||
{ 0x06db, 0x0448 }, /* Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */
|
||||
{ 0x06dc, 0x044d }, /* Cyrillic_e э CYRILLIC SMALL LETTER E */
|
||||
{ 0x06dd, 0x0449 }, /* Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */
|
||||
{ 0x06de, 0x0447 }, /* Cyrillic_che ч CYRILLIC SMALL LETTER CHE */
|
||||
{ 0x06df, 0x044a }, /* Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */
|
||||
{ 0x06e0, 0x042e }, /* Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */
|
||||
{ 0x06e1, 0x0410 }, /* Cyrillic_A А CYRILLIC CAPITAL LETTER A */
|
||||
{ 0x06e2, 0x0411 }, /* Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */
|
||||
{ 0x06e3, 0x0426 }, /* Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */
|
||||
{ 0x06e4, 0x0414 }, /* Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */
|
||||
{ 0x06e5, 0x0415 }, /* Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */
|
||||
{ 0x06e6, 0x0424 }, /* Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */
|
||||
{ 0x06e7, 0x0413 }, /* Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */
|
||||
{ 0x06e8, 0x0425 }, /* Cyrillic_HA Х CYRILLIC CAPITAL LETTER HA */
|
||||
{ 0x06e9, 0x0418 }, /* Cyrillic_I И CYRILLIC CAPITAL LETTER I */
|
||||
{ 0x06ea, 0x0419 }, /* Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */
|
||||
{ 0x06eb, 0x041a }, /* Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */
|
||||
{ 0x06ec, 0x041b }, /* Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */
|
||||
{ 0x06ed, 0x041c }, /* Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */
|
||||
{ 0x06ee, 0x041d }, /* Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */
|
||||
{ 0x06ef, 0x041e }, /* Cyrillic_O О CYRILLIC CAPITAL LETTER O */
|
||||
{ 0x06f0, 0x041f }, /* Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */
|
||||
{ 0x06f1, 0x042f }, /* Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */
|
||||
{ 0x06f2, 0x0420 }, /* Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */
|
||||
{ 0x06f3, 0x0421 }, /* Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */
|
||||
{ 0x06f4, 0x0422 }, /* Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */
|
||||
{ 0x06f5, 0x0423 }, /* Cyrillic_U У CYRILLIC CAPITAL LETTER U */
|
||||
{ 0x06f6, 0x0416 }, /* Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */
|
||||
{ 0x06f7, 0x0412 }, /* Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */
|
||||
{ 0x06f8, 0x042c }, /* Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */
|
||||
{ 0x06f9, 0x042b }, /* Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */
|
||||
{ 0x06fa, 0x0417 }, /* Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */
|
||||
{ 0x06fb, 0x0428 }, /* Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */
|
||||
{ 0x06fc, 0x042d }, /* Cyrillic_E Э CYRILLIC CAPITAL LETTER E */
|
||||
{ 0x06fd, 0x0429 }, /* Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */
|
||||
{ 0x06fe, 0x0427 }, /* Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */
|
||||
{ 0x06ff, 0x042a }, /* Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */
|
||||
{ 0x07a1, 0x0386 }, /* Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */
|
||||
{ 0x07a2, 0x0388 }, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */
|
||||
{ 0x07a3, 0x0389 }, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */
|
||||
{ 0x07a4, 0x038a }, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */
|
||||
{ 0x07a5, 0x03aa }, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */
|
||||
{ 0x07a7, 0x038c }, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */
|
||||
{ 0x07a8, 0x038e }, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */
|
||||
{ 0x07a9, 0x03ab }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */
|
||||
{ 0x07ab, 0x038f }, /* Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */
|
||||
{ 0x07ae, 0x0385 }, /* Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */
|
||||
{ 0x07af, 0x2015 }, /* Greek_horizbar ― HORIZONTAL BAR */
|
||||
{ 0x07b1, 0x03ac }, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */
|
||||
{ 0x07b2, 0x03ad }, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */
|
||||
{ 0x07b3, 0x03ae }, /* Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */
|
||||
{ 0x07b4, 0x03af }, /* Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */
|
||||
{ 0x07b5, 0x03ca }, /* Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */
|
||||
{ 0x07b6, 0x0390 }, /* Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */
|
||||
{ 0x07b7, 0x03cc }, /* Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */
|
||||
{ 0x07b8, 0x03cd }, /* Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */
|
||||
{ 0x07b9, 0x03cb }, /* Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */
|
||||
{ 0x07ba, 0x03b0 }, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */
|
||||
{ 0x07bb, 0x03ce }, /* Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */
|
||||
{ 0x07c1, 0x0391 }, /* Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */
|
||||
{ 0x07c2, 0x0392 }, /* Greek_BETA Β GREEK CAPITAL LETTER BETA */
|
||||
{ 0x07c3, 0x0393 }, /* Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */
|
||||
{ 0x07c4, 0x0394 }, /* Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */
|
||||
{ 0x07c5, 0x0395 }, /* Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */
|
||||
{ 0x07c6, 0x0396 }, /* Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */
|
||||
{ 0x07c7, 0x0397 }, /* Greek_ETA Η GREEK CAPITAL LETTER ETA */
|
||||
{ 0x07c8, 0x0398 }, /* Greek_THETA Θ GREEK CAPITAL LETTER THETA */
|
||||
{ 0x07c9, 0x0399 }, /* Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */
|
||||
{ 0x07ca, 0x039a }, /* Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */
|
||||
{ 0x07cb, 0x039b }, /* Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */
|
||||
{ 0x07cc, 0x039c }, /* Greek_MU Μ GREEK CAPITAL LETTER MU */
|
||||
{ 0x07cd, 0x039d }, /* Greek_NU Ν GREEK CAPITAL LETTER NU */
|
||||
{ 0x07ce, 0x039e }, /* Greek_XI Ξ GREEK CAPITAL LETTER XI */
|
||||
{ 0x07cf, 0x039f }, /* Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */
|
||||
{ 0x07d0, 0x03a0 }, /* Greek_PI Π GREEK CAPITAL LETTER PI */
|
||||
{ 0x07d1, 0x03a1 }, /* Greek_RHO Ρ GREEK CAPITAL LETTER RHO */
|
||||
{ 0x07d2, 0x03a3 }, /* Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */
|
||||
{ 0x07d4, 0x03a4 }, /* Greek_TAU Τ GREEK CAPITAL LETTER TAU */
|
||||
{ 0x07d5, 0x03a5 }, /* Greek_UPSILON Υ GREEK CAPITAL LETTER UPSILON */
|
||||
{ 0x07d6, 0x03a6 }, /* Greek_PHI Φ GREEK CAPITAL LETTER PHI */
|
||||
{ 0x07d7, 0x03a7 }, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */
|
||||
{ 0x07d8, 0x03a8 }, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */
|
||||
{ 0x07d9, 0x03a9 }, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */
|
||||
{ 0x07e1, 0x03b1 }, /* Greek_alpha α GREEK SMALL LETTER ALPHA */
|
||||
{ 0x07e2, 0x03b2 }, /* Greek_beta β GREEK SMALL LETTER BETA */
|
||||
{ 0x07e3, 0x03b3 }, /* Greek_gamma γ GREEK SMALL LETTER GAMMA */
|
||||
{ 0x07e4, 0x03b4 }, /* Greek_delta δ GREEK SMALL LETTER DELTA */
|
||||
{ 0x07e5, 0x03b5 }, /* Greek_epsilon ε GREEK SMALL LETTER EPSILON */
|
||||
{ 0x07e6, 0x03b6 }, /* Greek_zeta ζ GREEK SMALL LETTER ZETA */
|
||||
{ 0x07e7, 0x03b7 }, /* Greek_eta η GREEK SMALL LETTER ETA */
|
||||
{ 0x07e8, 0x03b8 }, /* Greek_theta θ GREEK SMALL LETTER THETA */
|
||||
{ 0x07e9, 0x03b9 }, /* Greek_iota ι GREEK SMALL LETTER IOTA */
|
||||
{ 0x07ea, 0x03ba }, /* Greek_kappa κ GREEK SMALL LETTER KAPPA */
|
||||
{ 0x07eb, 0x03bb }, /* Greek_lambda λ GREEK SMALL LETTER LAMDA */
|
||||
{ 0x07ec, 0x03bc }, /* Greek_mu μ GREEK SMALL LETTER MU */
|
||||
{ 0x07ed, 0x03bd }, /* Greek_nu ν GREEK SMALL LETTER NU */
|
||||
{ 0x07ee, 0x03be }, /* Greek_xi ξ GREEK SMALL LETTER XI */
|
||||
{ 0x07ef, 0x03bf }, /* Greek_omicron ο GREEK SMALL LETTER OMICRON */
|
||||
{ 0x07f0, 0x03c0 }, /* Greek_pi π GREEK SMALL LETTER PI */
|
||||
{ 0x07f1, 0x03c1 }, /* Greek_rho ρ GREEK SMALL LETTER RHO */
|
||||
{ 0x07f2, 0x03c3 }, /* Greek_sigma σ GREEK SMALL LETTER SIGMA */
|
||||
{ 0x07f3, 0x03c2 }, /* Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */
|
||||
{ 0x07f4, 0x03c4 }, /* Greek_tau τ GREEK SMALL LETTER TAU */
|
||||
{ 0x07f5, 0x03c5 }, /* Greek_upsilon υ GREEK SMALL LETTER UPSILON */
|
||||
{ 0x07f6, 0x03c6 }, /* Greek_phi φ GREEK SMALL LETTER PHI */
|
||||
{ 0x07f7, 0x03c7 }, /* Greek_chi χ GREEK SMALL LETTER CHI */
|
||||
{ 0x07f8, 0x03c8 }, /* Greek_psi ψ GREEK SMALL LETTER PSI */
|
||||
{ 0x07f9, 0x03c9 }, /* Greek_omega ω GREEK SMALL LETTER OMEGA */
|
||||
{ 0x08a1, 0x23b7 }, /* leftradical ⎷ ??? */
|
||||
{ 0x08a2, 0x250c }, /* topleftradical ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */
|
||||
{ 0x08a3, 0x2500 }, /* horizconnector ─ BOX DRAWINGS LIGHT HORIZONTAL */
|
||||
{ 0x08a4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */
|
||||
{ 0x08a5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */
|
||||
{ 0x08a6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */
|
||||
{ 0x08a7, 0x23a1 }, /* topleftsqbracket ⎡ ??? */
|
||||
{ 0x08a8, 0x23a3 }, /* botleftsqbracket ⎣ ??? */
|
||||
{ 0x08a9, 0x23a4 }, /* toprightsqbracket ⎤ ??? */
|
||||
{ 0x08aa, 0x23a6 }, /* botrightsqbracket ⎦ ??? */
|
||||
{ 0x08ab, 0x239b }, /* topleftparens ⎛ ??? */
|
||||
{ 0x08ac, 0x239d }, /* botleftparens ⎝ ??? */
|
||||
{ 0x08ad, 0x239e }, /* toprightparens ⎞ ??? */
|
||||
{ 0x08ae, 0x23a0 }, /* botrightparens ⎠ ??? */
|
||||
{ 0x08af, 0x23a8 }, /* leftmiddlecurlybrace ⎨ ??? */
|
||||
{ 0x08b0, 0x23ac }, /* rightmiddlecurlybrace ⎬ ??? */
|
||||
/* 0x08b1 topleftsummation ? ??? */
|
||||
/* 0x08b2 botleftsummation ? ??? */
|
||||
/* 0x08b3 topvertsummationconnector ? ??? */
|
||||
/* 0x08b4 botvertsummationconnector ? ??? */
|
||||
/* 0x08b5 toprightsummation ? ??? */
|
||||
/* 0x08b6 botrightsummation ? ??? */
|
||||
/* 0x08b7 rightmiddlesummation ? ??? */
|
||||
{ 0x08bc, 0x2264 }, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */
|
||||
{ 0x08bd, 0x2260 }, /* notequal ≠ NOT EQUAL TO */
|
||||
{ 0x08be, 0x2265 }, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */
|
||||
{ 0x08bf, 0x222b }, /* integral ∫ INTEGRAL */
|
||||
{ 0x08c0, 0x2234 }, /* therefore ∴ THEREFORE */
|
||||
{ 0x08c1, 0x221d }, /* variation ∝ PROPORTIONAL TO */
|
||||
{ 0x08c2, 0x221e }, /* infinity ∞ INFINITY */
|
||||
{ 0x08c5, 0x2207 }, /* nabla ∇ NABLA */
|
||||
{ 0x08c8, 0x223c }, /* approximate ∼ TILDE OPERATOR */
|
||||
{ 0x08c9, 0x2243 }, /* similarequal ≃ ASYMPTOTICALLY EQUAL TO */
|
||||
{ 0x08cd, 0x21d4 }, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */
|
||||
{ 0x08ce, 0x21d2 }, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */
|
||||
{ 0x08cf, 0x2261 }, /* identical ≡ IDENTICAL TO */
|
||||
{ 0x08d6, 0x221a }, /* radical √ SQUARE ROOT */
|
||||
{ 0x08da, 0x2282 }, /* includedin ⊂ SUBSET OF */
|
||||
{ 0x08db, 0x2283 }, /* includes ⊃ SUPERSET OF */
|
||||
{ 0x08dc, 0x2229 }, /* intersection ∩ INTERSECTION */
|
||||
{ 0x08dd, 0x222a }, /* union ∪ UNION */
|
||||
{ 0x08de, 0x2227 }, /* logicaland ∧ LOGICAL AND */
|
||||
{ 0x08df, 0x2228 }, /* logicalor ∨ LOGICAL OR */
|
||||
{ 0x08ef, 0x2202 }, /* partialderivative ∂ PARTIAL DIFFERENTIAL */
|
||||
{ 0x08f6, 0x0192 }, /* function ƒ LATIN SMALL LETTER F WITH HOOK */
|
||||
{ 0x08fb, 0x2190 }, /* leftarrow ← LEFTWARDS ARROW */
|
||||
{ 0x08fc, 0x2191 }, /* uparrow ↑ UPWARDS ARROW */
|
||||
{ 0x08fd, 0x2192 }, /* rightarrow → RIGHTWARDS ARROW */
|
||||
{ 0x08fe, 0x2193 }, /* downarrow ↓ DOWNWARDS ARROW */
|
||||
/* 0x09df blank ? ??? */
|
||||
{ 0x09e0, 0x25c6 }, /* soliddiamond ◆ BLACK DIAMOND */
|
||||
{ 0x09e1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */
|
||||
{ 0x09e2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */
|
||||
{ 0x09e3, 0x240c }, /* ff ␌ SYMBOL FOR FORM FEED */
|
||||
{ 0x09e4, 0x240d }, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */
|
||||
{ 0x09e5, 0x240a }, /* lf ␊ SYMBOL FOR LINE FEED */
|
||||
{ 0x09e8, 0x2424 }, /* nl  SYMBOL FOR NEWLINE */
|
||||
{ 0x09e9, 0x240b }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */
|
||||
{ 0x09ea, 0x2518 }, /* lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */
|
||||
{ 0x09eb, 0x2510 }, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */
|
||||
{ 0x09ec, 0x250c }, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */
|
||||
{ 0x09ed, 0x2514 }, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */
|
||||
{ 0x09ee, 0x253c }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
|
||||
{ 0x09ef, 0x23ba }, /* horizlinescan1 ⎺ HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */
|
||||
{ 0x09f0, 0x23bb }, /* horizlinescan3 ⎻ HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */
|
||||
{ 0x09f1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */
|
||||
{ 0x09f2, 0x23bc }, /* horizlinescan7 ⎼ HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */
|
||||
{ 0x09f3, 0x23bd }, /* horizlinescan9 ⎽ HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */
|
||||
{ 0x09f4, 0x251c }, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
|
||||
{ 0x09f5, 0x2524 }, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */
|
||||
{ 0x09f6, 0x2534 }, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */
|
||||
{ 0x09f7, 0x252c }, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
|
||||
{ 0x09f8, 0x2502 }, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */
|
||||
{ 0x0aa1, 0x2003 }, /* emspace EM SPACE */
|
||||
{ 0x0aa2, 0x2002 }, /* enspace EN SPACE */
|
||||
{ 0x0aa3, 0x2004 }, /* em3space THREE-PER-EM SPACE */
|
||||
{ 0x0aa4, 0x2005 }, /* em4space FOUR-PER-EM SPACE */
|
||||
{ 0x0aa5, 0x2007 }, /* digitspace FIGURE SPACE */
|
||||
{ 0x0aa6, 0x2008 }, /* punctspace PUNCTUATION SPACE */
|
||||
{ 0x0aa7, 0x2009 }, /* thinspace THIN SPACE */
|
||||
{ 0x0aa8, 0x200a }, /* hairspace HAIR SPACE */
|
||||
{ 0x0aa9, 0x2014 }, /* emdash — EM DASH */
|
||||
{ 0x0aaa, 0x2013 }, /* endash – EN DASH */
|
||||
{ 0x0aac, 0x2423 }, /* signifblank ␣ OPEN BOX */
|
||||
{ 0x0aae, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */
|
||||
{ 0x0aaf, 0x2025 }, /* doubbaselinedot ‥ TWO DOT LEADER */
|
||||
{ 0x0ab0, 0x2153 }, /* onethird ⅓ VULGAR FRACTION ONE THIRD */
|
||||
{ 0x0ab1, 0x2154 }, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */
|
||||
{ 0x0ab2, 0x2155 }, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */
|
||||
{ 0x0ab3, 0x2156 }, /* twofifths ⅖ VULGAR FRACTION TWO FIFTHS */
|
||||
{ 0x0ab4, 0x2157 }, /* threefifths ⅗ VULGAR FRACTION THREE FIFTHS */
|
||||
{ 0x0ab5, 0x2158 }, /* fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */
|
||||
{ 0x0ab6, 0x2159 }, /* onesixth ⅙ VULGAR FRACTION ONE SIXTH */
|
||||
{ 0x0ab7, 0x215a }, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */
|
||||
{ 0x0ab8, 0x2105 }, /* careof ℅ CARE OF */
|
||||
{ 0x0abb, 0x2012 }, /* figdash ‒ FIGURE DASH */
|
||||
{ 0x0abc, 0x27e8 }, /* leftanglebracket ⟨ MATHEMATICAL LEFT ANGLE BRACKET */
|
||||
{ 0x0abd, 0x002e }, /* decimalpoint . FULL STOP */
|
||||
{ 0x0abe, 0x27e9 }, /* rightanglebracket ⟩ MATHEMATICAL RIGHT ANGLE BRACKET */
|
||||
/* 0x0abf marker ? ??? */
|
||||
{ 0x0ac3, 0x215b }, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */
|
||||
{ 0x0ac4, 0x215c }, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */
|
||||
{ 0x0ac5, 0x215d }, /* fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */
|
||||
{ 0x0ac6, 0x215e }, /* seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */
|
||||
{ 0x0ac9, 0x2122 }, /* trademark ™ TRADE MARK SIGN */
|
||||
{ 0x0aca, 0x2613 }, /* signaturemark ☓ SALTIRE */
|
||||
/* 0x0acb trademarkincircle ? ??? */
|
||||
{ 0x0acc, 0x25c1 }, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */
|
||||
{ 0x0acd, 0x25b7 }, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */
|
||||
{ 0x0ace, 0x25cb }, /* emopencircle ○ WHITE CIRCLE */
|
||||
{ 0x0acf, 0x25af }, /* emopenrectangle ▯ WHITE VERTICAL RECTANGLE */
|
||||
{ 0x0ad0, 0x2018 }, /* leftsinglequotemark ‘ LEFT SINGLE QUOTATION MARK */
|
||||
{ 0x0ad1, 0x2019 }, /* rightsinglequotemark ’ RIGHT SINGLE QUOTATION MARK */
|
||||
{ 0x0ad2, 0x201c }, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */
|
||||
{ 0x0ad3, 0x201d }, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */
|
||||
{ 0x0ad4, 0x211e }, /* prescription ℞ PRESCRIPTION TAKE */
|
||||
{ 0x0ad5, 0x2030 }, /* permille ‰ PER MILLE SIGN */
|
||||
{ 0x0ad6, 0x2032 }, /* minutes ′ PRIME */
|
||||
{ 0x0ad7, 0x2033 }, /* seconds ″ DOUBLE PRIME */
|
||||
{ 0x0ad9, 0x271d }, /* latincross ✝ LATIN CROSS */
|
||||
/* 0x0ada hexagram ? ??? */
|
||||
{ 0x0adb, 0x25ac }, /* filledrectbullet ▬ BLACK RECTANGLE */
|
||||
{ 0x0adc, 0x25c0 }, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */
|
||||
{ 0x0add, 0x25b6 }, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */
|
||||
{ 0x0ade, 0x25cf }, /* emfilledcircle ● BLACK CIRCLE */
|
||||
{ 0x0adf, 0x25ae }, /* emfilledrect ▮ BLACK VERTICAL RECTANGLE */
|
||||
{ 0x0ae0, 0x25e6 }, /* enopencircbullet ◦ WHITE BULLET */
|
||||
{ 0x0ae1, 0x25ab }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */
|
||||
{ 0x0ae2, 0x25ad }, /* openrectbullet ▭ WHITE RECTANGLE */
|
||||
{ 0x0ae3, 0x25b3 }, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */
|
||||
{ 0x0ae4, 0x25bd }, /* opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */
|
||||
{ 0x0ae5, 0x2606 }, /* openstar ☆ WHITE STAR */
|
||||
{ 0x0ae6, 0x2022 }, /* enfilledcircbullet • BULLET */
|
||||
{ 0x0ae7, 0x25aa }, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */
|
||||
{ 0x0ae8, 0x25b2 }, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */
|
||||
{ 0x0ae9, 0x25bc }, /* filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */
|
||||
{ 0x0aea, 0x261c }, /* leftpointer ☜ WHITE LEFT POINTING INDEX */
|
||||
{ 0x0aeb, 0x261e }, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */
|
||||
{ 0x0aec, 0x2663 }, /* club ♣ BLACK CLUB SUIT */
|
||||
{ 0x0aed, 0x2666 }, /* diamond ♦ BLACK DIAMOND SUIT */
|
||||
{ 0x0aee, 0x2665 }, /* heart ♥ BLACK HEART SUIT */
|
||||
{ 0x0af0, 0x2720 }, /* maltesecross ✠ MALTESE CROSS */
|
||||
{ 0x0af1, 0x2020 }, /* dagger † DAGGER */
|
||||
{ 0x0af2, 0x2021 }, /* doubledagger ‡ DOUBLE DAGGER */
|
||||
{ 0x0af3, 0x2713 }, /* checkmark ✓ CHECK MARK */
|
||||
{ 0x0af4, 0x2717 }, /* ballotcross ✗ BALLOT X */
|
||||
{ 0x0af5, 0x266f }, /* musicalsharp ♯ MUSIC SHARP SIGN */
|
||||
{ 0x0af6, 0x266d }, /* musicalflat ♭ MUSIC FLAT SIGN */
|
||||
{ 0x0af7, 0x2642 }, /* malesymbol ♂ MALE SIGN */
|
||||
{ 0x0af8, 0x2640 }, /* femalesymbol ♀ FEMALE SIGN */
|
||||
{ 0x0af9, 0x260e }, /* telephone ☎ BLACK TELEPHONE */
|
||||
{ 0x0afa, 0x2315 }, /* telephonerecorder ⌕ TELEPHONE RECORDER */
|
||||
{ 0x0afb, 0x2117 }, /* phonographcopyright ℗ SOUND RECORDING COPYRIGHT */
|
||||
{ 0x0afc, 0x2038 }, /* caret ‸ CARET */
|
||||
{ 0x0afd, 0x201a }, /* singlelowquotemark ‚ SINGLE LOW-9 QUOTATION MARK */
|
||||
{ 0x0afe, 0x201e }, /* doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */
|
||||
/* 0x0aff cursor ? ??? */
|
||||
{ 0x0ba3, 0x003c }, /* leftcaret < LESS-THAN SIGN */
|
||||
{ 0x0ba6, 0x003e }, /* rightcaret > GREATER-THAN SIGN */
|
||||
{ 0x0ba8, 0x2228 }, /* downcaret ∨ LOGICAL OR */
|
||||
{ 0x0ba9, 0x2227 }, /* upcaret ∧ LOGICAL AND */
|
||||
{ 0x0bc0, 0x00af }, /* overbar ¯ MACRON */
|
||||
{ 0x0bc2, 0x22a4 }, /* downtack ⊤ DOWN TACK */
|
||||
{ 0x0bc3, 0x2229 }, /* upshoe ∩ INTERSECTION */
|
||||
{ 0x0bc4, 0x230a }, /* downstile ⌊ LEFT FLOOR */
|
||||
{ 0x0bc6, 0x005f }, /* underbar _ LOW LINE */
|
||||
{ 0x0bca, 0x2218 }, /* jot ∘ RING OPERATOR */
|
||||
{ 0x0bcc, 0x2395 }, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD (Unicode 3.0) */
|
||||
{ 0x0bce, 0x22a5 }, /* uptack ⊥ UP TACK */
|
||||
{ 0x0bcf, 0x25cb }, /* circle ○ WHITE CIRCLE */
|
||||
{ 0x0bd3, 0x2308 }, /* upstile ⌈ LEFT CEILING */
|
||||
{ 0x0bd6, 0x222a }, /* downshoe ∪ UNION */
|
||||
{ 0x0bd8, 0x2283 }, /* rightshoe ⊃ SUPERSET OF */
|
||||
{ 0x0bda, 0x2282 }, /* leftshoe ⊂ SUBSET OF */
|
||||
{ 0x0bdc, 0x22a2 }, /* lefttack ⊢ RIGHT TACK */
|
||||
{ 0x0bfc, 0x22a3 }, /* righttack ⊣ LEFT TACK */
|
||||
{ 0x0cdf, 0x2017 }, /* hebrew_doublelowline ‗ DOUBLE LOW LINE */
|
||||
{ 0x0ce0, 0x05d0 }, /* hebrew_aleph א HEBREW LETTER ALEF */
|
||||
{ 0x0ce1, 0x05d1 }, /* hebrew_bet ב HEBREW LETTER BET */
|
||||
{ 0x0ce2, 0x05d2 }, /* hebrew_gimel ג HEBREW LETTER GIMEL */
|
||||
{ 0x0ce3, 0x05d3 }, /* hebrew_dalet ד HEBREW LETTER DALET */
|
||||
{ 0x0ce4, 0x05d4 }, /* hebrew_he ה HEBREW LETTER HE */
|
||||
{ 0x0ce5, 0x05d5 }, /* hebrew_waw ו HEBREW LETTER VAV */
|
||||
{ 0x0ce6, 0x05d6 }, /* hebrew_zain ז HEBREW LETTER ZAYIN */
|
||||
{ 0x0ce7, 0x05d7 }, /* hebrew_chet ח HEBREW LETTER HET */
|
||||
{ 0x0ce8, 0x05d8 }, /* hebrew_tet ט HEBREW LETTER TET */
|
||||
{ 0x0ce9, 0x05d9 }, /* hebrew_yod י HEBREW LETTER YOD */
|
||||
{ 0x0cea, 0x05da }, /* hebrew_finalkaph ך HEBREW LETTER FINAL KAF */
|
||||
{ 0x0ceb, 0x05db }, /* hebrew_kaph כ HEBREW LETTER KAF */
|
||||
{ 0x0cec, 0x05dc }, /* hebrew_lamed ל HEBREW LETTER LAMED */
|
||||
{ 0x0ced, 0x05dd }, /* hebrew_finalmem ם HEBREW LETTER FINAL MEM */
|
||||
{ 0x0cee, 0x05de }, /* hebrew_mem מ HEBREW LETTER MEM */
|
||||
{ 0x0cef, 0x05df }, /* hebrew_finalnun ן HEBREW LETTER FINAL NUN */
|
||||
{ 0x0cf0, 0x05e0 }, /* hebrew_nun נ HEBREW LETTER NUN */
|
||||
{ 0x0cf1, 0x05e1 }, /* hebrew_samech ס HEBREW LETTER SAMEKH */
|
||||
{ 0x0cf2, 0x05e2 }, /* hebrew_ayin ע HEBREW LETTER AYIN */
|
||||
{ 0x0cf3, 0x05e3 }, /* hebrew_finalpe ף HEBREW LETTER FINAL PE */
|
||||
{ 0x0cf4, 0x05e4 }, /* hebrew_pe פ HEBREW LETTER PE */
|
||||
{ 0x0cf5, 0x05e5 }, /* hebrew_finalzade ץ HEBREW LETTER FINAL TSADI */
|
||||
{ 0x0cf6, 0x05e6 }, /* hebrew_zade צ HEBREW LETTER TSADI */
|
||||
{ 0x0cf7, 0x05e7 }, /* hebrew_qoph ק HEBREW LETTER QOF */
|
||||
{ 0x0cf8, 0x05e8 }, /* hebrew_resh ר HEBREW LETTER RESH */
|
||||
{ 0x0cf9, 0x05e9 }, /* hebrew_shin ש HEBREW LETTER SHIN */
|
||||
{ 0x0cfa, 0x05ea }, /* hebrew_taw ת HEBREW LETTER TAV */
|
||||
{ 0x0da1, 0x0e01 }, /* Thai_kokai ก THAI CHARACTER KO KAI */
|
||||
{ 0x0da2, 0x0e02 }, /* Thai_khokhai ข THAI CHARACTER KHO KHAI */
|
||||
{ 0x0da3, 0x0e03 }, /* Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */
|
||||
{ 0x0da4, 0x0e04 }, /* Thai_khokhwai ค THAI CHARACTER KHO KHWAI */
|
||||
{ 0x0da5, 0x0e05 }, /* Thai_khokhon ฅ THAI CHARACTER KHO KHON */
|
||||
{ 0x0da6, 0x0e06 }, /* Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */
|
||||
{ 0x0da7, 0x0e07 }, /* Thai_ngongu ง THAI CHARACTER NGO NGU */
|
||||
{ 0x0da8, 0x0e08 }, /* Thai_chochan จ THAI CHARACTER CHO CHAN */
|
||||
{ 0x0da9, 0x0e09 }, /* Thai_choching ฉ THAI CHARACTER CHO CHING */
|
||||
{ 0x0daa, 0x0e0a }, /* Thai_chochang ช THAI CHARACTER CHO CHANG */
|
||||
{ 0x0dab, 0x0e0b }, /* Thai_soso ซ THAI CHARACTER SO SO */
|
||||
{ 0x0dac, 0x0e0c }, /* Thai_chochoe ฌ THAI CHARACTER CHO CHOE */
|
||||
{ 0x0dad, 0x0e0d }, /* Thai_yoying ญ THAI CHARACTER YO YING */
|
||||
{ 0x0dae, 0x0e0e }, /* Thai_dochada ฎ THAI CHARACTER DO CHADA */
|
||||
{ 0x0daf, 0x0e0f }, /* Thai_topatak ฏ THAI CHARACTER TO PATAK */
|
||||
{ 0x0db0, 0x0e10 }, /* Thai_thothan ฐ THAI CHARACTER THO THAN */
|
||||
{ 0x0db1, 0x0e11 }, /* Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */
|
||||
{ 0x0db2, 0x0e12 }, /* Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */
|
||||
{ 0x0db3, 0x0e13 }, /* Thai_nonen ณ THAI CHARACTER NO NEN */
|
||||
{ 0x0db4, 0x0e14 }, /* Thai_dodek ด THAI CHARACTER DO DEK */
|
||||
{ 0x0db5, 0x0e15 }, /* Thai_totao ต THAI CHARACTER TO TAO */
|
||||
{ 0x0db6, 0x0e16 }, /* Thai_thothung ถ THAI CHARACTER THO THUNG */
|
||||
{ 0x0db7, 0x0e17 }, /* Thai_thothahan ท THAI CHARACTER THO THAHAN */
|
||||
{ 0x0db8, 0x0e18 }, /* Thai_thothong ธ THAI CHARACTER THO THONG */
|
||||
{ 0x0db9, 0x0e19 }, /* Thai_nonu น THAI CHARACTER NO NU */
|
||||
{ 0x0dba, 0x0e1a }, /* Thai_bobaimai บ THAI CHARACTER BO BAIMAI */
|
||||
{ 0x0dbb, 0x0e1b }, /* Thai_popla ป THAI CHARACTER PO PLA */
|
||||
{ 0x0dbc, 0x0e1c }, /* Thai_phophung ผ THAI CHARACTER PHO PHUNG */
|
||||
{ 0x0dbd, 0x0e1d }, /* Thai_fofa ฝ THAI CHARACTER FO FA */
|
||||
{ 0x0dbe, 0x0e1e }, /* Thai_phophan พ THAI CHARACTER PHO PHAN */
|
||||
{ 0x0dbf, 0x0e1f }, /* Thai_fofan ฟ THAI CHARACTER FO FAN */
|
||||
{ 0x0dc0, 0x0e20 }, /* Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */
|
||||
{ 0x0dc1, 0x0e21 }, /* Thai_moma ม THAI CHARACTER MO MA */
|
||||
{ 0x0dc2, 0x0e22 }, /* Thai_yoyak ย THAI CHARACTER YO YAK */
|
||||
{ 0x0dc3, 0x0e23 }, /* Thai_rorua ร THAI CHARACTER RO RUA */
|
||||
{ 0x0dc4, 0x0e24 }, /* Thai_ru ฤ THAI CHARACTER RU */
|
||||
{ 0x0dc5, 0x0e25 }, /* Thai_loling ล THAI CHARACTER LO LING */
|
||||
{ 0x0dc6, 0x0e26 }, /* Thai_lu ฦ THAI CHARACTER LU */
|
||||
{ 0x0dc7, 0x0e27 }, /* Thai_wowaen ว THAI CHARACTER WO WAEN */
|
||||
{ 0x0dc8, 0x0e28 }, /* Thai_sosala ศ THAI CHARACTER SO SALA */
|
||||
{ 0x0dc9, 0x0e29 }, /* Thai_sorusi ษ THAI CHARACTER SO RUSI */
|
||||
{ 0x0dca, 0x0e2a }, /* Thai_sosua ส THAI CHARACTER SO SUA */
|
||||
{ 0x0dcb, 0x0e2b }, /* Thai_hohip ห THAI CHARACTER HO HIP */
|
||||
{ 0x0dcc, 0x0e2c }, /* Thai_lochula ฬ THAI CHARACTER LO CHULA */
|
||||
{ 0x0dcd, 0x0e2d }, /* Thai_oang อ THAI CHARACTER O ANG */
|
||||
{ 0x0dce, 0x0e2e }, /* Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */
|
||||
{ 0x0dcf, 0x0e2f }, /* Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */
|
||||
{ 0x0dd0, 0x0e30 }, /* Thai_saraa ะ THAI CHARACTER SARA A */
|
||||
{ 0x0dd1, 0x0e31 }, /* Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */
|
||||
{ 0x0dd2, 0x0e32 }, /* Thai_saraaa า THAI CHARACTER SARA AA */
|
||||
{ 0x0dd3, 0x0e33 }, /* Thai_saraam ำ THAI CHARACTER SARA AM */
|
||||
{ 0x0dd4, 0x0e34 }, /* Thai_sarai ิ THAI CHARACTER SARA I */
|
||||
{ 0x0dd5, 0x0e35 }, /* Thai_saraii ี THAI CHARACTER SARA II */
|
||||
{ 0x0dd6, 0x0e36 }, /* Thai_saraue ึ THAI CHARACTER SARA UE */
|
||||
{ 0x0dd7, 0x0e37 }, /* Thai_sarauee ื THAI CHARACTER SARA UEE */
|
||||
{ 0x0dd8, 0x0e38 }, /* Thai_sarau ุ THAI CHARACTER SARA U */
|
||||
{ 0x0dd9, 0x0e39 }, /* Thai_sarauu ู THAI CHARACTER SARA UU */
|
||||
{ 0x0dda, 0x0e3a }, /* Thai_phinthu ฺ THAI CHARACTER PHINTHU */
|
||||
{ 0x0dde, 0x0e3e }, /* Thai_maihanakat_maitho ??? */
|
||||
{ 0x0ddf, 0x0e3f }, /* Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */
|
||||
{ 0x0de0, 0x0e40 }, /* Thai_sarae เ THAI CHARACTER SARA E */
|
||||
{ 0x0de1, 0x0e41 }, /* Thai_saraae แ THAI CHARACTER SARA AE */
|
||||
{ 0x0de2, 0x0e42 }, /* Thai_sarao โ THAI CHARACTER SARA O */
|
||||
{ 0x0de3, 0x0e43 }, /* Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */
|
||||
{ 0x0de4, 0x0e44 }, /* Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */
|
||||
{ 0x0de5, 0x0e45 }, /* Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */
|
||||
{ 0x0de6, 0x0e46 }, /* Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */
|
||||
{ 0x0de7, 0x0e47 }, /* Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */
|
||||
{ 0x0de8, 0x0e48 }, /* Thai_maiek ่ THAI CHARACTER MAI EK */
|
||||
{ 0x0de9, 0x0e49 }, /* Thai_maitho ้ THAI CHARACTER MAI THO */
|
||||
{ 0x0dea, 0x0e4a }, /* Thai_maitri ๊ THAI CHARACTER MAI TRI */
|
||||
{ 0x0deb, 0x0e4b }, /* Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */
|
||||
{ 0x0dec, 0x0e4c }, /* Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */
|
||||
{ 0x0ded, 0x0e4d }, /* Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */
|
||||
{ 0x0df0, 0x0e50 }, /* Thai_leksun ๐ THAI DIGIT ZERO */
|
||||
{ 0x0df1, 0x0e51 }, /* Thai_leknung ๑ THAI DIGIT ONE */
|
||||
{ 0x0df2, 0x0e52 }, /* Thai_leksong ๒ THAI DIGIT TWO */
|
||||
{ 0x0df3, 0x0e53 }, /* Thai_leksam ๓ THAI DIGIT THREE */
|
||||
{ 0x0df4, 0x0e54 }, /* Thai_leksi ๔ THAI DIGIT FOUR */
|
||||
{ 0x0df5, 0x0e55 }, /* Thai_lekha ๕ THAI DIGIT FIVE */
|
||||
{ 0x0df6, 0x0e56 }, /* Thai_lekhok ๖ THAI DIGIT SIX */
|
||||
{ 0x0df7, 0x0e57 }, /* Thai_lekchet ๗ THAI DIGIT SEVEN */
|
||||
{ 0x0df8, 0x0e58 }, /* Thai_lekpaet ๘ THAI DIGIT EIGHT */
|
||||
{ 0x0df9, 0x0e59 }, /* Thai_lekkao ๙ THAI DIGIT NINE */
|
||||
{ 0x0ea1, 0x3131 }, /* Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */
|
||||
{ 0x0ea2, 0x3132 }, /* Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */
|
||||
{ 0x0ea3, 0x3133 }, /* Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */
|
||||
{ 0x0ea4, 0x3134 }, /* Hangul_Nieun ㄴ HANGUL LETTER NIEUN */
|
||||
{ 0x0ea5, 0x3135 }, /* Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */
|
||||
{ 0x0ea6, 0x3136 }, /* Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */
|
||||
{ 0x0ea7, 0x3137 }, /* Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */
|
||||
{ 0x0ea8, 0x3138 }, /* Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */
|
||||
{ 0x0ea9, 0x3139 }, /* Hangul_Rieul ㄹ HANGUL LETTER RIEUL */
|
||||
{ 0x0eaa, 0x313a }, /* Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */
|
||||
{ 0x0eab, 0x313b }, /* Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */
|
||||
{ 0x0eac, 0x313c }, /* Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */
|
||||
{ 0x0ead, 0x313d }, /* Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */
|
||||
{ 0x0eae, 0x313e }, /* Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */
|
||||
{ 0x0eaf, 0x313f }, /* Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */
|
||||
{ 0x0eb0, 0x3140 }, /* Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */
|
||||
{ 0x0eb1, 0x3141 }, /* Hangul_Mieum ㅁ HANGUL LETTER MIEUM */
|
||||
{ 0x0eb2, 0x3142 }, /* Hangul_Pieub ㅂ HANGUL LETTER PIEUP */
|
||||
{ 0x0eb3, 0x3143 }, /* Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */
|
||||
{ 0x0eb4, 0x3144 }, /* Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */
|
||||
{ 0x0eb5, 0x3145 }, /* Hangul_Sios ㅅ HANGUL LETTER SIOS */
|
||||
{ 0x0eb6, 0x3146 }, /* Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */
|
||||
{ 0x0eb7, 0x3147 }, /* Hangul_Ieung ㅇ HANGUL LETTER IEUNG */
|
||||
{ 0x0eb8, 0x3148 }, /* Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */
|
||||
{ 0x0eb9, 0x3149 }, /* Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */
|
||||
{ 0x0eba, 0x314a }, /* Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */
|
||||
{ 0x0ebb, 0x314b }, /* Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */
|
||||
{ 0x0ebc, 0x314c }, /* Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */
|
||||
{ 0x0ebd, 0x314d }, /* Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */
|
||||
{ 0x0ebe, 0x314e }, /* Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */
|
||||
{ 0x0ebf, 0x314f }, /* Hangul_A ㅏ HANGUL LETTER A */
|
||||
{ 0x0ec0, 0x3150 }, /* Hangul_AE ㅐ HANGUL LETTER AE */
|
||||
{ 0x0ec1, 0x3151 }, /* Hangul_YA ㅑ HANGUL LETTER YA */
|
||||
{ 0x0ec2, 0x3152 }, /* Hangul_YAE ㅒ HANGUL LETTER YAE */
|
||||
{ 0x0ec3, 0x3153 }, /* Hangul_EO ㅓ HANGUL LETTER EO */
|
||||
{ 0x0ec4, 0x3154 }, /* Hangul_E ㅔ HANGUL LETTER E */
|
||||
{ 0x0ec5, 0x3155 }, /* Hangul_YEO ㅕ HANGUL LETTER YEO */
|
||||
{ 0x0ec6, 0x3156 }, /* Hangul_YE ㅖ HANGUL LETTER YE */
|
||||
{ 0x0ec7, 0x3157 }, /* Hangul_O ㅗ HANGUL LETTER O */
|
||||
{ 0x0ec8, 0x3158 }, /* Hangul_WA ㅘ HANGUL LETTER WA */
|
||||
{ 0x0ec9, 0x3159 }, /* Hangul_WAE ㅙ HANGUL LETTER WAE */
|
||||
{ 0x0eca, 0x315a }, /* Hangul_OE ㅚ HANGUL LETTER OE */
|
||||
{ 0x0ecb, 0x315b }, /* Hangul_YO ㅛ HANGUL LETTER YO */
|
||||
{ 0x0ecc, 0x315c }, /* Hangul_U ㅜ HANGUL LETTER U */
|
||||
{ 0x0ecd, 0x315d }, /* Hangul_WEO ㅝ HANGUL LETTER WEO */
|
||||
{ 0x0ece, 0x315e }, /* Hangul_WE ㅞ HANGUL LETTER WE */
|
||||
{ 0x0ecf, 0x315f }, /* Hangul_WI ㅟ HANGUL LETTER WI */
|
||||
{ 0x0ed0, 0x3160 }, /* Hangul_YU ㅠ HANGUL LETTER YU */
|
||||
{ 0x0ed1, 0x3161 }, /* Hangul_EU ㅡ HANGUL LETTER EU */
|
||||
{ 0x0ed2, 0x3162 }, /* Hangul_YI ㅢ HANGUL LETTER YI */
|
||||
{ 0x0ed3, 0x3163 }, /* Hangul_I ㅣ HANGUL LETTER I */
|
||||
{ 0x0ed4, 0x11a8 }, /* Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */
|
||||
{ 0x0ed5, 0x11a9 }, /* Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */
|
||||
{ 0x0ed6, 0x11aa }, /* Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */
|
||||
{ 0x0ed7, 0x11ab }, /* Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */
|
||||
{ 0x0ed8, 0x11ac }, /* Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */
|
||||
{ 0x0ed9, 0x11ad }, /* Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */
|
||||
{ 0x0eda, 0x11ae }, /* Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */
|
||||
{ 0x0edb, 0x11af }, /* Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */
|
||||
{ 0x0edc, 0x11b0 }, /* Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */
|
||||
{ 0x0edd, 0x11b1 }, /* Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */
|
||||
{ 0x0ede, 0x11b2 }, /* Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */
|
||||
{ 0x0edf, 0x11b3 }, /* Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */
|
||||
{ 0x0ee0, 0x11b4 }, /* Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */
|
||||
{ 0x0ee1, 0x11b5 }, /* Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */
|
||||
{ 0x0ee2, 0x11b6 }, /* Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */
|
||||
{ 0x0ee3, 0x11b7 }, /* Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */
|
||||
{ 0x0ee4, 0x11b8 }, /* Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */
|
||||
{ 0x0ee5, 0x11b9 }, /* Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */
|
||||
{ 0x0ee6, 0x11ba }, /* Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */
|
||||
{ 0x0ee7, 0x11bb }, /* Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */
|
||||
{ 0x0ee8, 0x11bc }, /* Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */
|
||||
{ 0x0ee9, 0x11bd }, /* Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */
|
||||
{ 0x0eea, 0x11be }, /* Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */
|
||||
{ 0x0eeb, 0x11bf }, /* Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */
|
||||
{ 0x0eec, 0x11c0 }, /* Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */
|
||||
{ 0x0eed, 0x11c1 }, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */
|
||||
{ 0x0eee, 0x11c2 }, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */
|
||||
{ 0x0eef, 0x316d }, /* Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */
|
||||
{ 0x0ef0, 0x3171 }, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */
|
||||
{ 0x0ef1, 0x3178 }, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */
|
||||
{ 0x0ef2, 0x317f }, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */
|
||||
/* 0x0ef3 Hangul_KkogjiDalrinIeung ? ??? */
|
||||
{ 0x0ef4, 0x3184 }, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */
|
||||
{ 0x0ef5, 0x3186 }, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */
|
||||
{ 0x0ef6, 0x318d }, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */
|
||||
{ 0x0ef7, 0x318e }, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */
|
||||
{ 0x0ef8, 0x11eb }, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */
|
||||
{ 0x0ef9, 0x11f0 }, /* Hangul_J_KkogjiDalrinIeung ᇰ HANGUL JONGSEONG YESIEUNG */
|
||||
{ 0x0efa, 0x11f9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */
|
||||
{ 0x0eff, 0x20a9 }, /* Korean_Won ₩ WON SIGN */
|
||||
{ 0x13a4, 0x20ac }, /* Euro € EURO SIGN */
|
||||
{ 0x13bc, 0x0152 }, /* OE Œ LATIN CAPITAL LIGATURE OE */
|
||||
{ 0x13bd, 0x0153 }, /* oe œ LATIN SMALL LIGATURE OE */
|
||||
{ 0x13be, 0x0178 }, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */
|
||||
{ 0x20a0, 0x20a0 }, /* EcuSign ₠ EURO-CURRENCY SIGN */
|
||||
{ 0x20a1, 0x20a1 }, /* ColonSign ₡ COLON SIGN */
|
||||
{ 0x20a2, 0x20a2 }, /* CruzeiroSign ₢ CRUZEIRO SIGN */
|
||||
{ 0x20a3, 0x20a3 }, /* FFrancSign ₣ FRENCH FRANC SIGN */
|
||||
{ 0x20a4, 0x20a4 }, /* LiraSign ₤ LIRA SIGN */
|
||||
{ 0x20a5, 0x20a5 }, /* MillSign ₥ MILL SIGN */
|
||||
{ 0x20a6, 0x20a6 }, /* NairaSign ₦ NAIRA SIGN */
|
||||
{ 0x20a7, 0x20a7 }, /* PesetaSign ₧ PESETA SIGN */
|
||||
{ 0x20a8, 0x20a8 }, /* RupeeSign ₨ RUPEE SIGN */
|
||||
{ 0x20a9, 0x20a9 }, /* WonSign ₩ WON SIGN */
|
||||
{ 0x20aa, 0x20aa }, /* NewSheqelSign ₪ NEW SHEQEL SIGN */
|
||||
{ 0x20ab, 0x20ab }, /* DongSign ₫ DONG SIGN */
|
||||
{ 0x20ac, 0x20ac }, /* EuroSign € EURO SIGN */
|
||||
};
|
||||
|
||||
xkb_keysym_t
|
||||
utf32_to_keysym(uint32_t ucs)
|
||||
{
|
||||
/* first check for Latin-1 characters (1:1 mapping) */
|
||||
if ((ucs >= 0x0020 && ucs <= 0x007e) ||
|
||||
(ucs >= 0x00a0 && ucs <= 0x00ff))
|
||||
return ucs;
|
||||
|
||||
/* special keysyms */
|
||||
if ((ucs >= (XKB_KEY_BackSpace & 0x7f) && ucs <= (XKB_KEY_Clear & 0x7f)) ||
|
||||
ucs == (XKB_KEY_Return & 0x7f) || ucs == (XKB_KEY_Escape & 0x7f))
|
||||
return ucs | 0xff00;
|
||||
if (ucs == (XKB_KEY_Delete & 0x7f))
|
||||
return XKB_KEY_Delete;
|
||||
|
||||
/* Unicode non-symbols and code points outside Unicode planes */
|
||||
if ((ucs >= 0xfdd0 && ucs <= 0xfdef) ||
|
||||
ucs > 0x10ffff || (ucs & 0xfffe) == 0xfffe)
|
||||
return XKB_KEY_NoSymbol;
|
||||
|
||||
/* search main table */
|
||||
for (size_t i = 0; i < sizeof(keysymtab)/sizeof(keysymtab[0]); i++)
|
||||
if (keysymtab[i].ucs == ucs)
|
||||
return keysymtab[i].keysym;
|
||||
|
||||
/* Use direct encoding if everything else fails */
|
||||
return ucs | 0x01000000;
|
||||
}
|
||||
627
glfw/xkb_glfw.c
vendored
627
glfw/xkb_glfw.c
vendored
@@ -29,221 +29,255 @@
|
||||
#include <stdlib.h>
|
||||
#include "internal.h"
|
||||
#include "xkb_glfw.h"
|
||||
START_ALLOW_CASE_RANGE
|
||||
#ifdef _GLFW_X11
|
||||
#include <X11/XKBlib.h>
|
||||
#endif
|
||||
|
||||
#define debug(...) if (_glfw.hints.init.debugKeyboard) printf(__VA_ARGS__);
|
||||
|
||||
|
||||
#define map_key(key) \
|
||||
switch(key) { \
|
||||
S(space, SPACE); \
|
||||
S(exclam, EXCLAM); \
|
||||
S(quotedbl, DOUBLE_QUOTE); \
|
||||
S(numbersign, NUMBER_SIGN); \
|
||||
S(dollar, DOLLAR); \
|
||||
S(ampersand, AMPERSAND); \
|
||||
S(apostrophe, APOSTROPHE); \
|
||||
S(parenleft, PARENTHESIS_LEFT); \
|
||||
S(parenright, PARENTHESIS_RIGHT); \
|
||||
S(plus, PLUS); \
|
||||
S(comma, COMMA); \
|
||||
S(minus, MINUS); \
|
||||
S(period, PERIOD); \
|
||||
S(slash, SLASH); \
|
||||
R(0, 9, 0, 9); \
|
||||
S(colon, COLON); \
|
||||
S(semicolon, SEMICOLON); \
|
||||
S(less, LESS); \
|
||||
S(equal, EQUAL); \
|
||||
S(greater, GREATER); \
|
||||
S(at, AT); \
|
||||
D(A, Z, A, Z); \
|
||||
S(bracketleft, LEFT_BRACKET); \
|
||||
S(backslash, BACKSLASH); \
|
||||
S(bracketright, RIGHT_BRACKET); \
|
||||
S(asciicircum, CIRCUMFLEX); \
|
||||
S(underscore, UNDERSCORE); \
|
||||
S(grave, GRAVE_ACCENT); \
|
||||
R(a, z, A, Z); \
|
||||
S(paragraph, PARAGRAPH); \
|
||||
S(masculine, MASCULINE); \
|
||||
S(agrave, A_GRAVE); \
|
||||
F(Agrave, A_GRAVE); \
|
||||
S(adiaeresis, A_DIAERESIS); \
|
||||
F(Adiaeresis, A_DIAERESIS); \
|
||||
S(aring, A_RING); \
|
||||
F(Aring, A_RING); \
|
||||
S(ae, AE); \
|
||||
F(AE, AE); \
|
||||
S(ccedilla, C_CEDILLA); \
|
||||
F(Ccedilla, C_CEDILLA); \
|
||||
S(egrave, E_GRAVE); \
|
||||
F(Egrave, E_GRAVE); \
|
||||
S(aacute, E_ACUTE); \
|
||||
F(Eacute, E_ACUTE); \
|
||||
S(igrave, I_GRAVE); \
|
||||
F(Igrave, I_GRAVE); \
|
||||
S(ntilde, N_TILDE); \
|
||||
F(Ntilde, N_TILDE); \
|
||||
S(ograve, O_GRAVE); \
|
||||
F(Ograve, O_GRAVE); \
|
||||
S(odiaeresis, O_DIAERESIS); \
|
||||
F(Odiaeresis, O_DIAERESIS); \
|
||||
S(oslash, O_SLASH); \
|
||||
F(Oslash, O_SLASH); \
|
||||
S(ugrave, U_GRAVE); \
|
||||
F(Ugrave, U_GRAVE); \
|
||||
S(udiaeresis, U_DIAERESIS); \
|
||||
F(Udiaeresis, U_DIAERESIS); \
|
||||
S(ssharp, S_SHARP); \
|
||||
S(Cyrillic_a, CYRILLIC_A); \
|
||||
F(Cyrillic_A, CYRILLIC_A); \
|
||||
S(Cyrillic_be, CYRILLIC_BE); \
|
||||
F(Cyrillic_BE, CYRILLIC_BE); \
|
||||
S(Cyrillic_ve, CYRILLIC_VE); \
|
||||
F(Cyrillic_VE, CYRILLIC_VE); \
|
||||
S(Cyrillic_ghe, CYRILLIC_GHE); \
|
||||
F(Cyrillic_GHE, CYRILLIC_GHE); \
|
||||
S(Cyrillic_de, CYRILLIC_DE); \
|
||||
F(Cyrillic_DE, CYRILLIC_DE); \
|
||||
S(Cyrillic_ie, CYRILLIC_IE); \
|
||||
F(Cyrillic_IE, CYRILLIC_IE); \
|
||||
S(Cyrillic_zhe, CYRILLIC_ZHE); \
|
||||
F(Cyrillic_ZHE, CYRILLIC_ZHE); \
|
||||
S(Cyrillic_ze, CYRILLIC_ZE); \
|
||||
F(Cyrillic_ZE, CYRILLIC_ZE); \
|
||||
S(Cyrillic_i, CYRILLIC_I); \
|
||||
F(Cyrillic_I, CYRILLIC_I); \
|
||||
S(Cyrillic_shorti, CYRILLIC_SHORT_I); \
|
||||
F(Cyrillic_SHORTI, CYRILLIC_SHORT_I); \
|
||||
S(Cyrillic_ka, CYRILLIC_KA); \
|
||||
F(Cyrillic_KA, CYRILLIC_KA); \
|
||||
S(Cyrillic_el, CYRILLIC_EL); \
|
||||
F(Cyrillic_EL, CYRILLIC_EL); \
|
||||
S(Cyrillic_em, CYRILLIC_EM); \
|
||||
F(Cyrillic_EM, CYRILLIC_EM); \
|
||||
S(Cyrillic_en, CYRILLIC_EN); \
|
||||
F(Cyrillic_EN, CYRILLIC_EN); \
|
||||
S(Cyrillic_o, CYRILLIC_O); \
|
||||
F(Cyrillic_O, CYRILLIC_O); \
|
||||
S(Cyrillic_pe, CYRILLIC_PE); \
|
||||
F(Cyrillic_PE, CYRILLIC_PE); \
|
||||
S(Cyrillic_er, CYRILLIC_ER); \
|
||||
F(Cyrillic_ER, CYRILLIC_ER); \
|
||||
S(Cyrillic_es, CYRILLIC_ES); \
|
||||
F(Cyrillic_ES, CYRILLIC_ES); \
|
||||
S(Cyrillic_te, CYRILLIC_TE); \
|
||||
F(Cyrillic_TE, CYRILLIC_TE); \
|
||||
S(Cyrillic_u, CYRILLIC_U); \
|
||||
F(Cyrillic_U, CYRILLIC_U); \
|
||||
S(Cyrillic_ef, CYRILLIC_EF); \
|
||||
F(Cyrillic_EF, CYRILLIC_EF); \
|
||||
S(Cyrillic_ha, CYRILLIC_HA); \
|
||||
F(Cyrillic_HA, CYRILLIC_HA); \
|
||||
S(Cyrillic_tse, CYRILLIC_TSE); \
|
||||
F(Cyrillic_TSE, CYRILLIC_TSE); \
|
||||
S(Cyrillic_che, CYRILLIC_CHE); \
|
||||
F(Cyrillic_CHE, CYRILLIC_CHE); \
|
||||
S(Cyrillic_sha, CYRILLIC_SHA); \
|
||||
F(Cyrillic_SHA, CYRILLIC_SHA); \
|
||||
S(Cyrillic_shcha, CYRILLIC_SHCHA); \
|
||||
F(Cyrillic_SHCHA, CYRILLIC_SHCHA); \
|
||||
S(Cyrillic_hardsign, CYRILLIC_HARD_SIGN); \
|
||||
F(Cyrillic_HARDSIGN, CYRILLIC_HARD_SIGN); \
|
||||
S(Cyrillic_yeru, CYRILLIC_YERU); \
|
||||
F(Cyrillic_YERU, CYRILLIC_YERU); \
|
||||
S(Cyrillic_softsign, CYRILLIC_SOFT_SIGN); \
|
||||
F(Cyrillic_SOFTSIGN, CYRILLIC_SOFT_SIGN); \
|
||||
S(Cyrillic_e, CYRILLIC_E); \
|
||||
F(Cyrillic_E, CYRILLIC_E); \
|
||||
S(Cyrillic_yu, CYRILLIC_YU); \
|
||||
F(Cyrillic_YU, CYRILLIC_YU); \
|
||||
S(Cyrillic_ya, CYRILLIC_YA); \
|
||||
F(Cyrillic_YA, CYRILLIC_YA); \
|
||||
S(Cyrillic_io, CYRILLIC_IO); \
|
||||
F(Cyrillic_IO, CYRILLIC_IO); \
|
||||
S(Escape, ESCAPE); \
|
||||
S(Return, ENTER); \
|
||||
S(Tab, TAB); \
|
||||
S(BackSpace, BACKSPACE); \
|
||||
S(Insert, INSERT); \
|
||||
S(Delete, DELETE); \
|
||||
S(Right, RIGHT); \
|
||||
S(Left, LEFT); \
|
||||
S(Up, UP); \
|
||||
S(Down, DOWN); \
|
||||
S(Page_Up, PAGE_UP); \
|
||||
S(Page_Down, PAGE_DOWN); \
|
||||
S(Home, HOME); \
|
||||
S(End, END); \
|
||||
S(Caps_Lock, CAPS_LOCK); \
|
||||
S(Scroll_Lock, SCROLL_LOCK); \
|
||||
S(Num_Lock, NUM_LOCK); \
|
||||
S(Print, PRINT_SCREEN); \
|
||||
S(Pause, PAUSE); \
|
||||
S(KP_Decimal, KP_DECIMAL); \
|
||||
S(KP_Divide, KP_DIVIDE); \
|
||||
S(KP_Multiply, KP_MULTIPLY); \
|
||||
S(KP_Subtract, KP_SUBTRACT); \
|
||||
S(KP_Add, KP_ADD); \
|
||||
S(KP_Enter, KP_ENTER); \
|
||||
S(KP_Equal, KP_EQUAL); \
|
||||
F(KP_Home, HOME); \
|
||||
F(KP_End, END); \
|
||||
F(KP_Page_Up, PAGE_UP); \
|
||||
F(KP_Page_Down, PAGE_DOWN); \
|
||||
F(KP_Insert, INSERT); \
|
||||
F(KP_Delete, DELETE); \
|
||||
S(Shift_L, LEFT_SHIFT); \
|
||||
S(Control_L, LEFT_CONTROL); \
|
||||
S(Alt_L, LEFT_ALT); \
|
||||
S(Super_L, LEFT_SUPER); \
|
||||
S(Shift_R, RIGHT_SHIFT); \
|
||||
S(Control_R, RIGHT_CONTROL); \
|
||||
S(Alt_R, RIGHT_ALT); \
|
||||
S(Super_R, RIGHT_SUPER); \
|
||||
S(Menu, MENU); \
|
||||
R(F1, F25, F1, F25); \
|
||||
R(KP_0, KP_9, KP_0, KP_9); \
|
||||
#ifdef XKB_HAS_NO_UTF32
|
||||
#include "xkb-compat-shim.h"
|
||||
#else
|
||||
#define utf32_to_keysym xkb_utf32_to_keysym
|
||||
#endif
|
||||
|
||||
static int
|
||||
glfw_key_for_sym(xkb_keysym_t key) {
|
||||
#define S(f, t) case XKB_KEY_##f: return GLFW_KEY_##t
|
||||
#define F(f, t) S(f, t)
|
||||
#define R(s, e, gs, ...) case XKB_KEY_##s ... XKB_KEY_##e: return GLFW_KEY_##gs + key - XKB_KEY_##s
|
||||
#define D(s, e, gs, ...) R(s, e, gs, __VA_ARGS__)
|
||||
map_key(key)
|
||||
S(KP_Up, UP);
|
||||
S(KP_Down, DOWN);
|
||||
S(KP_Left, LEFT);
|
||||
S(KP_Right, RIGHT);
|
||||
switch(key) {
|
||||
/* start xkb to glfw (auto generated by gen-key-constants.py do not edit) */
|
||||
case XKB_KEY_Escape: return GLFW_FKEY_ESCAPE;
|
||||
case XKB_KEY_Return: return GLFW_FKEY_ENTER;
|
||||
case XKB_KEY_Tab: return GLFW_FKEY_TAB;
|
||||
case XKB_KEY_BackSpace: return GLFW_FKEY_BACKSPACE;
|
||||
case XKB_KEY_Insert: return GLFW_FKEY_INSERT;
|
||||
case XKB_KEY_Delete: return GLFW_FKEY_DELETE;
|
||||
case XKB_KEY_Left: return GLFW_FKEY_LEFT;
|
||||
case XKB_KEY_Right: return GLFW_FKEY_RIGHT;
|
||||
case XKB_KEY_Up: return GLFW_FKEY_UP;
|
||||
case XKB_KEY_Down: return GLFW_FKEY_DOWN;
|
||||
case XKB_KEY_Page_Up: return GLFW_FKEY_PAGE_UP;
|
||||
case XKB_KEY_Page_Down: return GLFW_FKEY_PAGE_DOWN;
|
||||
case XKB_KEY_Home: return GLFW_FKEY_HOME;
|
||||
case XKB_KEY_End: return GLFW_FKEY_END;
|
||||
case XKB_KEY_Caps_Lock: return GLFW_FKEY_CAPS_LOCK;
|
||||
case XKB_KEY_Scroll_Lock: return GLFW_FKEY_SCROLL_LOCK;
|
||||
case XKB_KEY_Num_Lock: return GLFW_FKEY_NUM_LOCK;
|
||||
case XKB_KEY_Print: return GLFW_FKEY_PRINT_SCREEN;
|
||||
case XKB_KEY_Pause: return GLFW_FKEY_PAUSE;
|
||||
case XKB_KEY_Menu: return GLFW_FKEY_MENU;
|
||||
case XKB_KEY_F1: return GLFW_FKEY_F1;
|
||||
case XKB_KEY_F2: return GLFW_FKEY_F2;
|
||||
case XKB_KEY_F3: return GLFW_FKEY_F3;
|
||||
case XKB_KEY_F4: return GLFW_FKEY_F4;
|
||||
case XKB_KEY_F5: return GLFW_FKEY_F5;
|
||||
case XKB_KEY_F6: return GLFW_FKEY_F6;
|
||||
case XKB_KEY_F7: return GLFW_FKEY_F7;
|
||||
case XKB_KEY_F8: return GLFW_FKEY_F8;
|
||||
case XKB_KEY_F9: return GLFW_FKEY_F9;
|
||||
case XKB_KEY_F10: return GLFW_FKEY_F10;
|
||||
case XKB_KEY_F11: return GLFW_FKEY_F11;
|
||||
case XKB_KEY_F12: return GLFW_FKEY_F12;
|
||||
case XKB_KEY_F13: return GLFW_FKEY_F13;
|
||||
case XKB_KEY_F14: return GLFW_FKEY_F14;
|
||||
case XKB_KEY_F15: return GLFW_FKEY_F15;
|
||||
case XKB_KEY_F16: return GLFW_FKEY_F16;
|
||||
case XKB_KEY_F17: return GLFW_FKEY_F17;
|
||||
case XKB_KEY_F18: return GLFW_FKEY_F18;
|
||||
case XKB_KEY_F19: return GLFW_FKEY_F19;
|
||||
case XKB_KEY_F20: return GLFW_FKEY_F20;
|
||||
case XKB_KEY_F21: return GLFW_FKEY_F21;
|
||||
case XKB_KEY_F22: return GLFW_FKEY_F22;
|
||||
case XKB_KEY_F23: return GLFW_FKEY_F23;
|
||||
case XKB_KEY_F24: return GLFW_FKEY_F24;
|
||||
case XKB_KEY_F25: return GLFW_FKEY_F25;
|
||||
case XKB_KEY_F26: return GLFW_FKEY_F26;
|
||||
case XKB_KEY_F27: return GLFW_FKEY_F27;
|
||||
case XKB_KEY_F28: return GLFW_FKEY_F28;
|
||||
case XKB_KEY_F29: return GLFW_FKEY_F29;
|
||||
case XKB_KEY_F30: return GLFW_FKEY_F30;
|
||||
case XKB_KEY_F31: return GLFW_FKEY_F31;
|
||||
case XKB_KEY_F32: return GLFW_FKEY_F32;
|
||||
case XKB_KEY_F33: return GLFW_FKEY_F33;
|
||||
case XKB_KEY_F34: return GLFW_FKEY_F34;
|
||||
case XKB_KEY_F35: return GLFW_FKEY_F35;
|
||||
case XKB_KEY_KP_0: return GLFW_FKEY_KP_0;
|
||||
case XKB_KEY_KP_1: return GLFW_FKEY_KP_1;
|
||||
case XKB_KEY_KP_2: return GLFW_FKEY_KP_2;
|
||||
case XKB_KEY_KP_3: return GLFW_FKEY_KP_3;
|
||||
case XKB_KEY_KP_4: return GLFW_FKEY_KP_4;
|
||||
case XKB_KEY_KP_5: return GLFW_FKEY_KP_5;
|
||||
case XKB_KEY_KP_6: return GLFW_FKEY_KP_6;
|
||||
case XKB_KEY_KP_7: return GLFW_FKEY_KP_7;
|
||||
case XKB_KEY_KP_8: return GLFW_FKEY_KP_8;
|
||||
case XKB_KEY_KP_9: return GLFW_FKEY_KP_9;
|
||||
case XKB_KEY_KP_Decimal: return GLFW_FKEY_KP_DECIMAL;
|
||||
case XKB_KEY_KP_Divide: return GLFW_FKEY_KP_DIVIDE;
|
||||
case XKB_KEY_KP_Multiply: return GLFW_FKEY_KP_MULTIPLY;
|
||||
case XKB_KEY_KP_Subtract: return GLFW_FKEY_KP_SUBTRACT;
|
||||
case XKB_KEY_KP_Add: return GLFW_FKEY_KP_ADD;
|
||||
case XKB_KEY_KP_Enter: return GLFW_FKEY_KP_ENTER;
|
||||
case XKB_KEY_KP_Equal: return GLFW_FKEY_KP_EQUAL;
|
||||
case XKB_KEY_KP_Separator: return GLFW_FKEY_KP_SEPARATOR;
|
||||
case XKB_KEY_KP_Left: return GLFW_FKEY_KP_LEFT;
|
||||
case XKB_KEY_KP_Right: return GLFW_FKEY_KP_RIGHT;
|
||||
case XKB_KEY_KP_Up: return GLFW_FKEY_KP_UP;
|
||||
case XKB_KEY_KP_Down: return GLFW_FKEY_KP_DOWN;
|
||||
case XKB_KEY_KP_Page_Up: return GLFW_FKEY_KP_PAGE_UP;
|
||||
case XKB_KEY_KP_Page_Down: return GLFW_FKEY_KP_PAGE_DOWN;
|
||||
case XKB_KEY_KP_Home: return GLFW_FKEY_KP_HOME;
|
||||
case XKB_KEY_KP_End: return GLFW_FKEY_KP_END;
|
||||
case XKB_KEY_KP_Insert: return GLFW_FKEY_KP_INSERT;
|
||||
case XKB_KEY_KP_Delete: return GLFW_FKEY_KP_DELETE;
|
||||
case XKB_KEY_KP_Begin: return GLFW_FKEY_KP_BEGIN;
|
||||
case XKB_KEY_XF86AudioPlay: return GLFW_FKEY_MEDIA_PLAY;
|
||||
case XKB_KEY_XF86AudioPause: return GLFW_FKEY_MEDIA_PAUSE;
|
||||
case XKB_KEY_XF86AudioStop: return GLFW_FKEY_MEDIA_STOP;
|
||||
case XKB_KEY_XF86AudioForward: return GLFW_FKEY_MEDIA_FAST_FORWARD;
|
||||
case XKB_KEY_XF86AudioRewind: return GLFW_FKEY_MEDIA_REWIND;
|
||||
case XKB_KEY_XF86AudioNext: return GLFW_FKEY_MEDIA_TRACK_NEXT;
|
||||
case XKB_KEY_XF86AudioPrev: return GLFW_FKEY_MEDIA_TRACK_PREVIOUS;
|
||||
case XKB_KEY_XF86AudioRecord: return GLFW_FKEY_MEDIA_RECORD;
|
||||
case XKB_KEY_XF86AudioLowerVolume: return GLFW_FKEY_LOWER_VOLUME;
|
||||
case XKB_KEY_XF86AudioRaiseVolume: return GLFW_FKEY_RAISE_VOLUME;
|
||||
case XKB_KEY_XF86AudioMute: return GLFW_FKEY_MUTE_VOLUME;
|
||||
case XKB_KEY_Shift_L: return GLFW_FKEY_LEFT_SHIFT;
|
||||
case XKB_KEY_Control_L: return GLFW_FKEY_LEFT_CONTROL;
|
||||
case XKB_KEY_Alt_L: return GLFW_FKEY_LEFT_ALT;
|
||||
case XKB_KEY_Super_L: return GLFW_FKEY_LEFT_SUPER;
|
||||
case XKB_KEY_Hyper_L: return GLFW_FKEY_LEFT_HYPER;
|
||||
case XKB_KEY_Meta_L: return GLFW_FKEY_LEFT_META;
|
||||
case XKB_KEY_Shift_R: return GLFW_FKEY_RIGHT_SHIFT;
|
||||
case XKB_KEY_Control_R: return GLFW_FKEY_RIGHT_CONTROL;
|
||||
case XKB_KEY_Alt_R: return GLFW_FKEY_RIGHT_ALT;
|
||||
case XKB_KEY_Super_R: return GLFW_FKEY_RIGHT_SUPER;
|
||||
case XKB_KEY_Hyper_R: return GLFW_FKEY_RIGHT_HYPER;
|
||||
case XKB_KEY_Meta_R: return GLFW_FKEY_RIGHT_META;
|
||||
case XKB_KEY_ISO_Level3_Shift: return GLFW_FKEY_ISO_LEVEL3_SHIFT;
|
||||
case XKB_KEY_ISO_Level5_Shift: return GLFW_FKEY_ISO_LEVEL5_SHIFT;
|
||||
/* end xkb to glfw */
|
||||
default:
|
||||
break;
|
||||
return xkb_keysym_to_utf32(key);
|
||||
}
|
||||
return GLFW_KEY_UNKNOWN;
|
||||
#undef F
|
||||
#undef D
|
||||
#undef R
|
||||
#undef S
|
||||
}
|
||||
|
||||
xkb_keysym_t
|
||||
glfw_xkb_sym_for_key(int key) {
|
||||
#define S(f, t) case GLFW_KEY_##t: return XKB_KEY_##f
|
||||
#define F(...)
|
||||
#define R(s, e, gs, ge) case GLFW_KEY_##gs ... GLFW_KEY_##ge: return XKB_KEY_##s + key - GLFW_KEY_##gs
|
||||
#define D(...)
|
||||
map_key(key)
|
||||
default:
|
||||
break;
|
||||
glfw_xkb_sym_for_key(uint32_t key) {
|
||||
switch(key) {
|
||||
/* start glfw to xkb (auto generated by gen-key-constants.py do not edit) */
|
||||
case GLFW_FKEY_ESCAPE: return XKB_KEY_Escape;
|
||||
case GLFW_FKEY_ENTER: return XKB_KEY_Return;
|
||||
case GLFW_FKEY_TAB: return XKB_KEY_Tab;
|
||||
case GLFW_FKEY_BACKSPACE: return XKB_KEY_BackSpace;
|
||||
case GLFW_FKEY_INSERT: return XKB_KEY_Insert;
|
||||
case GLFW_FKEY_DELETE: return XKB_KEY_Delete;
|
||||
case GLFW_FKEY_LEFT: return XKB_KEY_Left;
|
||||
case GLFW_FKEY_RIGHT: return XKB_KEY_Right;
|
||||
case GLFW_FKEY_UP: return XKB_KEY_Up;
|
||||
case GLFW_FKEY_DOWN: return XKB_KEY_Down;
|
||||
case GLFW_FKEY_PAGE_UP: return XKB_KEY_Page_Up;
|
||||
case GLFW_FKEY_PAGE_DOWN: return XKB_KEY_Page_Down;
|
||||
case GLFW_FKEY_HOME: return XKB_KEY_Home;
|
||||
case GLFW_FKEY_END: return XKB_KEY_End;
|
||||
case GLFW_FKEY_CAPS_LOCK: return XKB_KEY_Caps_Lock;
|
||||
case GLFW_FKEY_SCROLL_LOCK: return XKB_KEY_Scroll_Lock;
|
||||
case GLFW_FKEY_NUM_LOCK: return XKB_KEY_Num_Lock;
|
||||
case GLFW_FKEY_PRINT_SCREEN: return XKB_KEY_Print;
|
||||
case GLFW_FKEY_PAUSE: return XKB_KEY_Pause;
|
||||
case GLFW_FKEY_MENU: return XKB_KEY_Menu;
|
||||
case GLFW_FKEY_F1: return XKB_KEY_F1;
|
||||
case GLFW_FKEY_F2: return XKB_KEY_F2;
|
||||
case GLFW_FKEY_F3: return XKB_KEY_F3;
|
||||
case GLFW_FKEY_F4: return XKB_KEY_F4;
|
||||
case GLFW_FKEY_F5: return XKB_KEY_F5;
|
||||
case GLFW_FKEY_F6: return XKB_KEY_F6;
|
||||
case GLFW_FKEY_F7: return XKB_KEY_F7;
|
||||
case GLFW_FKEY_F8: return XKB_KEY_F8;
|
||||
case GLFW_FKEY_F9: return XKB_KEY_F9;
|
||||
case GLFW_FKEY_F10: return XKB_KEY_F10;
|
||||
case GLFW_FKEY_F11: return XKB_KEY_F11;
|
||||
case GLFW_FKEY_F12: return XKB_KEY_F12;
|
||||
case GLFW_FKEY_F13: return XKB_KEY_F13;
|
||||
case GLFW_FKEY_F14: return XKB_KEY_F14;
|
||||
case GLFW_FKEY_F15: return XKB_KEY_F15;
|
||||
case GLFW_FKEY_F16: return XKB_KEY_F16;
|
||||
case GLFW_FKEY_F17: return XKB_KEY_F17;
|
||||
case GLFW_FKEY_F18: return XKB_KEY_F18;
|
||||
case GLFW_FKEY_F19: return XKB_KEY_F19;
|
||||
case GLFW_FKEY_F20: return XKB_KEY_F20;
|
||||
case GLFW_FKEY_F21: return XKB_KEY_F21;
|
||||
case GLFW_FKEY_F22: return XKB_KEY_F22;
|
||||
case GLFW_FKEY_F23: return XKB_KEY_F23;
|
||||
case GLFW_FKEY_F24: return XKB_KEY_F24;
|
||||
case GLFW_FKEY_F25: return XKB_KEY_F25;
|
||||
case GLFW_FKEY_F26: return XKB_KEY_F26;
|
||||
case GLFW_FKEY_F27: return XKB_KEY_F27;
|
||||
case GLFW_FKEY_F28: return XKB_KEY_F28;
|
||||
case GLFW_FKEY_F29: return XKB_KEY_F29;
|
||||
case GLFW_FKEY_F30: return XKB_KEY_F30;
|
||||
case GLFW_FKEY_F31: return XKB_KEY_F31;
|
||||
case GLFW_FKEY_F32: return XKB_KEY_F32;
|
||||
case GLFW_FKEY_F33: return XKB_KEY_F33;
|
||||
case GLFW_FKEY_F34: return XKB_KEY_F34;
|
||||
case GLFW_FKEY_F35: return XKB_KEY_F35;
|
||||
case GLFW_FKEY_KP_0: return XKB_KEY_KP_0;
|
||||
case GLFW_FKEY_KP_1: return XKB_KEY_KP_1;
|
||||
case GLFW_FKEY_KP_2: return XKB_KEY_KP_2;
|
||||
case GLFW_FKEY_KP_3: return XKB_KEY_KP_3;
|
||||
case GLFW_FKEY_KP_4: return XKB_KEY_KP_4;
|
||||
case GLFW_FKEY_KP_5: return XKB_KEY_KP_5;
|
||||
case GLFW_FKEY_KP_6: return XKB_KEY_KP_6;
|
||||
case GLFW_FKEY_KP_7: return XKB_KEY_KP_7;
|
||||
case GLFW_FKEY_KP_8: return XKB_KEY_KP_8;
|
||||
case GLFW_FKEY_KP_9: return XKB_KEY_KP_9;
|
||||
case GLFW_FKEY_KP_DECIMAL: return XKB_KEY_KP_Decimal;
|
||||
case GLFW_FKEY_KP_DIVIDE: return XKB_KEY_KP_Divide;
|
||||
case GLFW_FKEY_KP_MULTIPLY: return XKB_KEY_KP_Multiply;
|
||||
case GLFW_FKEY_KP_SUBTRACT: return XKB_KEY_KP_Subtract;
|
||||
case GLFW_FKEY_KP_ADD: return XKB_KEY_KP_Add;
|
||||
case GLFW_FKEY_KP_ENTER: return XKB_KEY_KP_Enter;
|
||||
case GLFW_FKEY_KP_EQUAL: return XKB_KEY_KP_Equal;
|
||||
case GLFW_FKEY_KP_SEPARATOR: return XKB_KEY_KP_Separator;
|
||||
case GLFW_FKEY_KP_LEFT: return XKB_KEY_KP_Left;
|
||||
case GLFW_FKEY_KP_RIGHT: return XKB_KEY_KP_Right;
|
||||
case GLFW_FKEY_KP_UP: return XKB_KEY_KP_Up;
|
||||
case GLFW_FKEY_KP_DOWN: return XKB_KEY_KP_Down;
|
||||
case GLFW_FKEY_KP_PAGE_UP: return XKB_KEY_KP_Page_Up;
|
||||
case GLFW_FKEY_KP_PAGE_DOWN: return XKB_KEY_KP_Page_Down;
|
||||
case GLFW_FKEY_KP_HOME: return XKB_KEY_KP_Home;
|
||||
case GLFW_FKEY_KP_END: return XKB_KEY_KP_End;
|
||||
case GLFW_FKEY_KP_INSERT: return XKB_KEY_KP_Insert;
|
||||
case GLFW_FKEY_KP_DELETE: return XKB_KEY_KP_Delete;
|
||||
case GLFW_FKEY_KP_BEGIN: return XKB_KEY_KP_Begin;
|
||||
case GLFW_FKEY_MEDIA_PLAY: return XKB_KEY_XF86AudioPlay;
|
||||
case GLFW_FKEY_MEDIA_PAUSE: return XKB_KEY_XF86AudioPause;
|
||||
case GLFW_FKEY_MEDIA_STOP: return XKB_KEY_XF86AudioStop;
|
||||
case GLFW_FKEY_MEDIA_FAST_FORWARD: return XKB_KEY_XF86AudioForward;
|
||||
case GLFW_FKEY_MEDIA_REWIND: return XKB_KEY_XF86AudioRewind;
|
||||
case GLFW_FKEY_MEDIA_TRACK_NEXT: return XKB_KEY_XF86AudioNext;
|
||||
case GLFW_FKEY_MEDIA_TRACK_PREVIOUS: return XKB_KEY_XF86AudioPrev;
|
||||
case GLFW_FKEY_MEDIA_RECORD: return XKB_KEY_XF86AudioRecord;
|
||||
case GLFW_FKEY_LOWER_VOLUME: return XKB_KEY_XF86AudioLowerVolume;
|
||||
case GLFW_FKEY_RAISE_VOLUME: return XKB_KEY_XF86AudioRaiseVolume;
|
||||
case GLFW_FKEY_MUTE_VOLUME: return XKB_KEY_XF86AudioMute;
|
||||
case GLFW_FKEY_LEFT_SHIFT: return XKB_KEY_Shift_L;
|
||||
case GLFW_FKEY_LEFT_CONTROL: return XKB_KEY_Control_L;
|
||||
case GLFW_FKEY_LEFT_ALT: return XKB_KEY_Alt_L;
|
||||
case GLFW_FKEY_LEFT_SUPER: return XKB_KEY_Super_L;
|
||||
case GLFW_FKEY_LEFT_HYPER: return XKB_KEY_Hyper_L;
|
||||
case GLFW_FKEY_LEFT_META: return XKB_KEY_Meta_L;
|
||||
case GLFW_FKEY_RIGHT_SHIFT: return XKB_KEY_Shift_R;
|
||||
case GLFW_FKEY_RIGHT_CONTROL: return XKB_KEY_Control_R;
|
||||
case GLFW_FKEY_RIGHT_ALT: return XKB_KEY_Alt_R;
|
||||
case GLFW_FKEY_RIGHT_SUPER: return XKB_KEY_Super_R;
|
||||
case GLFW_FKEY_RIGHT_HYPER: return XKB_KEY_Hyper_R;
|
||||
case GLFW_FKEY_RIGHT_META: return XKB_KEY_Meta_R;
|
||||
case GLFW_FKEY_ISO_LEVEL3_SHIFT: return XKB_KEY_ISO_Level3_Shift;
|
||||
case GLFW_FKEY_ISO_LEVEL5_SHIFT: return XKB_KEY_ISO_Level5_Shift;
|
||||
/* end glfw to xkb */
|
||||
default:
|
||||
return utf32_to_keysym(key);
|
||||
}
|
||||
return GLFW_KEY_UNKNOWN;
|
||||
#undef F
|
||||
#undef D
|
||||
#undef R
|
||||
#undef S
|
||||
}
|
||||
END_ALLOW_CASE_RANGE
|
||||
|
||||
#ifdef _GLFW_X11
|
||||
|
||||
@@ -283,11 +317,90 @@ glfw_xkb_update_x11_keyboard_id(_GLFWXKBData *xkb) {
|
||||
if (conn) state = xkb_x11_state_new_from_device(keymap, conn, xkb->keyboard_device_id); \
|
||||
}
|
||||
|
||||
static void
|
||||
glfw_xkb_update_masks(_GLFWXKBData *xkb) {
|
||||
// See https://github.com/kovidgoyal/kitty/pull/3430 for discussion
|
||||
bool succeeded = false;
|
||||
unsigned used_bits = 0; /* To avoid using the same bit twice */
|
||||
XkbDescPtr xkb_ptr = XkbGetMap( _glfw.x11.display, XkbVirtualModsMask | XkbVirtualModMapMask, XkbUseCoreKbd );
|
||||
|
||||
/* shift, control, and capsLock are special; they cannot be identified reliably on X11 */
|
||||
#define S(a, n) xkb->a##Idx = xkb_keymap_mod_get_index(xkb->keymap, n); xkb->a##Mask = 1 << xkb->a##Idx; used_bits |= xkb->a##Mask;
|
||||
S(control, XKB_MOD_NAME_CTRL);
|
||||
S(shift, XKB_MOD_NAME_SHIFT);
|
||||
S(capsLock, XKB_MOD_NAME_CAPS);
|
||||
#undef S
|
||||
#define S( a ) xkb->a##Idx = XKB_MOD_INVALID; xkb->a##Mask = 0
|
||||
S(alt); S(super); S(hyper); S(meta); S(numLock);
|
||||
#undef S
|
||||
if (xkb_ptr) {
|
||||
Status status = XkbGetNames(_glfw.x11.display, XkbVirtualModNamesMask, xkb_ptr);
|
||||
if (status == Success) {
|
||||
for (int indx = 0; indx < XkbNumVirtualMods; ++indx) {
|
||||
Atom atom = xkb_ptr->names->vmods[indx];
|
||||
if (atom) {
|
||||
unsigned mask_rtn = 0;
|
||||
if (XkbVirtualModsToReal( xkb_ptr, 1<<indx, &mask_rtn) ) {
|
||||
const char *name = XGetAtomName(_glfw.x11.display, atom);
|
||||
#define S( a, s ) if (!(used_bits & mask_rtn) && strcmp(name, #s) == 0) xkb->a##Mask = mask_rtn, used_bits |= mask_rtn
|
||||
/* Note that the order matters here; earlier is higher priority. */
|
||||
S(alt, Alt);
|
||||
S(super, Super);
|
||||
S(numLock, NumLock);
|
||||
S(meta, Meta);
|
||||
S(hyper, Hyper);
|
||||
#undef S
|
||||
}
|
||||
}
|
||||
}
|
||||
succeeded = true;
|
||||
}
|
||||
XkbFreeNames(xkb_ptr, XkbVirtualModNamesMask, True);
|
||||
XkbFreeKeyboard(xkb_ptr, 0, True);
|
||||
}
|
||||
if (succeeded) {
|
||||
unsigned indx, shifted;
|
||||
for (indx = 0, shifted = 1; used_bits; ++indx, shifted <<= 1, used_bits >>= 1) {
|
||||
#define S( a ) if ( ( xkb->a##Mask & shifted ) == shifted ) xkb->a##Idx = indx
|
||||
S(alt); S(super); S(hyper); S(meta); S(numLock);
|
||||
#undef S
|
||||
}
|
||||
}
|
||||
#define S(a, n) xkb->a##Idx = xkb_keymap_mod_get_index(xkb->keymap, n); xkb->a##Mask = 1 << xkb->a##Idx;
|
||||
if (!succeeded) {
|
||||
S(numLock, XKB_MOD_NAME_NUM);
|
||||
S(alt, XKB_MOD_NAME_ALT);
|
||||
S(super, XKB_MOD_NAME_LOGO);
|
||||
}
|
||||
#undef S
|
||||
debug("Modifier indices alt: 0x%x super: 0x%x hyper: 0x%x meta: 0x%x numlock: 0x%x shift: 0x%x capslock: 0x%x\n",
|
||||
xkb->altIdx, xkb->superIdx, xkb->hyperIdx, xkb->metaIdx, xkb->numLockIdx, xkb->shiftIdx, xkb->capsLockIdx);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#define xkb_glfw_load_keymap(keymap, map_str) keymap = xkb_keymap_new_from_string(xkb->context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0);
|
||||
#define xkb_glfw_load_state(keymap, state) state = xkb_state_new(keymap);
|
||||
|
||||
static void
|
||||
glfw_xkb_update_masks(_GLFWXKBData *xkb) {
|
||||
// Should find better solution under Wayland
|
||||
// See https://github.com/kovidgoyal/kitty/pull/3430 for discussion
|
||||
|
||||
#define S( a ) xkb->a##Idx = XKB_MOD_INVALID; xkb->a##Mask = 0
|
||||
S(hyper); S(meta);
|
||||
#undef S
|
||||
#define S(a, n) xkb->a##Idx = xkb_keymap_mod_get_index(xkb->keymap, n); xkb->a##Mask = 1 << xkb->a##Idx;
|
||||
S(control, XKB_MOD_NAME_CTRL);
|
||||
S(shift, XKB_MOD_NAME_SHIFT);
|
||||
S(capsLock, XKB_MOD_NAME_CAPS);
|
||||
S(numLock, XKB_MOD_NAME_NUM);
|
||||
S(alt, XKB_MOD_NAME_ALT);
|
||||
S(super, XKB_MOD_NAME_LOGO);
|
||||
#undef S
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
@@ -324,7 +437,9 @@ glfw_xkb_create_context(_GLFWXKBData *xkb) {
|
||||
"Failed to initialize XKB context");
|
||||
return false;
|
||||
}
|
||||
#ifndef _GLFW_WAYLAND
|
||||
glfw_connect_to_ibus(&xkb->ibus);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -359,6 +474,10 @@ load_compose_tables(_GLFWXKBData *xkb) {
|
||||
if (!locale) locale = getenv("LC_CTYPE");
|
||||
if (!locale) locale = getenv("LANG");
|
||||
if (!locale) locale = "C";
|
||||
|
||||
// See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=903373
|
||||
if (strcmp(locale, "en_IN") == 0) locale = "en_IN.UTF-8";
|
||||
|
||||
compose_table = xkb_compose_table_new_from_locale(xkb->context, locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
|
||||
if (!compose_table) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to create XKB compose table for locale %s", locale);
|
||||
@@ -382,11 +501,26 @@ active_unknown_modifiers(_GLFWXKBData *xkb, struct xkb_state *state) {
|
||||
return ans;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
update_one_modifier(XKBStateGroup *group, xkb_mod_mask_t mask,
|
||||
xkb_mod_index_t idx, unsigned int mod) {
|
||||
if ( idx == XKB_MOD_INVALID )
|
||||
return 0;
|
||||
/* Optimization in the case of a single real modifier */
|
||||
if ( mask && ( ( mask & ( mask-1 ) ) == 0 ) )
|
||||
return (xkb_state_mod_index_is_active(group->state, idx, XKB_STATE_MODS_EFFECTIVE) == 1) ? mod : 0;
|
||||
/* Multiple real mods map to the same virtual mod */
|
||||
for ( unsigned indx = 0; indx < 32 && mask; ++indx, mask >>= 1 )
|
||||
if ( ( mask & 1 ) && xkb_state_mod_index_is_active(group->state, indx, XKB_STATE_MODS_EFFECTIVE) == 1)
|
||||
return mod;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
update_modifiers(_GLFWXKBData *xkb) {
|
||||
XKBStateGroup *group = &xkb->states;
|
||||
#define S(attr, name) if (xkb_state_mod_index_is_active(group->state, xkb->attr##Idx, XKB_STATE_MODS_EFFECTIVE)) group->modifiers |= GLFW_MOD_##name
|
||||
S(control, CONTROL); S(alt, ALT); S(shift, SHIFT); S(super, SUPER); S(capsLock, CAPS_LOCK); S(numLock, NUM_LOCK);
|
||||
#define S(attr, name) group->modifiers |= update_one_modifier( group, xkb->attr##Mask, xkb->attr##Idx, GLFW_MOD_##name )
|
||||
S(control, CONTROL); S(alt, ALT); S(shift, SHIFT); S(super, SUPER); S(hyper, HYPER); S(meta, META); S(capsLock, CAPS_LOCK); S(numLock, NUM_LOCK);
|
||||
#undef S
|
||||
xkb->states.activeUnknownModifiers = active_unknown_modifiers(xkb, xkb->states.state);
|
||||
|
||||
@@ -410,18 +544,12 @@ glfw_xkb_compile_keymap(_GLFWXKBData *xkb, const char *map_str) {
|
||||
return false;
|
||||
}
|
||||
load_compose_tables(xkb);
|
||||
#define S(a, n) xkb->a##Idx = xkb_keymap_mod_get_index(xkb->keymap, n); xkb->a##Mask = 1 << xkb->a##Idx;
|
||||
S(control, XKB_MOD_NAME_CTRL);
|
||||
S(alt, XKB_MOD_NAME_ALT);
|
||||
S(shift, XKB_MOD_NAME_SHIFT);
|
||||
S(super, XKB_MOD_NAME_LOGO);
|
||||
S(capsLock, XKB_MOD_NAME_CAPS);
|
||||
S(numLock, XKB_MOD_NAME_NUM);
|
||||
#undef S
|
||||
|
||||
glfw_xkb_update_masks(xkb);
|
||||
size_t capacity = arraysz(xkb->unknownModifiers), j = 0;
|
||||
for (xkb_mod_index_t i = 0; i < capacity; i++) xkb->unknownModifiers[i] = XKB_MOD_INVALID;
|
||||
for (xkb_mod_index_t i = 0; i < xkb_keymap_num_mods(xkb->keymap) && j < capacity - 1; i++) {
|
||||
if (i != xkb->controlIdx && i != xkb->altIdx && i != xkb->shiftIdx && i != xkb->superIdx && i != xkb->capsLockIdx && i != xkb->numLockIdx) xkb->unknownModifiers[j++] = i;
|
||||
if (i != xkb->controlIdx && i != xkb->altIdx && i != xkb->shiftIdx && i != xkb->superIdx && i != xkb->hyperIdx && i != xkb->metaIdx && i != xkb->capsLockIdx && i != xkb->numLockIdx) xkb->unknownModifiers[j++] = i;
|
||||
}
|
||||
xkb->states.modifiers = 0;
|
||||
xkb->states.activeUnknownModifiers = 0;
|
||||
@@ -493,6 +621,8 @@ format_mods(unsigned int mods) {
|
||||
if (mods & GLFW_MOD_ALT) pr("alt+");
|
||||
if (mods & GLFW_MOD_SHIFT) pr("shift+");
|
||||
if (mods & GLFW_MOD_SUPER) pr("super+");
|
||||
if (mods & GLFW_MOD_META) pr("meta+");
|
||||
if (mods & GLFW_MOD_HYPER) pr("hyper+");
|
||||
if (mods & GLFW_MOD_CAPS_LOCK) pr("capslock+");
|
||||
if (mods & GLFW_MOD_NUM_LOCK) pr("numlock+");
|
||||
if (p == s) pr("none");
|
||||
@@ -526,16 +656,16 @@ format_xkb_mods(_GLFWXKBData *xkb, const char* name, xkb_mod_mask_t mods) {
|
||||
}
|
||||
|
||||
void
|
||||
glfw_xkb_update_ime_state(_GLFWwindow *w, _GLFWXKBData *xkb, int which, int a, int b, int c, int d) {
|
||||
glfw_xkb_update_ime_state(_GLFWwindow *w, _GLFWXKBData *xkb, const GLFWIMEUpdateEvent *ev) {
|
||||
int x = 0, y = 0;
|
||||
switch(which) {
|
||||
case 1:
|
||||
glfw_ibus_set_focused(&xkb->ibus, a ? true : false);
|
||||
switch(ev->type) {
|
||||
case GLFW_IME_UPDATE_FOCUS:
|
||||
glfw_ibus_set_focused(&xkb->ibus, ev->focused);
|
||||
break;
|
||||
case 2:
|
||||
case GLFW_IME_UPDATE_CURSOR_POSITION:
|
||||
_glfwPlatformGetWindowPos(w, &x, &y);
|
||||
x += a; y += b;
|
||||
glfw_ibus_set_cursor_geometry(&xkb->ibus, x, y, c, d);
|
||||
x += ev->cursor.left; y += ev->cursor.top;
|
||||
glfw_ibus_set_cursor_geometry(&xkb->ibus, x, y, ev->cursor.width, ev->cursor.height);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -545,9 +675,8 @@ glfw_xkb_key_from_ime(_GLFWIBUSKeyEvent *ev, bool handled_by_ime, bool failed) {
|
||||
_GLFWwindow *window = _glfwWindowForId(ev->window_id);
|
||||
if (failed && window && window->callbacks.keyboard) {
|
||||
// notify application to remove any existing pre-edit text
|
||||
GLFWkeyevent fake_ev;
|
||||
_glfwInitializeKeyEvent(&fake_ev, GLFW_KEY_UNKNOWN, 0, GLFW_PRESS, 0);
|
||||
fake_ev.ime_state = 1;
|
||||
GLFWkeyevent fake_ev = {.action = GLFW_PRESS};
|
||||
fake_ev.ime_state = GLFW_IME_PREEDIT_CHANGED;
|
||||
window->callbacks.keyboard((GLFWwindow*) window, &fake_ev);
|
||||
}
|
||||
static xkb_keycode_t last_handled_press_keycode = 0;
|
||||
@@ -566,27 +695,31 @@ glfw_xkb_key_from_ime(_GLFWIBUSKeyEvent *ev, bool handled_by_ime, bool failed) {
|
||||
format_mods(ev->glfw_ev.mods), ev->glfw_ev.text
|
||||
);
|
||||
|
||||
ev->glfw_ev.ime_state = 0;
|
||||
ev->glfw_ev.ime_state = GLFW_IME_NONE;
|
||||
_glfwInputKeyboard(window, &ev->glfw_ev);
|
||||
} else debug("↳ discarded\n");
|
||||
if (!is_release && handled_by_ime)
|
||||
last_handled_press_keycode = ev->glfw_ev.native_key;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_switch_layout_key(xkb_keysym_t xkb_sym) {
|
||||
return xkb_sym == XKB_KEY_ISO_First_Group || xkb_sym == XKB_KEY_ISO_Last_Group || xkb_sym == XKB_KEY_ISO_Next_Group || xkb_sym == XKB_KEY_ISO_Prev_Group || xkb_sym == XKB_KEY_Mode_switch;
|
||||
}
|
||||
|
||||
void
|
||||
glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t xkb_keycode, int action) {
|
||||
static char key_text[64] = {0};
|
||||
const xkb_keysym_t *syms, *clean_syms, *default_syms;
|
||||
xkb_keysym_t xkb_sym;
|
||||
xkb_keysym_t xkb_sym, shifted_xkb_sym = XKB_KEY_NoSymbol, alternate_xkb_sym = XKB_KEY_NoSymbol;
|
||||
xkb_keycode_t code_for_sym = xkb_keycode, ibus_keycode = xkb_keycode;
|
||||
GLFWkeyevent glfw_ev;
|
||||
_glfwInitializeKeyEvent(&glfw_ev, GLFW_KEY_UNKNOWN, 0, GLFW_PRESS, 0); // init with default values
|
||||
GLFWkeyevent glfw_ev = {.action = GLFW_PRESS};
|
||||
#ifdef _GLFW_WAYLAND
|
||||
code_for_sym += 8;
|
||||
#else
|
||||
ibus_keycode -= 8;
|
||||
#endif
|
||||
debug("%s xkb_keycode: 0x%x ", action == GLFW_RELEASE ? "Release" : "Press", xkb_keycode);
|
||||
debug("%s xkb_keycode: 0x%x ", action == GLFW_RELEASE ? "\x1b[32mRelease\x1b[m" : "\x1b[31mPress\x1b[m", xkb_keycode);
|
||||
XKBStateGroup *sg = &xkb->states;
|
||||
int num_syms = xkb_state_key_get_syms(sg->state, code_for_sym, &syms);
|
||||
int num_clean_syms = xkb_state_key_get_syms(sg->clean_state, code_for_sym, &clean_syms);
|
||||
@@ -598,6 +731,7 @@ glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t
|
||||
return;
|
||||
}
|
||||
xkb_sym = clean_syms[0];
|
||||
shifted_xkb_sym = syms[0];
|
||||
debug("clean_sym: %s ", glfw_xkb_keysym_name(clean_syms[0]));
|
||||
if (action == GLFW_PRESS || action == GLFW_REPEAT) {
|
||||
const char *text_type = "composed_text";
|
||||
@@ -616,9 +750,9 @@ glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t
|
||||
xkb_mod_mask_t consumed_unknown_mods = xkb_state_key_get_consumed_mods(sg->state, code_for_sym) & sg->activeUnknownModifiers;
|
||||
if (sg->activeUnknownModifiers) debug("%s", format_xkb_mods(xkb, "active_unknown_mods", sg->activeUnknownModifiers));
|
||||
if (consumed_unknown_mods) { debug("%s", format_xkb_mods(xkb, "consumed_unknown_mods", consumed_unknown_mods)); }
|
||||
else xkb_sym = clean_syms[0];
|
||||
else if (!is_switch_layout_key(xkb_sym)) xkb_sym = clean_syms[0];
|
||||
// xkb returns text even if alt and/or super are pressed
|
||||
if ( ((GLFW_MOD_CONTROL | GLFW_MOD_ALT | GLFW_MOD_SUPER) & sg->modifiers) == 0) {
|
||||
if ( ((GLFW_MOD_CONTROL | GLFW_MOD_ALT | GLFW_MOD_SUPER | GLFW_MOD_HYPER | GLFW_MOD_META) & sg->modifiers) == 0) {
|
||||
xkb_state_key_get_utf8(sg->state, code_for_sym, key_text, sizeof(key_text));
|
||||
}
|
||||
text_type = "text";
|
||||
@@ -628,25 +762,31 @@ glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t
|
||||
}
|
||||
if (key_text[0]) { debug("%s: %s ", text_type, key_text); }
|
||||
}
|
||||
if (xkb_sym == XKB_KEY_ISO_First_Group || xkb_sym == XKB_KEY_ISO_Last_Group || xkb_sym == XKB_KEY_ISO_Next_Group || xkb_sym == XKB_KEY_ISO_Prev_Group || xkb_sym == XKB_KEY_Mode_switch) {
|
||||
return;
|
||||
if (is_switch_layout_key(xkb_sym)) { debug(" is a keyboard layout shift key, ignoring.\n"); return; }
|
||||
if (sg->modifiers & GLFW_MOD_NUM_LOCK && XKB_KEY_KP_Space <= xkb_sym && xkb_sym <= XKB_KEY_KP_9) {
|
||||
xkb_sym = xkb_state_key_get_one_sym(sg->state, code_for_sym);
|
||||
}
|
||||
int num_default_syms = xkb_state_key_get_syms(sg->default_state, code_for_sym, &default_syms);
|
||||
if (num_default_syms > 0) alternate_xkb_sym = default_syms[0];
|
||||
int glfw_sym = glfw_key_for_sym(xkb_sym);
|
||||
bool is_fallback = false;
|
||||
if (glfw_sym == GLFW_KEY_UNKNOWN && !key_text[0]) {
|
||||
int num_default_syms = xkb_state_key_get_syms(sg->default_state, code_for_sym, &default_syms);
|
||||
if (num_default_syms > 0) {
|
||||
xkb_sym = default_syms[0];
|
||||
glfw_sym = glfw_key_for_sym(xkb_sym);
|
||||
is_fallback = true;
|
||||
}
|
||||
}
|
||||
|
||||
debug(
|
||||
"%s%s: %d (%s) xkb_key: %d (%s)\n",
|
||||
"%s%s: %d (%s) xkb_key: %d (%s)",
|
||||
format_mods(sg->modifiers),
|
||||
is_fallback ? "glfw_fallback_key" : "glfw_key", glfw_sym, _glfwGetKeyName(glfw_sym),
|
||||
"glfw_key", glfw_sym, _glfwGetKeyName(glfw_sym),
|
||||
xkb_sym, glfw_xkb_keysym_name(xkb_sym)
|
||||
);
|
||||
bool has_shifted_key = shifted_xkb_sym != xkb_sym && shifted_xkb_sym != XKB_KEY_NoSymbol;
|
||||
bool has_alternate_key = alternate_xkb_sym != xkb_sym && alternate_xkb_sym != XKB_KEY_NoSymbol;
|
||||
if (has_shifted_key) {
|
||||
glfw_ev.shifted_key = glfw_key_for_sym(shifted_xkb_sym);
|
||||
if (glfw_ev.shifted_key) debug(" shifted_key: %d (%s)", glfw_ev.shifted_key, _glfwGetKeyName(glfw_ev.shifted_key))
|
||||
}
|
||||
if (has_alternate_key) {
|
||||
glfw_ev.alternate_key = glfw_key_for_sym(alternate_xkb_sym);
|
||||
if (glfw_ev.alternate_key) debug(" alternate_key: %d (%s)", glfw_ev.alternate_key, _glfwGetKeyName(glfw_ev.alternate_key))
|
||||
}
|
||||
debug("%s", "\n");
|
||||
|
||||
// NOTE: On linux, the reported native key identifier is the XKB keysym value.
|
||||
// Do not confuse `native_key` with `xkb_keycode` (the native keycode reported for the
|
||||
@@ -662,7 +802,6 @@ glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t
|
||||
glfw_ev.key = glfw_sym;
|
||||
glfw_ev.mods = sg->modifiers;
|
||||
glfw_ev.text = key_text;
|
||||
|
||||
_GLFWIBUSKeyEvent ibus_ev;
|
||||
ibus_ev.glfw_ev = glfw_ev;
|
||||
ibus_ev.ibus_keycode = ibus_keycode;
|
||||
|
||||
8
glfw/xkb_glfw.h
vendored
8
glfw/xkb_glfw.h
vendored
@@ -54,12 +54,16 @@ typedef struct {
|
||||
xkb_mod_index_t altIdx;
|
||||
xkb_mod_index_t shiftIdx;
|
||||
xkb_mod_index_t superIdx;
|
||||
xkb_mod_index_t hyperIdx;
|
||||
xkb_mod_index_t metaIdx;
|
||||
xkb_mod_index_t capsLockIdx;
|
||||
xkb_mod_index_t numLockIdx;
|
||||
xkb_mod_mask_t controlMask;
|
||||
xkb_mod_mask_t altMask;
|
||||
xkb_mod_mask_t shiftMask;
|
||||
xkb_mod_mask_t superMask;
|
||||
xkb_mod_mask_t hyperMask;
|
||||
xkb_mod_mask_t metaMask;
|
||||
xkb_mod_mask_t capsLockMask;
|
||||
xkb_mod_mask_t numLockMask;
|
||||
xkb_mod_index_t unknownModifiers[256];
|
||||
@@ -89,8 +93,8 @@ bool glfw_xkb_compile_keymap(_GLFWXKBData *xkb, const char *map_str);
|
||||
void glfw_xkb_update_modifiers(_GLFWXKBData *xkb, xkb_mod_mask_t depressed, xkb_mod_mask_t latched, xkb_mod_mask_t locked, xkb_layout_index_t base_group, xkb_layout_index_t latched_group, xkb_layout_index_t locked_group);
|
||||
bool glfw_xkb_should_repeat(_GLFWXKBData *xkb, xkb_keycode_t keycode);
|
||||
const char* glfw_xkb_keysym_name(xkb_keysym_t sym);
|
||||
xkb_keysym_t glfw_xkb_sym_for_key(int key);
|
||||
xkb_keysym_t glfw_xkb_sym_for_key(uint32_t key);
|
||||
void glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t keycode, int action);
|
||||
int glfw_xkb_keysym_from_name(const char *name, bool case_sensitive);
|
||||
void glfw_xkb_update_ime_state(_GLFWwindow *w, _GLFWXKBData *xkb, int which, int a, int b, int c, int d);
|
||||
void glfw_xkb_update_ime_state(_GLFWwindow *w, _GLFWXKBData *xkb, const GLFWIMEUpdateEvent *ev);
|
||||
void glfw_xkb_key_from_ime(_GLFWIBUSKeyEvent *ev, bool handled_by_ime, bool failed);
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
See https://sw.kovidgoyal.net/kitty/graphics-protocol.html
|
||||
@@ -1 +0,0 @@
|
||||
See https://sw.kovidgoyal.net/kitty/key-encoding.html
|
||||
@@ -13,7 +13,8 @@ from kitty.constants import cache_dir
|
||||
from kitty.typing import BossType
|
||||
|
||||
from ..tui.handler import result_handler
|
||||
from ..tui.operations import alternate_screen, set_cursor_visible, styled
|
||||
from ..tui.operations import alternate_screen, styled
|
||||
from ..tui.utils import get_key_press
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import readline
|
||||
@@ -70,7 +71,7 @@ class HistoryCompleter:
|
||||
def option_text() -> str:
|
||||
return '''\
|
||||
--type -t
|
||||
choices=line,yesno
|
||||
choices=line,yesno,choices
|
||||
default=line
|
||||
Type of input. Defaults to asking for a line of text.
|
||||
|
||||
@@ -83,6 +84,16 @@ message is shown.
|
||||
--name -n
|
||||
The name for this question. Used to store history of previous answers which can
|
||||
be used for completions and via the browse history readline bindings.
|
||||
|
||||
|
||||
--choice -c
|
||||
type=list
|
||||
dest=choices
|
||||
A choice for the choices type. Every choice has the syntax: letter:text Where
|
||||
letter is the accelerator key and text is the corresponding text. There can be
|
||||
an optional color specification after the letter to indicate what color it should
|
||||
be.
|
||||
For example: y:Yes and n;red:No
|
||||
'''
|
||||
|
||||
|
||||
@@ -97,23 +108,34 @@ class Response(TypedDict):
|
||||
response: Optional[str]
|
||||
|
||||
|
||||
def yesno(cli_opts: AskCLIOptions, items: List[str]) -> Response:
|
||||
import tty
|
||||
def choice(cli_opts: AskCLIOptions, items: List[str]) -> Response:
|
||||
with alternate_screen():
|
||||
if cli_opts.message:
|
||||
print(styled(cli_opts.message, bold=True))
|
||||
print()
|
||||
print(' ', styled('Y', fg='green') + 'es', ' ', styled('N', fg='red') + 'o', set_cursor_visible(False))
|
||||
sys.stdout.flush()
|
||||
tty.setraw(sys.stdin.fileno())
|
||||
try:
|
||||
response = sys.stdin.buffer.read(1)
|
||||
yes = response in (b'y', b'Y', b'\r', b'\n' b' ')
|
||||
return {'items': items, 'response': 'y' if yes else 'n'}
|
||||
finally:
|
||||
sys.stdout.write(set_cursor_visible(True))
|
||||
tty.setcbreak(sys.stdin.fileno())
|
||||
sys.stdout.flush()
|
||||
allowed = ''
|
||||
for choice in cli_opts.choices:
|
||||
color = 'green'
|
||||
letter, text = choice.split(':', maxsplit=1)
|
||||
if ';' in letter:
|
||||
letter, color = letter.split(';', maxsplit=1)
|
||||
letter = letter.lower()
|
||||
idx = text.lower().index(letter)
|
||||
allowed += letter
|
||||
print(text[:idx], styled(text[idx], fg=color), text[idx + 1:], sep='', end=' ')
|
||||
print()
|
||||
response = get_key_press(allowed, '')
|
||||
return {'items': items, 'response': response}
|
||||
|
||||
|
||||
def yesno(cli_opts: AskCLIOptions, items: List[str]) -> Response:
|
||||
with alternate_screen():
|
||||
if cli_opts.message:
|
||||
print(styled(cli_opts.message, bold=True))
|
||||
print()
|
||||
print(' ', styled('Y', fg='green') + 'es', ' ', styled('N', fg='red') + 'o')
|
||||
response = get_key_press('yn', 'n')
|
||||
return {'items': items, 'response': response}
|
||||
|
||||
|
||||
def main(args: List[str]) -> Response:
|
||||
@@ -132,6 +154,8 @@ def main(args: List[str]) -> Response:
|
||||
|
||||
if cli_opts.type == 'yesno':
|
||||
return yesno(cli_opts, items)
|
||||
if cli_opts.type == 'choices':
|
||||
return choice(cli_opts, items)
|
||||
|
||||
import readline as rl
|
||||
readline = rl
|
||||
|
||||
114
kittens/broadcast/main.py
Normal file
114
kittens/broadcast/main.py
Normal file
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import sys
|
||||
from base64 import standard_b64encode
|
||||
from gettext import gettext as _
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from kitty.cli import parse_args
|
||||
from kitty.cli_stub import BroadcastCLIOptions
|
||||
from kitty.key_encoding import encode_key_event
|
||||
from kitty.rc.base import MATCH_TAB_OPTION, MATCH_WINDOW_OPTION
|
||||
from kitty.remote_control import create_basic_command, encode_send
|
||||
from kitty.typing import KeyEventType, ScreenSize
|
||||
|
||||
from ..tui.handler import Handler
|
||||
from ..tui.line_edit import LineEdit
|
||||
from ..tui.loop import Loop
|
||||
from ..tui.operations import RESTORE_CURSOR, SAVE_CURSOR, styled
|
||||
|
||||
|
||||
class Broadcast(Handler):
|
||||
|
||||
def __init__(self, opts: BroadcastCLIOptions, initial_strings: List[str]) -> None:
|
||||
self.opts = opts
|
||||
self.initial_strings = initial_strings
|
||||
self.payload = {'exclude_active': True, 'data': '', 'match': opts.match_tab, 'match_tab': opts.match_tab}
|
||||
self.line_edit = LineEdit()
|
||||
if not opts.match and not opts.match_tab:
|
||||
self.payload['all'] = True
|
||||
|
||||
def initialize(self) -> None:
|
||||
self.print('Type the text to broadcast below, press', styled('Ctrl+c', fg='yellow'), 'to quit:')
|
||||
for x in self.initial_strings:
|
||||
self.write_broadcast_text(x)
|
||||
self.write(SAVE_CURSOR)
|
||||
|
||||
def commit_line(self) -> None:
|
||||
self.write(RESTORE_CURSOR + SAVE_CURSOR)
|
||||
self.cmd.clear_to_end_of_screen()
|
||||
self.line_edit.write(self.write, screen_cols=self.screen_size.cols)
|
||||
|
||||
def on_resize(self, screen_size: ScreenSize) -> None:
|
||||
super().on_resize(screen_size)
|
||||
self.commit_line()
|
||||
|
||||
def on_text(self, text: str, in_bracketed_paste: bool = False) -> None:
|
||||
self.write_broadcast_text(text)
|
||||
self.line_edit.on_text(text, in_bracketed_paste)
|
||||
self.commit_line()
|
||||
|
||||
def on_interrupt(self) -> None:
|
||||
self.quit_loop(0)
|
||||
|
||||
def on_eot(self) -> None:
|
||||
self.write_broadcast_text('\x04')
|
||||
|
||||
def on_key(self, key_event: KeyEventType) -> None:
|
||||
if self.line_edit.on_key(key_event):
|
||||
self.commit_line()
|
||||
if key_event.matches('enter'):
|
||||
self.write_broadcast_text('\r')
|
||||
self.print('')
|
||||
self.line_edit.clear()
|
||||
self.write(SAVE_CURSOR)
|
||||
return
|
||||
|
||||
ek = encode_key_event(key_event)
|
||||
ek = standard_b64encode(ek.encode('utf-8')).decode('ascii')
|
||||
self.write_broadcast_data('kitty-key:' + ek)
|
||||
|
||||
def write_broadcast_text(self, text: str) -> None:
|
||||
self.write_broadcast_data('base64:' + standard_b64encode(text.encode('utf-8')).decode('ascii'))
|
||||
|
||||
def write_broadcast_data(self, data: str) -> None:
|
||||
payload = self.payload.copy()
|
||||
payload['data'] = data
|
||||
send = create_basic_command('send-text', payload, no_response=True)
|
||||
self.write(encode_send(send))
|
||||
|
||||
|
||||
OPTIONS = (MATCH_WINDOW_OPTION + '\n\n' + MATCH_TAB_OPTION.replace('--match -m', '--match-tab -t')).format
|
||||
help_text = 'Broadcast typed text to all kitty windows. By default text is sent to all windows, unless one of the matching options is specified'
|
||||
usage = '[initial text to send ...]'
|
||||
|
||||
|
||||
def parse_broadcast_args(args: List[str]) -> Tuple[BroadcastCLIOptions, List[str]]:
|
||||
return parse_args(args, OPTIONS, usage, help_text, 'kitty +kitten broadcast', result_class=BroadcastCLIOptions)
|
||||
|
||||
|
||||
def main(args: List[str]) -> Optional[Dict[str, Any]]:
|
||||
try:
|
||||
opts, items = parse_broadcast_args(args[1:])
|
||||
except SystemExit as e:
|
||||
if e.code != 0:
|
||||
print(e.args[0], file=sys.stderr)
|
||||
input(_('Press Enter to quit'))
|
||||
return None
|
||||
|
||||
print('Type text to be broadcast below, Ctrl-C to quit:', end='\r\n')
|
||||
sys.stdout.flush()
|
||||
loop = Loop()
|
||||
handler = Broadcast(opts, items)
|
||||
loop.loop(handler)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv)
|
||||
elif __name__ == '__doc__':
|
||||
cd = sys.cli_docs # type: ignore
|
||||
cd['usage'] = usage
|
||||
cd['options'] = OPTIONS
|
||||
cd['help_text'] = help_text
|
||||
@@ -30,8 +30,6 @@ typedef uint8_t len_t;
|
||||
typedef uint32_t text_t;
|
||||
|
||||
#define LEN_MAX UINT8_MAX
|
||||
#define UTF8_ACCEPT 0
|
||||
#define UTF8_REJECT 1
|
||||
#define IS_LOWERCASE(x) (x) >= 'a' && (x) <= 'z'
|
||||
#define IS_UPPERCASE(x) (x) >= 'A' && (x) <= 'Z'
|
||||
#define LOWERCASE(x) ((IS_UPPERCASE(x)) ? (x) + 32 : (x))
|
||||
|
||||
@@ -111,7 +111,7 @@ end:
|
||||
if (job_data[i] && job_data[i]->started) wait_for_thread(threads, i);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < num_threads; i++) job_data[i] = free_job(job_data[i]);
|
||||
if (job_data) { for (i = 0; i < num_threads; i++) job_data[i] = free_job(job_data[i]); }
|
||||
free(job_data);
|
||||
free_threads(threads);
|
||||
return ret;
|
||||
@@ -130,7 +130,7 @@ run_search(Options *opts, GlobalData *global, const char * const *lines, const s
|
||||
ALLOC_VEC(text_t, chars, 8192 * 20);
|
||||
if (chars.data == NULL) return 1;
|
||||
ALLOC_VEC(Candidate, candidates, 8192);
|
||||
if (candidates.data == NULL) { FREE_VEC(chars) return 1; }
|
||||
if (candidates.data == NULL) { FREE_VEC(chars); return 1; }
|
||||
|
||||
for (size_t i = 0; i < num_lines; i++) {
|
||||
sz = sizes[i];
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "choose-data-types.h"
|
||||
#include "../../kitty/iqsort.h"
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
@@ -45,13 +46,6 @@ output_text(GlobalData *global, const text_t *data, size_t sz) {
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
cmpscore(const void *a, const void *b) {
|
||||
double sa = FIELD(a, score), sb = FIELD(b, score);
|
||||
// Sort descending
|
||||
return (sa > sb) ? -1 : ((sa == sb) ? ((int)FIELD(a, idx) - (int)FIELD(b, idx)) : 1);
|
||||
}
|
||||
|
||||
static void
|
||||
output_with_marks(GlobalData *global, Options *opts, text_t *src, size_t src_sz, len_t *positions, len_t poslen) {
|
||||
size_t pos, i = 0;
|
||||
@@ -96,7 +90,9 @@ output_result(GlobalData *global, Candidate *c, Options *opts, len_t needle_len)
|
||||
void
|
||||
output_results(GlobalData *global, Candidate *haystack, size_t count, Options *opts, len_t needle_len) {
|
||||
Candidate *c;
|
||||
qsort(haystack, count, sizeof(*haystack), cmpscore);
|
||||
#define lt(b, a) ( (a)->score < (b)->score || ((a)->score == (b)->score && (a->idx < b->idx)) )
|
||||
QSORT(Candidate, haystack, count, lt);
|
||||
#undef lt
|
||||
size_t left = opts->limit > 0 ? opts->limit : count;
|
||||
for (size_t i = 0; i < left; i++) {
|
||||
c = haystack + i;
|
||||
|
||||
@@ -28,8 +28,9 @@
|
||||
#define ENSURE_SPACE(TYPE, vec, amt) \
|
||||
if (vec.size + amt >= vec.capacity) { \
|
||||
vec.capacity = MAX(vec.capacity * 2, vec.size + amt); \
|
||||
vec.data = (TYPE*)realloc(vec.data, sizeof(TYPE) * vec.capacity); \
|
||||
if (vec.data == NULL) { REPORT_OOM; ret = 1; break; } \
|
||||
void *temp = realloc(vec.data, sizeof(TYPE) * vec.capacity); \
|
||||
if (temp == NULL) { REPORT_OOM; ret = 1; free(vec.data); vec.data = NULL; vec.size = 0; vec.capacity = 0; break; } \
|
||||
else vec.data = temp; \
|
||||
}
|
||||
|
||||
#define NEXT(vec) (vec.data[vec.size])
|
||||
|
||||
@@ -7,7 +7,7 @@ import re
|
||||
from contextlib import suppress
|
||||
from functools import lru_cache
|
||||
from hashlib import md5
|
||||
from mimetypes import guess_type
|
||||
from kitty.guess_mime_type import guess_type
|
||||
from typing import TYPE_CHECKING, Dict, List, Set, Optional, Iterator, Tuple, Union
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -15,6 +15,11 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
path_name_map: Dict[str, str] = {}
|
||||
remote_dirs: Dict[str, str] = {}
|
||||
|
||||
|
||||
def add_remote_dir(val: str) -> None:
|
||||
remote_dirs[val] = os.path.basename(val).rpartition('-')[-1]
|
||||
|
||||
|
||||
class Segment:
|
||||
@@ -68,7 +73,10 @@ class Collection:
|
||||
self.removed_count += len(lines_for_path(left_path))
|
||||
|
||||
def finalize(self) -> None:
|
||||
self.all_paths.sort(key=path_name_map.get)
|
||||
def key(x: str) -> str:
|
||||
return path_name_map.get(x, '')
|
||||
|
||||
self.all_paths.sort(key=key)
|
||||
|
||||
def __iter__(self) -> Iterator[Tuple[str, str, Optional[str]]]:
|
||||
for path in self.all_paths:
|
||||
@@ -85,6 +93,20 @@ class Collection:
|
||||
return len(self.all_paths)
|
||||
|
||||
|
||||
def remote_hostname(path: str) -> Tuple[Optional[str], Optional[str]]:
|
||||
for q in remote_dirs:
|
||||
if path.startswith(q):
|
||||
return q, remote_dirs[q]
|
||||
return None, None
|
||||
|
||||
|
||||
def resolve_remote_name(path: str, default: str) -> str:
|
||||
remote_dir, rh = remote_hostname(path)
|
||||
if remote_dir and rh:
|
||||
return rh + ':' + os.path.relpath(path, remote_dir)
|
||||
return default
|
||||
|
||||
|
||||
def collect_files(collection: Collection, left: str, right: str) -> None:
|
||||
left_names: Set[str] = set()
|
||||
right_names: Set[str] = set()
|
||||
@@ -133,7 +155,7 @@ def sanitize(text: str) -> str:
|
||||
|
||||
@lru_cache(maxsize=1024)
|
||||
def mime_type_for_path(path: str) -> str:
|
||||
return guess_type(path)[0] or 'application/octet-stream'
|
||||
return guess_type(path) or 'application/octet-stream'
|
||||
|
||||
|
||||
@lru_cache(maxsize=1024)
|
||||
@@ -181,8 +203,8 @@ def create_collection(left: str, right: str) -> Collection:
|
||||
collect_files(collection, left, right)
|
||||
else:
|
||||
pl, pr = os.path.abspath(left), os.path.abspath(right)
|
||||
path_name_map[pl] = left
|
||||
path_name_map[pr] = right
|
||||
path_name_map[pl] = resolve_remote_name(pl, left)
|
||||
path_name_map[pr] = resolve_remote_name(pr, right)
|
||||
collection.add_change(pl, pr)
|
||||
collection.finalize()
|
||||
return collection
|
||||
|
||||
@@ -3,21 +3,16 @@
|
||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import os
|
||||
from typing import Any, Dict, Iterable, Optional, Tuple, Type, Union
|
||||
from typing import Any, Dict, Iterable, Optional
|
||||
|
||||
from kitty.conf.definition import config_lines
|
||||
from kitty.cli_stub import DiffCLIOptions
|
||||
from kitty.conf.utils import (
|
||||
init_config as _init_config, key_func, load_config as _load_config,
|
||||
merge_dicts, parse_config_base, parse_kittens_key, resolve_config
|
||||
load_config as _load_config, parse_config_base, resolve_config
|
||||
)
|
||||
from kitty.constants import config_dir
|
||||
from kitty.options_stub import DiffOptions
|
||||
from kitty.cli_stub import DiffCLIOptions
|
||||
from kitty.rgb import color_as_sgr
|
||||
|
||||
from .config_data import all_options, type_convert
|
||||
|
||||
defaults: Optional[DiffOptions] = None
|
||||
from .options.types import Options as DiffOptions, defaults
|
||||
|
||||
formats: Dict[str, str] = {
|
||||
'title': '',
|
||||
@@ -42,94 +37,30 @@ def set_formats(opts: DiffOptions) -> None:
|
||||
formats['added_highlight'] = '48' + color_as_sgr(opts.highlight_added_bg)
|
||||
|
||||
|
||||
func_with_args, args_funcs = key_func()
|
||||
|
||||
|
||||
@func_with_args('scroll_by')
|
||||
def parse_scroll_by(func: str, rest: str) -> Tuple[str, int]:
|
||||
try:
|
||||
return func, int(rest)
|
||||
except Exception:
|
||||
return func, 1
|
||||
|
||||
|
||||
@func_with_args('scroll_to')
|
||||
def parse_scroll_to(func: str, rest: str) -> Tuple[str, str]:
|
||||
rest = rest.lower()
|
||||
if rest not in {'start', 'end', 'next-change', 'prev-change', 'next-page', 'prev-page', 'next-match', 'prev-match'}:
|
||||
rest = 'start'
|
||||
return func, rest
|
||||
|
||||
|
||||
@func_with_args('change_context')
|
||||
def parse_change_context(func: str, rest: str) -> Tuple[str, Union[int, str]]:
|
||||
rest = rest.lower()
|
||||
if rest in {'all', 'default'}:
|
||||
return func, rest
|
||||
try:
|
||||
amount = int(rest)
|
||||
except Exception:
|
||||
amount = 5
|
||||
return func, amount
|
||||
|
||||
|
||||
@func_with_args('start_search')
|
||||
def parse_start_search(func: str, rest: str) -> Tuple[str, Tuple[bool, bool]]:
|
||||
rest_ = rest.lower().split()
|
||||
is_regex = bool(rest_ and rest_[0] == 'regex')
|
||||
is_backward = bool(len(rest_) > 1 and rest_[1] == 'backward')
|
||||
return func, (is_regex, is_backward)
|
||||
|
||||
|
||||
def special_handling(key: str, val: str, ans: Dict) -> bool:
|
||||
if key == 'map':
|
||||
x = parse_kittens_key(val, args_funcs)
|
||||
if x is not None:
|
||||
action, key_def = x
|
||||
ans['key_definitions'][key_def] = action
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def parse_config(lines: Iterable[str], check_keys: bool = True) -> Dict[str, Any]:
|
||||
ans: Dict[str, Any] = {'key_definitions': {}}
|
||||
parse_config_base(
|
||||
lines,
|
||||
defaults,
|
||||
type_convert,
|
||||
special_handling,
|
||||
ans,
|
||||
check_keys=check_keys
|
||||
)
|
||||
return ans
|
||||
|
||||
|
||||
def merge_configs(defaults: Dict, vals: Dict) -> Dict:
|
||||
ans = {}
|
||||
for k, v in defaults.items():
|
||||
if isinstance(v, dict):
|
||||
newvals = vals.get(k, {})
|
||||
ans[k] = merge_dicts(v, newvals)
|
||||
else:
|
||||
ans[k] = vals.get(k, v)
|
||||
return ans
|
||||
|
||||
|
||||
def parse_defaults(lines: Iterable[str], check_keys: bool = False) -> Dict[str, Any]:
|
||||
return parse_config(lines, check_keys)
|
||||
|
||||
|
||||
x = _init_config(config_lines(all_options), parse_defaults)
|
||||
Options: Type[DiffOptions] = x[0]
|
||||
defaults = x[1]
|
||||
SYSTEM_CONF = '/etc/xdg/kitty/diff.conf'
|
||||
defconf = os.path.join(config_dir, 'diff.conf')
|
||||
|
||||
|
||||
def load_config(*paths: str, overrides: Optional[Iterable[str]] = None) -> DiffOptions:
|
||||
return _load_config(Options, defaults, parse_config, merge_configs, *paths, overrides=overrides)
|
||||
from .options.parse import (
|
||||
create_result_dict, merge_result_dicts, parse_conf_item
|
||||
)
|
||||
|
||||
def parse_config(lines: Iterable[str]) -> Dict[str, Any]:
|
||||
ans: Dict[str, Any] = create_result_dict()
|
||||
parse_config_base(
|
||||
lines,
|
||||
parse_conf_item,
|
||||
ans,
|
||||
)
|
||||
return ans
|
||||
|
||||
SYSTEM_CONF = '/etc/xdg/kitty/diff.conf'
|
||||
defconf = os.path.join(config_dir, 'diff.conf')
|
||||
overrides = tuple(overrides) if overrides is not None else ()
|
||||
opts_dict, paths = _load_config(defaults, parse_config, merge_result_dicts, *paths, overrides=overrides)
|
||||
opts = DiffOptions(opts_dict)
|
||||
opts.config_paths = paths
|
||||
opts.config_overrides = overrides
|
||||
return opts
|
||||
|
||||
|
||||
def init_config(args: DiffCLIOptions) -> DiffOptions:
|
||||
@@ -137,4 +68,6 @@ def init_config(args: DiffCLIOptions) -> DiffOptions:
|
||||
overrides = (a.replace('=', ' ', 1) for a in args.override or ())
|
||||
opts = load_config(*config, overrides=overrides)
|
||||
set_formats(opts)
|
||||
for (sc, action) in opts.map:
|
||||
opts.key_definitions[sc] = action
|
||||
return opts
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
|
||||
# Utils {{{
|
||||
from functools import partial
|
||||
from gettext import gettext as _
|
||||
from typing import Any, Dict, Sequence, Union
|
||||
|
||||
from kitty.conf.definition import Option, Shortcut, option_func
|
||||
from kitty.conf.utils import (
|
||||
positive_int, python_string, to_color, to_color_or_none
|
||||
)
|
||||
|
||||
# }}}
|
||||
|
||||
all_options: Dict[str, Union[Option, Sequence[Shortcut]]] = {}
|
||||
o, k, g, all_groups = option_func(all_options, {
|
||||
'colors': [_('Colors')],
|
||||
'diff': [_('Diffing'), ],
|
||||
'shortcuts': [_('Keyboard shortcuts')],
|
||||
})
|
||||
|
||||
|
||||
g('diff')
|
||||
|
||||
|
||||
def syntax_aliases(raw: str) -> Dict[str, str]:
|
||||
ans = {}
|
||||
for x in raw.split():
|
||||
a, b = x.partition(':')[::2]
|
||||
if a and b:
|
||||
ans[a.lower()] = b
|
||||
return ans
|
||||
|
||||
|
||||
o('syntax_aliases', 'pyj:py pyi:py recipe:py', option_type=syntax_aliases, long_text=_('''
|
||||
File extension aliases for syntax highlight
|
||||
For example, to syntax highlight :file:`file.xyz` as
|
||||
:file:`file.abc` use a setting of :code:`xyz:abc`
|
||||
'''))
|
||||
|
||||
o('num_context_lines', 3, option_type=positive_int, long_text=_('''
|
||||
The number of lines of context to show around each change.'''))
|
||||
|
||||
o('diff_cmd', 'auto', long_text=_('''
|
||||
The diff command to use. Must contain the placeholder :code:`_CONTEXT_`
|
||||
which will be replaced by the number of lines of context. The default
|
||||
is to search the system for either git or diff and use that, if found.
|
||||
'''))
|
||||
|
||||
o('replace_tab_by', r'\x20\x20\x20\x20', option_type=python_string, long_text=_('''
|
||||
The string to replace tabs with. Default is to use four spaces.'''))
|
||||
|
||||
|
||||
g('colors')
|
||||
|
||||
o('pygments_style', 'default', long_text=_('''
|
||||
The pygments color scheme to use for syntax highlighting.
|
||||
See :link:`pygments colors schemes <https://help.farbox.com/pygments.html>` for a list of schemes.'''))
|
||||
|
||||
|
||||
c = partial(o, option_type=to_color)
|
||||
c('foreground', 'black', long_text=_('Basic colors'))
|
||||
c('background', 'white')
|
||||
|
||||
c('title_fg', 'black', long_text=_('Title colors'))
|
||||
c('title_bg', 'white')
|
||||
|
||||
c('margin_bg', '#fafbfc', long_text=_('Margin colors'))
|
||||
c('margin_fg', '#aaaaaa')
|
||||
|
||||
c('removed_bg', '#ffeef0', long_text=_('Removed text backgrounds'))
|
||||
c('highlight_removed_bg', '#fdb8c0')
|
||||
c('removed_margin_bg', '#ffdce0')
|
||||
|
||||
c('added_bg', '#e6ffed', long_text=_('Added text backgrounds'))
|
||||
c('highlight_added_bg', '#acf2bd')
|
||||
c('added_margin_bg', '#cdffd8')
|
||||
|
||||
c('filler_bg', '#fafbfc', long_text=_('Filler (empty) line background'))
|
||||
c('margin_filler_bg', 'none', option_type=to_color_or_none, long_text=_(
|
||||
'Filler (empty) line background in margins, defaults to the filler background'))
|
||||
|
||||
c('hunk_margin_bg', '#dbedff', long_text=_('Hunk header colors'))
|
||||
c('hunk_bg', '#f1f8ff')
|
||||
|
||||
c('search_bg', '#444', long_text=_('Highlighting'))
|
||||
c('search_fg', 'white')
|
||||
c('select_bg', '#b4d5fe')
|
||||
c('select_fg', 'black')
|
||||
|
||||
g('shortcuts')
|
||||
k('quit', 'q', 'quit', _('Quit'))
|
||||
k('quit', 'esc', 'quit', _('Quit'))
|
||||
|
||||
k('scroll_down', 'j', 'scroll_by 1', _('Scroll down'))
|
||||
k('scroll_down', 'down', 'scroll_by 1', _('Scroll down'))
|
||||
k('scroll_up', 'k', 'scroll_by -1', _('Scroll up'))
|
||||
k('scroll_up', 'up', 'scroll_by -1', _('Scroll up'))
|
||||
|
||||
k('scroll_top', 'home', 'scroll_to start', _('Scroll to top'))
|
||||
k('scroll_bottom', 'end', 'scroll_to end', _('Scroll to bottom'))
|
||||
|
||||
k('scroll_page_down', 'page_down', 'scroll_to next-page', _('Scroll to next page'))
|
||||
k('scroll_page_down', 'space', 'scroll_to next-page', _('Scroll to next page'))
|
||||
k('scroll_page_up', 'page_up', 'scroll_to prev-page', _('Scroll to previous page'))
|
||||
|
||||
k('next_change', 'n', 'scroll_to next-change', _('Scroll to next change'))
|
||||
k('prev_change', 'p', 'scroll_to prev-change', _('Scroll to previous change'))
|
||||
|
||||
k('all_context', 'a', 'change_context all', _('Show all context'))
|
||||
k('default_context', '=', 'change_context default', _('Show default context'))
|
||||
k('increase_context', '+', 'change_context 5', _('Increase context'))
|
||||
k('decrease_context', '-', 'change_context -5', _('Decrease context'))
|
||||
|
||||
k('search_forward', '/', 'start_search regex forward', _('Search forward'))
|
||||
k('search_backward', '?', 'start_search regex backward', _('Search backward'))
|
||||
k('next_match', '.', 'scroll_to next-match', _('Scroll to next search match'))
|
||||
k('prev_match', ',', 'scroll_to prev-match', _('Scroll to previous search match'))
|
||||
k('next_match', '>', 'scroll_to next-match', _('Scroll to next search match'))
|
||||
k('prev_match', '<', 'scroll_to prev-match', _('Scroll to previous search match'))
|
||||
k('search_forward_simple', 'f', 'start_search substring forward', _('Search forward (no regex)'))
|
||||
k('search_backward_simple', 'b', 'start_search substring backward', _('Search backward (no regex)'))
|
||||
|
||||
|
||||
def type_convert(name: str, val: Any) -> Any:
|
||||
o = all_options.get(name)
|
||||
if isinstance(o, Option):
|
||||
val = o.option_type(val)
|
||||
return val
|
||||
@@ -159,13 +159,12 @@ def highlight_collection(collection: Collection, aliases: Optional[Dict[str, str
|
||||
|
||||
|
||||
def main() -> None:
|
||||
from .config import defaults
|
||||
# kitty +runpy "from kittens.diff.highlight import main; main()" file
|
||||
from .options.types import defaults
|
||||
import sys
|
||||
initialize_highlighter()
|
||||
if defaults is not None:
|
||||
with open(sys.argv[-1]) as f:
|
||||
highlighted = highlight_data(f.read(), f.name, defaults.syntax_aliases)
|
||||
if highlighted is None:
|
||||
raise SystemExit('Unknown filetype: {}'.format(sys.argv[-1]))
|
||||
print(highlighted)
|
||||
with open(sys.argv[-1]) as f:
|
||||
highlighted = highlight_data(f.read(), f.name, defaults.syntax_aliases)
|
||||
if highlighted is None:
|
||||
raise SystemExit('Unknown filetype: {}'.format(sys.argv[-1]))
|
||||
print(highlighted)
|
||||
|
||||
@@ -13,36 +13,40 @@ from collections import defaultdict
|
||||
from contextlib import suppress
|
||||
from functools import partial
|
||||
from gettext import gettext as _
|
||||
from typing import DefaultDict, Dict, Iterable, List, Optional, Tuple, Union
|
||||
from typing import (
|
||||
Any, DefaultDict, Dict, Iterable, List, Optional, Tuple, Union
|
||||
)
|
||||
|
||||
from kitty.cli import CONFIG_HELP, parse_args
|
||||
from kitty.cli_stub import DiffCLIOptions
|
||||
from kitty.conf.utils import KittensKeyAction
|
||||
from kitty.conf.utils import KeyAction
|
||||
from kitty.constants import appname
|
||||
from kitty.fast_data_types import wcswidth
|
||||
from kitty.key_encoding import RELEASE, KeyEvent, enter_key, key_defs as K
|
||||
from kitty.options_stub import DiffOptions
|
||||
from kitty.key_encoding import EventType, KeyEvent
|
||||
from kitty.utils import ScreenSize
|
||||
|
||||
from . import global_data
|
||||
from .collect import (
|
||||
Collection, create_collection, data_for_path, lines_for_path, sanitize,
|
||||
set_highlight_data
|
||||
)
|
||||
from .config import init_config
|
||||
from .patch import Differ, Patch, set_diff_command, worker_processes
|
||||
from .render import (
|
||||
ImagePlacement, ImageSupportWarning, Line, LineRef, Reference, render_diff
|
||||
)
|
||||
from .search import BadRegex, Search
|
||||
from ..tui.handler import Handler
|
||||
from ..tui.images import ImageManager, Placement
|
||||
from ..tui.line_edit import LineEdit
|
||||
from ..tui.loop import Loop
|
||||
from ..tui.operations import styled
|
||||
from . import global_data
|
||||
from .collect import (
|
||||
Collection, add_remote_dir, create_collection, data_for_path,
|
||||
lines_for_path, sanitize, set_highlight_data
|
||||
)
|
||||
from .config import init_config
|
||||
from .options.types import Options as DiffOptions
|
||||
from .patch import Differ, Patch, set_diff_command, worker_processes
|
||||
from .render import (
|
||||
ImagePlacement, ImageSupportWarning, Line, LineRef, Reference, render_diff
|
||||
)
|
||||
from .search import BadRegex, Search
|
||||
|
||||
try:
|
||||
from .highlight import initialize_highlighter, highlight_collection, DiffHighlight
|
||||
from .highlight import (
|
||||
DiffHighlight, highlight_collection, initialize_highlighter
|
||||
)
|
||||
has_highlighter = True
|
||||
DiffHighlight
|
||||
except ImportError:
|
||||
@@ -53,7 +57,6 @@ except ImportError:
|
||||
|
||||
|
||||
INITIALIZING, COLLECTED, DIFFED, COMMAND, MESSAGE = range(5)
|
||||
ESCAPE = K['ESCAPE']
|
||||
|
||||
|
||||
def generate_diff(collection: Collection, context: int) -> Union[str, Dict[str, Patch]]:
|
||||
@@ -90,16 +93,16 @@ class DiffHandler(Handler):
|
||||
self.highlighting_done = False
|
||||
self.restore_position: Optional[Reference] = None
|
||||
for key_def, action in self.opts.key_definitions.items():
|
||||
self.add_shortcut(action, *key_def)
|
||||
self.add_shortcut(action, key_def)
|
||||
|
||||
def perform_action(self, action: KittensKeyAction) -> None:
|
||||
def perform_action(self, action: KeyAction) -> None:
|
||||
func, args = action
|
||||
if func == 'quit':
|
||||
self.quit_loop(0)
|
||||
return
|
||||
if self.state <= DIFFED:
|
||||
if func == 'scroll_by':
|
||||
return self.scroll_lines(int(args[0]))
|
||||
return self.scroll_lines(int(args[0] or 0))
|
||||
if func == 'scroll_to':
|
||||
where = str(args[0])
|
||||
if 'change' in where:
|
||||
@@ -119,7 +122,7 @@ class DiffHandler(Handler):
|
||||
elif to == 'default':
|
||||
new_ctx = self.original_context_count
|
||||
else:
|
||||
new_ctx += int(to)
|
||||
new_ctx += int(to or 0)
|
||||
return self.change_context_count(new_ctx)
|
||||
if func == 'start_search':
|
||||
self.start_search(bool(args[0]), bool(args[1]))
|
||||
@@ -334,8 +337,8 @@ class DiffHandler(Handler):
|
||||
if candidate.image.image_id == image_id:
|
||||
q = self.xpos_for_image(row, candidate, is_left)
|
||||
if q is not None:
|
||||
pl['x'] = q[0]
|
||||
pl['y'] = row
|
||||
pl.x = q[0]
|
||||
pl.y = row
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -479,48 +482,44 @@ class DiffHandler(Handler):
|
||||
self.message = sanitize(_('No matches found'))
|
||||
self.cmd.bell()
|
||||
|
||||
def on_text(self, text: str, in_bracketed_paste: bool = False) -> None:
|
||||
if self.state is COMMAND:
|
||||
self.line_edit.on_text(text, in_bracketed_paste)
|
||||
self.draw_status_line()
|
||||
return
|
||||
if self.state is MESSAGE:
|
||||
self.state = DIFFED
|
||||
self.draw_status_line()
|
||||
return
|
||||
action = self.shortcut_action(text)
|
||||
if action is not None:
|
||||
return self.perform_action(action)
|
||||
|
||||
def on_key(self, key_event: KeyEvent) -> None:
|
||||
if self.state is MESSAGE:
|
||||
if key_event.type is not RELEASE:
|
||||
def on_key_event(self, key_event: KeyEvent, in_bracketed_paste: bool = False) -> None:
|
||||
if key_event.text:
|
||||
if self.state is COMMAND:
|
||||
self.line_edit.on_text(key_event.text, in_bracketed_paste)
|
||||
self.draw_status_line()
|
||||
return
|
||||
if self.state is MESSAGE:
|
||||
self.state = DIFFED
|
||||
self.draw_status_line()
|
||||
return
|
||||
if self.state is COMMAND:
|
||||
if self.line_edit.on_key(key_event):
|
||||
if not self.line_edit.current_input:
|
||||
return
|
||||
else:
|
||||
if self.state is MESSAGE:
|
||||
if key_event.type is not EventType.RELEASE:
|
||||
self.state = DIFFED
|
||||
self.draw_status_line()
|
||||
self.draw_status_line()
|
||||
return
|
||||
if key_event.type is RELEASE:
|
||||
return
|
||||
if self.state is COMMAND:
|
||||
if key_event.key is ESCAPE:
|
||||
self.state = DIFFED
|
||||
self.draw_status_line()
|
||||
return
|
||||
if key_event is enter_key:
|
||||
self.state = DIFFED
|
||||
self.do_search()
|
||||
self.line_edit.clear()
|
||||
if self.state is COMMAND:
|
||||
if self.line_edit.on_key(key_event):
|
||||
if not self.line_edit.current_input:
|
||||
self.state = DIFFED
|
||||
self.draw_status_line()
|
||||
return
|
||||
if key_event.matches('enter'):
|
||||
self.state = DIFFED
|
||||
self.do_search()
|
||||
self.line_edit.clear()
|
||||
self.draw_screen()
|
||||
return
|
||||
if key_event.matches('esc'):
|
||||
self.state = DIFFED
|
||||
self.draw_status_line()
|
||||
return
|
||||
if self.state >= DIFFED and self.current_search is not None and key_event.matches('esc'):
|
||||
self.current_search = None
|
||||
self.draw_screen()
|
||||
return
|
||||
if self.state >= DIFFED and self.current_search is not None and key_event.key is ESCAPE:
|
||||
self.current_search = None
|
||||
self.draw_screen()
|
||||
return
|
||||
if key_event.type is EventType.RELEASE:
|
||||
return
|
||||
action = self.shortcut_action(key_event)
|
||||
if action is not None:
|
||||
return self.perform_action(action)
|
||||
@@ -566,8 +565,8 @@ class ShowWarning:
|
||||
def __init__(self) -> None:
|
||||
self.warnings: List[str] = []
|
||||
|
||||
def __call__(self, message: str, category: object, filename: str, lineno: int, file: object = None, line: object = None) -> None:
|
||||
if category is ImageSupportWarning:
|
||||
def __call__(self, message: Any, category: Any, filename: str, lineno: int, file: object = None, line: object = None) -> None:
|
||||
if category is ImageSupportWarning and isinstance(message, str):
|
||||
showwarning.warnings.append(message)
|
||||
|
||||
|
||||
@@ -582,17 +581,39 @@ def terminate_processes(processes: Iterable[int]) -> None:
|
||||
os.kill(pid, signal.SIGKILL)
|
||||
|
||||
|
||||
def get_ssh_file(hostname: str, rpath: str) -> str:
|
||||
import io
|
||||
import shutil
|
||||
import tarfile
|
||||
tdir = tempfile.mkdtemp(suffix=f'-{hostname}')
|
||||
add_remote_dir(tdir)
|
||||
atexit.register(shutil.rmtree, tdir)
|
||||
is_abs = rpath.startswith('/')
|
||||
rpath = rpath.lstrip('/')
|
||||
cmd = ['ssh', hostname, 'tar', '-c', '-f', '-']
|
||||
if is_abs:
|
||||
cmd.extend(('-C', '/'))
|
||||
cmd.append(rpath)
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||
assert p.stdout is not None
|
||||
raw = p.stdout.read()
|
||||
if p.wait() != 0:
|
||||
raise SystemExit(p.returncode)
|
||||
with tarfile.open(fileobj=io.BytesIO(raw), mode='r:') as tf:
|
||||
members = tf.getmembers()
|
||||
tf.extractall(tdir)
|
||||
if len(members) == 1:
|
||||
for root, dirs, files in os.walk(tdir):
|
||||
if files:
|
||||
return os.path.join(root, files[0])
|
||||
return os.path.abspath(os.path.join(tdir, rpath))
|
||||
|
||||
|
||||
def get_remote_file(path: str) -> str:
|
||||
if path.startswith('ssh:'):
|
||||
parts = path.split(':', 2)
|
||||
if len(parts) == 3:
|
||||
hostname, rpath = parts[1:]
|
||||
with tempfile.NamedTemporaryFile(suffix='-' + os.path.basename(rpath), prefix='remote:', delete=False) as tf:
|
||||
atexit.register(os.remove, tf.name)
|
||||
p = subprocess.Popen(['ssh', hostname, 'cat', rpath], stdout=tf)
|
||||
if p.wait() != 0:
|
||||
raise SystemExit(p.returncode)
|
||||
return tf.name
|
||||
return get_ssh_file(parts[1], parts[2])
|
||||
return path
|
||||
|
||||
|
||||
@@ -603,12 +624,12 @@ def main(args: List[str]) -> None:
|
||||
raise SystemExit('You must specify exactly two files/directories to compare')
|
||||
left, right = items
|
||||
global_data.title = _('{} vs. {}').format(left, right)
|
||||
if os.path.isdir(left) != os.path.isdir(right):
|
||||
raise SystemExit('The items to be diffed should both be either directories or files. Comparing a directory to a file is not valid.')
|
||||
opts = init_config(cli_opts)
|
||||
set_diff_command(opts.diff_cmd)
|
||||
lines_for_path.replace_tab_by = opts.replace_tab_by
|
||||
left, right = map(get_remote_file, (left, right))
|
||||
if os.path.isdir(left) != os.path.isdir(right):
|
||||
raise SystemExit('The items to be diffed should both be either directories or files. Comparing a directory to a file is not valid.')
|
||||
for f in left, right:
|
||||
if not os.path.exists(f):
|
||||
raise SystemExit('{} does not exist'.format(f))
|
||||
@@ -637,5 +658,5 @@ elif __name__ == '__doc__':
|
||||
cd['options'] = OPTIONS
|
||||
cd['help_text'] = help_text
|
||||
elif __name__ == '__conf__':
|
||||
from .config_data import all_options
|
||||
sys.all_options = all_options # type: ignore
|
||||
from .options.definition import definition
|
||||
sys.options_definition = definition # type: ignore
|
||||
|
||||
0
kittens/diff/options/__init__.py
Normal file
0
kittens/diff/options/__init__.py
Normal file
247
kittens/diff/options/definition.py
Normal file
247
kittens/diff/options/definition.py
Normal file
@@ -0,0 +1,247 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
# After editing this file run ./gen-config.py to apply the changes
|
||||
|
||||
from kitty.conf.types import Action, Definition
|
||||
|
||||
|
||||
definition = Definition(
|
||||
'kittens.diff',
|
||||
Action('map', 'parse_map', {'key_definitions': 'kitty.conf.utils.KittensKeyMap'}, ['kitty.types.ParsedShortcut', 'kitty.conf.utils.KeyAction']),
|
||||
)
|
||||
|
||||
agr = definition.add_group
|
||||
egr = definition.end_group
|
||||
opt = definition.add_option
|
||||
map = definition.add_map
|
||||
mma = definition.add_mouse_map
|
||||
|
||||
# diff {{{
|
||||
agr('diff', 'Diffing')
|
||||
|
||||
opt('syntax_aliases', 'pyj:py pyi:py recipe:py',
|
||||
option_type='syntax_aliases',
|
||||
long_text='''
|
||||
File extension aliases for syntax highlight For example, to syntax highlight
|
||||
:file:`file.xyz` as :file:`file.abc` use a setting of :code:`xyz:abc`
|
||||
'''
|
||||
)
|
||||
|
||||
opt('num_context_lines', '3',
|
||||
option_type='positive_int',
|
||||
long_text='The number of lines of context to show around each change.'
|
||||
)
|
||||
|
||||
opt('diff_cmd', 'auto',
|
||||
long_text='''
|
||||
The diff command to use. Must contain the placeholder :code:`_CONTEXT_` which
|
||||
will be replaced by the number of lines of context. The default is to search the
|
||||
system for either git or diff and use that, if found.
|
||||
'''
|
||||
)
|
||||
|
||||
opt('replace_tab_by', '\\x20\\x20\\x20\\x20',
|
||||
option_type='python_string',
|
||||
long_text='The string to replace tabs with. Default is to use four spaces.'
|
||||
)
|
||||
egr() # }}}
|
||||
|
||||
# colors {{{
|
||||
agr('colors', 'Colors')
|
||||
|
||||
opt('pygments_style', 'default',
|
||||
long_text='''
|
||||
The pygments color scheme to use for syntax highlighting. See :link:`pygments
|
||||
colors schemes <https://help.farbox.com/pygments.html>` for a list of schemes.
|
||||
'''
|
||||
)
|
||||
|
||||
opt('foreground', 'black',
|
||||
option_type='to_color',
|
||||
long_text='Basic colors'
|
||||
)
|
||||
|
||||
opt('background', 'white',
|
||||
option_type='to_color',
|
||||
)
|
||||
|
||||
opt('title_fg', 'black',
|
||||
option_type='to_color',
|
||||
long_text='Title colors'
|
||||
)
|
||||
|
||||
opt('title_bg', 'white',
|
||||
option_type='to_color',
|
||||
)
|
||||
|
||||
opt('margin_bg', '#fafbfc',
|
||||
option_type='to_color',
|
||||
long_text='Margin colors'
|
||||
)
|
||||
|
||||
opt('margin_fg', '#aaaaaa',
|
||||
option_type='to_color',
|
||||
)
|
||||
|
||||
opt('removed_bg', '#ffeef0',
|
||||
option_type='to_color',
|
||||
long_text='Removed text backgrounds'
|
||||
)
|
||||
|
||||
opt('highlight_removed_bg', '#fdb8c0',
|
||||
option_type='to_color',
|
||||
)
|
||||
|
||||
opt('removed_margin_bg', '#ffdce0',
|
||||
option_type='to_color',
|
||||
)
|
||||
|
||||
opt('added_bg', '#e6ffed',
|
||||
option_type='to_color',
|
||||
long_text='Added text backgrounds'
|
||||
)
|
||||
|
||||
opt('highlight_added_bg', '#acf2bd',
|
||||
option_type='to_color',
|
||||
)
|
||||
|
||||
opt('added_margin_bg', '#cdffd8',
|
||||
option_type='to_color',
|
||||
)
|
||||
|
||||
opt('filler_bg', '#fafbfc',
|
||||
option_type='to_color',
|
||||
long_text='Filler (empty) line background'
|
||||
)
|
||||
|
||||
opt('margin_filler_bg', 'none',
|
||||
option_type='to_color_or_none',
|
||||
long_text='Filler (empty) line background in margins, defaults to the filler background'
|
||||
)
|
||||
|
||||
opt('hunk_margin_bg', '#dbedff',
|
||||
option_type='to_color',
|
||||
long_text='Hunk header colors'
|
||||
)
|
||||
|
||||
opt('hunk_bg', '#f1f8ff',
|
||||
option_type='to_color',
|
||||
)
|
||||
|
||||
opt('search_bg', '#444',
|
||||
option_type='to_color',
|
||||
long_text='Highlighting'
|
||||
)
|
||||
|
||||
opt('search_fg', 'white',
|
||||
option_type='to_color',
|
||||
)
|
||||
|
||||
opt('select_bg', '#b4d5fe',
|
||||
option_type='to_color',
|
||||
)
|
||||
|
||||
opt('select_fg', 'black',
|
||||
option_type='to_color_or_none',
|
||||
)
|
||||
egr() # }}}
|
||||
|
||||
# shortcuts {{{
|
||||
agr('shortcuts', 'Keyboard shortcuts')
|
||||
|
||||
map('Quit',
|
||||
'quit q quit',
|
||||
)
|
||||
map('Quit',
|
||||
'quit esc quit',
|
||||
)
|
||||
|
||||
map('Scroll down',
|
||||
'scroll_down j scroll_by 1',
|
||||
)
|
||||
map('Scroll down',
|
||||
'scroll_down down scroll_by 1',
|
||||
)
|
||||
|
||||
map('Scroll up',
|
||||
'scroll_up k scroll_by -1',
|
||||
)
|
||||
map('Scroll up',
|
||||
'scroll_up up scroll_by -1',
|
||||
)
|
||||
|
||||
map('Scroll to top',
|
||||
'scroll_top home scroll_to start',
|
||||
)
|
||||
|
||||
map('Scroll to bottom',
|
||||
'scroll_bottom end scroll_to end',
|
||||
)
|
||||
|
||||
map('Scroll to next page',
|
||||
'scroll_page_down page_down scroll_to next-page',
|
||||
)
|
||||
map('Scroll to next page',
|
||||
'scroll_page_down space scroll_to next-page',
|
||||
)
|
||||
|
||||
map('Scroll to previous page',
|
||||
'scroll_page_up page_up scroll_to prev-page',
|
||||
)
|
||||
|
||||
map('Scroll to next change',
|
||||
'next_change n scroll_to next-change',
|
||||
)
|
||||
|
||||
map('Scroll to previous change',
|
||||
'prev_change p scroll_to prev-change',
|
||||
)
|
||||
|
||||
map('Show all context',
|
||||
'all_context a change_context all',
|
||||
)
|
||||
|
||||
map('Show default context',
|
||||
'default_context = change_context default',
|
||||
)
|
||||
|
||||
map('Increase context',
|
||||
'increase_context + change_context 5',
|
||||
)
|
||||
|
||||
map('Decrease context',
|
||||
'decrease_context - change_context -5',
|
||||
)
|
||||
|
||||
map('Search forward',
|
||||
'search_forward / start_search regex forward',
|
||||
)
|
||||
|
||||
map('Search backward',
|
||||
'search_backward ? start_search regex backward',
|
||||
)
|
||||
|
||||
map('Scroll to next search match',
|
||||
'next_match . scroll_to next-match',
|
||||
)
|
||||
map('Scroll to next search match',
|
||||
'next_match > scroll_to next-match',
|
||||
)
|
||||
|
||||
map('Scroll to previous search match',
|
||||
'prev_match , scroll_to prev-match',
|
||||
)
|
||||
map('Scroll to previous search match',
|
||||
'prev_match < scroll_to prev-match',
|
||||
)
|
||||
|
||||
map('Search forward (no regex)',
|
||||
'search_forward_simple f start_search substring forward',
|
||||
)
|
||||
|
||||
map('Search backward (no regex)',
|
||||
'search_backward_simple b start_search substring backward',
|
||||
)
|
||||
egr() # }}}
|
||||
120
kittens/diff/options/parse.py
generated
Normal file
120
kittens/diff/options/parse.py
generated
Normal file
@@ -0,0 +1,120 @@
|
||||
# generated by gen-config.py DO NOT edit
|
||||
# vim:fileencoding=utf-8
|
||||
|
||||
import typing
|
||||
from kittens.diff.options.utils import parse_map, syntax_aliases
|
||||
from kitty.conf.utils import merge_dicts, positive_int, python_string, to_color, to_color_or_none
|
||||
|
||||
|
||||
class Parser:
|
||||
|
||||
def added_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['added_bg'] = to_color(val)
|
||||
|
||||
def added_margin_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['added_margin_bg'] = to_color(val)
|
||||
|
||||
def background(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['background'] = to_color(val)
|
||||
|
||||
def diff_cmd(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['diff_cmd'] = str(val)
|
||||
|
||||
def filler_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['filler_bg'] = to_color(val)
|
||||
|
||||
def foreground(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['foreground'] = to_color(val)
|
||||
|
||||
def highlight_added_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['highlight_added_bg'] = to_color(val)
|
||||
|
||||
def highlight_removed_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['highlight_removed_bg'] = to_color(val)
|
||||
|
||||
def hunk_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['hunk_bg'] = to_color(val)
|
||||
|
||||
def hunk_margin_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['hunk_margin_bg'] = to_color(val)
|
||||
|
||||
def margin_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['margin_bg'] = to_color(val)
|
||||
|
||||
def margin_fg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['margin_fg'] = to_color(val)
|
||||
|
||||
def margin_filler_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['margin_filler_bg'] = to_color_or_none(val)
|
||||
|
||||
def num_context_lines(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['num_context_lines'] = positive_int(val)
|
||||
|
||||
def pygments_style(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['pygments_style'] = str(val)
|
||||
|
||||
def removed_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['removed_bg'] = to_color(val)
|
||||
|
||||
def removed_margin_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['removed_margin_bg'] = to_color(val)
|
||||
|
||||
def replace_tab_by(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['replace_tab_by'] = python_string(val)
|
||||
|
||||
def search_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['search_bg'] = to_color(val)
|
||||
|
||||
def search_fg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['search_fg'] = to_color(val)
|
||||
|
||||
def select_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['select_bg'] = to_color(val)
|
||||
|
||||
def select_fg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['select_fg'] = to_color_or_none(val)
|
||||
|
||||
def syntax_aliases(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['syntax_aliases'] = syntax_aliases(val)
|
||||
|
||||
def title_bg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['title_bg'] = to_color(val)
|
||||
|
||||
def title_fg(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['title_fg'] = to_color(val)
|
||||
|
||||
def map(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
for k in parse_map(val):
|
||||
ans['map'].append(k)
|
||||
|
||||
|
||||
def create_result_dict() -> typing.Dict[str, typing.Any]:
|
||||
return {
|
||||
'map': [],
|
||||
}
|
||||
|
||||
|
||||
actions = frozenset(('map',))
|
||||
|
||||
|
||||
def merge_result_dicts(defaults: typing.Dict[str, typing.Any], vals: typing.Dict[str, typing.Any]) -> typing.Dict[str, typing.Any]:
|
||||
ans = {}
|
||||
for k, v in defaults.items():
|
||||
if isinstance(v, dict):
|
||||
ans[k] = merge_dicts(v, vals.get(k, {}))
|
||||
elif k in actions:
|
||||
ans[k] = v + vals.get(k, [])
|
||||
else:
|
||||
ans[k] = vals.get(k, v)
|
||||
return ans
|
||||
|
||||
|
||||
parser = Parser()
|
||||
|
||||
|
||||
def parse_conf_item(key: str, val: str, ans: typing.Dict[str, typing.Any]) -> bool:
|
||||
func = getattr(parser, key, None)
|
||||
if func is not None:
|
||||
func(val, ans)
|
||||
return True
|
||||
return False
|
||||
168
kittens/diff/options/types.py
generated
Normal file
168
kittens/diff/options/types.py
generated
Normal file
@@ -0,0 +1,168 @@
|
||||
# generated by gen-config.py DO NOT edit
|
||||
# vim:fileencoding=utf-8
|
||||
|
||||
import typing
|
||||
from kitty.conf.utils import KeyAction, KittensKeyMap
|
||||
import kitty.conf.utils
|
||||
from kitty.rgb import Color
|
||||
import kitty.rgb
|
||||
from kitty.types import ParsedShortcut
|
||||
import kitty.types
|
||||
|
||||
|
||||
option_names = ( # {{{
|
||||
'added_bg',
|
||||
'added_margin_bg',
|
||||
'background',
|
||||
'diff_cmd',
|
||||
'filler_bg',
|
||||
'foreground',
|
||||
'highlight_added_bg',
|
||||
'highlight_removed_bg',
|
||||
'hunk_bg',
|
||||
'hunk_margin_bg',
|
||||
'map',
|
||||
'margin_bg',
|
||||
'margin_fg',
|
||||
'margin_filler_bg',
|
||||
'num_context_lines',
|
||||
'pygments_style',
|
||||
'removed_bg',
|
||||
'removed_margin_bg',
|
||||
'replace_tab_by',
|
||||
'search_bg',
|
||||
'search_fg',
|
||||
'select_bg',
|
||||
'select_fg',
|
||||
'syntax_aliases',
|
||||
'title_bg',
|
||||
'title_fg') # }}}
|
||||
|
||||
|
||||
class Options:
|
||||
added_bg: Color = Color(red=230, green=255, blue=237)
|
||||
added_margin_bg: Color = Color(red=205, green=255, blue=216)
|
||||
background: Color = Color(red=255, green=255, blue=255)
|
||||
diff_cmd: str = 'auto'
|
||||
filler_bg: Color = Color(red=250, green=251, blue=252)
|
||||
foreground: Color = Color(red=0, green=0, blue=0)
|
||||
highlight_added_bg: Color = Color(red=172, green=242, blue=189)
|
||||
highlight_removed_bg: Color = Color(red=253, green=184, blue=192)
|
||||
hunk_bg: Color = Color(red=241, green=248, blue=255)
|
||||
hunk_margin_bg: Color = Color(red=219, green=237, blue=255)
|
||||
margin_bg: Color = Color(red=250, green=251, blue=252)
|
||||
margin_fg: Color = Color(red=170, green=170, blue=170)
|
||||
margin_filler_bg: typing.Optional[kitty.rgb.Color] = None
|
||||
num_context_lines: int = 3
|
||||
pygments_style: str = 'default'
|
||||
removed_bg: Color = Color(red=255, green=238, blue=240)
|
||||
removed_margin_bg: Color = Color(red=255, green=220, blue=224)
|
||||
replace_tab_by: str = ' '
|
||||
search_bg: Color = Color(red=68, green=68, blue=68)
|
||||
search_fg: Color = Color(red=255, green=255, blue=255)
|
||||
select_bg: Color = Color(red=180, green=213, blue=254)
|
||||
select_fg: typing.Optional[kitty.rgb.Color] = Color(red=0, green=0, blue=0)
|
||||
syntax_aliases: typing.Dict[str, str] = {'pyj': 'py', 'pyi': 'py', 'recipe': 'py'}
|
||||
title_bg: Color = Color(red=255, green=255, blue=255)
|
||||
title_fg: Color = Color(red=0, green=0, blue=0)
|
||||
map: typing.List[typing.Tuple[kitty.types.ParsedShortcut, kitty.conf.utils.KeyAction]] = []
|
||||
key_definitions: KittensKeyMap = {}
|
||||
config_paths: typing.Tuple[str, ...] = ()
|
||||
config_overrides: typing.Tuple[str, ...] = ()
|
||||
|
||||
def __init__(self, options_dict: typing.Optional[typing.Dict[str, typing.Any]] = None) -> None:
|
||||
if options_dict is not None:
|
||||
for key in option_names:
|
||||
setattr(self, key, options_dict[key])
|
||||
|
||||
@property
|
||||
def _fields(self) -> typing.Tuple[str, ...]:
|
||||
return option_names
|
||||
|
||||
def __iter__(self) -> typing.Iterator[str]:
|
||||
return iter(self._fields)
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(self._fields)
|
||||
|
||||
def _copy_of_val(self, name: str) -> typing.Any:
|
||||
ans = getattr(self, name)
|
||||
if isinstance(ans, dict):
|
||||
ans = ans.copy()
|
||||
elif isinstance(ans, list):
|
||||
ans = ans[:]
|
||||
return ans
|
||||
|
||||
def _asdict(self) -> typing.Dict[str, typing.Any]:
|
||||
return {k: self._copy_of_val(k) for k in self}
|
||||
|
||||
def _replace(self, **kw: typing.Any) -> "Options":
|
||||
ans = Options()
|
||||
for name in self:
|
||||
setattr(ans, name, self._copy_of_val(name))
|
||||
for name, val in kw.items():
|
||||
setattr(ans, name, val)
|
||||
return ans
|
||||
|
||||
def __getitem__(self, key: typing.Union[int, str]) -> typing.Any:
|
||||
k = option_names[key] if isinstance(key, int) else key
|
||||
try:
|
||||
return getattr(self, k)
|
||||
except AttributeError:
|
||||
pass
|
||||
raise KeyError(f"No option named: {k}")
|
||||
|
||||
|
||||
defaults = Options()
|
||||
defaults.map = [
|
||||
# quit
|
||||
(ParsedShortcut(mods=0, key_name='q'), KeyAction('quit')),
|
||||
# quit
|
||||
(ParsedShortcut(mods=0, key_name='ESCAPE'), KeyAction('quit')),
|
||||
# scroll_down
|
||||
(ParsedShortcut(mods=0, key_name='j'), KeyAction('scroll_by', (1,))),
|
||||
# scroll_down
|
||||
(ParsedShortcut(mods=0, key_name='DOWN'), KeyAction('scroll_by', (1,))),
|
||||
# scroll_up
|
||||
(ParsedShortcut(mods=0, key_name='k'), KeyAction('scroll_by', (-1,))),
|
||||
# scroll_up
|
||||
(ParsedShortcut(mods=0, key_name='UP'), KeyAction('scroll_by', (-1,))),
|
||||
# scroll_top
|
||||
(ParsedShortcut(mods=0, key_name='HOME'), KeyAction('scroll_to', ('start',))),
|
||||
# scroll_bottom
|
||||
(ParsedShortcut(mods=0, key_name='END'), KeyAction('scroll_to', ('end',))),
|
||||
# scroll_page_down
|
||||
(ParsedShortcut(mods=0, key_name='PAGE_DOWN'), KeyAction('scroll_to', ('next-page',))),
|
||||
# scroll_page_down
|
||||
(ParsedShortcut(mods=0, key_name=' '), KeyAction('scroll_to', ('next-page',))),
|
||||
# scroll_page_up
|
||||
(ParsedShortcut(mods=0, key_name='PAGE_UP'), KeyAction('scroll_to', ('prev-page',))),
|
||||
# next_change
|
||||
(ParsedShortcut(mods=0, key_name='n'), KeyAction('scroll_to', ('next-change',))),
|
||||
# prev_change
|
||||
(ParsedShortcut(mods=0, key_name='p'), KeyAction('scroll_to', ('prev-change',))),
|
||||
# all_context
|
||||
(ParsedShortcut(mods=0, key_name='a'), KeyAction('change_context', ('all',))),
|
||||
# default_context
|
||||
(ParsedShortcut(mods=0, key_name='='), KeyAction('change_context', ('default',))),
|
||||
# increase_context
|
||||
(ParsedShortcut(mods=0, key_name='+'), KeyAction('change_context', (5,))),
|
||||
# decrease_context
|
||||
(ParsedShortcut(mods=0, key_name='-'), KeyAction('change_context', (-5,))),
|
||||
# search_forward
|
||||
(ParsedShortcut(mods=0, key_name='/'), KeyAction('start_search', (True, False))),
|
||||
# search_backward
|
||||
(ParsedShortcut(mods=0, key_name='?'), KeyAction('start_search', (True, True))),
|
||||
# next_match
|
||||
(ParsedShortcut(mods=0, key_name='.'), KeyAction('scroll_to', ('next-match',))),
|
||||
# next_match
|
||||
(ParsedShortcut(mods=0, key_name='>'), KeyAction('scroll_to', ('next-match',))),
|
||||
# prev_match
|
||||
(ParsedShortcut(mods=0, key_name=','), KeyAction('scroll_to', ('prev-match',))),
|
||||
# prev_match
|
||||
(ParsedShortcut(mods=0, key_name='<'), KeyAction('scroll_to', ('prev-match',))),
|
||||
# search_forward_simple
|
||||
(ParsedShortcut(mods=0, key_name='f'), KeyAction('start_search', (False, False))),
|
||||
# search_backward_simple
|
||||
(ParsedShortcut(mods=0, key_name='b'), KeyAction('start_search', (False, True))),
|
||||
]
|
||||
62
kittens/diff/options/utils.py
Normal file
62
kittens/diff/options/utils.py
Normal file
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
|
||||
from typing import Any, Dict, Iterable, Sequence, Tuple, Union
|
||||
|
||||
from kitty.conf.utils import KittensKeyDefinition, key_func, parse_kittens_key
|
||||
|
||||
func_with_args, args_funcs = key_func()
|
||||
FuncArgsType = Tuple[str, Sequence[Any]]
|
||||
|
||||
|
||||
@func_with_args('scroll_by')
|
||||
def parse_scroll_by(func: str, rest: str) -> Tuple[str, int]:
|
||||
try:
|
||||
return func, int(rest)
|
||||
except Exception:
|
||||
return func, 1
|
||||
|
||||
|
||||
@func_with_args('scroll_to')
|
||||
def parse_scroll_to(func: str, rest: str) -> Tuple[str, str]:
|
||||
rest = rest.lower()
|
||||
if rest not in {'start', 'end', 'next-change', 'prev-change', 'next-page', 'prev-page', 'next-match', 'prev-match'}:
|
||||
rest = 'start'
|
||||
return func, rest
|
||||
|
||||
|
||||
@func_with_args('change_context')
|
||||
def parse_change_context(func: str, rest: str) -> Tuple[str, Union[int, str]]:
|
||||
rest = rest.lower()
|
||||
if rest in {'all', 'default'}:
|
||||
return func, rest
|
||||
try:
|
||||
amount = int(rest)
|
||||
except Exception:
|
||||
amount = 5
|
||||
return func, amount
|
||||
|
||||
|
||||
@func_with_args('start_search')
|
||||
def parse_start_search(func: str, rest: str) -> Tuple[str, Tuple[bool, bool]]:
|
||||
rest_ = rest.lower().split()
|
||||
is_regex = bool(rest_ and rest_[0] == 'regex')
|
||||
is_backward = bool(len(rest_) > 1 and rest_[1] == 'backward')
|
||||
return func, (is_regex, is_backward)
|
||||
|
||||
|
||||
def syntax_aliases(raw: str) -> Dict[str, str]:
|
||||
ans = {}
|
||||
for x in raw.split():
|
||||
a, b = x.partition(':')[::2]
|
||||
if a and b:
|
||||
ans[a.lower()] = b
|
||||
return ans
|
||||
|
||||
|
||||
def parse_map(val: str) -> Iterable[KittensKeyDefinition]:
|
||||
x = parse_kittens_key(val, args_funcs)
|
||||
if x is not None:
|
||||
yield x
|
||||
@@ -3,16 +3,17 @@
|
||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import warnings
|
||||
from functools import lru_cache
|
||||
from gettext import gettext as _
|
||||
from itertools import repeat, zip_longest
|
||||
from math import ceil
|
||||
from typing import Callable, Dict, Generator, Iterable, List, Optional, Tuple
|
||||
|
||||
from kitty.fast_data_types import truncate_point_for_length, wcswidth
|
||||
from kitty.cli_stub import DiffCLIOptions
|
||||
from kitty.fast_data_types import truncate_point_for_length, wcswidth
|
||||
from kitty.types import run_once
|
||||
from kitty.utils import ScreenSize
|
||||
|
||||
from ..tui.images import ImageManager, can_display_images
|
||||
from .collect import (
|
||||
Collection, Segment, data_for_path, highlights_for_path, is_image,
|
||||
lines_for_path, path_name_map, sanitize
|
||||
@@ -20,14 +21,13 @@ from .collect import (
|
||||
from .config import formats
|
||||
from .diff_speedup import split_with_highlights as _split_with_highlights
|
||||
from .patch import Chunk, Hunk, Patch
|
||||
from ..tui.images import ImageManager, can_display_images
|
||||
|
||||
|
||||
class ImageSupportWarning(Warning):
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(maxsize=2)
|
||||
@run_once
|
||||
def images_supported() -> bool:
|
||||
ans = can_display_images()
|
||||
if not ans:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user