-
копирование произоводится корректно, как при Ctrl+C, Ctrl+Ins там и при вызове из локального меню
-
Игорь Шевченко © (21.05.10 23:16) [20]
копирование произоводится корректно, как при Ctrl+C, Ctrl+Ins там и при вызове из локального меню спасибо за пример - он безусловно пока самый рабочий. В принципе у меня он был немного в другом виде, но метод запомнить раскладку, сменить на русский и затем обратно я уже использовал. Я как раз ищу рабочий пример без смены раскладки. Во-вторых, вопрос к вам как к программисту: как поведет себя код при отсутствии русской раскладки? Я пробовал удалять раскладки и код работает, но все же, какие могут быть курьезы? И в-третьих, как же быть со вставкой? Основная проблема здесь: Открываем блокнот Windows. переключаем раскладку на русский. пишем текст. переключаем обратно на англ. копируем в буфер. вставляем в мемо в нашу программу (форма и мемо). результат: "?" и абракадабра... Здесь уже не моможет включение русской раскладки перед вставкой, т.к. русский текст был скопирован с некорректной кодовой страницей в Clipboard.
-
да, и еще вопрос, как это размножить на 100 мемо программно procedure TForm1.FormCreate(Sender: TObject);
begin
FOldMemoWndProc := Memo1.WindowProc;
Memo1.WindowProc := MemoWndProc;
FOldEditWndProc := Edit1.WindowProc;
Edit1.WindowProc := EditWndProc;
Memo1.Lines.Text := 'Это русский текст';
end;
procedure TForm1.MemoWndProc(var Message: TMessage);
var
LKL: array [0..1023] of char;
begin
if Message.Msg = WM_COPY then
begin
GetKeyboardLayoutName(LKL);
LoadKeyboardLayout('00000419',KLF_ACTIVATE);
end;
FOldMemoWndProc(Message);
if Message.Msg = WM_COPY then
LoadKeyboardLayout(LKL,KLF_ACTIVATE);
end;
-
allrussia (22.05.10 00:08) [21] Мне, если честно, лень искать материалы по работе с Clipboard. Разумеется, переключение языка раскладки - это грубый (и не всегда полезный) метод. То, что при этом Clipboard устанавливает нужный формат - это побочный эффект от переключения, я уверен, что этого же эффекта можно добиться прямым путем. вот тут http://www.codeguru.com/cpp/w-p/clipboard/article.php/c3009есть неплохая программка, которая позволяет крутить данные в Clipboard под разным углом. Вот тут ( http://msdn.microsoft.com/en-us/library/ms649013(VS.85).aspx ) есть описание, почему действует переключение клавиатуры: "The data is a handle to the locale identifier associated with text in the clipboard. When you close the clipboard, if it contains CF_TEXT data but no CF_LOCALE data, the system automatically sets the CF_LOCALE format to the current input language. You can use the CF_LOCALE format to associate a different locale with the clipboard text. An application that pastes text from the clipboard can retrieve this format to determine which character set was used to generate the text." Твори, выдумывай, пробуй.
-
allrussia (22.05.10 00:25) [22]
> да, и еще вопрос, как это размножить на 100 мемо программно
Написать наследник от TMemo и использовать наследник. Заменять можно и в runtime
-
> Заменять можно и в runtime
<offtop> Эх, если бы были механизмы/утилиты сделать подобное в designtime. </offtop>
-
спасибо, но со вставкой все равно непонятно в этом случае как быть
Открываем блокнот Windows. переключаем раскладку на русский. пишем текст. переключаем обратно на англ. копируем в буфер. вставляем в мемо в нашу программу (форма и мемо). результат: "?" и абракадабра...
здеть уже SetClipBoardData(CF_Locale,0419) не помогает..... ведь копирование было средствами ОС из чужой программы
-
вот тут http://www.codeguru.com/cpp/w-p/clipboard/article.php/c3009 есть неплохая программка, которая позволяет крутить данные в Clipboard под разным углом.да а смысл? я сам могу "крутить" данные с помощью кнопок и мыши (вы сами мне давали функцию BufferToClipBoard)... Мне-то нужно перехватывать системную вставку-копирование.. тем более прога под последними ОС не фурычит...
-
Вот как я это делел, без завязки на русский: procedure SendKeyboardLayout(Wnd, Msg:int; lParam:int=0; wParam:int=0);
var a:HKL; s:string;
begin
SetLength(s,8);
Win32Check(GetKeyboardLayoutName(ptr(s)));
if s='00000409' then
begin
a:=ActivateKeyboardLayout(
LoadKeyBoardLayout(ptr(intToHex(GetUserDefaultLangID,8)),0),0);
if a=0 then RaiseLastOSError;
SendMessage(Wnd, Msg, lParam, wParam);
if ActivateKeyboardLayout(a,0)=0 then RaiseLastOSError;
end else
SendMessage(Wnd, Msg, lParam, wParam);
end;
procedure TForm1.Copy1Click(Sender: TObject);
begin
SendKeyboardLayout(GetFocus, WM_COPY);
end;
procedure TForm1.Cut1Click(Sender: TObject);
begin
SendKeyboardLayout(GetFocus, WM_CUT);
end;
procedure TForm1.Paste1Click(Sender: TObject);
begin
SendMessage(GetFocus, WM_PASTE, 0, 0);
end; Это код для пунктов меню. Если кодировка английская, он устанавливает кодировку для языка пользователя. Перехват оконной процедуры у тебя нормальный, только не понятно, откуда ты нашел Handle у TComponent - он только у TWinControl. Игорь Шевченко © (21.05.10 19:58) [12] Но гораздо проще надписать компоненты и в них заменять оконную процедуру на нужную (как это неоднократно демонстрируется в stdctrls.pas)Не-не-не. Только лишняя морока. А этот метод еще можно продолжыть, отлавливая создание дочерних контролов. Игорь Шевченко © (22.05.10 0:28) [23]Спасибо, это интересно.
-
GrayFace © (22.05.10 22:20) [28]
> Не-не-не. Только лишняя морока. А этот метод еще можно продолжыть, > отлавливая создание дочерних контролов.
Сказки не рассказывай, ладно ?
> procedure SendKeyboardLayout(Wnd, Msg:int; lParam:int=0; > wParam:int=0);
Срочно читать Фаулера. Наизусть.
Почему помогает смена языка клавиатуры - потому что ясным английским языком написано, что если при закрытии Clipboard locale не установлен, то он становится равным текущему языку ввода. Умные люди советуют передавать CF_UNICODETEXT и, соответственно, строку в Unicode (UCS-2), которая при вставке в Ansi-контрол должна быть преобразована в соотвествии с locale потока, а не языка ввода. А он по умолчанию равен языку локализации системы :)
-
GrayFace > Это код для пунктов меню.
тема совсем не о пунктах меню. с пунктами меню проблем нет, причем приведены более удобные методы BufferToClipBoardкстати, вот это
procedure TForm1.Paste1Click(Sender: TObject);
begin
SendMessage(GetFocus, WM_PASTE, 0, 0);
end; у вас даже не сработает, если Открываем блокнот Windows. переключаем раскладку на русский. пишем текст. переключаем обратно на англ. копируем в буфер. вставляем в мемо в нашу программу (форма и мемо). результат: "?" и абракадабра...будет та же абракадабра... :)) увы, ваш вариант не принимается :( просто с помощью меню никто не копирует это долго и нудно основная задача заменить операции стандартных комбинации клавиш на свои
-
> allrussia
не совсем вкурсе вопроса насчет раскладок и кодовых страниц клипбоарда, сам не сталкивался с этой проблемой в плане разработки, только слышал.
но что если просто отслеживать буфер обмена (благо есть такие функции) и, в случае появления кривого, текста вручную подменять его, к примеру, на юникодовский вариант?
-
-
Я сильно извиняюсь, а что, пользователей нельзя попросить вручную переключиться на русский язык перед копированием ? Мои пользователи и я научились.
К тому же в последних версиях Delphi этой проблемы нет, так как юникод.
Я к чему - конечно чистое искусство, это хорошо и красиво, но стоит ли овчинка выделки ? Если бы подобный механизм был бы действительно необходим и востребован, MS бы давно придумал нужный API для изменения поведения Clipboard в желаемую сторону.
-
> Я к чему - конечно чистое искусство, это хорошо и красиво, > но стоит ли овчинка выделки ?
+1
-
> Я сильно извиняюсь, а что, пользователей нельзя попросить > вручную переключиться на русский язык перед копированием > ? Мои пользователи и я научились. >
Можно, просто у меня другой подход к созданию собственных программ. Просто я - админ, и мое кредо: для пользователей должно быть все прозрачно. Для меня - "кривые руки программиста" - это не "кривой" (пусть даже дебильный) для вас, программистов с большой буквы, код, а "кривая" работа программы, в данном случае, непродуманность в отношении буфера обмена Windows; в общих случаях, ка правило, это неюзабельный интерфейс, отсутствие горячих клавиш, многозадачности и многопоточности и пр. Меня красота кода не волнует. Поэтому и считаю, что хороший и талантливый программист, как правило, хреновый дизайнер и наоборот. Я из последних.
-
> Просто я - админ, и мое кредо: для пользователей должно > быть все прозрачно.
Переходи на Delphi 2009 и выше. На неюникодных версиях красивого решения, боюсь, нет.
-
> непродуманность в отношении буфера обмена Windows
> хороший и талантливый программист
на самом деле все в буфере продумано,а вы видимо не такой талантливый, раз в этом сомневаетесь для начала стоит изучить первоисточники,типа msdn а не "самоучитель дельфи глава 7 TClipboard"
так вот ,о чем это я 1)чтобы "перехватить" Ctrl+с и тд нужно просто перерегистрировать данный хоткей в своей проге (невероятно ,правда?) 2)буфер может хранить текст сразу в 3х кодировках дос,анси и уникод. Но! все почемуто используют тока одну (вот и зависимость от текущей клавы) что из этого следует... 1)ловим нажатие хоткея в очереди главного окна 2)смотрим какая кодировка в буфере и конвертируем в нужную или винда сделает это сама если в буфере установить нужный локаль(иначе возьмет текущую раскладку клавы) 3)когда копируем из себя то,либо забиваем в буфер сразу в 3х кодировках, либо одну и в буфере установить нужный локаль(иначе возьмет текущую раскладку клавы) 4)и естествено мы забиваем на всякие TClipboard ,а используем АПИ вот и вся теория...
ps есть ищо варианты
-
> нужно просто перерегистрировать данный хоткей в своей проге
правда придется еще чучуть доработать штоб работало во всей системе после етого ;)
-
Окончательный рабочий вариант
var cl: string;
...
procedure ClipboardCopy(const Text: String);
var
Len, wLen: Integer;
hClip: THandle;
pwStr: PWideChar;
begin
with Clipboard do
begin
Open;
try
if (Win32Platform = VER_PLATFORM_WIN32_NT) then
begin
Len := Length(Text) + 1;
wLen := Len shl 1;
hClip := GlobalAlloc(GMEM_MOVEABLE, wLen);
try
pwStr := PWideChar(GlobalLock(hClip));
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, PChar(Text), Len, pwStr, wLen);
GlobalUnlock(hClip);
SetAsHandle(CF_UNICODETEXT, hClip);
except
GlobalFree(hClip);
raise;
end;
end else
SetTextBuf(PChar(Text));
finally
Close;
end;
end;
end;
procedure ClipboardPaste(var Text: String);
var
Len, wLen: Integer;
hClip: THandle;
pwStr: PWideChar;
begin
Text := '';
with Clipboard do
try
Open;
if HasFormat(CF_TEXT) or HasFormat(CF_UNICODETEXT) then
begin
if (Win32Platform = VER_PLATFORM_WIN32_NT) then
begin
hClip := GetAsHandle(CF_UNICODETEXT);
wlen := GlobalSize(hClip);
pwStr := GlobalLock(hClip);
try
Len := (wLen div 2) - 1;
SetLength(Text, Len);
WideCharToMultiByte(CP_ACP, 0, pwStr, wlen, PChar(Text), Len, nil, nil);
finally
GlobalUnlock(hClip);
end;
end else
begin
hClip := GetAsHandle(CF_TEXT);
Len := GlobalSize(hClip);
SetLength(Text, Len);
SetLength(Text, GetTextBuf(PChar(Text), Len));
end;
end;
finally
Close;
end;
end;
function NewMemoProc(wnd:HWND; uMsg:UINT;
wParam:WPARAM; lParam:LPARAM):integer; stdcall;
begin
case uMsg of
WM_COPY:
begin
uMsg:=0;
ClipboardCopy(cl);
end;
WM_CUT:
begin
SendMessage(wnd,EM_REPLACESEL,1,cardinal(pchar('')));
uMsg:=0;
ClipboardCopy(cl);
end;
WM_PASTE:
begin
uMsg:=0;
ClipboardPaste(cl);
end;
end;
Result:= CallWindowProc(Pointer(GetWindowLong(wnd,GWL_USERDATA)),
wnd,uMsg,wParam,lParam);
end;
form1.create
procedure CreateOwnClipboard;
var i: integer;
h: hwnd;
c: TComboBoxInfo;
begin
with form1 do
for i :=0 to componentCount - 1 do
begin
if Components[i] is TEdit then
begin
h:= TEdit(Components[i]).Handle;
SetWindowLong(h,GWL_USERDATA,SetWindowLong(h, GWL_WNDPROC, LPARAM(@NewMemoProc)))
end;
if Components[i] is TMemo then
begin
h:= TMemo(Components[i]).Handle;
SetWindowLong(h,GWL_USERDATA,SetWindowLong(h, GWL_WNDPROC, LPARAM(@NewMemoProc)))
end;
if Components[i] is TComboBox then
begin
c.cbSize:= SizeOf(TCOMBOBOXINFO);
GetComboBoxInfo(TComboBox(Components[i]).Handle,c);
h:= c.hwndItem;
SetWindowLong(h,GWL_USERDATA,SetWindowLong(h, GWL_WNDPROC, LPARAM(@NewMemoProc)))
end;
end;
end;
MemoKeyDown
begin
with TFlat(Sender) do
begin
if not ReadOnly then
if ((Key = ord('V')) and (ssCtrl in Shift)) or
((Key = VK_INSERT) and (ssShift in Shift)) then
begin
SelText:=cl;
end;
if ((Key = ord('C')) and (ssCtrl in Shift)) or
((Key = VK_INSERT) and (ssCtrl in Shift)) or
((Key = ord('X')) and (ssCtrl in Shift)) or
((Key = VK_DELETE) and (ssShift in Shift)) then
cl:= SelText;
end;
end;
так же по аналогии с EditOnKeyDown и ComboboxOnKeyDown
|