EloiStree / 2024_08_29_ScratchToWarcraft

Apprendre la programmation par warcraft via Scratch 😁
https://github.com/EloiStree/2024_08_29_CodeToWarcraft
0 stars 1 forks source link

Topic: Installer Tamper Monkey pour utiliser Scratch avec Warcraft #7

Open EloiStree opened 3 months ago

EloiStree commented 3 months ago

Installation

Étapes d'installation :

  1. Installez Opera GX ou Chrome.
  2. Installez Tampermonkey.
  3. Copiez le code "Scratch to Local Websocket".
  4. Créez un projet Scratch avec une variable wsvar requet.
  5. Installez Python.
  6. Téléchargez et lancez le serveur local.
  7. Téléchargez et exécutez le code "Entier à Warcraft".
  8. Vous êtes prêt(e) 🏁😁
  9. Testez que tout fonctionne avec le projet suivant :

Source: https://github.com/EloiStree/2024_05_10_TamperMonkeyToRsaTunnelingIID/tree/main/ScratchToLocalWebsocket

Ce script convertit toutes les variables commençant par wsvar en entiers, puis les transmet du site Scratch à une application locale qui fonctionne comme un serveur Python.


// ==UserScript==
// @name         Push Scratch wsvar to Local WS IID
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Source: https://github.com/EloiStree/2024_05_10_TamperMonkeyToRsaTunnelingIID/blob/main/ScratchToLocalWebsocket/ScratchVarToLocalWebsocket.js
// @description  Test zone: https://scratch.mit.edu/projects/1018462085
// @author       Eloi stree
// @match        https://scratch.mit.edu/projects/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=integergames.be
// @require      http://code.jquery.com/jquery-1.8.3.min.js

// @grant        none

