|
| 1 | +import { css, customElement, html, LitElement } from 'lit-element'; |
| 2 | +import { SPACE_KEYS } from './utils/keys'; |
| 3 | + |
| 4 | +const irKeyCodes: { [key: string]: number } = { |
| 5 | + power: 0xa2, |
| 6 | + menu: 0xe2, |
| 7 | + test: 0x22, |
| 8 | + plus: 0x02, |
| 9 | + back: 0xc2, |
| 10 | + prev: 0xe0, |
| 11 | + play: 0xa8, |
| 12 | + next: 0x90, |
| 13 | + 0: 0x68, |
| 14 | + minus: 0x98, |
| 15 | + c: 0xb0, |
| 16 | + 1: 0x30, |
| 17 | + 2: 0x18, |
| 18 | + 3: 0x7a, |
| 19 | + 4: 0x10, |
| 20 | + 5: 0x38, |
| 21 | + 6: 0x5a, |
| 22 | + 7: 0x42, |
| 23 | + 8: 0x4a, |
| 24 | + 9: 0x52, |
| 25 | +}; |
| 26 | + |
| 27 | +const keyboardKeyMap: { [key: string]: string } = { |
| 28 | + o: 'power', |
| 29 | + m: 'menu', |
| 30 | + t: 'test', |
| 31 | + '+': 'plus', |
| 32 | + b: 'back', |
| 33 | + arrowleft: 'prev', |
| 34 | + p: 'play', |
| 35 | + arrowright: 'next', |
| 36 | + 0: '0', |
| 37 | + '-': 'minus', |
| 38 | + c: 'c', |
| 39 | + 1: '1', |
| 40 | + 2: '2', |
| 41 | + 3: '3', |
| 42 | + 4: '4', |
| 43 | + 5: '5', |
| 44 | + 6: '6', |
| 45 | + 7: '7', |
| 46 | + 8: '8', |
| 47 | + 9: '9', |
| 48 | +}; |
| 49 | + |
| 50 | +@customElement('wokwi-ir-remote') |
| 51 | +export class IRRemoteElement extends LitElement { |
| 52 | + static get styles() { |
| 53 | + return css` |
| 54 | + use { |
| 55 | + fill: #fff; |
| 56 | + } |
| 57 | +
|
| 58 | + use.red { |
| 59 | + fill: #e6252e; |
| 60 | + } |
| 61 | +
|
| 62 | + use.black { |
| 63 | + fill: #121115; |
| 64 | + } |
| 65 | +
|
| 66 | + use[tabindex] { |
| 67 | + cursor: pointer; |
| 68 | + } |
| 69 | +
|
| 70 | + use.active { |
| 71 | + fill: #8c8; |
| 72 | + } |
| 73 | +
|
| 74 | + use.red.active, |
| 75 | + use.black.active { |
| 76 | + fill: green; |
| 77 | + } |
| 78 | +
|
| 79 | + use:focus { |
| 80 | + --circle-stroke-color: cyan; |
| 81 | + outline: none; |
| 82 | + } |
| 83 | + `; |
| 84 | + } |
| 85 | + |
| 86 | + eventHandler(target: SVGElement, buttonId: string, type: 'up' | 'down') { |
| 87 | + target.focus(); |
| 88 | + const irCode = irKeyCodes[buttonId]; |
| 89 | + switch (type) { |
| 90 | + case 'up': |
| 91 | + target.classList.remove('active'); |
| 92 | + this.dispatchEvent( |
| 93 | + new CustomEvent('button-release', { |
| 94 | + detail: { key: buttonId, irCode }, |
| 95 | + }) |
| 96 | + ); |
| 97 | + break; |
| 98 | + case 'down': |
| 99 | + target.classList.add('active'); |
| 100 | + this.dispatchEvent( |
| 101 | + new CustomEvent('button-press', { |
| 102 | + detail: { key: buttonId, irCode }, |
| 103 | + }) |
| 104 | + ); |
| 105 | + break; |
| 106 | + } |
| 107 | + } |
| 108 | + |
| 109 | + buttonEvent(event: Event, type: 'up' | 'down') { |
| 110 | + const target = event.target; |
| 111 | + if (!(target instanceof SVGElement)) { |
| 112 | + return null; |
| 113 | + } |
| 114 | + const buttonId = target.dataset.btn ?? ''; |
| 115 | + if (buttonId == null) { |
| 116 | + return; |
| 117 | + } |
| 118 | + event.preventDefault(); |
| 119 | + this.eventHandler(target, buttonId, type); |
| 120 | + } |
| 121 | + |
| 122 | + keyboardEvent(event: KeyboardEvent, type: 'up' | 'down') { |
| 123 | + if (SPACE_KEYS.includes(event.key)) { |
| 124 | + this.buttonEvent(event, type); |
| 125 | + } |
| 126 | + const target = event.target; |
| 127 | + const buttonId = keyboardKeyMap[event.key.toLowerCase()]; |
| 128 | + if (!(target instanceof SVGElement) || buttonId == null) { |
| 129 | + return; |
| 130 | + } |
| 131 | + const buttonElement = this.shadowRoot?.querySelector(`use[data-btn="${buttonId}"]`); |
| 132 | + if (buttonElement && buttonElement instanceof SVGElement) { |
| 133 | + this.eventHandler(buttonElement, buttonId, type); |
| 134 | + } |
| 135 | + } |
| 136 | + |
| 137 | + render() { |
| 138 | + return html` |
| 139 | + <?xml version="1.0" encoding="UTF-8"?> |
| 140 | + <svg |
| 141 | + version="1.1" |
| 142 | + viewBox="0 0 151 316" |
| 143 | + width="40mm" |
| 144 | + height="83.653mm" |
| 145 | + font-family="sans-serif" |
| 146 | + xmlns="http://www.w3.org/2000/svg" |
| 147 | + @mousedown=${(e: MouseEvent) => this.buttonEvent(e, 'down')} |
| 148 | + @mouseup=${(e: MouseEvent) => this.buttonEvent(e, 'up')} |
| 149 | + @touchstart=${(e: TouchEvent) => this.buttonEvent(e, 'down')} |
| 150 | + @touchend=${(e: TouchEvent) => this.buttonEvent(e, 'up')} |
| 151 | + @keydown=${(e: KeyboardEvent) => this.keyboardEvent(e, 'down')} |
| 152 | + @keyup=${(e: KeyboardEvent) => this.keyboardEvent(e, 'up')} |
| 153 | + > |
| 154 | + <defs> |
| 155 | + <g id="button" stroke-width="1.29"> |
| 156 | + <path |
| 157 | + fill="#272726" |
| 158 | + d="m0 -17.5c-9.73 0-17.6 7.9-17.6 17.6 0 9.73 7.9 17.6 17.6 17.6 9.73 0 17.6-7.9 17.6-17.6 0-9.73-7.9-17.6-17.6-17.6zm0 1.29c9.01 0 16.3 7.32 16.3 16.3 0 9.01-7.32 16.3-16.3 16.3-9.02 0-16.3-7.32-16.3-16.3 0-9.02 7.32-16.3 16.3-16.3z" |
| 159 | + /> |
| 160 | + <circle r="16.3" style="stroke: var(--circle-stroke-color)" /> |
| 161 | + </g> |
| 162 | + <circle id="button2" r="16.3" style="stroke: var(--circle-stroke-color)" /> |
| 163 | + </defs> |
| 164 | + <path |
| 165 | + d="m149 21.3c0-10.5-8.52-19-19-19h-109c-10.5 0-19 8.52-19 19v274c0 10.5 8.52 19 19 19h109c10.5 0 19-8.52 19-19z" |
| 166 | + fill="#fff" |
| 167 | + stroke="#272726" |
| 168 | + stroke-width="4.53px" |
| 169 | + /> |
| 170 | + <use xlink:href="#button2" x="39.2" y="37.9" data-btn="power" class="red" tabindex="0" /> |
| 171 | + <use xlink:href="#button" x="120" y="37.9" data-btn="menu" tabindex="0" fill="#fff" /> |
| 172 | + <use xlink:href="#button" x="39.2" y="75.2" data-btn="test" tabindex="0" fill="#fff" /> |
| 173 | + <use xlink:href="#button2" x="79.9" y="75.2" data-btn="plus" class="black" tabindex="0" /> |
| 174 | + <use xlink:href="#button" x="120" y="75.2" data-btn="back" tabindex="0" fill="#fff" /> |
| 175 | + <use xlink:href="#button2" x="39.2" y="113" data-btn="prev" class="black" tabindex="0" /> |
| 176 | + <use xlink:href="#button" x="79.9" y="113" data-btn="play" tabindex="0" fill="#fff" /> |
| 177 | + <use xlink:href="#button2" x="120" y="113" data-btn="next" class="black" tabindex="0" /> |
| 178 | + <use xlink:href="#button" x="39.2" y="152" data-btn="0" tabindex="0" fill="#fff" /> |
| 179 | + <use xlink:href="#button2" x="79.9" y="152" data-btn="minus" class="black" tabindex="0" /> |
| 180 | + <use xlink:href="#button" x="120" y="152" data-btn="c" tabindex="0" fill="#fff" /> |
| 181 | + <use xlink:href="#button" x="39.2" y="190" data-btn="1" tabindex="0" fill="#fff" /> |
| 182 | + <use xlink:href="#button" x="79.9" y="190" data-btn="2" tabindex="0" fill="#fff" /> |
| 183 | + <use xlink:href="#button" x="120" y="190" data-btn="3" tabindex="0" fill="#fff" /> |
| 184 | + <use xlink:href="#button" x="39.2" y="228" data-btn="4" tabindex="0" fill="#fff" /> |
| 185 | + <use xlink:href="#button" x="79.9" y="228" data-btn="5" tabindex="0" fill="#fff" /> |
| 186 | + <use xlink:href="#button" x="120" y="228" data-btn="6" tabindex="0" fill="#fff" /> |
| 187 | + <use xlink:href="#button" x="39.2" y="266" data-btn="7" tabindex="0" fill="#fff" /> |
| 188 | + <use xlink:href="#button" x="79.9" y="266" data-btn="8" tabindex="0" fill="#fff" /> |
| 189 | + <use xlink:href="#button" x="120" y="266" data-btn="9" tabindex="0" fill="#fff" /> |
| 190 | + <g style="pointer-events: none"> |
| 191 | + <g fill="none" stroke="#fff" stroke-width="1.94px"> |
| 192 | + <path |
| 193 | + d="m43.1 33c2.05 1.28 3.42 3.56 3.42 6.16 0 4.01-3.26 7.26-7.26 7.26-4.01 0-7.26-3.25-7.26-7.26 0-2.49 1.26-4.69 3.17-6" |
| 194 | + /> |
| 195 | + <path d="m39.2 29.3v7.41" /> |
| 196 | + </g> |
| 197 | + <path d="m86.5 113-9.58 4.79v-9.58z" fill="#121115" stroke-width="1.29" /> |
| 198 | + <path d="m122 113-9.58 4.79v-9.58z" fill="#fff" stroke-width="1.29" /> |
| 199 | + <path d="m128 113-8.95 4.79v-9.58z" fill="#fff" stroke-width="1.29" /> |
| 200 | + <path d="m128 109v9.58" fill="none" stroke="#fff" stroke-width="1.29" /> |
| 201 | + <path d="m37.5 113 9.58 4.79v-9.58z" fill="#fff" stroke-width="1.29" /> |
| 202 | + <path d="m31.4 113 8.95 4.79v-9.58z" fill="#fff" stroke-width="1.29" /> |
| 203 | + <path d="m32 109v9.58" fill="none" stroke="#fff" stroke-width="1.29" /> |
| 204 | + <text fill="#e6252e" font-size="9.72px" font-weight="700" stroke-width="1.29"> |
| 205 | + <tspan x="105.492 114.069 121.032 128.531" y="41.288"> |
| 206 | + MENU |
| 207 | + </tspan> |
| 208 | + <tspan x="26.088 32.504 39.466 46.429" y="78.679"> |
| 209 | + TEST |
| 210 | + </tspan> |
| 211 | + </text> |
| 212 | + <g fill="none" stroke="#fff" stroke-width="1.29"> |
| 213 | + <path d="m72.1 152h15.5" /> |
| 214 | + <path d="m72.1 75.2h15.5M79.9 67.4v15.5" /> |
| 215 | + </g> |
| 216 | + <g fill="#121115" stroke-width="1.29"> |
| 217 | + <path |
| 218 | + d="m118 70.7v-3.25l-6.95 4.84 6.71 4.45 0.111-2.2s6.65-0.357 7.05 3.15c0.397 3.51-6.66 5.21-6.66 5.21s10.9-2.33 10.7-6.82c-0.276-5.4-10.9-5.39-10.9-5.39z" |
| 219 | + /> |
| 220 | + <text font-size="13.9px" font-weight="700"> |
| 221 | + <tspan x="35.427" y="156.434">0</tspan> |
| 222 | + <tspan x="115.573" y="156.498">C</tspan> |
| 223 | + <tspan x="34.912" y="194.685">1</tspan> |
| 224 | + <tspan x="76.176" y="194.685">2</tspan> |
| 225 | + <tspan x="116.66" y="194.6">3</tspan> |
| 226 | + <tspan x="34.912" y="232.851">4</tspan> |
| 227 | + <tspan x="76.176" y="232.679">5</tspan> |
| 228 | + <tspan x="116.799" y="232.767">6</tspan> |
| 229 | + <tspan x="34.912" y="270.931">7</tspan> |
| 230 | + <tspan x="76.176" y="270.931">8</tspan> |
| 231 | + <tspan x="116.724" y="270.931">9</tspan> |
| 232 | + </text> |
| 233 | + </g> |
| 234 | + <g fill="#fff" stroke-width="1.29"> |
| 235 | + <path |
| 236 | + d="m27.6 28.5c0.687-0.757 1.5-1.41 2.39-1.99 1.26-0.814 2.7-1.43 4.22-1.87 0.974-0.281 1.98-0.481 3-0.607 0.673-0.0828 1.35-0.129 2.03-0.147 0.68-0.0181 1.36-0.0078 2.03 0.0427 1.02 0.0789 2.03 0.243 3 0.511 2.48 0.686 4.72 2.02 6.31 4.19 0.0323 0.0479 0.097 0.0608 0.145 0.0298 0.0479-0.0323 0.0621-0.097 0.0298-0.145-0.846-1.45-1.96-2.62-3.27-3.53-0.894-0.623-1.87-1.12-2.91-1.5-1.19-0.433-2.45-0.709-3.73-0.828-0.543-0.0504-1.09-0.0698-1.64-0.0582-0.728 0.0155-1.46 0.0841-2.18 0.202-1.08 0.177-2.14 0.46-3.16 0.839-0.772 0.288-1.51 0.632-2.21 1.03-1.7 0.965-3.16 2.22-4.22 3.7-0.0362 0.0453-0.0298 0.111 0.0155 0.146 0.0453 0.0362 0.11 0.0298 0.146-0.0155z" |
| 237 | + /> |
| 238 | + <path |
| 239 | + d="m68.4 65.5c0.687-0.757 1.5-1.41 2.39-1.99 1.26-0.814 2.7-1.43 4.22-1.87 0.974-0.281 1.98-0.481 3-0.607 0.673-0.0815 1.35-0.129 2.03-0.147 0.679-0.0181 1.36-0.0078 2.03 0.044 1.02 0.0776 2.03 0.242 3 0.51 2.48 0.686 4.72 2.02 6.31 4.19 0.031 0.0479 0.0957 0.0621 0.145 0.0298 0.0479-0.031 0.0608-0.0957 0.0297-0.145-0.847-1.45-1.97-2.62-3.27-3.53-0.892-0.623-1.87-1.12-2.91-1.5-1.19-0.433-2.45-0.709-3.73-0.828-0.545-0.0504-1.09-0.0698-1.64-0.0582-0.728 0.0155-1.46 0.0841-2.18 0.202-1.08 0.177-2.14 0.46-3.16 0.839-0.772 0.288-1.51 0.632-2.22 1.03-1.7 0.965-3.16 2.22-4.22 3.7-0.0362 0.0453-0.0285 0.111 0.0155 0.147 0.0453 0.0362 0.111 0.0285 0.147-0.0168z" |
| 240 | + /> |
| 241 | + <path |
| 242 | + d="m27.6 104c0.687-0.757 1.5-1.42 2.39-1.99 1.26-0.814 2.7-1.43 4.22-1.87 0.974-0.281 1.98-0.481 3-0.607 0.673-0.0815 1.35-0.129 2.03-0.147 0.68-0.0181 1.36-8e-3 2.03 0.044 1.02 0.0776 2.03 0.242 3 0.51 2.48 0.686 4.72 2.02 6.31 4.19 0.0323 0.0478 0.097 0.0621 0.145 0.0297 0.0479-0.031 0.0621-0.0957 0.0298-0.145-0.846-1.45-1.96-2.62-3.27-3.53-0.894-0.623-1.87-1.12-2.91-1.5-1.19-0.433-2.45-0.709-3.73-0.828-0.543-0.0504-1.09-0.0698-1.64-0.0582-0.728 0.0155-1.46 0.0841-2.18 0.202-1.08 0.177-2.14 0.46-3.16 0.839-0.772 0.288-1.51 0.632-2.21 1.03-1.7 0.965-3.16 2.22-4.22 3.7-0.0362 0.0453-0.0298 0.111 0.0155 0.147 0.0453 0.0362 0.11 0.0285 0.146-0.0168z" |
| 243 | + /> |
| 244 | + <path |
| 245 | + d="m109 104c0.687-0.757 1.5-1.42 2.39-1.99 1.26-0.814 2.7-1.43 4.22-1.87 0.974-0.281 1.98-0.481 3-0.607 0.673-0.0815 1.35-0.129 2.03-0.147 0.68-0.0181 1.36-8e-3 2.03 0.044 1.02 0.0776 2.03 0.242 3 0.51 2.48 0.686 4.72 2.02 6.31 4.19 0.031 0.0478 0.0957 0.0621 0.145 0.0297 0.0479-0.031 0.0608-0.0957 0.0298-0.145-0.847-1.45-1.97-2.62-3.27-3.53-0.892-0.623-1.87-1.12-2.91-1.5-1.19-0.433-2.45-0.709-3.73-0.828-0.545-0.0504-1.09-0.0698-1.64-0.0582-0.728 0.0155-1.46 0.0841-2.18 0.202-1.08 0.177-2.14 0.46-3.16 0.839-0.772 0.288-1.51 0.632-2.22 1.03-1.7 0.965-3.16 2.22-4.22 3.7-0.0362 0.0453-0.0285 0.111 0.0155 0.147 0.0453 0.0362 0.111 0.0285 0.147-0.0168z" |
| 246 | + /> |
| 247 | + <path |
| 248 | + d="m68.4 142c0.687-0.758 1.5-1.42 2.39-1.99 1.26-0.815 2.7-1.43 4.22-1.87 0.974-0.279 1.98-0.481 3-0.605 0.673-0.0828 1.35-0.129 2.03-0.147 0.679-0.0181 1.36-9e-3 2.03 0.0427 1.02 0.0789 2.03 0.243 3 0.511 2.48 0.686 4.72 2.02 6.31 4.19 0.031 0.0491 0.0957 0.0621 0.145 0.031 0.0479-0.0323 0.0608-0.097 0.0297-0.145-0.847-1.45-1.97-2.62-3.27-3.54-0.892-0.623-1.87-1.12-2.91-1.5-1.19-0.435-2.45-0.71-3.73-0.829-0.545-0.0504-1.09-0.0698-1.64-0.0569-0.728 0.0155-1.46 0.0841-2.18 0.202-1.08 0.177-2.14 0.459-3.16 0.838-0.772 0.29-1.51 0.632-2.22 1.03-1.7 0.965-3.16 2.22-4.22 3.7-0.0362 0.044-0.0285 0.11 0.0155 0.146 0.0453 0.0362 0.111 0.0284 0.147-0.0155z" |
| 249 | + /> |
| 250 | + </g> |
| 251 | + </g> |
| 252 | + </svg> |
| 253 | + `; |
| 254 | + } |
| 255 | +} |
0 commit comments