Xamarin TcpClient Chat

Xamarin TcpClient Chat
WO
  • Rejestracja:prawie 9 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Kraków
  • Postów:135
0

Witam,
Napisałem działającą tcp czat lan aplikacje na windows. Następnie chciałem przenieść aplikacje na androida poprzez xamarina by połączyć komputer(server) i telefon(client)
Ustawilem na xamarinie permission Internet oraz operuję na wifi 192.168.x.x

Program się łączy z serwerem( serwer na kompie):

Kopiuj
private void buttonClickConnect(object sender, EventArgs e)
                {
                    client = new TcpClient();
                    IPEndPoint IP_End = new IPEndPoint(IPAddress.Parse("192.168.1.1"), int.Parse("13000"));
                    try
                    {
                        client.Connect(IP_End);
                        if (client.Connected)
                        {
                            textviewConversation.Text += "Connected to server" + "\n";
                            STR = new StreamReader(client.GetStream());
                            STW = new StreamWriter(client.GetStream());
                            STW.AutoFlush = true;
                            worker1.RunWorkerAsync();
                            worker2.WorkerSupportsCancellation = true;
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                }

Łączy się z serwerem ale nie może wysłać wiadomości. Raz wciskam send to nic sie nie dzieje, drugi raz klikam to wywala że thread jesy busy.

Kopiuj
private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)   //sending message, here error probably
        {
            if (client.Connected)
            {
                STW.WriteLine(text_to_send);
            }
            else
            {
                Console.WriteLine("send failed !");
            }
            worker2.CancelAsync();
        }

Nie ma pętli w tym wątku powinno zatem wysłać i zwolnić wątek.
Pełny kod napisany na xamarn: http://pastebin.com/DJxHUdXn,

Błagam o pomoc, wierzę ze nie wiele trzeba by to wszystko działało : ))
Pozdrawiam


/We learn not for school but for our life/ Pozdrawiam
edytowany 1x, ostatnio: wonman
NeuroXiq
  • Rejestracja:prawie 9 lat
  • Ostatnio:około 5 lat
  • Lokalizacja:Racibórz
  • Postów:101
1

Spróbuj może coś takiego:

Kopiuj
 
//w kodzie buttonClickConnect, ns to pole klasy typu NetworkStream
ns = client.GetStream();
//w backgroundWorder2 daj coś takiego:

byte[] msg = Encoding.ASCII.GetBytes("jakas wiadomosc");
ns.Write(msg,0,msg.Leght);

Ale coś mi ogólnie nie gra z tymi backgroundWorker'ami. Nie lepiej po prostu odpalić normalnego Taska z while który by cały czas odbierał wiadomości, a jakbyś chciał wysłać to po prostu wysyłasz 'normalnie' (synchronicznie) ?

WO
Dziękuję za post, zmiany nie usunęły błędu. :/ To dziwne bo minimalnie zmieniona (buttony, text inputy, labele) na c# wpf śmiga pięknie ta apka. A na xamarin niezbyt. Pełny komentarz do tych zmian w poście moim niżej.
DibbyDum
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Polska, Kraków
1
wonman napisał(a):

Łączy się z serwerem ale nie może wysłać wiadomości. Raz wciskam send to nic sie nie dzieje, drugi raz klikam to wywala że thread jesy busy.

Powodem jest to że próbujesz uruchomić jeszcze raz już wcześniej uruchomiony "BackgroundWorker", żeby się przed tym uchronić możesz użyć if (worker1.IsBusy){...}.

A co do kodu to trochę ciężko się w tym połapać, wyrzuć na początek te wszystkie operacje po sieci do osobnej klasy żeby jakoś nad tym zapanować.


Yubby dibby dibby dibby dibby dibby dibby dum..
WO
Dziękuję za post, co do podziału na klasy wolę nie. Gdyż pogubię się z tym a pewnie coś w między czasie przestanie nowego działać. Jestem wstanie opisać funkcje: 1. backgroundWorker1_DoWork - odbiera w pętli wszystkie wiadomości 2. backgroundWorker2_DoWork - wysyła wiadomość 3. buttonClickConnect - łączy się z serwerem 4. buttonClickSend - wysyła wiadomość
WO
  • Rejestracja:prawie 9 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Kraków
  • Postów:135
0

<quote="1282116">Spróbuj może coś takiego:

Kopiuj
 
//w kodzie buttonClickConnect, ns to pole klasy typu NetworkStream
ns = client.GetStream();
//w backgroundWorder2 daj coś takiego:

byte[] msg = Encoding.ASCII.GetBytes("jakas wiadomosc");
ns.Write(msg,0,msg.Leght);

Zastosowałem w tych miejscach: ( public NetworkStream ns dalem na początku klasy )

