В итоге через несколько дней изысканий и прочтения документации было найдено решение и оно было внедрено в PaintCAD 4Windows для виртклавы и для рисования любым стилусом на рисунке:В Windows 10 (да и в восьмёрке, и ранее) нажатия на сенсорный экран обрабатываются в Windows, а потом только передаются окошкам программ.
Длительное нажатие и удерживание пальца/стилуса в одном месте экрана, как известно, дает по дефолту короткий "правый клик". При этом о том, что нажали - не сообщается никуда (окошко, над которым это происходит - о нажатии не догадывается), о том что держат - не сообщается никуда, и по прошествии некоторого времени сразу прилетает в прогу "опа, здесь по координатам X:Y произошел короткий правый клик а ля нажатие и через N миллисекунд отпускание".
Поэтому нельзя просто взять и сделать такие программы как, например, виртуальное пианино, где при нажатии - прилетит mousedown и клавиша нажмется, при удерживании - она будет нажата (т.к. нажатие было, а отпускания не было), при отпускании - прилетит mouseup и она отпустится. И любые другие проги, где длительное нажатие пальца будет именно честным нажатием и последующим отпусканием.
Кто нибудь боролся с этим и как поборол (если поборол)?
p.s. поиск в инете по этой проблеме дает в основном "молчание" либо "а зачем тебе нужно длительное нажатие? проектируй прогу так, чтоб там не было такого, а были короткие клики правой и левой кнопкой, а также нажатие с последующим перетягиванием, ибо оно то корректно передается в окно".
А так охота пробить этот "сенсорный слой" и получить на окошко события нажатия и отпускания пальца в одном и том же месте окна.
Для каждого компонента, с которого хотим убрать "сенсорный слой", чтобы стилус/палец мгновенно нажимал на компонент при нажатии и отпускал его при отпускании пальца без задержек, правого клика по долгому нажатию и т.д.:
1) Вызываем RegisterTouchWindow из user32.dll с двумя параметрами: HWND компонента и флаг TWF_WANTPALM (флаг говорит винде не расчитывать положение нажатия по всей ладони прижатой, а быстро взять первое касание до сенсора, чтоб не тратить время на распознавание средних координат нажатия "ладонью" на экран).
Код: Выделить всё
RegisterTouchWindow(Form1.Handle,TWF_WANTPALM);
Если у вас прога на разные версии Windows, в том числе на XP и более ранние (где этой функции не было), то можно обойти это дело так:
Код: Выделить всё
type TRTW = function(hwnd: HWND; ulFlags: Cardinal): BOOL; stdcall;
type UTRTW = function(hwnd: HWND): BOOL; stdcall;
const
TWF_WANTPALM = $00000002;
var
touchinited:boolean=false;
HLib:THandle;
tou:TRTW;
utou:UTRTW;
procedure TForm1.InitTouch();
begin
try
Hlib:=LoadLibrary('USER32.DLL');
if HLib>HINSTANCE_ERROR then
begin
tou:=GetProcAddress(Hlib,'RegisterTouchWindow');
utou:=GetProcAddress(Hlib,'UnregisterTouchWindow');
if Assigned(tou) and Assigned(utou) then touchinited:=true;
end;
except
if HLib>HINSTANCE_ERROR then FreeLibrary(HLib);
touchinited:=false;
end;
end;
Код: Выделить всё
if touchinited then tou(Form1.Handle,TWF_WANTPALM);
Код: Выделить всё
procedure TForm1.DisablePressAndHold(handa:HWND);
var
Atom :TAtom;
const
tabletAtom = 'MicrosoftTabletPenServiceProperty';
TABLET_DISABLE_PRESSANDHOLD = $00000001;
TABLET_DISABLE_PENTAPFEEDBACK =$00000008;
TABLET_DISABLE_PENBARRELFEEDBACK =$00000010;
TABLET_DISABLE_FLICKS =$00010000;
TABLET_DISABLE_TOUCHUIFORCEON =$00000100;
TABLET_DISABLE_TOUCHUIFORCEOFF =$00000200;
TABLET_DISABLE_TOUCHSWITCH =$00008000;
TABLET_ENABLE_FLICKSONCONTEXT =$00020000;
TABLET_ENABLE_FLICKLEARNINGMODE =$00040000;
TABLET_DISABLE_SMOOTHSCROLLING =$00080000;
TABLET_DISABLE_FLICKFALLBACKKEYS =$00100000;
TABLET_ENABLE_MULTITOUCHDATA =$01000000;
TABLET_ALL = TABLET_DISABLE_PRESSANDHOLD or TABLET_DISABLE_PENTAPFEEDBACK or TABLET_DISABLE_PENBARRELFEEDBACK or TABLET_DISABLE_FLICKS or TABLET_DISABLE_TOUCHSWITCH or TABLET_DISABLE_SMOOTHSCROLLING or TABLET_DISABLE_FLICKFALLBACKKEYS or TABLET_DISABLE_TOUCHUIFORCEON or TABLET_DISABLE_TOUCHUIFORCEOFF;
begin
Atom := GlobalAddAtom(tabletAtom);
if Atom <> 0 then
begin
SetProp(handa, tabletAtom, TABLET_ALL);
GlobalDeleteAtom(Atom);
end;
end;
Код: Выделить всё
UnregisterTouchWindow(Form1.Handle);
Код: Выделить всё
if touchinited then utou(Form1.Handle);
Код: Выделить всё
procedure TForm1.FreeTouch();
begin
if HLib>HINSTANCE_ERROR then FreeLibrary(HLib);
end;
Все компоненты, которые не обвесили - будут работать как раньше (с правым кликом по долгому удерживанию и т.п.). На дочерние компоненты эта фича не распространяется (нельзя на окошко кинуть такую штуку и все его компоненты чтоб автоматически тоже стали такими с простыми нажатиями стилусом). Поэтому ручками кидаем RegisterTouchWindow и потом DisablePressAndHold на каждый отвязываемый от "тач-оверлея" компонент. И вроде бы все работает. Проверено:
- на ноутбуке с Win8 и резистивным экраном, на котором хоть стилусом, хоть пальцем, хоть зубочисткой деревянной можно нажимать
- на планшете с Win10 и электронным стилусом а ля wacom, который даже просто вблизи экрана без касания - уже елозит точкой по экрану
p.s. в инете рассматривают также вариант отслеживания очереди сообщений с выделением тач-сообщений. Можно подойти с того конца с этой проблемы, но мне хватило и с этого (надо было TImage сделать рисуемым стилусом, и еще десяток TPanel сделать нажимаемыми пальцем).