Перейти к содержанию
  • Регистрация

Вадим Смоленский

Пользователи
  • Публикаций

    194
  • Зарегистрирован

  • Посещение

  • Победитель дней

    5

Весь контент Вадим Смоленский

  1. Да, я это видел, конечно. Но очень плохо растолковано. Какое из этих значений соответствует монохромному изображению? L, может быть? И как именно этот формат выставлять? У TBitmap это свойство Read-only.
  2. Имею в своем проекте огромный невидимый TImage, из которого при необходимости вырезаются те или иные кусочки и показываются пользователям. Так оказалось сделать удобнее, чем хранить эти кусочки в БД. Изображение монохромное, из черных и белых пикселей, цвета не нужны. Я полагал, что достаточно загрузить в TImage.MultiResBitmap монохромный файл, чтобы битмэп и трактовался программой как монохромный. Но сейчас проверил это функцией PixelFormatToString - и увидел, что пиксельный формат имеет значение BGRA. Похоже, под цвета по-прежнему выделяются ресурсы, которые можно было бы сэкономить. Возникают следующие вопросы: 1. Действительно ли PixelFormat=BGRA означает, что мой TBitmap не является монохромным и занимает в памяти в разы больше места? 2. Если да, то есть ли способ сделать его монохромным?
  3. Узнал, что в UWP API включены средства для получения уникального идентификатора компьютера. Это юнит Windows.System.Profile, класс HardwareIdentification, метод getPackageSpecificToken. Существуют ли способы обратиться к этим средствам из Delphi? Вообще, я привык считать, что такая идентификация компьютера в принципе невозможна, в отличие от мобильных устройств. Но прогресс, как известно, не остановить.
  4. Немножко улучшил свой вариант. Теперь вообще как часы всё заработало. var TheFormIsMinimized: Boolean = False; TheFormWasMaximized: Boolean = False; function NewWndProc(Wnd: HWND; Msg: UINT; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall; begin if (Msg = WM_SHOWWINDOW) and (LParam = SW_PARENTCLOSING) and (not TheFormIsMinimized) then begin TheFormIsMinimized := True; TheFormWasMaximized := (MainForm.WindowState=TWindowState.wsMaximized); SendMessage(FormToHWND(MainForm), WM_SYSCOMMAND, SC_MINIMIZE, 0); MainFormp.WindowState := TWindowState.wsMinimized; end else if (Msg = WM_SHOWWINDOW) and (LParam = SW_PARENTOPENING) and (TheFormIsMinimized) then begin TheFormIsMinimized := False; SendMessage(FormToHWND(MainForm), WM_SYSCOMMAND, SC_RESTORE, 0); if TheFormWasMaximized then MainForm.WindowState := TWindowState.wsMaximized else MainForm.WindowState := TWindowState.wsNormal; end else Result:=CallWindowProc(OldWndProc, Wnd, Msg, WParam, LParam); end; Единственный недостаток: при восстановлении из wsMinimized в wsMaximized на долю секунды окно фиксируется как wsNormal. Но это, в общем-то, не страшно.
  5. Да, я сейчас тоже попробовал сделать через перехват, только попроще. Работает. Вот как выглядит функция: function NewWndProc(Wnd: HWND; Msg: UINT; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall; begin if (Msg = WM_SHOWWINDOW) and (LParam = SW_PARENTCLOSING) then begin SendMessage(FormToHWND(MainForm), WM_SYSCOMMAND, SC_MINIMIZE, 0); Application.ProcessMessages; MainForm.WindowState := TWindowState.wsMinimized; end else Result := CallWindowProc(OldWndProc, Wnd, Msg, WParam, LParam); end; ProcessMessages пришлось вставить из-за того, что без этого приложение перед сворачиванием на долю секунды становилось черным. Наверное, можно сделать изящнее - в вашем примере, как я понял, TThread помогает. Но все-таки оно работает, и это, безусловно, изящнее, чем курочить FMX.Platform.Win и таскать его туда-сюда.
  6. Воспроизвел изменения у себя - и увы! Не только сворачивание не стало работать правильно, но даже перетащить окно теперь не получается. Что-то с этим кодом всё равно не так... Кстати, попробовал перехватить событие WM_SYSCOMMAND и обнаружил, что оно происходит только при щелчке по кнопке Minimize в шапке окна, а при щелчке по иконке в трее уже не происходит. Не то мы ловим.
  7. Да! С таким булевым заграждением всё получилось! Видимо, у вас просто компьютер помощнее, процедура отрабатывает быстрее, чем вызывается по второму разу. Очень и очень признателен. Желаю всяческих благ - и отдельно успехов дочери на поприще японистики!
  8. И что - прямо заводите японский текст, и выскакивает candidate window, и располагается на точке (100,100)?
  9. Вынес всё, касающееся этой проблемы, в отдельный проект. У меня продолжает падать и в таком виде. Не поленитесь проверить, упадет ли у вас. Файл FMX.Platform.Win.pas я в свое время чуть изменил из-за каких-то проблем (сходу и не вспомню, каких), и с тех пор держу его в одной папке с проектом. Может, с ним что не так? ImeProject.zip
  10. LookUp - это название моей формы, которое я забыл поменять на MyForm. Но можно и без него, конечно. Однако же, у меня и в таком виде всё равно валится. Что еще тут стоит проверить?..
  11. Да, действительно. Теперь управление в нужные моменты передается WMIMENotify. Спасибо еще раз. Однако, к сожалению, это пока не помогло мне решить исходной проблемы. Не знаю, уместно ли будет изложить эту проблему здесь - все-таки она связана с процедурами IME для ввода японского текста; с этим мало кто сталкивается. И тем не менее: когда включена японская локаль и выбран ввод хираганой (слоговой азбукой), то при печатании в TEdit на экран автоматически выдается маленькое окошко (candidate window) со списком иероглифов или слов, которые могли бы соответствовать набранному чтению. Пользователь может выбрать одного из этих кандидатов. Проблема в том, что когда включено экранное масштабирование (скажем, 125%), candidate window выскакивает не строго под TEdit, как должно, а левее и выше. Похоже, это недоработка FireMonkey - при передаче координат курсора ввода масштабирование не учитывается. Я хотел наладить перехват выдачи candidate window с присвоением ему других координат. Сам перехват теперь получается (при вызове candidate window выдается сообщение WM_IME_NOTIFY с WParam=IMN_SETCANDIDATEPOS). А вот так выглядит у меня обработка этого перехвата в рекомендованной вами процедуре: uses imm; procedure TMyForm.WMIMENotify(var Msg: TMessage); var Imc: HIMC; ImeCandidateFormProperties: TCandidateForm; begin Imc:=ImmGetContext(FMXHandleToHWND(LookUp.Handle)); ImmGetCandidateWindow(Imc,0,@ImeCandidateFormProperties); ImeCandidateFormProperties.dwStyle:=CFS_CANDIDATEPOS; ImeCandidateFormProperties.ptCurrentPos.X:=100; ImeCandidateFormProperties.ptCurrentPos.Y:=100; ImmSetCandidateWindow(Imc,@ImeCandidateFormProperties); ImmReleaseContext(FMXHandleToHWND(LookUp.Handle),Imc); end; Сколь могу судить, ImmGetCandidateWindow успешно считывает данные о candidate window. Но заменить их на исправленные уже не выходит, при вызове ImmSetCandidateWindow происходит переполнение стека. Документация о ImmSetCandidateWindow лежит здесь. Опять же: трудно надеяться, что вы сможете помочь - но вдруг?
  12. Да вот, kami говорит, что в FireMonkey всё по-другому...
  13. Попробовал повторить у себя. Получилось странно. Во время запуска приложения управление множество раз переходит в NewWndProc, в том числе и дважды с сообщением WM_IME_NOTIFY. Но как только главное окно появилось на экране - больше ни разу, ни с какими сообщениями вообще. Что-то где-то недокручено, такое впечатление...
  14. Можно считать, что в рамках окна. Спасибо, Некрасов-сан. Выглядит интригующе. Но я не могу понять, как управление перейдет в процедуру WMIMENotify. Она ведь у вас вообще нигде не вызывается. P.S. А, понял. Она вызывается в FMX.Platform.Win: WM_IME_NOTIFY: begin Result := WMImeNotify(LForm, hwnd, uMsg, wParam, lParam); end;
  15. Для задач, связанных с вводом японского текста, мне нужно научиться перехватывать системное сообщение WM_IME_NOTIFY. Насколько могу судить, в FireMonkey эти вещи делаются (если вообще делаются) принципиально иначе, нежели в VCL. Конкретного ничего не нагуглил. Не поможет ли кто?
  16. Спасибо. Вижу, что не у одного меня такая проблема. Библиотека по ссылке - это что-то дотнетовское, едва ли подойдет. Придется, видимо, подождать до релиза 10.3. Хотя вот еще нашелся интересный компонент. Платный, но стоит попробовать, думаю.
  17. В многомесячной борьбе с Microsoft Store за размещение у них своего Windows-приложения я продвинулся настолько, что вплотную подошел к организации взимания денег с покупателей посредством механизма add-ons (in-app purchases). Но здесь меня ждала очередная засада. Необходимые программные инструменты, главным из которых считается класс StoreContext, лежат в пространстве имен Windows.Services.Store; файлы с такими именами (windows.services.store.h и windows.services.store.idl) в Windows 10 действительно находятся; но в Delphi я не могу найти юнита с чем-то подобным. Хотя на одном форуме видел утверждение годичной давности, что в релизе 10.2 Tokyo это уже есть. Не может ли кто-нибудь пролить свет? Не там ищу? Все-таки еще не добавили? Или, может, это появилось лишь в самой последней сборке 10.2.3? У меня стоит 10.2.2. Обещание написать подробную статью по итогам моих мытарств остается в силе. На этом пути столько подводных камней и неочевидных ходов, что грех о них не поведать. Но сначала нужно дойти до победного конца.
  18. В феврале я сетовал, что мое Windows-приложение не хочет нормально запускаться в Linux под Wine 3.0. Но время идет, вышел Wine 3.6 - и теперь один из тестировщиков радостно сообщил, что всё заработало, за вычетом одного досадного момента. А именно: приложение способно сохранять фокус ввода лишь долю секунды, потом теряет. Соответственно, невозможно ничего ввести в текстовые боксы, разве только одну-две буквы. Можно щелкнуть по заголовку приложения, оно опять получит фокус - и через мгновение снова потеряет. Куда именно при этом переходит фокус, непонятно. Тестировщик утверждает, что только мое приложение ведет себя так, все остальные работают нормально. Нет ли у кого-нибудь идей? Что нужно проверить?
  19. Хорошо, если получится исправить. В моем-то проекте гифки самые простые, без прозрачности и черезстрочности, так что я ничего такого и не заметил.
  20. Да нет, всё понятно теперь. Я просто упустил из вида, что внутри функции CallNextHookEx еще много всякого разного может происходить и ее выходное значение в данном случае - не самое главное. Кстати, в отладчике посмотрел - оно в штатном режиме действительно получается нулевым. Так что теперь в тех случаях, когда нажатие клавиши точно обработано моим приложением и я больше не хочу от него никаких сюрпризов, просто присваиваю Result:=1. Всё работает, как часы. Огромное спасибо!
  21. Это непонятно. Какой именно <>0? Любой кроме ноля? А если, как советуют, присвоить CallNextHookEx(CurrentHook, nCode, wParam, lparam), то это всегда будет ноль, что ли?
  22. Такого раздела там нет. Вы, видимо, имели в виду раздел "Return value". В частности, там сказано, что CallNextHookEx нужно вызывать в том случае, если (цитирую) the hook procedure did not process the message. То есть, насколько я понял, если моя процедура FormKeyDown установила Key:=0, то это можно трактовать в том ключе, что message обработан, и тогда CallNextHookEx вызывать необязательно. Так или не так? Ваши рекомендации меня запутали: строчку убирать не надо, я должен вызвать следующий хук, но лучше этот вызов пропустить. Как это всё трактовать в терминах конкретных действий? Я так и не смог понять разницы между WH_KEYBOARD_LL и WH_KEYBOARD. Мне казалось, что лишь первый вариант относится ко всей системе целиком и проверяется всеми приложениями, где есть хук, в то время как второй ограничен лишь одним-единственным приложением. Всё сложнее?
  23. Вы имеете в виду, убрать эту строчку: Result := CallNextHookEx(CurrentHook, nCode, wParam, lparam); Я полагал, что "следующий хук" относится к возможному нажатию следующей клавиши, которое хранится в очереди. Разве это не так? И что присваивать результату в таком случае? Ноль?
  24. Выявилась проблемка. Когда FormKeyDown вызывался как обработчик события, в самом его конце выполнялся оператор Key:=0. Это обнуляло нажатие клавиши, гарантировало, что оно не сработает каким-то дополнительным, непредвиденным образом. В новой конфигурации это не работает, я уже столкнулся с досадными побочными эффектами. Нажатие нужно обнулить в обработчике хука KeyboardProc. Но как?
  25. Да, с виртуальным кодом клавиши проблем нет. Сложнее оказалось с параметром Shift - но нагуглилась страничка с хорошим примером, там я взял всё, что мне было нужно. Вот как теперь выглядит функция: function KeyboardProc(nCode: integer; wParam: integer; lParam: integer ): LongWord; stdcall; var W: Word; C: Char; KeyUp : Boolean; KeyState: TKeyboardState; TheShift: TShiftState; begin if (nCode < 0) then begin Result := CallNextHookEx(CurrentHook, nCode, wParam, lParam); Exit; end; KeyUp := ((lParam AND (1 shl 31)) <> 0); if not KeyUp then begin W:=wParam; C:=Chr(wParam); TheShift:=[]; if GetKeyboardState(KeyState) then begin if (lParam AND (1 shl 29))<>0 then TheShift:=[ssAlt]; if (GetKeyState(VK_CONTROL) AND (1 shl 15))<>0 then TheShift:=TheShift+[ssCtrl]; if (GetKeyState(VK_SHIFT) AND (1 shl 15))<>0 then TheShift:=TheShift+[ssShift]; end; Form1.FormKeyDown(Form1,W,C,TheShift); end; Result := CallNextHookEx(CurrentHook, nCode, wParam, lparam); end; Придирчиво еще не тестировал, но в первом приближении всё работает.
×
×
  • Создать...