Kopiuj
private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)   //sending message, here error probably
        {
           

            if (client.Connected)
            {
                byte[] msg = Encoding.ASCII.GetBytes("jakas wiadomosc");
                ns.Write(msg, 0, msg.Length);<-----------@@@@@@@@@@@@@@@@@@@@@@@@ TUTAJ DAŁEM
                //STW.WriteLine(text_to_send); <------ to zakomentowałe
            }
            else 

oraz:

Kopiuj
private void buttonClickConnect(object sender, EventArgs e)
        {
            client = new TcpClient();

            IPEndPoint IP_End = new IPEndPoint(IPAddress.Parse("192.168.1.1"), int.Parse("13000"));
             
            try
            {
                client.Connect(IP_End);
                if (client.Connected)
                {
                    textviewConversation.Text += "Connected to server" + "\n";
                    STR = new StreamReader(client.GetStream());
                    STW = new StreamWriter(client.GetStream());
                    STW.AutoFlush = true;
                    ns = client.GetStream(); <-----------@@@@@@@@@@@@@@@@@@@@@@@@ TUTAJ DAŁEM
                    worker1.RunWorkerAsync();
                    worker2.WorkerSupportsCancellation = true; 

W kwestii logiki kodu hm... bazowałem na różnych źródłach tworząc tą aplikacje, nie mam dużego doświadczenia. Aplikacja działa na widnowsie to zostawiłem tak :)

Po zastosowaniu Twoich zmian wciąż to samo - nie działa, jednak mogę nadmienić dokładniej:
Klikam połącz, łączy się.
Wpisuje i wysyłam #1 wiadomość, nic sie nie dzieje
Wpisuje i wysyłam #2 wiadomość, i nagle przycina wypisuje że thread busy.
Sam jednak sygnał dochodzi do servera który wariuje, dostaje jak by dziesiątki wiadomosci pustych. I tam też crashuje że thread multi. Ciekawe zjawisko.
Mi się wydaje że ta wiadomość leci w cząstkach? temu tak dużo przychodzi na server powiadomień ale pustych wiadomości w stringu.

kod SERWERA na PC

Kopiuj
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace serverDoWielu
{
    public partial class MainWindow : Window
    {
       
        private List<TcpClient> listaClientow = new List<TcpClient>();
        private List<StreamReader> listaSTR = new List<StreamReader>();
        private List<StreamWriter> listaSTW = new List<StreamWriter>();
        StreamReader STR;
        StreamWriter STW;

        private string received;
        private String text_to_send;                                            
        public BackgroundWorker worker2;
        public BackgroundWorker worker3;
        int licznikClientow;

        public MainWindow()
        {
            InitializeComponent();
            worker2 = new BackgroundWorker();
            worker2.DoWork += backgroundWorker2_DoWork;
            worker3 = new BackgroundWorker();
            worker3.DoWork += backgroundWorker3_DoWork;
            worker2.WorkerSupportsCancellation = true;
        }

        private void button_Click(object sender, RoutedEventArgs e)
        {
            worker3.RunWorkerAsync(); 
        }

        private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
        {
                string wiadomosc = (string)e.Argument;
                List<StreamWriter> tmp = new List<StreamWriter>(listaSTW);

                foreach (var item in tmp)      
                {
                    item.WriteLine(wiadomosc);
                }   
            
            
            worker2.CancelAsync();
        }
        private void backgroundWorker3_DoWork(object sender, DoWorkEventArgs e)                                                              
        {
            TcpListener listener = new TcpListener(IPAddress.Parse("192.168.1.1"), 13000);
            // TcpListener listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 13000);

            licznikClientow = 0;
            while (true)
            {
                listener.Start(); 
                listaClientow.Add(new TcpClient()); // add new
                listaClientow[licznikClientow] = listener.AcceptTcpClient(); //przypisujemy 
                listaSTR.Add(new StreamReader(  listaClientow[licznikClientow].GetStream() ) );  // to read
                listaSTW.Add(new StreamWriter(  listaClientow[licznikClientow].GetStream() ) );   // to send 
                listaSTW[licznikClientow].AutoFlush = true; //clear

                BackgroundWorker clientThread = new BackgroundWorker();
                clientThread.WorkerSupportsCancellation = true;
                clientThread.DoWork += new DoWorkEventHandler(clientThread_DoWork);
                clientThread.RunWorkerAsync(licznikClientow);
                
                licznikClientow++;
            }
        }

        private void clientThread_DoWork(object sender, DoWorkEventArgs e)                                                               
        {
            int ktoryKlient = (int)e.Argument;
            
            
                while (listaClientow[ktoryKlient].Connected)  
                {
                try
                {
                    received = "";
                            received = listaSTR[ktoryKlient].ReadLine();
                    Console.WriteLine("@@@@@@   "+received); <------------------------------------@@@@@@@@@@@@@@@@ To wypluwa w dziesiątkach @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
                            text_to_send = received;

                            if (text_to_send != "")
                            {
                                this.textBox.Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate () { textBox.AppendText("->> " + text_to_send + "\n"); });
                                worker2.RunWorkerAsync(text_to_send);    
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            foreach (var item in listaSTW)     // sending to all people
            {
                item.WriteLine(textBox1.Text);
            }
        }
    }
}
 

/We learn not for school but for our life/ Pozdrawiam
edytowany 2x, ostatnio: wonman
NeuroXiq
  • Rejestracja:prawie 9 lat
  • Ostatnio:około 5 lat
  • Lokalizacja:Racibórz
  • Postów:101
1

o dziwne bo minimalnie zmieniona (buttony, text inputy, labele) na c# wpf śmiga pięknie ta apka. A na xamarin niezbyt

Po 1. Zmień na serwie IPAddress.Parse(...) na IPAddress.Any,

Hmm trochę dziwne, trzeba się teraz zastanowić czy to w ogóle nie działa bo jest błąd w kodzie czy to nie działa z innego powodu.
Na mój gust to można by było po protu spróbować, czy w ogóle najprostsze wysyłanie/odbieranie wiadomości ma miejsce. Ja bym w ogóle zaczął to budować od podstawowego połączenia i wysłania jednej wiadomości do serwa i odbiór od serwa. Coś w stylu:

klient się połączył:
klient ---->[asdf]----> serwer
klient <---[asdf]---- serwer

Sprawdź czy w ogóle działa to tak jak napisałem.
Mniej więcej coś takiego:

Kopiuj
 
//[serwer]//
TcpListener l = new TcpListener(IPAddress.Any,12345);
l.Start();
TcpClient c = l.AcceptTcpClient()

byte[] buff = new byte[32];
c.GetStream().Read(buff,0,32);
string msg= Encoding.ASCII.GetString(buff);
//wyświetl wiadomość.
string reply = "simple reply to client";
byte[] r = Encoding.ASCII.GetBytes(reply);
c.GetStream().Write(r,0,r.Lenght); // czy coś takiego nie pamietam dokładnie.

//[Klient]//
TcpClient c = new Tcp(...);
c.Connect(...)
string msg = "asdf";
byte[] buff = Encoding.ASCII.GetBytes(msg);
c.GetStream().Write(buff,0,buff.Lenght);
//
byte[] receive = new byte[32];
c.GetStream().Read(receive);

//encoding i wyświetl

Sprawdź czy takie podstawowe wysłanie/odebranie działa w ogóle

edytowany 1x, ostatnio: NeuroXiq
WO
Client rozumiem xamarin, a server PC (takie założenia były początkowe) Raz wstawie kod tylko przemiele. : )
NeuroXiq
Dokładnie - klient tam gdzie chcesz (gdzie ma być finalnie) i serwer tak samo - po prostu tu sprawdzimy czy jakiekolwiek wysyłanie działa
WO
Rozumiem, dobry pomysł rozbić wszystko na poszczególne party. Tu są całe plik jak by Cię czasem ciekawiło http://www.speedyshare.com/UK4VA/serwerPC-AndroidClient.rar PC serwer i Client android.
WO
  • Rejestracja:prawie 9 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Kraków
  • Postów:135
0

Android client:

Kopiuj
public class MainActivity : Activity
    {
        public TextView napis;

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            SetContentView(Resource.Layout.Main);
            Button button = FindViewById<Button>(Resource.Id.MyButton);
            button.Click += Start;
            napis = FindViewById<Button>(Resource.Id.MyButton);
        }
       

        private void Start(object sender, EventArgs e)
        {
            TcpClient c = new TcpClient();
            IPEndPoint IP_End = new IPEndPoint(IPAddress.Any, 13000);
            c.Connect(IP_End);
            //c.Connect(...)
            string msg = "asdf";
            byte[] buff = Encoding.ASCII.GetBytes(msg);
            c.GetStream().Write(buff, 0, buff.Length);

            byte[] receive = new byte[32];
            var otrzymane = c.GetStream().Read(receive, 0, receive.Length); //@@@@@@@@ ??
            napis.Text = otrzymane.ToString();
        }
    } 

Mam pewne wątpliwości co do: c.GetStream().Read(receive, 0, receive.Length); to pod jakąś zmienną podczepić czy bez?
Serwer zrobie w cmd c#.


/We learn not for school but for our life/ Pozdrawiam
WO
  • Rejestracja:prawie 9 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Kraków
  • Postów:135
0

serwer cmd:
Dałem Parse zamiast Any. Chodzi o to że mam skonfigurowany VirtualBox, dodatkowo xamarin nie działa na 127.0.0.1, tylko na WIFI 192.168.x.x.
Powoduje to problemy pozostanę przy parse.

Kopiuj
static void Main(string[] args)
        {

            TcpListener l = new TcpListener(IPAddress.Parse("192.168.1.1"), 12345);
            l.Start();
            TcpClient c = l.AcceptTcpClient();
            //IPAddress.Parse("192.168.1.1")

            byte[] buff = new byte[32];
            c.GetStream().Read(buff, 0, 32);
            string msg = Encoding.ASCII.GetString(buff);
            Console.WriteLine("wiadomosc: " + msg);
            string reply = "simple reply to client";
            byte[] r = Encoding.ASCII.GetBytes(reply);
            c.GetStream().Write(r, 0, r.Length);
            System.Console.ReadKey();
        } 

screen z odpalenia:
https://scr.hu/2pdc/286m6

Wiadomosc przeszła ! Sukces : )))) WIELKIE DZIĘKI !
Teraz już kwestia rozbudowy tej małej cegiełki do budowy pałacu.