// ==/UserScript==
//TO LOOK LATER
//https://github.com/travist/jsencrypt
(function() {
    'use strict';

/*
What this code do ?
This code overlook at the HTML code when you are on https://scratch.mit.edu/projects/*
It searches about the HTML of a variable display in the scratch game that are a HTML Div code.
The div Id are
- name: .monitor_label_ci1ok
- value: .monitor_value_3Yexa

It add the key value in a dictionary if the value changed only to avoid spam when send outside of the script.

With the help of a unsecure websocket client it send the value as a integer converted to 4 bytes in little format.
To use this script you need to recover it with a websocket server of your own and turn back the 4 bytes to integer.

*/

//Just show in console that the script is injected
console.log("Hello Tamper to Integer :).\n Websocket client will try to connect to websocket server. \n  ")

// Creating url to push on local computer at the port 7073 the integer that changed.
var socketUrl= 'ws://localhost:7073';
// Defined the var of the future websocket client
var socket = null;
// Will be use to have a way to know that the server is still in theory connected
var isConnectionValide=false;
// Dictionnary that is storing the previous state when a change happened
// Used to detect any change in the Scratch variable
var previousData = {};

// Do we want to display console log in the browser or not.
var useConsoleDebug=false;

/* This function is use to make some test. It allow to push randomply a integer if the connection is still active */
   function PushMessageToServerRandomInteger(){
       if(!isConnectionValide){
           return;
       }
       const randomInt = Math.floor(Math.random() * 1000000000) + 1;
       PushMessageToServerInteger(randomInt)

   }
    /*This function send an integer into a exportable value with the date of when it was detected as a ulong format */
   function PushMessageToServerIntegerDate(integer){
    if(!isConnectionValide){return;}
      var value =integer;
       // Get the current UTC time in milliseconds
     const currentTimeMillis = Date.now();

     // Convert to an unsigned long (assuming 64-bit)
     const ulongVar = BigInt(currentTimeMillis);

     // Create a byte array of length 12
     const byteArray = new Uint8Array(12);
     // Set the first 4 bytes of the array from the value in little-endian format
     byteArray[0] = value & 0xFF;
     byteArray[1] = (value >> 8) & 0xFF;
     byteArray[2] = (value >> 16) & 0xFF;
     byteArray[3] = (value >> 24) & 0xFF;

     // Set the next 8 bytes of the array from ulongVar in little-endian format
     const view = new DataView(byteArray.buffer);
     view.setBigUint64(4, ulongVar, true);
     socket.send(byteArray);
    if(useConsoleDebug)
     console.log("Random date with date:", value)
}

/*This function send an integer into a exportable value and don't attach to it a date value */
function PushMessageToServerInteger(integer){
    if(!isConnectionValide){return;}

      var value =integer;
     const byteArray = new Uint8Array(4);
     byteArray[0] = value & 0xFF;
     byteArray[1] = (value >> 8) & 0xFF;
     byteArray[2] = (value >> 16) & 0xFF;
     byteArray[3] = (value >> 24) & 0xFF;
     socket.send(byteArray);
    if(useConsoleDebug)
     console.log("Int Pushed to web local server:", value)
}

var server_is_offline=false;

/*Try to reconnect with a new websocket client if it detect that the current is for any reason not there */
function ReconnectIfOffline(){

    if (socket !=null && socket && socket.readyState === WebSocket.OPEN) {
    }
    else{
        isConnectionValide=false
        try{
            if(useConsoleDebug)
            console.log('Try estabalish connection with: '+socketUrl);
            socket = new WebSocket(socketUrl);
            // Event listener for when the connection is established
            socket.addEventListener('open', () => {
                console.log('WebSocket connection established');
                isConnectionValide=true
            });

            // Event listener for incoming messages
            socket.addEventListener('message', (event) => {
                console.log('Received message from server:', event.data);

            });

            // Event listener for when the connection is closed
            socket.addEventListener('close', () => {
                console.log('WebSocket connection closed');
                isConnectionValide=false

            });

            // Event listener for errors
            socket.addEventListener('error', (error) => {
                console.error('WebSocket error:', error);
            });
            server_is_offline=false;
            console.log("Server Online");
        }catch(Exception){
            server_is_offline=true;
        }
    }
}

    /*This will send key value as integer if it detect the variable start with "wsvar " and connection is open */
    function sentKeyValueToOpenWebsocket(label, value) {

        if (socket && socket.readyState === WebSocket.OPEN) {
            const lowerStr = label.toLowerCase().trim();

            if (lowerStr.startsWith("wsvar ")) {
                const number = parseInt(value);
                //console.log("The string starts with 'wsvar'");
                if (!isNaN(number)) {

                    console.log("Change detectected wsvar int: "+value)
                    PushMessageToServerInteger(number);
                    //console.log("The string is a valid integer:", number);
                } else {
                    //console.log("The string is not a valid integer");
                }
            }

        }
    }

    /*This will look in the HTML code for the Scratch variable as HTML.
    If it find the div of the key value that start with "wsvar ". It will set them in the dictionary and notify if it changed*/
    function extractAndSendData() {
        var dataString = '';
        // Find all elements with class 'react-contextmenu-wrapper'
        var elements = document.getElementsByClassName('react-contextmenu-wrapper');
        // Iterate through each element
        for (var i = 0; i < elements.length; i++) {
            var element = elements[i];
            // Find elements with classes 'monitor_label_ci1ok' and 'monitor_value_3Yexa' within current element
            var labelElement = element.querySelector('.monitor_label_ci1ok');
            var valueElement = element.querySelector('.monitor_value_3Yexa');

            // Extract text content from label and value elements
            var label = labelElement ? labelElement.textContent.trim() : '';
            var value = valueElement ? valueElement.textContent.trim() : '';

            if (label && value) {
                if(label.startsWith("wsvar ") ){
                   dataString += label + ': ' + value + '\n';
                    if (!previousData[label]) {
                        previousData[label] = value;
                        sentKeyValueToOpenWebsocket(label, value);
                    } else {
                        if (previousData[label] !== value) {
                            previousData[label] = value;

                            console.log("Change detectected: "+value)
                            sentKeyValueToOpenWebsocket(label, value);
                        }
                    }
                }
            }
        }
    }

    if(useConsoleDebug)
        console.log("Interval :) Start ")

    setInterval(ReconnectIfOffline, 1000);
    setInterval(extractAndSendData,15);
    if(useConsoleDebug)
        console.log('Code end reach');

})();

Grâce à ce client web dans le navigateur, on peut rediriger les messages vers un serveur UDP, disponible dans tous les langages de programmation.

import asyncio
import websockets
import socket

udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_websocket_port= 7072
target_udp_ip = "127.0.0.1"
target_udp_port = 7073
bool_display_received = True

