From ea1c6567cf251bd530c06b91d85359703c938b03 Mon Sep 17 00:00:00 2001 From: Ada Date: Mon, 7 Apr 2025 22:47:35 +1000 Subject: [PATCH 1/4] Initial prototype for VR keyboard shortcuts --- interface/resources/config/keyboard.json | 75 ++++++++++++++++++ .../resources/meshes/keyboard/key_copy.png | Bin 0 -> 2395 bytes .../resources/meshes/keyboard/key_paste.png | Bin 0 -> 2360 bytes .../meshes/keyboard/key_select_all.png | Bin 0 -> 2422 bytes interface/src/ui/Keyboard.cpp | 60 ++++++++++++++ interface/src/ui/Keyboard.h | 5 +- 6 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 interface/resources/meshes/keyboard/key_copy.png create mode 100644 interface/resources/meshes/keyboard/key_paste.png create mode 100644 interface/resources/meshes/keyboard/key_select_all.png diff --git a/interface/resources/config/keyboard.json b/interface/resources/config/keyboard.json index e16c6156ab..5ae05d4044 100644 --- a/interface/resources/config/keyboard.json +++ b/interface/resources/config/keyboard.json @@ -811,6 +811,81 @@ "z": 0.707 } }, + { + "key": "Copy", + "type": "copy", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.65333323516845703, + "y": 0.019300000742077827, + "z": -0.07 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_copy.png", + "file10": "meshes/keyboard/key_copy.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Paste", + "type": "paste", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.65333323516845703, + "y": 0.019300000742077827, + "z": -0.12 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_paste.png", + "file10": "meshes/keyboard/key_paste.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Select All", + "type": "select_all", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.65333323516845703, + "y": 0.019300000742077827, + "z": -0.02 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_select_all.png", + "file10": "meshes/keyboard/key_select_all.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, { "key": "numbers", "type": "layer", diff --git a/interface/resources/meshes/keyboard/key_copy.png b/interface/resources/meshes/keyboard/key_copy.png new file mode 100644 index 0000000000000000000000000000000000000000..253adc5a378ee8184cd9384cdf47224da7a60945 GIT binary patch literal 2395 zcmeHIeM}p57=G@0mO@*11ky3O(Q{!=XNXmSAfml8ay(D4);{{z#0KUe==koz+fO`@6q#_9Ll_$k% z(+hfjzx=fB5*t{0t~xtnD9e)F9iOpoY3D?B^|PTHKKwx!^XEZF``!X=7~R^NS6hBj zwX0_AZfqO2|S&>y+GSowS>UOmbcU zi%RC9(o499dCwM}*rG1VOZdDyyz@5Ty=tP44=Oc%#U`ZJX_l{lKpusSp5Yz_}TPY4$t7O4dfkx`7iq%3nSn#aXcEv;x z=q5oTe#Lp=Q>THLJ5}OCZ%g|l!GKABlgiARnh<4tw<86Y@(9_np}qMxY?BB5Xz-lb zboK%*VxVu-K58-MG>&Afr7Zy{f^uHOh|4^IyiL^sLyK1PNj8io` zlbA6IDhg_P*mP@B{wXP&#$=$uGVOl1YwR_4g~t73)6xTIJRT!u3>%HZ4xh+-y8)}Z z>#$r9ib5#xRo2ZE1DO5iBq%z3;wEwl7C00K2^gak67ULsm?RKtAkxY{f6A8xO{o0U z$&#pPGhhjtVZdE>MZDWC>av%$I$mUXtNEz2Xf&a$Wl9L`R_&^(KaEo7XGi3xSLvK2 z2yEjlYwJ&Ju-OxUl~p{mX{@h#U^fuQ23ae^`|iTGOJc1mCAc~R=Z;IZ!>l40aC>O= zxE9d*>+NQM%;tF?0EjaU`TNxUZf2z;4D-LBEo6Bf%kfgey@Y$@`oE<3|ISbs jXJqr7X>PU`CMcur!F^ZW=}k68*a0BvNnKoRtiI$go#v)H literal 0 HcmV?d00001 diff --git a/interface/resources/meshes/keyboard/key_paste.png b/interface/resources/meshes/keyboard/key_paste.png new file mode 100644 index 0000000000000000000000000000000000000000..e3f7e1d52c3157275f26c5a0160cd04e16094015 GIT binary patch literal 2360 zcmds2Yfw~W7=F�~{{v9+VLXbPrMtr6Ez_MqCa>Tt=dep^=Pfx9DPo?G}d2fN~N+ zv%*_5D3oC}k?zvp{josuATyT=WHJSj0Q6`(;L))~NL-qjfZuKL91a{%{c*>_KL{5A*`IkoqLk2@L8vIKd^edMw314FhJeqp{>WR96-a0jQqirtwfd$&9}qCzA+kHCV8 zIiy@9+@ZW9g(J40MlBLPuZMR(2GZXT5qF{AQ;O);D7RX>46{`(%+4*UBQ4&0sq0I& z2Y^Lzw5b@}{;jCIGNzgBrfm(D600|$3<4x=gP#DgcWn?T>~@H<@9JgUR9_|p2^M2LI5Df@o(PT-)d;9=bkPdifJ=ji%&l3oE)*(^qsHzRh8{ax%0n95ba2JwVP6Xisoj-@ zc6haL?X#$!muVW8a$W@kpX!?rc3HN`Jt2KgUCz?SMO@kN_@{mrn>OM|cTlU5!PreO%+ zAyTViYfR(D7#5qt(njU&M`VBeI4V2G(1?(KP*-yCxb=jp#{8uF!35NUcH zFv-bwnlj&Rwkxbndl3wUrnK8$znK&?YRocvo_}!X542kAz|!c{x5d9QT?8EPh}T(* z=9|oitp=<8sA!2?U-q4_zGqt>Q|7exdxq=Q&V7p`N(TE%%dGa6HJ&ZbH!5smi^By| z3K~5DLxmiHaS*1OeY=@)Clx<(m}B(y!-SHT{}@>l9x90$zNnDV<@y;HZ@>`4LK4CW{-%m( zO#=lN|v2sK~H5fP}E5VgNHKUGo5J)sgRLfOQ*$Mc`baGhpi-6&AWT zrDv?S_YIc=baw2QWi2xUPG|fJ55~#(+^I z`$lQJsR|8n04RU~KmbyJH5Gr-)*9iKB35O$z%86si#?quy|!zuD8k~3%|8fORm>vg z8sQe@Eh#K9p&eFmTXoCY$NN_%tFo{5# zK|oxTCX%A5greZAPwn44U#z%5&T$6slv#S~Ffd0U-!o5QDxHO~%F!x_3NSL_*dgTJkwBBC)TmO+Dia zDL&UX*18UfJs6+fxd*3M7t74*#Jjy4%96r?Ky-HQI9}5)kSdtJ>8nXZu z&jEBe1I{(ecf@EYl|33`0-sI)62ks%<8fH|rssTEYEs*)4F(?N*Cf<>{6bR>4getPrimaryWidget(), pressEvent); + QCoreApplication::postEvent(qApp->getPrimaryWidget(), releaseEvent); + } else { + QCoreApplication::postEvent(QCoreApplication::instance(), pressEvent); + QCoreApplication::postEvent(QCoreApplication::instance(), releaseEvent); + } + + _typedCharacters.clear(); + updateTextDisplay(); + return; + } + // TODO, macOS: If macOS support comes back, these should be revisited + case Key::Type::PASTE: { + QKeyEvent* pressEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_V, Qt::ControlModifier); + QKeyEvent* releaseEvent = new QKeyEvent(QEvent::KeyRelease, Qt::Key_V, Qt::ControlModifier); + + if (_inputToHudUI) { + QCoreApplication::postEvent(qApp->getPrimaryWidget(), pressEvent); + QCoreApplication::postEvent(qApp->getPrimaryWidget(), releaseEvent); + } else { + QCoreApplication::postEvent(QCoreApplication::instance(), pressEvent); + QCoreApplication::postEvent(QCoreApplication::instance(), releaseEvent); + } + + _typedCharacters.clear(); + updateTextDisplay(); + return; + } + // TODO, macOS: If macOS support comes back, these should be revisited + case Key::Type::SELECT_ALL: { + QKeyEvent* pressEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::ControlModifier); + QKeyEvent* releaseEvent = new QKeyEvent(QEvent::KeyRelease, Qt::Key_A, Qt::ControlModifier); + + if (_inputToHudUI) { + QCoreApplication::postEvent(qApp->getPrimaryWidget(), pressEvent); + QCoreApplication::postEvent(qApp->getPrimaryWidget(), releaseEvent); + } else { + QCoreApplication::postEvent(QCoreApplication::instance(), pressEvent); + QCoreApplication::postEvent(QCoreApplication::instance(), releaseEvent); + } + + _typedCharacters.clear(); + updateTextDisplay(); + return; + } case Key::Type::CHARACTER: if (keyString != " ") { _typedCharacters.push_back((_password ? "*" : keyString)); diff --git a/interface/src/ui/Keyboard.h b/interface/src/ui/Keyboard.h index 44fddd9e42..88fef2555c 100644 --- a/interface/src/ui/Keyboard.h +++ b/interface/src/ui/Keyboard.h @@ -40,7 +40,10 @@ public: LAYER, BACKSPACE, SPACE, - ENTER + ENTER, + COPY, + PASTE, + SELECT_ALL, }; static Key::Type getKeyTypeFromString(const QString& keyTypeString); From ff46c739a369bafdcb67ccc6e6cfbc9e0a7e21dd Mon Sep 17 00:00:00 2001 From: Ada Date: Mon, 7 Apr 2025 23:41:46 +1000 Subject: [PATCH 2/4] Cut key --- interface/resources/config/keyboard.json | 79 ++++++++----- .../resources/meshes/keyboard/key_cut.png | Bin 0 -> 2525 bytes interface/src/ui/Keyboard.cpp | 110 +++++++++--------- interface/src/ui/Keyboard.h | 6 +- 4 files changed, 110 insertions(+), 85 deletions(-) create mode 100644 interface/resources/meshes/keyboard/key_cut.png diff --git a/interface/resources/config/keyboard.json b/interface/resources/config/keyboard.json index 5ae05d4044..6a6cc4d6b7 100644 --- a/interface/resources/config/keyboard.json +++ b/interface/resources/config/keyboard.json @@ -811,6 +811,56 @@ "z": 0.707 } }, + { + "key": "Select All", + "type": "select_all", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.65333323516845703, + "y": 0.019300000742077827, + "z": -0.02 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_select_all.png", + "file10": "meshes/keyboard/key_select_all.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Cut", + "type": "cut", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.70333323516845703, + "y": 0.019300000742077827, + "z": -0.02 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_cut.png", + "file10": "meshes/keyboard/key_cut.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, { "key": "Copy", "type": "copy", @@ -845,9 +895,9 @@ "y": 0.04787999764084816 }, "position": { - "x": -0.65333323516845703, + "x": -0.70333323516845703, "y": 0.019300000742077827, - "z": -0.12 + "z": -0.07 }, "modelURL": "meshes/keyboard/SM_key.fbx", "texture": { @@ -861,31 +911,6 @@ "z": 0.707 } }, - { - "key": "Select All", - "type": "select_all", - "dimensions": { - "x": 0.04787999764084816, - "z": 0.020519999787211418, - "y": 0.04787999764084816 - }, - "position": { - "x": -0.65333323516845703, - "y": 0.019300000742077827, - "z": -0.02 - }, - "modelURL": "meshes/keyboard/SM_key.fbx", - "texture": { - "file9": "meshes/keyboard/key_select_all.png", - "file10": "meshes/keyboard/key_select_all.png" - }, - "localOrientation": { - "w": 0.000, - "x": 0.000, - "y": 0.707, - "z": 0.707 - } - }, { "key": "numbers", "type": "layer", diff --git a/interface/resources/meshes/keyboard/key_cut.png b/interface/resources/meshes/keyboard/key_cut.png new file mode 100644 index 0000000000000000000000000000000000000000..6d8cc4b9fb6baddd06ff24e00e3ecace8c59bfb9 GIT binary patch literal 2525 zcmds2eNYs27=Ctdf#u_3O|%mnZj+JDuQ-+PM#)=LzABH8OfhBx%hAkBP?$snZViP| zkGV0OrVtg=i6jF`9h(7SH3ypMCMZIL@D2e{0XZ)*Ih5OGu}Nv15&EO1{`k$#zWctv z_j%vv-RIpMtBaI-_<8`4M@KD-2S`YVb_Fny@$(P>_tdD>X@KWM=@2L^QULCz=w)Fm zGFoq5j@vZxWuNdkqoUyBy;Hmz)wyfb#yXWD?trF0y|Tx$aAWqfN8M^|oqeUcqDIG- z>TDT4$+|lkJOBz{0T2KUa3hJq;7Omx>HaVYIhNZWxi!57f1gbu@zHxmr6@KkE##$ZR;yL%wA3dVs=~PFlG|4^ zZ-)q9ej7xAz?IG*irduM{JG+fFca;RDE`EAiakDtzrX`{28?ZU%u|P>I2d<+4-1Kkc z%=xP74GDAO+dk#}km`Bs9UrS-g!Z7YTu$Pn&}sF)9miAh(}vs#xSBIa65RzI=2_ie zl-HzDw1PpbuH>3IdTEbCOF}Ia1PC{j6!=ChjnC3b+vaH^hc9oBDEt0It7Kqm~y@`^tj7c52f42b6D&N$Ez+^h7IW;hpo)T9(5BAoxl zl>ztmhzYWZ7n-y*R4-^Eq`s_8aghlez#&~*2dz`4Gg#) zQBxd4MlFrxcuMgq0|ArVw$>hlR0;Z_Yd2*O1;!sx|+J1{Ga`AviT4-)8B(-gjrW^@g&0 z;h~`BgJ+3;Qq@gOnP?CQ z_K!K@Pm@qBb~e?vNVW_W?W zL93=IFfUO&5a?an>@}j^T>k#e*Y=;bd4Pb|)P{c1)#S~9>#Oh!W56X)CqtZXy85Rr zOe$NDBC9BjJbZJnOB*n|`_$$I&aa778L(;m8|Q(x{HMh6A76FsI5zkwt^Sv`$N#B8 a5%;`nVg~5+Uj2sv5FM^tR<getPrimaryWidget(), pressEvent); + QCoreApplication::postEvent(qApp->getPrimaryWidget(), releaseEvent); + } else { + QCoreApplication::postEvent(QCoreApplication::instance(), pressEvent); + QCoreApplication::postEvent(QCoreApplication::instance(), releaseEvent); + } + + _typedCharacters.clear(); + updateTextDisplay(); +} + void Keyboard::handleTriggerBegin(const QUuid& id, const PointerEvent& event) { auto buttonType = event.getButton(); if (!shouldProcessEntityAndPointerEvent(event) || buttonType != PointerEvent::PrimaryButton) { @@ -582,57 +625,12 @@ void Keyboard::handleTriggerBegin(const QUuid& id, const PointerEvent& event) { _typedCharacters.clear(); updateTextDisplay(); break; - // TODO, macOS: If macOS support comes back, these should be revisited - case Key::Type::COPY: { - QKeyEvent* pressEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_C, Qt::ControlModifier); - QKeyEvent* releaseEvent = new QKeyEvent(QEvent::KeyRelease, Qt::Key_C, Qt::ControlModifier); - - if (_inputToHudUI) { - QCoreApplication::postEvent(qApp->getPrimaryWidget(), pressEvent); - QCoreApplication::postEvent(qApp->getPrimaryWidget(), releaseEvent); - } else { - QCoreApplication::postEvent(QCoreApplication::instance(), pressEvent); - QCoreApplication::postEvent(QCoreApplication::instance(), releaseEvent); - } - - _typedCharacters.clear(); - updateTextDisplay(); + case Key::Type::SELECT_ALL: + case Key::Type::COPY: + case Key::Type::CUT: + case Key::Type::PASTE: + handleShortcut(key.getKeyType()); return; - } - // TODO, macOS: If macOS support comes back, these should be revisited - case Key::Type::PASTE: { - QKeyEvent* pressEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_V, Qt::ControlModifier); - QKeyEvent* releaseEvent = new QKeyEvent(QEvent::KeyRelease, Qt::Key_V, Qt::ControlModifier); - - if (_inputToHudUI) { - QCoreApplication::postEvent(qApp->getPrimaryWidget(), pressEvent); - QCoreApplication::postEvent(qApp->getPrimaryWidget(), releaseEvent); - } else { - QCoreApplication::postEvent(QCoreApplication::instance(), pressEvent); - QCoreApplication::postEvent(QCoreApplication::instance(), releaseEvent); - } - - _typedCharacters.clear(); - updateTextDisplay(); - return; - } - // TODO, macOS: If macOS support comes back, these should be revisited - case Key::Type::SELECT_ALL: { - QKeyEvent* pressEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::ControlModifier); - QKeyEvent* releaseEvent = new QKeyEvent(QEvent::KeyRelease, Qt::Key_A, Qt::ControlModifier); - - if (_inputToHudUI) { - QCoreApplication::postEvent(qApp->getPrimaryWidget(), pressEvent); - QCoreApplication::postEvent(qApp->getPrimaryWidget(), releaseEvent); - } else { - QCoreApplication::postEvent(QCoreApplication::instance(), pressEvent); - QCoreApplication::postEvent(QCoreApplication::instance(), releaseEvent); - } - - _typedCharacters.clear(); - updateTextDisplay(); - return; - } case Key::Type::CHARACTER: if (keyString != " ") { _typedCharacters.push_back((_password ? "*" : keyString)); diff --git a/interface/src/ui/Keyboard.h b/interface/src/ui/Keyboard.h index 88fef2555c..0b0de6110f 100644 --- a/interface/src/ui/Keyboard.h +++ b/interface/src/ui/Keyboard.h @@ -41,9 +41,10 @@ public: BACKSPACE, SPACE, ENTER, - COPY, - PASTE, SELECT_ALL, + COPY, + CUT, + PASTE, }; static Key::Type getKeyTypeFromString(const QString& keyTypeString); @@ -164,6 +165,7 @@ private: void startLayerSwitchTimer(); bool isLayerSwitchTimerFinished() const; + void handleShortcut(Key::Type keyType); bool _raised { false }; bool _resetKeyboardPositionOnRaise { true }; From a73652008713440cfa9d5ddd763158d5cd4008b7 Mon Sep 17 00:00:00 2001 From: Ada Date: Tue, 8 Apr 2025 01:40:29 +1000 Subject: [PATCH 3/4] Move copy/paste, add cursor keys --- interface/resources/config/keyboard.json | 518 +++++++++++++++++- .../resources/meshes/keyboard/key_down.png | Bin 0 -> 2294 bytes .../resources/meshes/keyboard/key_left.png | Bin 0 -> 2268 bytes .../resources/meshes/keyboard/key_right.png | Bin 0 -> 2276 bytes .../resources/meshes/keyboard/key_up.png | Bin 0 -> 2300 bytes interface/src/ui/Keyboard.cpp | 45 +- interface/src/ui/Keyboard.h | 6 +- 7 files changed, 555 insertions(+), 14 deletions(-) create mode 100644 interface/resources/meshes/keyboard/key_down.png create mode 100644 interface/resources/meshes/keyboard/key_left.png create mode 100644 interface/resources/meshes/keyboard/key_right.png create mode 100644 interface/resources/meshes/keyboard/key_up.png diff --git a/interface/resources/config/keyboard.json b/interface/resources/config/keyboard.json index 6a6cc4d6b7..4528003602 100644 --- a/interface/resources/config/keyboard.json +++ b/interface/resources/config/keyboard.json @@ -820,9 +820,9 @@ "y": 0.04787999764084816 }, "position": { - "x": -0.65333323516845703, + "x": -0.026292800903320312, "y": 0.019300000742077827, - "z": -0.02 + "z": 0.09745675086975098 }, "modelURL": "meshes/keyboard/SM_key.fbx", "texture": { @@ -841,13 +841,13 @@ "type": "cut", "dimensions": { "x": 0.04787999764084816, - "z": 0.020519999787211418, + "z": 0.02051999792456627, "y": 0.04787999764084816 }, "position": { - "x": -0.70333323516845703, + "x": -0.08203601837158203, "y": 0.019300000742077827, - "z": -0.02 + "z": 0.09745675086975098 }, "modelURL": "meshes/keyboard/SM_key.fbx", "texture": { @@ -870,9 +870,9 @@ "y": 0.04787999764084816 }, "position": { - "x": -0.65333323516845703, + "x": -0.47769832611083984, "y": 0.019300000742077827, - "z": -0.07 + "z": 0.09745675086975098 }, "modelURL": "meshes/keyboard/SM_key.fbx", "texture": { @@ -895,9 +895,9 @@ "y": 0.04787999764084816 }, "position": { - "x": -0.70333323516845703, + "x": -0.5332040786743164, "y": 0.019300000742077827, - "z": -0.07 + "z": 0.09745675086975098 }, "modelURL": "meshes/keyboard/SM_key.fbx", "texture": { @@ -911,6 +911,106 @@ "z": 0.707 } }, + { + "key": "Up", + "type": "cursor_up", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.68333323516845703, + "y": 0.019300000742077827, + "z": -0.02282185554504395 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_up.png", + "file10": "meshes/keyboard/key_up.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Left", + "type": "cursor_left", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.63333323516845703, + "y": 0.019300000742077827, + "z": -0.07282185554504395 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_left.png", + "file10": "meshes/keyboard/key_left.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Down", + "type": "cursor_down", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.68333323516845703, + "y": 0.019300000742077827, + "z": -0.07282185554504395 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_down.png", + "file10": "meshes/keyboard/key_down.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Right", + "type": "cursor_right", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.73333323516845703, + "y": 0.019300000742077827, + "z": -0.07282185554504395 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_right.png", + "file10": "meshes/keyboard/key_right.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, { "key": "numbers", "type": "layer", @@ -1689,6 +1789,206 @@ "z": 0.707 } }, + { + "key": "Select All", + "type": "select_all", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.026292800903320312, + "y": 0.019300000742077827, + "z": 0.09745675086975098 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_select_all.png", + "file10": "meshes/keyboard/key_select_all.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Cut", + "type": "cut", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.02051999792456627, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.08203601837158203, + "y": 0.019300000742077827, + "z": 0.09745675086975098 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_cut.png", + "file10": "meshes/keyboard/key_cut.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Copy", + "type": "copy", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.47769832611083984, + "y": 0.019300000742077827, + "z": 0.09745675086975098 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_copy.png", + "file10": "meshes/keyboard/key_copy.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Paste", + "type": "paste", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.5332040786743164, + "y": 0.019300000742077827, + "z": 0.09745675086975098 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_paste.png", + "file10": "meshes/keyboard/key_paste.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Up", + "type": "cursor_up", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.68333323516845703, + "y": 0.019300000742077827, + "z": -0.02282185554504395 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_up.png", + "file10": "meshes/keyboard/key_up.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Left", + "type": "cursor_left", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.63333323516845703, + "y": 0.019300000742077827, + "z": -0.07282185554504395 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_left.png", + "file10": "meshes/keyboard/key_left.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Down", + "type": "cursor_down", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.68333323516845703, + "y": 0.019300000742077827, + "z": -0.07282185554504395 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_down.png", + "file10": "meshes/keyboard/key_down.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Right", + "type": "cursor_right", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.73333323516845703, + "y": 0.019300000742077827, + "z": -0.07282185554504395 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_right.png", + "file10": "meshes/keyboard/key_right.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, { "key": "numbers", "type": "layer", @@ -2515,6 +2815,206 @@ "z": 0.707 } }, + { + "key": "Select All", + "type": "select_all", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.026292800903320312, + "y": 0.019300000742077827, + "z": 0.09745675086975098 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_select_all.png", + "file10": "meshes/keyboard/key_select_all.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Cut", + "type": "cut", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.02051999792456627, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.08203601837158203, + "y": 0.019300000742077827, + "z": 0.09745675086975098 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_cut.png", + "file10": "meshes/keyboard/key_cut.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Copy", + "type": "copy", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.47769832611083984, + "y": 0.019300000742077827, + "z": 0.09745675086975098 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_copy.png", + "file10": "meshes/keyboard/key_copy.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Paste", + "type": "paste", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.5332040786743164, + "y": 0.019300000742077827, + "z": 0.09745675086975098 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_paste.png", + "file10": "meshes/keyboard/key_paste.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Up", + "type": "cursor_up", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.68333323516845703, + "y": 0.019300000742077827, + "z": -0.02282185554504395 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_up.png", + "file10": "meshes/keyboard/key_up.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Left", + "type": "cursor_left", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.63333323516845703, + "y": 0.019300000742077827, + "z": -0.07282185554504395 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_left.png", + "file10": "meshes/keyboard/key_left.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Down", + "type": "cursor_down", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.68333323516845703, + "y": 0.019300000742077827, + "z": -0.07282185554504395 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_down.png", + "file10": "meshes/keyboard/key_down.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, + { + "key": "Right", + "type": "cursor_right", + "dimensions": { + "x": 0.04787999764084816, + "z": 0.020519999787211418, + "y": 0.04787999764084816 + }, + "position": { + "x": -0.73333323516845703, + "y": 0.019300000742077827, + "z": -0.07282185554504395 + }, + "modelURL": "meshes/keyboard/SM_key.fbx", + "texture": { + "file9": "meshes/keyboard/key_right.png", + "file10": "meshes/keyboard/key_right.png" + }, + "localOrientation": { + "w": 0.000, + "x": 0.000, + "y": 0.707, + "z": 0.707 + } + }, { "key": "numbers", "type": "layer", diff --git a/interface/resources/meshes/keyboard/key_down.png b/interface/resources/meshes/keyboard/key_down.png new file mode 100644 index 0000000000000000000000000000000000000000..fd9cc215e2884cceede805eb77165769e64d39cb GIT binary patch literal 2294 zcmds2VN8`(7=F&V-~H~9dx0Z4xQWCU%<>1fbhRwd_z;-f7WAdL=J@kDr!;4BH&$R! z9D`^Y6l*P~vbZjqRMTi|U`6ufZPkx(Y-Q8D+r^rtI0_>gBHY`~?Y1kf4X*s_$N9GJ zocDd7=Y8JuzGuHtu`xMmc@ltRZ&}GEfI=>&0{FA;`)L46d}Ui}0OuWY5ghJt1FYLy zQuI{ak7L21XGisAEf@Kd$-mh%etyWe=Dx2c+snK1SXz7Mp+`a!dGD4TEZEvn`?@FP z*u*@L%U+JKS5`2h;)vd<=@+B>YoN=4An_eMSe)I(9vgX0hB8Fr50=bai2hKm5UlEZZB9}X_jAd0FZErkp{c5ujZLSR?l>0Lcj1k0*K zM*)Lx;yG17bY18sjDfYGzp*Nr!nGk%706c5wVS+|V{K2B{=Pm9TD`F{*m_(dZCh$i zrb?2{ZM_OXj#Yks+(Gcx0TkINg61o&y*7dz{~trq{gc--!y2q~ZHE&KoZP*19CMglsb@N%_FgDt@K5?@uCktK2SIbGI9teoehD+_iT-F0QV_V($exJo zisS!q@n6$ty-Hmx7~Bujh6){m`EEEAjMoQ3W7!G}(`ioGC|s2~z|uIxQ740TFKuQF z7E}esditeo7jv1}s%TSt5AEoU98yXP)EqSGtGu)bk7L0Vf;@ zbq#@aIm@LoPjgZ8)!gJ?jaAw?h&=0>r+Kc1D*kyBjs1ErWu}$LWPkAb`Iq_Kcl?*W z{q5^8q1ZAyr{U(|q&l?}RXl_zqHh+!4P&cM55^_L>>*&JQUi}FpIqyNR%i8sx}pEP zdp@bSVVH6VY$kTdBm^Us3~c<*_r^Q2io~f(CQufmE=kJ3zFOjo*;Uk~(0!v5eJSFA zk&tV_v%uv(Vc%eJU=?!7lqC%PsA#yH&OUdikp!n2$m z=7ejgT+g;pV>;Z}RD`-l9enb_f;~X2i(-nXB#%hg?{rtiula6p|a3{gmEZec>) z|9|C%lhy24?A;`aYnDYG5pKs&l?6U|;c4{rfApCHA+UtgsE3Deqmv&%L_%}{0Wh#Z zsuBjSC3=PjW@T)B{9wEgwa|t(cx<4cZCqQ!)jJx%^qE~P%g&uf0o?KqHv=2ULL7im z6$f)(wTV`&H=OVgEP$V_tsp^{6igBaJe#3Gmq77GC27ut-g9kUxn(}Z2EY8!K}E&& z8d}_>1H9!bS+h3s9pZmu=KtnW%&m1C9nW;N Jo^I}Y>kl(0WYGWs literal 0 HcmV?d00001 diff --git a/interface/resources/meshes/keyboard/key_right.png b/interface/resources/meshes/keyboard/key_right.png new file mode 100644 index 0000000000000000000000000000000000000000..aa082807c3bd3b951b99121684c90de245ea74b6 GIT binary patch literal 2276 zcmcIlZ)_7~9DeS0ZC}=vU4huSX7n0EvMV`&psk(+-S)2qF_n7%pMV54t8Z-C?yD{NPA1Gb^K=s}dwg8yTK>Yt5a+W#O`QS^V(k z?tbs@p6B_!&-?z~?oEvwErq3p04xplp3MLYbr2(f+y2XU0W9;?KerPwuT%$vW5-JX z@0HQ`e-_#=0XG!uxpG}|Dq!(LQC%?F|=8%Yx zNq!W13#b=UeVs$0yWaVFa34}$=z7lS#qLAbbB@5l=uXV~HjhVnQRpGfja3ZGgszK> zY{)9p@xS|u4W*Z-$69Y!VP|LV1P=y#dPaD9$8SRO>&g-3EfLuJshd!sqZT|ULF3m$ z3_Dy$k8tM=@L93^=Qwsp>*Ce$g075jKeMesGJr(5uu=O<O*i+z-Ix2WGPr^B=j}a#WB^9!!;r&05!G$Jw^*%MWpMc z!5s`f{42G~-sEa%+A@0j-2)h3J(&u)1f;)p&MI z4&Hn3kG3h3%~?UvgwTVou%#SWYHo!-DA&pUb=v%D&Dk?rh{fA zyB$6T{oB~k1_Gg+Q-$D@)`*2)%4weOwEq7Gc@h0<9x)3~Eur1zfv(rp^kNI^T-xQ8 l=WV067<#e1N+5vnP4UA!jvc=mg@efC~aOVI3 literal 0 HcmV?d00001 diff --git a/interface/resources/meshes/keyboard/key_up.png b/interface/resources/meshes/keyboard/key_up.png new file mode 100644 index 0000000000000000000000000000000000000000..65b7e6707c0d38ff220a08f69f1c324696b76145 GIT binary patch literal 2300 zcmc&#ZERCz6n@@&Z=2VxjaNrz!)SLW8VF%Q6c`S57dBuE*)oVG5Ogac2vL->shf!F zy9JvOHktkq{K(jX3H;fdj%+LgTGGf+65JHySSPHC*@w>EDP*0N)x1}dw)oLDCi3I` zao_WtbDneFbDy)nxM;08X?79-b3uOI20#Em)Ck~u<)z;M+~vsMR1PGk@I&z42Nr;~ z7UZpbvT|U2u&?k(Rd%hf*-$vR?&&&T?Sb8kTj$Y?E48y|N5yc?@MKAY{nf*}dR$-q zu&3Kiu>OjbfC8$X2Qt6_NPq%>AciSHcsNO1(ZldCr@y<4%~MURtmq_Uh~9P+Z+re* z+E~qxW*O!rB>arGB85Z5H4uUN_PIFIa^boba_xRaEj~Y5cKTbZXbFBH69ufzzsT5> zIsxW)|2`}T7;yv+K!!S^-A5E)rC(M7*HQ(n*1u?>3J9VM^-D)8w`P^AKn=eb-LgCxZ|Lp&c4Ojo?%1z6Z#>_|akc3x80o(-?*8;6gA9AX zCon)aoxGWqLOP(pqfG?g$>cn?c++L5n%2o(_uWerc*d`erE|YyCY_T#&^@j9@pEm8 ziV{wqO`5%(3NSgdp5-OXe?0hxnZmKvY;DlldDFKi3;5*0mY&k-lGUJ?U!GgIciGRJ zr#-MW83Ni2{KY(Y$;iM`yXvzmWY}rfbapa_q*ZQi+@A>wRf2%Q8A7n+q2R}yp(~An zjdeP`S9vd)T_AWdpzI0M9ryEAv1X3AVPk$+ibu#F>=uj!q5 z#&mSS`$Fz43EDL_b-1ZMlN}L9FTRNZOFotXX=@HG7YX*Q0R?NIfnY^7N>7RCmzX(D zsrt*`5;@~)p?7&`?E7!FmF9hI@FC3Wq&Aoy_8q0ch@6v*PnwNSuR8)3lC zTe{fvz(HPo^>An8h@R7d#!yA-s|b0%3N$mfp;#spOAA3D3|;ksYl zRdae9`9@k{9D3{JcTH6?pc-r>LinS|$FX=4AQs*(-0T06&+zVyoW$G6#56^7j|q>c e?oKs`4LpI26-CmuZI2uSfP&RUd9ADLHGcq6pJRpq literal 0 HcmV?d00001 diff --git a/interface/src/ui/Keyboard.cpp b/interface/src/ui/Keyboard.cpp index 3d7d4bf264..a4d346fd2c 100644 --- a/interface/src/ui/Keyboard.cpp +++ b/interface/src/ui/Keyboard.cpp @@ -88,6 +88,10 @@ static const QString SELECT_ALL_STRING = "select_all"; static const QString COPY_STRING = "copy"; static const QString CUT_STRING = "cut"; static const QString PASTE_STRING = "paste"; +static const QString CURSOR_UP_STRING = "cursor_up"; +static const QString CURSOR_RIGHT_STRING = "cursor_right"; +static const QString CURSOR_DOWN_STRING = "cursor_down"; +static const QString CURSOR_LEFT_STRING = "cursor_left"; static const QString KEY_HOVER_HIGHLIGHT = "keyHoverHiglight"; static const QString KEY_PRESSED_HIGHLIGHT = "keyPressesHighlight"; @@ -216,6 +220,14 @@ Key::Type Key::getKeyTypeFromString(const QString& keyTypeString) { return Type::CUT; } else if (keyTypeString == PASTE_STRING) { return Type::PASTE; + } else if (keyTypeString == CURSOR_UP_STRING) { + return Type::CURSOR_UP; + } else if (keyTypeString == CURSOR_RIGHT_STRING) { + return Type::CURSOR_RIGHT; + } else if (keyTypeString == CURSOR_DOWN_STRING) { + return Type::CURSOR_DOWN; + } else if (keyTypeString == CURSOR_LEFT_STRING) { + return Type::CURSOR_LEFT; } return Type::CHARACTER; @@ -520,7 +532,8 @@ bool Keyboard::shouldProcessPointerEvent(const PointerEvent& event) const { return ((isStylusEvent && preferMalletsOverLasers) || (isLaserEvent && !preferMalletsOverLasers)); } -void Keyboard::handleShortcut(Key::Type keyType) { +void Keyboard::handleSpecialKey(Key::Type keyType) { + Qt::KeyboardModifier keyMod = Qt::ControlModifier; int keyCode; switch (keyType) { case Key::Type::SELECT_ALL: @@ -539,14 +552,34 @@ void Keyboard::handleShortcut(Key::Type keyType) { keyCode = Qt::Key_V; break; + case Key::Type::CURSOR_UP: + keyCode = Qt::Key_Up; + keyMod = Qt::NoModifier; + break; + + case Key::Type::CURSOR_RIGHT: + keyCode = Qt::Key_Right; + keyMod = Qt::NoModifier; + break; + + case Key::Type::CURSOR_DOWN: + keyCode = Qt::Key_Down; + keyMod = Qt::NoModifier; + break; + + case Key::Type::CURSOR_LEFT: + keyCode = Qt::Key_Left; + keyMod = Qt::NoModifier; + break; + // shouldn't reach here default: return; } // Qt automatically remaps ⌘A, ⌘C, etc. to ^A and ^C on macOS - QKeyEvent* pressEvent = new QKeyEvent(QEvent::KeyPress, keyCode, Qt::ControlModifier); - QKeyEvent* releaseEvent = new QKeyEvent(QEvent::KeyRelease, keyCode, Qt::ControlModifier); + QKeyEvent* pressEvent = new QKeyEvent(QEvent::KeyPress, keyCode, keyMod); + QKeyEvent* releaseEvent = new QKeyEvent(QEvent::KeyRelease, keyCode, keyMod); if (_inputToHudUI) { QCoreApplication::postEvent(qApp->getPrimaryWidget(), pressEvent); @@ -629,7 +662,11 @@ void Keyboard::handleTriggerBegin(const QUuid& id, const PointerEvent& event) { case Key::Type::COPY: case Key::Type::CUT: case Key::Type::PASTE: - handleShortcut(key.getKeyType()); + case Key::Type::CURSOR_UP: + case Key::Type::CURSOR_RIGHT: + case Key::Type::CURSOR_DOWN: + case Key::Type::CURSOR_LEFT: + handleSpecialKey(key.getKeyType()); return; case Key::Type::CHARACTER: if (keyString != " ") { diff --git a/interface/src/ui/Keyboard.h b/interface/src/ui/Keyboard.h index 0b0de6110f..81f2e13019 100644 --- a/interface/src/ui/Keyboard.h +++ b/interface/src/ui/Keyboard.h @@ -45,6 +45,10 @@ public: COPY, CUT, PASTE, + CURSOR_UP, + CURSOR_RIGHT, + CURSOR_DOWN, + CURSOR_LEFT, }; static Key::Type getKeyTypeFromString(const QString& keyTypeString); @@ -165,7 +169,7 @@ private: void startLayerSwitchTimer(); bool isLayerSwitchTimerFinished() const; - void handleShortcut(Key::Type keyType); + void handleSpecialKey(Key::Type keyType); bool _raised { false }; bool _resetKeyboardPositionOnRaise { true }; From b0594d651ec832dc65164c97ffd041779bd8be10 Mon Sep 17 00:00:00 2001 From: Ada Date: Tue, 8 Apr 2025 02:55:53 +1000 Subject: [PATCH 4/4] Keycap art for new keys --- .../resources/meshes/keyboard/key_copy.png | Bin 2395 -> 2593 bytes .../resources/meshes/keyboard/key_cut.png | Bin 2525 -> 5660 bytes .../resources/meshes/keyboard/key_down.png | Bin 2294 -> 2795 bytes .../resources/meshes/keyboard/key_left.png | Bin 2268 -> 2707 bytes .../resources/meshes/keyboard/key_paste.png | Bin 2360 -> 2920 bytes .../resources/meshes/keyboard/key_right.png | Bin 2276 -> 2664 bytes .../meshes/keyboard/key_select_all.png | Bin 2422 -> 3513 bytes .../resources/meshes/keyboard/key_up.png | Bin 2300 -> 2682 bytes 8 files changed, 0 insertions(+), 0 deletions(-) diff --git a/interface/resources/meshes/keyboard/key_copy.png b/interface/resources/meshes/keyboard/key_copy.png index 253adc5a378ee8184cd9384cdf47224da7a60945..d4d1e17165e65a976a95817382cf03e716b901f8 100644 GIT binary patch delta 1118 zcmV-k1fl!e5}_23Dt`gkZ~y_=Z~>v%EW!W)02y>eSaefwW^{L9a%BK_cXuvnZfkR6 zVQ^(GZ*pgw?mQX*012*1L_t(|+U?uFOWb!H$MN^qczR0+$Vnhk4jgVs(CZ|QW{TIr z43aam85}ztm@!D{5HWjGNQMk0Q5+nK3Z-!jS;`q)912GohbDM*NQSD1UYCx=_C&1HIz{exEQ?tO@t^+qgj zY{gEa=|ci3kzAWxY?}d2)|0ys_wL?^>cmKNC5b`)!*RPEOY2+l;PHz%Y#kW{oB%-j zFaD42PsQl)pfOI+l_YVeQjVd4zL=d~5dm=Czq2NQlg&@fjJx=EV03se=4QqX0RjNh zt5ht+bfs*F4oz3eQ7RS;0RjNhsX9@1&;K+(EJ+g83E>0+08+})zwJN(Kn7jCe8~v5 z0|5Y8lkf4MjO~$u7!!O^9@K?1bp6)DRKNc1)tWaEoRi@OGJjdsZ30M-Qn3)XZ;r%R zxfoaaFGjvMcdlRW_G;}+|Nj0#D|Yuj#LIdkmN&Lyr_uBw0RaGCkDlCxxOewPR3}EF zD@hFUuY7MVh6eg#XrM3deEUr-t#8GH$1mcrbz~e60FeHR|D*d;F*-bGj1zPvN!+QF zV`!i+X6IK#09SnMJ7WSk-{xk<{f005Jg1`d(!9ue^W=r#d-y|!0tMgW`u0007$&T1GgfzxQni0svC#?Ys9zIHlb^+kpUplzR30jS*}I0syjRX}uoD?Y1F0blh&o z(t6zxAOIkpb{frizUD&Kspo6;*l9Ek0RjNhYvIYJCNa+4nk kC6izR7aM>8001)LA87^g#}2C1XaE2J07*qoM6N<$f+KSEkN^Mx literal 2395 zcmeHIeM}p57=G@0mO@*11ky3O(Q{!=XNXmSAfml8ay(D4);{{z#0KUe==koz+fO`@6q#_9Ll_$k% z(+hfjzx=fB5*t{0t~xtnD9e)F9iOpoY3D?B^|PTHKKwx!^XEZF``!X=7~R^NS6hBj zwX0_AZfqO2|S&>y+GSowS>UOmbcU zi%RC9(o499dCwM}*rG1VOZdDyyz@5Ty=tP44=Oc%#U`ZJX_l{lKpusSp5Yz_}TPY4$t7O4dfkx`7iq%3nSn#aXcEv;x z=q5oTe#Lp=Q>THLJ5}OCZ%g|l!GKABlgiARnh<4tw<86Y@(9_np}qMxY?BB5Xz-lb zboK%*VxVu-K58-MG>&Afr7Zy{f^uHOh|4^IyiL^sLyK1PNj8io` zlbA6IDhg_P*mP@B{wXP&#$=$uGVOl1YwR_4g~t73)6xTIJRT!u3>%HZ4xh+-y8)}Z z>#$r9ib5#xRo2ZE1DO5iBq%z3;wEwl7C00K2^gak67ULsm?RKtAkxY{f6A8xO{o0U z$&#pPGhhjtVZdE>MZDWC>av%$I$mUXtNEz2Xf&a$Wl9L`R_&^(KaEo7XGi3xSLvK2 z2yEjlYwJ&Ju-OxUl~p{mX{@h#U^fuQ23ae^`|iTGOJc1mCAc~R=Z;IZ!>l40aC>O= zxE9d*>+NQM%;tF?0EjaU`TNxUZf2z;4D-LBEo6Bf%kfgey@Y$@`oE<3|ISbs jXJqr7X>PU`CMcur!F^ZW=}k68*a0BvNnKoRtiI$go#v)H diff --git a/interface/resources/meshes/keyboard/key_cut.png b/interface/resources/meshes/keyboard/key_cut.png index 6d8cc4b9fb6baddd06ff24e00e3ecace8c59bfb9..bd894a43b2a21be0c4be21c5729955285c025ed8 100644 GIT binary patch delta 4399 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 literal 2525 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 ZJ(R$o1fbhRwd_z;-f7WAdL=J@kDr!;4BH&$R! z9D`^Y6l*P~vbZjqRMTi|U`6ufZPkx(Y-Q8D+r^rtI0_>gBHY`~?Y1kf4X*s_$N9GJ zocDd7=Y8JuzGuHtu`xMmc@ltRZ&}GEfI=>&0{FA;`)L46d}Ui}0OuWY5ghJt1FYLy zQuI{ak7L21XGisAEf@Kd$-mh%etyWe=Dx2c+snK1SXz7Mp+`a!dGD4TEZEvn`?@FP z*u*@L%U+JKS5`2h;)vd<=@+B>YoN=4An_eMSe)I(9vgX0hB8Fr50=bai2hKm5UlEZZB9}X_jAd0FZErkp{c5ujZLSR?l>0Lcj1k0*K zM*)Lx;yG17bY18sjDfYGzp*Nr!nGk%706c5wVS+|V{K2B{=Pm9TD`F{*m_(dZCh$i zrb?2{ZM_OXj#Yks+(Gcx0TkINg61o&y*7dz{~trq{gc--!y2q~ZHE&KoZP*19CMglsb@N%_FgDt@K5?@uCktK2SIbGI9teoehD+_iT-F0QV_V($exJo zisS!q@n6$ty-Hmx7~Bujh6){m`EEEAjMoQ3W7!G}(`ioGC|s2~z|uIxQ740TFKuQF z7E}esdite>}@F(DJ&L^LW?5XJzJ0X~2s1cU*CRsn0v(g#x97J()HwLgBzx!*bGJLmhI zn|p4ehx-;2BU2*)COlW?j{pW#hh+dj7T)k2z$}p~KLkXxNOg#;X6sS_3qxH#3Egqn zH#E#USctH&uoVXm9Sjk8i-ao<2m5_Jz%>PoNS^cNo#A);TWSx^4_#C-G#u+?&@Ln0 zc5mNmWY=3HN%L(ODv5nDYapku-lm6h-bu<`&kb$fmPM`R&MhtSTHLrKCxKa*Gkf_5 z8P4+drkD*84^8`?D2r-4hS(09JU_R5)HITRxX7->7?Nd*On?cH00@8uP--dQ05o3b znr8S!ktwlHgirMJPuT1GB&R29QV|-1%*lvq+EW!U(fO3RoS4Bh!*zO^{us4-ry*-{ z5hiW<3NqE}QSr>YEb5M@wr8Ch{UeY~n3&0!b;&Iy1|6Lx1=7l}@&}3gl=67s$mI^f z7Y`JPP5XVqZwkP`kxQxVSq^qV??qtfI9F^T*=r_<=E|&hoYh>Pzm){TOM_?S#Ui$bWh=~q(NIO^z7=; zLc&cNh(8XcJZ;fN@!PbCDWh7b)OKuVL7F28a&y<&-cKJJGBGz@ksEpD1wlYxm??i> ztg>#rv|NN|$1$IAO9yKZ4SXq5vurObb}X$l=fK0wq+7|djH5u!z93d5ALYhmpXtf; zljvU%%kQj9PComDbrIBW0qchKSg?|O8{$ZV4(z(mCgFcv^&nYNqX2_Wa8L!9cHCzV zw#lLx;9&4-u)up+xuu_=tNvVbb6+F}1hu@;z9dNbAUbrZUq@HzJ~o4df92z<0P*Qd zi*j@GrH`wAFeErAl3Ig=|4BY5)U7H64T-leLC5`R*6%jV)wB7&XL)=bXr26v7shRX9+O6}WLR+#6- z$weS=uRqswpu*3yHF?XPE8#tZM;9!*$(KIskFafxRNS~Y=4CVQtJtU4!NAXZhHve% zjvfx#D}V0J-Ei4HGb+-vs&=(Qoq0vY+c)gWq6Er&QMdXJjjDOirSq>@fCX2NGHb6n zV8Y@%?|G|cfq@eZtBg-EL4bGOk4OUvlJ`s-QkALi#-KqvXB5&raFAjZqRkQ3FqRS& zsPjK+Y17wgNZz@5T9aesQ>_WnxAj%iO6Dxouy`caziOn8BdI4;u4Bg@YHqbb;1h0D z<0d{P5E%ZVXj{KNwkF;w`}szqK^P%i>%MJY^6ecT?~f4v9uEd~zdBqBe;+Oj{)v2W z)FUJz+3u@SQC6)|nUJ9m0!g;UV8GOO9++5DZ4H)s<}VYx)d|_vjB5hTYYEJs(Mp){ zw~8~<75m>-*XtJeq)n%z?#=Iz|1U`A`v2vJj0EVVFZ2S-c(K3c>^cVkJQsK8{13f8 F`wL_}VV3{^ literal 2268 zcmd^9ZD?Cn7=F&Zr@eP;v)t*A^h4X*varIWsj%7~j`pmrw6)mQO&OEWwNo7jv1}s%TSt5AEoU98yXP)EqSGtGu)bk7L0Vf;@ zbq#@aIm@LoPjgZ8)!gJ?jaAw?h&=0>r+Kc1D*kyBjs1ErWu}$LWPkAb`Iq_Kcl?*W z{q5^8q1ZAyr{U(|q&l?}RXl_zqHh+!4P&cM55^_L>>*&JQUi}FpIqyNR%i8sx}pEP zdp@bSVVH6VY$kTdBm^Us3~c<*_r^Q2io~f(CQufmE=kJ3zFOjo*;Uk~(0!v5eJSFA zk&tV_v%uv(Vc%eJU=?!7lqC%PsA#yH&OUdikp!n2$m z=7ejgT+g;pV>;Z}RD`-l9enb_f;~X2i(-nXB#%hg?{rtiula6p|a3{gmEZec>) z|9|C%lhy24?A;`aYnDYG5pKs&l?6U|;c4{rfApCHA+UtgsE3Deqmv&%L_%}{0Wh#Z zsuBjSC3=PjW@T)B{9wEgwa|t(cx<4cZCqQ!)jJx%^qE~P%g&uf0o?KqHv=2ULL7im z6$f)(wTV`&H=OVgEP$V_tsp^{6igBaJe#3Gmq77GC27ut-g9kUxn(}Z2EY8!K}E&& z8d}_>1H9!bS+h3s9pZmu=KtnW%&m1C9nW;N Jo^I}Y>kl(0WYGWs diff --git a/interface/resources/meshes/keyboard/key_paste.png b/interface/resources/meshes/keyboard/key_paste.png index e3f7e1d52c3157275f26c5a0160cd04e16094015..893a4003d5cec033a480b41cfed30488c696b997 100644 GIT binary patch delta 1490 zcmZ8heK^w#7=3?hHw#xQVLoE28)=~rba8D+QqmJb-T7!kWSODnvTW-1q0+Dv38~c8 zE;T$+Qlyd4EG5fVxQ$39hQ+q~@Z7)d-|u-6ZS4i4J~waGuJd8u08v=y1gH*;+sX>nPcBz!`VUt zXGL+A(wLk5?$4d7QZP;@Z|EK2@`=ugvwU z@Lh1S!TE`HffeslvrRP9o-r*x%$lvgC+973zA3NKS;dq0&J6x6`?*uJGGy2i_O?co|{fL*Q;{!@!)2)6r3BZXZUx-Bp2ikD=LDQ?;EW*fOW{w1CSq}a7_R7P^$Av&{5ev0KO zZO}xaVGWhx^fjNooJgKONy7>Y>DVjER%0}1;`<)kC1Jsu!ewmf4}}LE!TnDSJpN+{%invg+7upPAMk*GLUNyvmYXvjK&7>qc=_tkcmr zUM_z+_N}hpTt~wTi-8cc7HM3^VhjKYYV#|-`M(?DA*79vwO$~Qj8q>zLfiC!QcPx? zAOSe^OMWz0#mJ5k{NLRW)6AaaZ!cfj{MKdE{^aL30dod&}bBNHnpl=wVppd;qgJ7LA#dkFdwYm z#h7)2x^QbpalmkHtLn&^rCRRA0Wk{_4%!x!+mZkP1yhf+4)nYS1Wtw*lT*`L{rXCx zsO37lKAzJ?qk!GHMAQ-7aEf0^efUT>E!<&Tw&m(rKxye8DDZwk<)lBuRK*UaI78{e zGQa}NcLxoy-~~VuZyHE1jSPv)izud2FDWH{P1jq2LF+N!f;ZG+^7twfERcwFB{Mqc zv&1aL-Mx&F_$8smb9X|ni6*Wx3h-__g)SmnRpm;jtwu$ZI*v1dBEq&{*GB<@%+q{O z3B37tzISo}9^LmXeclkxA8PFBqzSzrQfl$QNuH!B!pK#L4wv~+;)n;;PC+*%7e9_% zHG>fNzu!bHWu;;}G|4Bf+|xv2e##Kx*d%U65MAHJh&e-1QnVP6S;8^n18iR%OYhRP+ zT0ag4PR^RJg-oJy0lI&z#Ev2Vp_utp*o8PmR=1}X7OD`1%bQqLu&sw=#?= fl8H&hagcF4+Tt=dep^=Pfx9DPo?G}d2fN~N+ zv%*_5D3oC}k?zvp{josuATyT=WHJSj0Q6`(;L))~NL-qjfZuKL91a{%{c*>_KL{5A*`IkoqLk2@L8vIKd^edMw314FhJeqp{>WR96-a0jQqirtwfd$&9}qCzA+kHCV8 zIiy@9+@ZW9g(J40MlBLPuZMR(2GZXT5qF{AQ;O);D7RX>46{`(%+4*UBQ4&0sq0I& z2Y^Lzw5b@}{;jCIGNzgBrfm(D600|$3<4x=gP#DgcWn?T>~@H<@9JgUR9_|p2^M2LI5Df@o(PT-)d;9=bkPdifJ=ji%&l3oE)*(^qsHzRh8{ax%0n95ba2JwVP6Xisoj-@ zc6haL?X#$!muVW8a$W@kpX!?rc3HN`Jt2KgUCz?SMO@kN_@{mrn>OM|cTlU5!PreO%+ zAyTViYfR(D7#5qt(njU&M`VBeI4V2G(1?(KP*-yCxb=jp#{8uF!35NUcH zFv-bwnlj&Rwkxbndl3wUrnK8$znK&?YRocvo_}!X542kAz|!c{x5d9QT?8EPh}T(* z=9|oitp=<8sA!2?U-q4_zGqt>Q|7exdxq=Q&V7p`N(TE%%dGa6HJ&ZbH!5smi^By| z3K~5DLxmiHaS*1OeY=@)Clx<(m}B(y!-SHT{}@>l9x90$zNnDV<@y;HZ@>`4LK4CW{-%m( z+{u)kG{y6bk~$jJBn0Q8w9&P=>8Q=e;BiKkTqL9j8Cu%s21ebMCq4&fM?I z@b~o~s_Lo&0MX0S?GOM0=tocjfInG}763pc!83>sxb_6}!+qJlrvU(T816?I0r61` zW+*KZm`tYGyC1~T!$T7y&Ejd%c@vJh04g(HZqA2U9phb2v4x2{8lPA-k*-fH*i)mp{cq|@8N9kz9trl(h*rkrxcUlZUjiGAzidD-P({p!>5wYWa>s%y3B z)?9-a?~b|c_$GGu_=@dMbxV_?slFPD>%(d9w{ehbIi>gt5U+)-YOdCvB44(=t zG*j@vOGCQ0q%j+o@Iy9VMB4uZQ>WKGf2HIMF z{k^?S2Yq~5Bs@^Pw~8iON2Xlb3a&gjTakvPH3R_;(3#=^9X1KjnWFnp-P%E`F14Sm zqz|AwJ>GF6|Jc0!sEv)I5(1AyZ*u5{MP(^D4`ORsYIvv)Xb-w! zXiL_OXd5x7P=Tm_1mIb$0(^=AvQ`7`Vt_Mza>qWY$-pxe7QWD${~zsJ`N~%8;C0=o zT$sea$eQ1D+0D-7B|H)LUz=F}`}f-{ko| zpXbf@m)flD$bB8K)&SNTf)ghl0QX*dt8YhW?)LorUC%z{Jd|MJxE9u0EnlOXD{)Pk`_}Ir$puYt?D2I-(rU*0LMvt=>O$ges>P8Ct z;%%uW1VC$2yU*<^Q%&GvY}8!3l2{7t$E5oXFeW>9-!W4w_`OxZa)Z`J4QSL123xJf zhFkg7!sN*3mehCq(hQBp8^9T|I$^wjPLeL1ZL*1Y@frY@f zf`i0zr0d&doZHqPg#ioNfFYZ}@_=8p zM1ZXkxG4~<0zrB$7?ddVWpKbOc;J{{Vg+BTUJ9i|{ zzI_;T>oRgy76s(KanUtjmeIV02Pn{41Op@OTE2mDz+!c24P7P@z&-n;GHOzviPd>} z(|yGcb~>h;ip8b^2W`ooePQNEhkW~t{M(g<(L+0rg}j>+E*9#cc(4A_hb}YgkmH8| zkDeH1V^(k)J|&jYDNrd2pkEwZ(8B-C=WxqY)w4_vu~#~NO@C39gb(nGEwxd-FBn8+3mLOp9V v!ACu@DqiuHH!DfYQt6kjT5cHXfbezo1A9)Kyt}gTT>xl*xTAH#-`)Q&_v2R) diff --git a/interface/resources/meshes/keyboard/key_select_all.png b/interface/resources/meshes/keyboard/key_select_all.png index 8788824d8f61b96afc12da9a02bc4c782705d5b7..ac7fac724636f4e1f1f40c461cc044b17a7458e5 100644 GIT binary patch delta 2174 zcmYk7XH=Be7KZotISvy+Kt<^?h-d_4C@Rv1NfZ%~5`n0f4uTMR9Z-f3G(sdu$w-kB zP>Q0Vir~-&jC2qw;z*YsX^z0)Q13#s?z+FuT6@1||9JO#-ox3;5Ra3?5SBL}EN|oi zOW`E|i2CbZ_BZo#_NUtWIsuhRRdn@q^K-QKc2e~6y_Pz!B?hqjoc`G#%!B&o2JKz$ ztw`3ghjWbH-mJjOx*46nljo23^CbP{e(TC9<#>Brf16(?5}fw0Iuz}4<=K%?Ruq+2 zBz#eFIf2xsZp#-Ttkqe@U-lrlI2ixV!NcXZ|C~^?R!#QEVN_4!Y03thc}W8k+z=a` z*p9&k#o(GDzu-;A^L~DF6q@egW$5t)89I?5LdQ@Ix)4Dzek2r$rtcvr(@lBiabci@ z(!)_TOb~zw5a#}3m@vXSyvE5Y&N?bJBZVDKN!0m*l`}$?orMCW3|FbVmK6>ieyMcM z`y102(oWNkxn_*I(K;Cw>aH2DAK|;o7F=RRDYkuM8nj~^Newz@J)>WuzuZ5koy&Ff z;clc3H4(wiS!{txvf1P&eqjsLIEhd&=NCB2q&jy83M!Lp!@)hxQi2e7vU)K14B+5u z`)cDQQIrTox0+)2Vrf7@Wo1WP>vjnM0U!WS03e_>Kdia5=SE|!P3i@5!+1~n_*lpi zJAHgCI>zK@nhllANL{xgrzIPZUq|jUYiR& zeU>Q>jlIi1NmK|G*02LZ0#_E*F@jR;ivXZOuA|9R9B8ogQX1^9rC);%3wzH9gmS zZ9aH~Gwx{Azsm~*A(GW z%)Dex?^J>-W`{#T<>P98UK@Eue4p933lVw^UuC^QkuA#Ub*<2yU?3FP@~v4AJs4AW zkz@Spt(=kogaVYZIi2f@W>S#?vC)m2SyNS?OvnD(Ny)v!H$B81b==}w@=d>=GkGN= zpCmi?Y~_up4vqjvGglROthDRHYo=#ijQbuf<{@4NDy_b?N|D?1FU3?j3D#CEO46l~ z16ZarLjc+y+zynVTC`H}aRs~#)&S*AR!&N&w7Zmm;Tz88-nzSPcH4M!IcKH*PNVJe zW3zW&Mxrkj29uRE1;O-DgkHlp(O28&R466?7|2GQal&o^0?Yrju;xS*)Z=r+6cX}z z0fmqKn^{vKY3X)BSG71&+Sde$kXb_uTv=p2U$`nkVn}?l$dykxZ6jyN1Czg5B7aNh z)*2RO+^y@Gk#TrmC}A9UlZ-bbSF|L>d!P3%jkz~XIOv&>`z%uiVx?4S|9$39xb&?gkIV1GHZ;|O zKhz$DBJY3#<4Wp!I%cxaF#Wt))Qg$xp}WKxpYc@uwt|_Dnn>2WBQm~2-9)g%M-?v1 zdSKj-?cdLmPmRs-4suf}CUwkqf2D!_`GeZbq%t$;(>=8l+3RWIh`EV2ZHXCoP?HFD zHu=BU%olHG)uW4f!;xfb_G&nQ^Vn*BUIh)CRXdVf6-I=x_aX;HS6B!FSIi{j8vP}0 z@W}<{4^NwO(3{)puUmRMe8<1Yyi5@YFfzl!maMF4X=E*xgKM#WF1`#0sEO&A58Z}5 zdMu}}MncIt?-l#vdku)&Gmj(q2_dBF&{KFr;p04f1ZYZ;cPt-MPmu8v#Sy`doW7mT zH!yMA%Ft4FagYo5k0&*oM6e5I-I$J+RuJs)#13g_cKu8hf~)sQ2uer3J9N_2q8BB0 zbI9fDu504^%zVaQ?Y#B$2R&n}^EP}099-?;9Jki*x2?Hu20f3TO%1E!&W~*8O#=lN|v2sK~H5fP}E5VgNHKUGo5J)sgRLfOQ*$Mc`baGhpi-6&AWT zrDv?S_YIc=baw2QWi2xUPG|fJ55~#(+^I z`$lQJsR|8n04RU~KmbyJH5Gr-)*9iKB35O$z%86si#?quy|!zuD8k~3%|8fORm>vg z8sQe@Eh#K9p&eFmTXoCY$NN_%tFo{5# zK|oxTCX%A5greZAPwn44U#z%5&T$6slv#S~Ffd0U-!o5QDxHO~%F!x_3NSL_*dgTJkwBBC)TmO+Dia zDL&UX*18UfJs6+fxd*3M7t74*#Jjy4%96r?Ky-HQI9}5)kSdtJ>8nXZu z&jEBe1I{(ecf@EYl|33`0-sI)62ks%<8fH|rssTEYEs*)4F(?N*Cf<>{6bR>4E@JLa6S$?BL7hENzVkz^GGUB|;fqyr>S1|n1MNJv#@u=l7Cm0=wgCc{{@-iR}Dx>tLt?*m!tqC)lSXi=UfBbTD&pp5M z{oL#CM_`d3Fa@2^vO9ipDH%5~+7qU;EWChw{r45hh1o11{t zhiGqhwT(QWf#_aA2>=a%4FD7X27njl1sebvyzFS6>2o4xRi8_rV|r2S<(%yKUF#VU z89ZESp2Q0coWH40)v0E_!85Svum9pTGpTb=+J3aK_x5jjx*(asAcV3>-E-;mKQ zIk7X~elO9X8yb0!Yq^;MA=O5GT91mqz1aRiEYbQCi$;U?x?bi?!+KyqX(Wr-Q{ECs zCXfkx=s<;-_V$Oj*)}w2uaK*C!V)VKYYZ39EIz;nS+j~5NU&j0A?8NLal)GF4R9=V zv=RRhSS!$s;?S$1dY%T=2s~fO{Nj+84R{@Cb{w*&9RzS*x?$LrL8CyhlcBW_Cmk4- zOK{RalE?SBz$>>>!h}d>P4Gn1x87_9lyZU;XK(?__mvI`9I^@Ger-xGGVs-?6z7N9 zFVisSsb6PSW6+`|m3R_|c&vK7TAWCFVmk7VU9<%YmkU++=xBf!hh!ayHp6s<%z`?z9yGrrK3vL1ShNm5ga0h#SL9qKT1N7i>} z?RN}u--wk|XOsh{O-GvqNT5;rW9FwOzW#yKn$6CGLftYqHpu8Xo{n5M_w7b{-W_Q) z8BxG%YrE!Ih|3)xJ)pXNZ&x~bKd!Fks`Hreo}pd_va#XRH`QEz*-%GKwSK6hsN-<4 z71bNO?w-~D!d$*}fY7_mUPc8*ck6sOV`{0t&an|0DO&rd-IkW{j0rLlJwx46kHdNO z1Z#?zghnHO7WmtdV!3`+t<=m9!dq7 zf5StD#A0?2_s5S($hDqXc*`5Mp9mvneVhnDu9dFcAyy@;joT+rVOUou*1lwok(r}f zWJfy)vemv0afM0R664egv>o%a?hTL=tR+<@Hf3)5SL-I#(%jqokobjVDTU!<3NpXK zBwoSmymnD1Ayp;4=%T@I4L+(nDIwpml>l--@K`n_^b=yXw&4(BTeGLrJ}#b^^*O6I zvBlVmyQLQMmCSP|wKK_?(TIg}v9jgPC5@4}LQdx}4o`-aH8HgM zhDWw1J8w-;PMb48p6goXPK3EpU{>3o>%a3%|6BiEa0~AX{k`Y${_$vlx6PTR&v~-o qPX5p4-9ksmf_?h;N8SI~pg@I2;9xJ+NZqCZ0Jiz@d@p|#aqutCk2G@t literal 2300 zcmc&#ZERCz6n@@&Z=2VxjaNrz!)SLW8VF%Q6c`S57dBuE*)oVG5Ogac2vL->shf!F zy9JvOHktkq{K(jX3H;fdj%+LgTGGf+65JHySSPHC*@w>EDP*0N)x1}dw)oLDCi3I` zao_WtbDneFbDy)nxM;08X?79-b3uOI20#Em)Ck~u<)z;M+~vsMR1PGk@I&z42Nr;~ z7UZpbvT|U2u&?k(Rd%hf*-$vR?&&&T?Sb8kTj$Y?E48y|N5yc?@MKAY{nf*}dR$-q zu&3Kiu>OjbfC8$X2Qt6_NPq%>AciSHcsNO1(ZldCr@y<4%~MURtmq_Uh~9P+Z+re* z+E~qxW*O!rB>arGB85Z5H4uUN_PIFIa^boba_xRaEj~Y5cKTbZXbFBH69ufzzsT5> zIsxW)|2`}T7;yv+K!!S^-A5E)rC(M7*HQ(n*1u?>3J9VM^-D)8w`P^AKn=eb-LgCxZ|Lp&c4Ojo?%1z6Z#>_|akc3x80o(-?*8;6gA9AX zCon)aoxGWqLOP(pqfG?g$>cn?c++L5n%2o(_uWerc*d`erE|YyCY_T#&^@j9@pEm8 ziV{wqO`5%(3NSgdp5-OXe?0hxnZmKvY;DlldDFKi3;5*0mY&k-lGUJ?U!GgIciGRJ zr#-MW83Ni2{KY(Y$;iM`yXvzmWY}rfbapa_q*ZQi+@A>wRf2%Q8A7n+q2R}yp(~An zjdeP`S9vd)T_AWdpzI0M9ryEAv1X3AVPk$+ibu#F>=uj!q5 z#&mSS`$Fz43EDL_b-1ZMlN}L9FTRNZOFotXX=@HG7YX*Q0R?NIfnY^7N>7RCmzX(D zsrt*`5;@~)p?7&`?E7!FmF9hI@FC3Wq&Aoy_8q0ch@6v*PnwNSuR8)3lC zTe{fvz(HPo^>An8h@R7d#!yA-s|b0%3N$mfp;#spOAA3D3|;ksYl zRdae9`9@k{9D3{JcTH6?pc-r>LinS|$FX=4AQs*(-0T06&+zVyoW$G6#56^7j|q>c e?oKs`4LpI26-CmuZI2uSfP&RUd9ADLHGcq6pJRpq