Jeżeli masz jeszcze jakieś sugestie, coś sprawdzić cos wstawić itp to proszę napisz z chęcią to przetestuję. Przepraszam jeżeli Musiałeś dłużej czasem czekać.
Xamarin wciąż bym nazwał aplkacją w fazie BETA, duzo jej brakuje jeszcze, a programuje w niej przed wczoraj i się czasem gubię. Najważniejsze dla mnie było zbudować most między dwoma platformami.

C.d. TcpClient słyszałem że na Xamarinie są tez z tym problemy. Tutaj widze jednak pięknie śmiga. Zdradzę że mój główny cel to zabawa komórką moim laptopem. By sobie kliknięciem odpalić muzykę z laptopa, albo go wyłączyć shutdown-s. Czy tez tam regulować film wyświetlany z laptopa bedąc w kanapie z komórką. ( takie tam marzenie)

Dziękuję bardzo za pomoc ! Dałeś nadzieje : )) i się udało.


/We learn not for school but for our life/ Pozdrawiam
edytowany 2x, ostatnio: wonman
NeuroXiq
To dobrze zrobiłeś z tym ip, ja po prosty nie wiedziałem, że wymaga to jakiejś dodatkowej konfiguracji ;)
NeuroXiq
  • Rejestracja:prawie 9 lat
  • Ostatnio:około 5 lat
  • Lokalizacja:Racibórz
  • Postów:101
