Уважаемый prom-net-pixel,
на вскидку могу предложить такой вариант:
Предположим у нас есть 
Memo1 и две кнопки 
Up и 
Down, тогда:
- Код: Выделить всё
 procedure TForm1.UpClick(Sender: TObject);
var
  cp:integer;
begin
  cp:=Memo1.SelStart-Memo1.CaretPos.X-2;
  if cp<0 then cp:=0;
  Memo1.SelStart:=cp
end;
- Код: Выделить всё
 procedure TForm1.DownClick(Sender: TObject);
var
  cp:integer;
begin
  if Memo1.CaretPos.y<Memo1.Lines.Count then begin
    cp:=Memo1.SelStart+2+Length(Memo1.Lines[Memo1.CaretPos.y])-Memo1.CaretPos.x;
    Memo1.SelStart:=cp
  end;
end;
Поясню:
У 
TMemo есть доступное только для чтения свойство 
CaretPos (собственно, будь оно Read-Write - вообще всё было бы просто) типа 
TPoint, где X - положение курсора в текущей строке, а Y - номер текущей строки. В то же самое время в 
TMemo есть свойство 
SelStart, отвечающее за, так сказать, "глобальную" позицию курсора.
Таким образом, вычтя 
CaretPos.X из 
SelStart, мы переведем курсор в начало текущей строки, а, вычтя еще и 
2 (в Linux, предполагаю, 1) - в конец предыдущей строки.
Аналогично, прибавив к SelStart разницу между длиной текущей строки и позицией курсора в ней же 
Length(Memo1.Lines[Memo1.CaretPos.y])-Memo1.CaretPos.x
, мы переведём курсор в конец текущей строки, а прибавив 2 (1) - на следующую строку.
Ну, а для полного счастья, можно в код подставить  константу (скажем, 
EoLLen) значение, которой определять с помощью директив:
- Код: Выделить всё
 const
{$ifDef UNIX}
  EoLLen=1;
{$EndIf}
{$IfDef WINDOWS}
  EoLLen=2;
{$EndIf}
Надеюсь, предлагаемый способ не покажется Вам излишне извращенным.
С уважением, Алексей.