async def handler(websocket, path):
    byte_counter = 0
    while True:
            global target_port
            data = await websocket.recv()
            try:
                udp_socket.sendto(data, (target_udp_ip, target_udp_port))
                byte_counter += 8 + len(data)
                if(bool_display_received):
                    print(f"Received {len(data)} | {data}")
                    print(f"Sent {byte_counter} bytes, {byte_counter/(1024)} KB, {byte_counter/(1024*1024)} MB")
            except ValueError:
                pass

start_server = websockets.serve(handler, "localhost", server_websocket_port)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

Maintenant que nous avons notre entier localement avec UDP, il faut envoyé les commandes à World of Warcraft:

Source: 2024_05_14_IntegerIndexDateToRemoteControl

EloiStree commented 3 months ago

AllKey.md

AllPress.md AllRelease.md

Key Decimal Hexadecimal
Backspace 8 0x08
Tab 9 0x09
Clear 12 0x0C
Enter 13 0x0D
Shift 16 0x10
Ctrl 17 0x11
Alt 18 0x12
Pause 19 0x13
CapsLock 20 0x14
Esc 27 0x1B
Escape 27 0x1B
Space 32 0x20
PageUp 33 0x21
PageDown 34 0x22
End 35 0x23
Home 36 0x24
LeftArrow 37 0x25
Left 37 0x25
UpArrow 38 0x26
Up 38 0x26
RightArrow 39 0x27
Right 39 0x27
DownArrow 40 0x28
Down 40 0x28
Select 41 0x29
Print 42 0x2A
Execute 43 0x2B
PrintScreen 44 0x2C
Insert 45 0x2D
Delete 46 0x2E
0 48 0x30
1 49 0x31
2 50 0x32
3 51 0x33
4 52 0x34
5 53 0x35
6 54 0x36
7 55 0x37
8 56 0x38
9 57 0x39
A 65 0x41
B 66 0x42
C 67 0x43
D 68 0x44
E 69 0x45
F 70 0x46
G 71 0x47
H 72 0x48
I 73 0x49
J 74 0x4A
K 75 0x4B
L 76 0x4C
M 77 0x4D
N 78 0x4E
O 79 0x4F
P 80 0x50
Q 81 0x51
R 82 0x52
S 83 0x53
T 84 0x54
U 85 0x55
V 86 0x56
W 87 0x57
X 88 0x58
Y 89 0x59
Z 90 0x5A
LeftWindows 91 0x5B
RightWindows 92 0x5C
Applications 93 0x5D
Sleep 95 0x5F
Numpad0 96 0x60
Numpad1 97 0x61
Numpad2 98 0x62
Numpad3 99 0x63
Numpad4 100 0x64
Numpad5 101 0x65
Numpad6 102 0x66
Numpad7 103 0x67
Numpad8 104 0x68
Numpad9 105 0x69
Multiply 106 0x6A
Add 107 0x6B
Separator 108 0x6C
Subtract 109 0x6D
Decimal 110 0x6E
Divide 111 0x6F
F1 112 0x70
F2 113 0x71
F3 114 0x72
F4 115 0x73
F5 116 0x74
F6 117 0x75
F7 118 0x76
F8 119 0x77
F9 120 0x78
F10 121 0x79
F11 122 0x7A
F12 123 0x7B
F13 124 0x7C
F14 125 0x7D
F15 126 0x7E
F16 127 0x7F
F17 128 0x80
F18 129 0x81
F19 130 0x82
F20 131 0x83
F21 132 0x84
F22 133 0x85
F23 134 0x86
F24 135 0x87
NumLock 144 0x90
ScrollLock 145 0x91
LeftShift 160 0xA0
RightShift 161 0xA1
LeftControl 162 0xA2
RightControl 163 0xA3
LeftAlt 164 0xA4
RightAlt 165 0xA5
LeftMenu 164 0xA4
RightMenu 165 0xA5
BrowserBack 166 0xA6
BrowserForward 167 0xA7
BrowserRefresh 168 0xA8
BrowserStop 169 0xA9
BrowserSearch 170 0xAA
BrowserFavorites 171 0xAB
BrowserHome 172 0xAC
VolumeMute 173 0xAD
VolumeDown 174 0xAE
VolumeUp 175 0xAF
MediaNextTrack 176 0xB0
MediaPreviousTrack 177 0xB1
MediaStop 178 0xB2
MediaPlay 179 0xB3
LaunchMail 180 0xB4
LaunchMediaSelect 181 0xB5
LaunchApp1 182 0xB6
LaunchApp2 183 0xB7
OEM1 186 0xBA
OEMPlus 187 0xBB
OEMComma 188 0xBC
OEMMinus 189 0xBD
OEMPeriod 190 0xBE
OEM2 191 0xBF
OEM3 192 0xC0
OEM4 219 0xDB
OEM5 220 0xDC
OEM6 221 0xDD
OEM7 222 0xDE
OEM8 223 0xDF
OEM102 226 0xE2
ProcessKey 229 0xE5
Packet 231 0xE7
Attn 246 0xF6
CrSel 247 0xF7
ExSel 248 0xF8
EraseEOF 249 0xF9
Play 250 0xFA
Zoom 251 0xFB
PA1 253 0xFD
Key Decimal Hexadecimal Press Release
Backspace 8 0x08 1008 2008
Tab 9 0x09 1009 2009
Clear 12 0x0C 1012 2012
Enter 13 0x0D 1013 2013
Shift 16 0x10 1016 2016
Ctrl 17 0x11 1017 2017
Alt 18 0x12 1018 2018
Pause 19 0x13 1019 2019
CapsLock 20 0x14 1020 2020
Esc 27 0x1B 1027 2027
Escape 27 0x1B 1027 2027
Space 32 0x20 1032 2032
PageUp 33 0x21 1033 2033
PageDown 34 0x22 1034 2034
End 35 0x23 1035 2035
Home 36 0x24 1036 2036
LeftArrow 37 0x25 1037 2037
Left 37 0x25 1037 2037
UpArrow 38 0x26 1038 2038
Up 38 0x26 1038 2038
RightArrow 39 0x27 1039 2039
Right 39 0x27 1039 2039
DownArrow 40 0x28 1040 2040
Down 40 0x28 1040 2040
Select 41 0x29 1041 2041
Print 42 0x2A 1042 2042
Execute 43 0x2B 1043 2043
PrintScreen 44 0x2C 1044 2044
Insert 45 0x2D 1045 2045
Delete 46 0x2E 1046 2046
0 48 0x30 1048 2048
1 49 0x31 1049 2049
2 50 0x32 1050 2050
3 51 0x33 1051 2051
4 52 0x34 1052 2052
5 53 0x35 1053 2053
6 54 0x36 1054 2054
7 55 0x37 1055 2055
8 56 0x38 1056 2056
9 57 0x39 1057 2057
A 65 0x41 1065 2065
B 66 0x42 1066 2066
C 67 0x43 1067 2067
D 68 0x44 1068 2068
E 69 0x45 1069 2069
F 70 0x46 1070 2070
G 71 0x47 1071 2071
H 72 0x48 1072 2072
I 73 0x49 1073 2073
J 74 0x4A 1074 2074
K 75 0x4B 1075 2075
L 76 0x4C 1076 2076
M 77 0x4D 1077 2077
N 78 0x4E 1078 2078
O 79 0x4F 1079 2079
P 80 0x50 1080 2080
Q 81 0x51 1081 2081
R 82 0x52 1082 2082
S 83 0x53 1083 2083
T 84 0x54 1084 2084
U 85 0x55 1085 2085
V 86 0x56 1086 2086
W 87 0x57 1087 2087
X 88 0x58 1088 2088
Y 89 0x59 1089 2089
Z 90 0x5A 1090 2090
LeftWindows 91 0x5B 1091 2091
RightWindows 92 0x5C 1092 2092
Applications 93 0x5D 1093 2093
Sleep 95 0x5F 1095 2095
Numpad0 96 0x60 1096 2096
Numpad1 97 0x61 1097 2097
Numpad2 98 0x62 1098 2098
Numpad3 99 0x63 1099 2099
Numpad4 100 0x64 1100 2100
Numpad5 101 0x65 1101 2101
Numpad6 102 0x66 1102 2102
Numpad7 103 0x67 1103 2103
Numpad8 104 0x68 1104 2104
Numpad9 105 0x69 1105 2105
Multiply 106 0x6A 1106 2106
Add 107 0x6B 1107 2107
Separator 108 0x6C 1108 2108
Subtract 109 0x6D 1109 2109
Decimal 110 0x6E 1110 2110
Divide 111 0x6F 1111 2111
F1 112 0x70 1112 2112
F2 113 0x71 1113 2113
F3 114 0x72 1114 2114
F4 115 0x73 1115 2115
F5 116 0x74 1116 2116
F6 117 0x75 1117 2117
F7 118 0x76 1118 2118
F8 119 0x77 1119 2119
F9 120 0x78 1120 2120
F10 121 0x79 1121 2121
F11 122 0x7A 1122 2122
F12 123 0x7B 1123 2123
F13 124 0x7C 1124 2124
F14 125 0x7D 1125 2125
F15 126 0x7E 1126 2126
F16 127 0x7F 1127 2127
F17 128 0x80 1128 2128
F18 129 0x81 1129 2129
F19 130 0x82 1130 2130
F20 131 0x83 1131 2131
F21 132 0x84 1132 2132
F22 133 0x85 1133 2133
F23 134 0x86 1134 2134
F24 135 0x87 1135 2135
NumLock 144 0x90 1144 2144
ScrollLock 145 0x91 1145 2145
LeftShift 160 0xA0 1160 2160
RightShift 161 0xA1 1161 2161
LeftControl 162 0xA2 1162 2162
RightControl 163 0xA3 1163 2163
LeftAlt 164 0xA4 1164 2164
RightAlt 165 0xA5 1165 2165
LeftMenu 164 0xA4 1164 2164
RightMenu 165 0xA5 1165 2165
BrowserBack 166 0xA6 1166 2166
BrowserForward 167 0xA7 1167 2167
BrowserRefresh 168 0xA8 1168 2168
BrowserStop 169 0xA9 1169 2169
BrowserSearch 170 0xAA 1170 2170
BrowserFavorites 171 0xAB 1171 2171
BrowserHome 172 0xAC 1172 2172
VolumeMute 173 0xAD 1173 2173
VolumeDown 174 0xAE 1174 2174
VolumeUp 175 0xAF 1175 2175
MediaNextTrack 176 0xB0 1176 2176
MediaPreviousTrack 177 0xB1 1177 2177
MediaStop 178 0xB2 1178 2178
MediaPlay 179 0xB3 1179 2179
LaunchMail 180 0xB4 1180 2180
LaunchMediaSelect 181 0xB5 1181 2181
LaunchApp1 182 0xB6 1182 2182
LaunchApp2 183 0xB7 1183 2183
OEM1 186 0xBA 1186 2186
OEMPlus 187 0xBB 1187 2187
OEMComma 188 0xBC 1188 2188
OEMMinus 189 0xBD 1189 2189
OEMPeriod 190 0xBE 1190 2190
OEM2 191 0xBF 1191 2191
OEM3 192 0xC0 1192 2192
OEM4 219 0xDB 1219 2219
OEM5 220 0xDC 1220 2220
OEM6 221 0xDD 1221 2221
OEM7 222 0xDE 1222 2222
OEM8 223 0xDF 1223 2223
OEM102 226 0xE2 1226 2226
ProcessKey 229 0xE5 1229 2229
Packet 231 0xE7 1231 2231
Attn 246 0xF6 1246 2246
CrSel 247 0xF7 1247 2247
ExSel 248 0xF8 1248 2248
EraseEOF 249 0xF9 1249 2249
Play 250 0xFA 1250 2250
Zoom 251 0xFB 1251 2251
PA1 253 0xFD 1253 2253
0x08 8   1008 2008
0x09 9   1009 2009
0x0C 12   1012 2012
0x0D 13   1013 2013
0x10 16   1016 2016
0x11 17   1017 2017
0x12 18   1018 2018
0x13 19   1019 2019
0x14 20   1020 2020
0x1B 27   1027 2027
0x1B 27   1027 2027
0x20 32   1032 2032
0x21 33   1033 2033
0x22 34   1034 2034
0x23 35   1035 2035
0x24 36   1036 2036
0x25 37   1037 2037
0x25 37   1037 2037
0x26 38   1038 2038
0x26 38   1038 2038
0x27 39   1039 2039
0x27 39   1039 2039
0x28 40   1040 2040
0x28 40   1040 2040
0x29 41   1041 2041
0x2A 42   1042 2042
0x2B 43   1043 2043
0x2C 44   1044 2044
0x2D 45   1045 2045
0x2E 46   1046 2046
0x30 48   1048 2048
0x31 49   1049 2049
0x32 50   1050 2050
0x33 51   1051 2051
0x34 52   1052 2052
0x35 53   1053 2053
0x36 54   1054 2054
0x37 55   1055 2055
0x38 56   1056 2056
0x39 57   1057 2057
0x41 65   1065 2065
0x42 66   1066 2066
0x43 67   1067 2067
0x44 68   1068 2068
0x45 69   1069 2069
0x46 70   1070 2070
0x47 71   1071 2071
0x48 72   1072 2072
0x49 73   1073 2073
0x4A 74   1074 2074
0x4B 75   1075 2075
0x4C 76   1076 2076
0x4D 77   1077 2077
0x4E 78   1078 2078
0x4F 79   1079 2079
0x50 80   1080 2080
0x51 81   1081 2081
0x52 82   1082 2082
0x53 83   1083 2083
0x54 84   1084 2084
0x55 85   1085 2085
0x56 86   1086 2086
0x57 87   1087 2087
0x58 88   1088 2088
0x59 89   1089 2089
0x5A 90   1090 2090
0x5B 91   1091 2091
0x5C 92   1092 2092
0x5D 93   1093 2093
0x5F 95   1095 2095
0x60 96   1096 2096
0x61 97   1097 2097
0x62 98   1098 2098
0x63 99   1099 2099
0x64 100   1100 2100
0x65 101   1101 2101
0x66 102   1102 2102
0x67 103   1103 2103
0x68 104   1104 2104
0x69 105   1105 2105
0x6A 106   1106 2106
0x6B 107   1107 2107
0x6C 108   1108 2108
0x6D 109   1109 2109
0x6E 110   1110 2110
0x6F 111   1111 2111
0x70 112   1112 2112
0x71 113   1113 2113
0x72 114   1114 2114
0x73 115   1115 2115
0x74 116   1116 2116
0x75 117   1117 2117
0x76 118   1118 2118
0x77 119   1119 2119
0x78 120   1120 2120
0x79 121   1121 2121
0x7A 122   1122 2122
0x7B 123   1123 2123
0x7C 124   1124 2124
0x7D 125   1125 2125
0x7E 126   1126 2126
0x7F 127   1127 2127
0x80 128   1128 2128
0x81 129   1129 2129
0x82 130   1130 2130
0x83 131   1131 2131
0x84 132   1132 2132
0x85 133   1133 2133
0x86 134   1134 2134
0x87 135   1135 2135
0x90 144   1144 2144
0x91 145   1145 2145
0xA0 160   1160 2160
0xA1 161   1161 2161
0xA2 162   1162 2162
0xA3 163   1163 2163
0xA4 164   1164 2164
0xA5 165   1165 2165
0xA4 164   1164 2164
0xA5 165   1165 2165
0xA6 166   1166 2166
0xA7 167   1167 2167
0xA8 168   1168 2168
0xA9 169   1169 2169
0xAA 170   1170 2170
0xAB 171   1171 2171
0xAC 172   1172 2172
0xAD 173   1173 2173
0xAE 174   1174 2174
0xAF 175   1175 2175
0xB0 176   1176 2176
0xB1 177   1177 2177
0xB2 178   1178 2178
0xB3 179   1179 2179
0xB4 180   1180 2180
0xB5 181   1181 2181
0xB6 182   1182 2182
0xB7 183   1183 2183
0xBA 186   1186 2186
0xBB 187   1187 2187
0xBC 188   1188 2188
0xBD 189   1189 2189
0xBE 190   1190 2190
0xBF 191   1191 2191
0xC0 192   1192 2192
0xDB 219   1219 2219
0xDC 220   1220 2220
0xDD 221   1221 2221
0xDE 222   1222 2222
0xDF 223   1223 2223
0xE2 226   1226 2226
0xE5 229   1229 2229
0xE7 231   1231 2231
0xF6 246   1246 2246
0xF7 247   1247 2247
0xF8 248   1248 2248
0xF9 249   1249 2249
0xFA 250   1250 2250
0xFB 251   1251 2251
0xFD 253   1253 2253