0

Coś tak czułem, że z tymi całymi backgroundworkerami są jakieś problemy ale to trzeba by było debbugować a i tak kod jest trochę przekombinowany. Wiadomość dotarła to bardzo dobrze. Klika uwag na przyszłość:

  1. Uważaj bo pakiety nie dochodzą w całości, na localhost będzie ci wszystko śmigało bardzo dobrze ale później próbuj się łączyć przez sieć i czy wszystko działa.
  2. Jeżeli wysyłasz wiadomość (dla przykładu): "ABCD" to:
Kopiuj
 
byte[] buffer = new byte[8];
int received = networkstream.Read(buffer);

w buforze w tym momencie pierwsze cztery bajty to twoje litery, pozostałe są wyzerowane (pamiętaj o tym). To, ile bajtów zostało odebranych przechowywane jest teraz w received (w tym wypadku będzie 4, Read zwraca ilość przeczytanych bajtów).

Musiałbyś także stworzyć jakieś zakończenie wiadomości (coś na końcu co określa jej koniec, jakiś nieużywany ciąg czy coś) ponieważ wysyłając dwie lub więcej mogą się nałożyć w końcowym buforze, może być pierwsza cała i kilka bajtów następnej itp.

NetworkStream posiada także coś takiego jak IsAvailable (chyba tak,zapomniałem dokładnie - poszukaj jak sprawdzić czy są dane do czytania dla NetworkStream) i tylko wtedy, gdy są takie dane czytaj z networkstream.

WO
  • Rejestracja:prawie 9 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Kraków
  • Postów:135
0

Hmmm dziękuję za wskazówkę. Wiem że wysyłam cały buffor. Poczytam o tym jak to wygląda by ładnie wszystko chodziło. Co do localhota/ wifi. Operowanie na localhost nie wchodzi rachubę jeżeli chce operować na dwóch maszynach. Będę liczyć się z błędami. Jednak wciąż myślę że jak stoję 5m od urządzenia (bo będę raczej prowadzić prace w obrębie swojego pokoju) to nie będzie większych zakłóceń.

Pozdrawiam Serdecznie !


/We learn not for school but for our life/ Pozdrawiam
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)