MacroStick’e core_payload endpoint’i üzerinden gönderilen her komut tam olarak 16 byte’lık sabit uzunlukta bir pakettir. Bu sayfa komut yapısını, doğrulama değerinin nasıl hesaplandığını ve yaygın komut türleri için hazır örnekleri kapsar.


Temel Yardımcı Sınıf

Aşağıdaki sınıfı doğrudan projelerinizde kullanabilirsiniz. Sayfanın geri kalanındaki tüm örnekler bu sınıf üzerine kuruludur.

  import struct
import requests


class MacroStick:
    """MacroStick HTTP API istemcisi."""

    SYNC    = 0xA5
    KEYBOARD       = 0x02
    MOUSE          = 0x03
    GAMEPAD        = 0x04
    CONSUMER       = 0x05
    SYSTEM_CONTROL = 0x06

    FLAG_DISABLE_AUTO_RELEASE = 0x01

    def __init__(self, host: str = "192.168.7.1", username: str = "", password: str = ""):
        self.base_url = f"http://{host}/api/core_payload"
        self.auth = (username, password)
        self._queue: list[bytes] = []

    # ------------------------------------------------------------------ #
    #  Paket oluşturma                                                     #
    # ------------------------------------------------------------------ #

    @staticmethod
    def _crc8(data: bytes) -> int:
        crc = 0x00
        for byte in data:
            crc ^= byte
            for _ in range(8):
                crc = ((crc << 1) ^ 0x07) & 0xFF if crc & 0x80 else (crc << 1) & 0xFF
        return crc

    @classmethod
    def _build(cls, type_byte: int, command_data: bytes, flags: int = 0x00) -> bytes:
        assert len(command_data) == 12
        crc_input = bytes([cls.SYNC, type_byte]) + command_data + bytes([flags])
        checksum = cls._crc8(crc_input)
        return bytes([cls.SYNC, type_byte]) + command_data + bytes([checksum, flags])

    # ------------------------------------------------------------------ #
    #  Toplu gönderim                                                      #
    # ------------------------------------------------------------------ #

    def send(self, *packets: bytes) -> int:
        """
        1–10 paket alır, tek HTTP isteğiyle gönderir.
        Dönüş değeri: HTTP durum kodu.
        """
        assert 1 <= len(packets) <= 10
        payload = b"".join(packets).hex()
        resp = requests.post(self.base_url, auth=self.auth, json={"payload": payload})
        return resp.status_code

    def queue(self, *packets: bytes):
        """Paketi kuyruğa ekle; flush() ile toplu gönder."""
        self._queue.extend(packets)

    def flush(self) -> list[int]:
        """Kuyruktaki tüm paketleri 10'arlı gruplar halinde gönderir."""
        codes = []
        while self._queue:
            batch = self._queue[:10]
            self._queue = self._queue[10:]
            codes.append(self.send(*batch))
        return codes

    # ------------------------------------------------------------------ #
    #  Klavye                                                              #
    # ------------------------------------------------------------------ #

    @classmethod
    def key_press(cls, keycode: int, modifier: int = 0x00, flags: int = 0x00) -> bytes:
        data = bytes([modifier, 0x00, keycode, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
        return cls._build(cls.KEYBOARD, data, flags)

    @classmethod
    def key_combo(cls, keycodes: list[int], modifier: int = 0x00, flags: int = 0x00) -> bytes:
        """En fazla 6 tuşu aynı anda basılı tut."""
        assert len(keycodes) <= 6
        padded = (keycodes + [0x00] * 6)[:6]
        data = bytes([modifier, 0x00] + padded + [0x00, 0x00, 0x00, 0x00])
        return cls._build(cls.KEYBOARD, data, flags)

    @classmethod
    def key_release(cls) -> bytes:
        return cls._build(cls.KEYBOARD, bytes(12))

    # ------------------------------------------------------------------ #
    #  Fare                                                                #
    # ------------------------------------------------------------------ #

    @classmethod
    def mouse_move(cls, x: int, y: int) -> bytes:
        data = struct.pack("bbbbb7x", 0, x, y, 0, 0)
        return cls._build(cls.MOUSE, data)

    @classmethod
    def mouse_button(cls, buttons: int) -> bytes:
        data = bytes([buttons]) + bytes(11)
        return cls._build(cls.MOUSE, data)

    @classmethod
    def mouse_scroll(cls, wheel: int, pan: int = 0) -> bytes:
        data = struct.pack("bbbbb7x", 0, 0, 0, wheel, pan)
        return cls._build(cls.MOUSE, data)

    # ------------------------------------------------------------------ #
    #  Consumer                                                            #
    # ------------------------------------------------------------------ #

    @classmethod
    def consumer_key(cls, usage: int) -> bytes:
        data = struct.pack("<H10x", usage)
        return cls._build(cls.CONSUMER, data)

    # ------------------------------------------------------------------ #
    #  Gamepad                                                             #
    # ------------------------------------------------------------------ #

    @classmethod
    def gamepad(cls, x=0, y=0, z=0, rx=0, ry=0, rz=0, hat=0, buttons=0) -> bytes:
        btn_bytes = struct.pack("<I", buttons)  # 4 byte, little-endian
        data = struct.pack("bbbbbbb", x, y, z, rx, ry, rz, hat) + btn_bytes + b"\x00"
        return cls._build(cls.GAMEPAD, data)

    # ------------------------------------------------------------------ #
    #  System Control                                                      #
    # ------------------------------------------------------------------ #

    @classmethod
    def system_control(cls, usage: int) -> bytes:
        data = bytes([usage]) + bytes(11)
        return cls._build(cls.SYSTEM_CONTROL, data)
  

Paket Yapısı

Her komut tam olarak 16 byte’tır; daha kısa veya uzun paketler geçersiz sayılır. Endpoint’e gönderirken bu 16 byte’lık paket hex string olarak yazılır; bu nedenle tek paket 32 hex karakterdir.

KonumBoyutAlanAçıklama
01syncHer zaman 0xA5 — paket başlangıç işareti
11typeKomut türü
2–1312commandDataTüre özgü veri
141checksumCRC-8 doğrulama değeri
151flagsDavranış bayrakları

Komut Türleri

DeğerTürKullanım
0x02KEYBOARDKlavye tuşu
0x03MOUSEFare hareketi ve tıklama
0x04GAMEPADOyun kumandası
0x05CONSUMERSes, medya, parlaklık
0x06SYSTEM_CONTROLGüç, uyku, uyanış

Flags

BitDeğerAnlamı
00x01DISABLE_AUTO_RELEASE — Bu komut için otomatik bırakma devre dışı

Otomatik bırakma aktifken cihaz belirli bir süre sonra tüm tuşları otomatik serbest bırakır. Bu bayrağı 0x01 yaparsanız bırakma komutu siz gönderene kadar tuş basılı kalır. Uzun süreli basılı tutma senaryolarında bu bayrağı kullanın.

Endpoint ile Gönderim

core_payload endpoint’i aynı istekte en fazla 10 paketi taşıyacak şekilde kullanılmalıdır. 10 paketten fazla komut gönderecekseniz paketleri gruplara ayırın.

  ms = MacroStick(username="KULLANICI_ADI", password="SIFRE")
ms.send(ms.key_press(0x04), ms.key_release())
  

Paket formatı geçersizse ilgili paket çalıştırılmaz. HTTP yanıt kodu istek seviyesini gösterir; her paketin ayrı başarı bilgisini döndürmez.


CRC-8 Hesaplama

checksum şu alanların sırayla birleştirilmesiyle hesaplanır: sync (1 byte) + type (1 byte) + commandData (12 byte) + flags (1 byte). Toplamda 15 byte girdi, checksum baytının kendisi dahil değil.

Algoritma: CRC-8, polinom 0x07, başlangıç değeri 0x00.

  def crc8(data: bytes) -> int:
    crc = 0x00
    for byte in data:
        crc ^= byte                         # Geçerli baytı XOR ile karıştır
        for _ in range(8):                  # 8 bit işle
            if crc & 0x80:                  # MSB set ise
                crc = ((crc << 1) ^ 0x07) & 0xFF
            else:
                crc = (crc << 1) & 0xFF
    return crc
  

Adım adım örnek — sync=0xA5, type=0x02, commandData=bytes(12), flags=0x00:

  data = bytes([0xA5, 0x02]) + bytes(12) + bytes([0x00])
checksum = crc8(data)
print(hex(checksum))  # 0xe1
  

Klavye Komutları (KEYBOARD — 0x02)

commandData Düzeni

OffsetAlanBoyutAçıklama
0modifier1Modifier tuş kombinasyonu
1reserved10x00
2–7keycodes[6]6Aynı anda basılan tuşların HID kodları
8–11reserved40x00

Modifier Bitleri

Her bit bir modifier tuşunu temsil eder. Birden fazla modifier için bitleri OR’layın.

BitDeğerTuş
00x01Sol Ctrl
10x02Sol Shift
20x04Sol Alt
30x08Sol GUI (Win / Cmd)
40x10Sağ Ctrl
50x20Sağ Shift
60x40Sağ Alt (AltGr)
70x80Sağ GUI

Örnekler:

  • Sol Shift → 0x02
  • Sol Ctrl + Sol Alt → 0x01 | 0x04 = 0x05
  • Sol Ctrl + Sol Shift → 0x01 | 0x02 = 0x03
  • Sol Ctrl + Sol Shift + Sol Alt → 0x07

USB HID Klavye Kodları

Harfler (büyük/küçük harf modifier ile belirlenir, kod aynıdır)

TuşKodTuşKodTuşKod
A0x04J0x0DS0x16
B0x05K0x0ET0x17
C0x06L0x0FU0x18
D0x07M0x10V0x19
E0x08N0x11W0x1A
F0x09O0x12X0x1B
G0x0AP0x13Y0x1C
H0x0BQ0x14Z0x1D
I0x0CR0x15

Rakamlar ve Semboller

TuşKodTuşKod
10x1E60x23
20x1F70x24
30x2080x25
40x2190x26
50x2200x27

Özel Tuşlar

TuşKodTuşKod
Enter0x28F10x3A
Escape0x29F20x3B
Backspace0x2AF30x3C
Tab0x2BF40x3D
Boşluk0x2CF50x3E
Caps Lock0x39F60x3F
Print Screen0x46F70x40
Insert0x49F80x41
Home0x4AF90x42
Page Up0x4BF100x43
Delete0x4CF110x44
End0x4DF120x45
Page Down0x4E
Sağ ok0x4FYukarı ok0x52
Sol ok0x50
Aşağı ok0x51

Klavye Örnekleri

Tek tuş: “A” basma ve bırakma

  ms = MacroStick(username="KULLANICI_ADI", password="SIFRE")

press   = ms.key_press(0x04)   # A
release = ms.key_release()

ms.send(press, release)
  

Büyük harf: “A” (Shift + a)

  press   = ms.key_press(0x04, modifier=0x02)  # Sol Shift + A
release = ms.key_release()
ms.send(press, release)
  

Kısayol: Ctrl+C

  press   = ms.key_press(0x06, modifier=0x01)  # Sol Ctrl + C
release = ms.key_release()
ms.send(press, release)
  

Kısayol: Ctrl+Alt+Delete

  press   = ms.key_combo([0x4C], modifier=0x05)  # Ctrl+Alt + Delete (0x4C)
release = ms.key_release()
ms.send(press, release)
  

Windows Çalıştır kutusu açma ve komut çalıştırma

Win+R açar, notepad yazar, Enter’a basar:

  import time

ms = MacroStick(username="KULLANICI_ADI", password="SIFRE")

KEY = {
    "enter": 0x28, "n": 0x11, "o": 0x12, "t": 0x17,
    "e": 0x08, "p": 0x13, "a": 0x04, "d": 0x07
}
WIN_R = ms.key_combo([0x15], modifier=0x08)  # GUI + R

ms.send(WIN_R, ms.key_release())
time.sleep(0.5)

for char, code in [("n", KEY["n"]), ("o", KEY["o"]), ("t", KEY["t"]),
                   ("e", KEY["e"]), ("p", KEY["p"]), ("a", KEY["a"]),
                   ("d", KEY["d"])]:
    ms.send(ms.key_press(code), ms.key_release())
    time.sleep(0.05)

ms.send(ms.key_press(KEY["enter"]), ms.key_release())
  

Metin yazdırma (batch ile)

10’dan uzun metinler için queue + flush kullanın:

  import time

ms = MacroStick(username="KULLANICI_ADI", password="SIFRE")

# "hello" → h=0x0B, e=0x08, l=0x0F, l=0x0F, o=0x12
for code in [0x0B, 0x08, 0x0F, 0x0F, 0x12]:
    ms.queue(ms.key_press(code), ms.key_release())

ms.flush()
  

Aynı anda birden fazla tuş (gaming combo)

  # W + Shift (sprint) — oyun senaryosu
press   = ms.key_combo([0x1A], modifier=0x02)  # Shift + W
release = ms.key_release()
ms.send(press, release)
  

Fare Komutları (MOUSE — 0x03)

commandData Düzeni

OffsetAlanTürAçıklama
0buttonsuint8Bit 0=Sol, Bit 1=Sağ, Bit 2=Orta
1xint8Yatay hareket: -128 (sol) … +127 (sağ)
2yint8Dikey hareket: -128 (yukarı) … +127 (aşağı)
3wheelint8Dikey tekerlek: + yukarı, - aşağı
4panint8Yatay kaydırma: + sağ, - sol
5–11reserved0x00

Fare hareketi görecelidir; her komut mevcut konumdan offset ekler. 127 pikselden fazla hareket için birden fazla komut gönderin.

Fare Örnekleri

Sağa 50 piksel hareket

  ms.send(ms.mouse_move(50, 0))
  

Büyük hareket — 300 piksel sağa (birden fazla komut)

  # 127 piksel sınırını aşmak için parçalara bölün
import time

remaining = 300
while remaining > 0:
    step = min(remaining, 127)
    ms.send(ms.mouse_move(step, 0))
    remaining -= step
    time.sleep(0.01)
  

Sol tık

  press   = ms.mouse_button(0x01)
release = ms.mouse_button(0x00)
ms.send(press, release)
  

Sağ tık

  press   = ms.mouse_button(0x02)
release = ms.mouse_button(0x00)
ms.send(press, release)
  

Çift tık

  import time

click = [ms.mouse_button(0x01), ms.mouse_button(0x00)]
ms.send(*click)
time.sleep(0.05)
ms.send(*click)
  

Sürükleme (drag) — sol tık basılı tutarak hareket

  ms.send(ms.mouse_button(0x01))   # Sol tık basılı
ms.send(ms.mouse_move(100, 0))   # 100 piksel sağa sürükle
ms.send(ms.mouse_button(0x00))   # Bırak
  

Tekerlek kaydırma

  ms.send(ms.mouse_scroll(3))   # Yukarı kaydır
ms.send(ms.mouse_scroll(-3))  # Aşağı kaydır
  

Consumer Komutları (CONSUMER — 0x05)

Ses düzeyi, medya kontrolü, parlaklık gibi özel tuşlar için kullanılır.

commandData Düzeni

OffsetAlanTürAçıklama
0–1usageuint16 LEUSB HID Consumer usage kodu
2–11reserved0x00

Sık Kullanılan Consumer Kodları

İşlevKod
Ses artır0x00E9
Ses kıs0x00EA
Sessiz aç/kapat0x00E2
Oynat / Duraklat0x00CD
Dur0x00B7
Sonraki parça0x00B5
Önceki parça0x00B6
Baştan başlat0x00B4
Hızlı ileri0x00B3
Geri sar0x00B2
Parlaklık artır0x006F
Parlaklık azalt0x0070
Hesap makinesi0x0192
Tarayıcı ana sayfa0x0223

Consumer Örnekleri

Ses artırma (3 kez)

  import time

for _ in range(3):
    ms.send(
        ms.consumer_key(0x00E9),  # Ses artır
        ms.consumer_key(0x0000)   # Bırak
    )
    time.sleep(0.1)
  

Oynat/Duraklat

  ms.send(
    ms.consumer_key(0x00CD),
    ms.consumer_key(0x0000)
)
  

Sonraki parça

  ms.send(
    ms.consumer_key(0x00B5),
    ms.consumer_key(0x0000)
)
  

Gamepad Komutları (GAMEPAD — 0x04)

commandData Düzeni

OffsetAlanTürAçıklama
0xint8Sol analog: yatay (-128 sol … +127 sağ)
1yint8Sol analog: dikey (-128 yukarı … +127 aşağı)
2zint8Sağ analog: yatay
3rxint8Sağ analog: dikey
4ryint8Ekstra eksen
5rzint8Ekstra eksen
6hatint8D-Pad (0=serbest, 1=kuzey, 2=KB, 3=doğu…)
7–10buttons[4]uint32 LE32 bit düğme maskesi
11reserved0x00

Gamepad Örnekleri

Sol analog çubuğu sağa it

  ms.send(
    ms.gamepad(x=100),     # Sağa %78 (100/127)
    ms.gamepad(x=0)        # Serbest bırak
)
  

A düğmesine bas (bit 0)

  ms.send(
    ms.gamepad(buttons=0x01),   # A basılı
    ms.gamepad(buttons=0x00)    # Bırak
)
  

D-Pad yukarı

  ms.send(
    ms.gamepad(hat=1),    # Kuzey
    ms.gamepad(hat=0)     # Serbest
)
  

System Control Komutları (SYSTEM_CONTROL — 0x06)

Güç yönetimi komutları için kullanılır.

commandData Düzeni

OffsetAlanTürAçıklama
0usageuint8USB HID System Control usage kodu
1–11reserved0x00

Sık Kullanılan Kodlar

İşlevKod
Güç kapat0x81
Uyku0x82
Uyan0x83

Örnek: Uyku moduna al

  ms.send(
    ms.system_control(0x82),   # Uyku
    ms.system_control(0x00)    # Bırak
)
  

Hata Durumları

DurumSonuç
Yanlış sync baytı (0xA5 değil)Paket sessizce düşürülür
CRC-8 uyuşmazlığıPaket sessizce düşürülür
Geçersiz type değeriPaket sessizce düşürülür
payload 320 hex karakterden uzunPayload’ı 10 paketlik isteklere bölün
Komut kuyruğu doluPaket sessizce düşürülür
Yanlış kimlik bilgisi401 Unauthorized

Birden fazla paket içeren bir istekte geçerli paketler işlenmeye devam eder; geçersiz paketler yalnızca kendisi atlanır.


Zamanlama

MacroStick paketler arasına otomatik gecikme eklemez. Basış ve bırakma arasındaki süre tamamen gönderdiğiniz isteklerin sırasına ve arasına koyduğunuz gecikmelere bağlıdır.

  • Tek tuş basışı: basma + bırakma komutunu aynı istekte gönderin.
  • Tuş arası gecikme: birden fazla tuş arasına time.sleep(0.05) ekleyin; bazı uygulamalar çok hızlı ardışık girişleri kaçırabilir.
  • Uzun basılı tutma: FLAG_DISABLE_AUTO_RELEASE bayrağını 0x01 yapın ve bırakma komutunu istediğiniz süre sonra gönderin.
  import time

# Shift tuşunu 2 saniye basılı tut
ms.send(ms.key_press(0x02, flags=MacroStick.FLAG_DISABLE_AUTO_RELEASE))  # Sol Shift
time.sleep(2)
ms.send(ms.key_release())
  
Bu sayfa yardımcı oldu mu?