Как поизящнее отключить предварительную обработку касаний сенсорного экрана в Windows 8?

Всем привет.


Пишу на дельфи свой графический редактор. Одна из его функций — это рисование стилусом или пальцем на сенсорном экране. Все нажатия на Image, который лежит в обычном таком ScrollBox-е ( скрин blackstrip.ru/tmp/pcw120ni/1.jpg ), должны передаваться программе.


У меня ноутбук довольно не новый (Asus T101MT) с резистивной сенсорной накладкой на экран, распознающей до 2 касаний одновременно (мультитач). В Windows XP этот экран даже без драйверов распознается и все касания экрана распознаются операционкой как «переход курсора в место касания и нажатие там левой кнопки мыши», отпускание экрана как «отпустить левую кнопку», касание+протаскивание+отпускание как «нажатие левой кнопки мыши, протаскивание мыши с удерживанием левой кнопки, отпускание левой кнопки», а нажатие в одном месте экрана, а потом в другом — как «нажатие правой кнопки». Т.е. простая прямая передача всех касаний как нажатий левой кнопки мыши + фича с правым кликом.


В Windows 8 с этим беда — она распознала мой сенсорный экран, даже показывает его в настройках сенсорного ввода. И теперь когда я вожу пальцем по окну, то виндоус перехватывает все касания и сам решает что делать. Например, когда я вожу по Image, лежащем в ScrollBox-е — виндоус думает что я хочу скроллить ScrollBox, и двигает Image там в такт моим движениям пальца.


Искал как программировать это дело — нашел статью французскую Delphi et le multi-touch (вот она andnotor.developpez.com/tutoriels/delphi/delphi-et... ).


Судя по этой статье, в Windows 7 и Windows 8 появились функции API на регистрацию управляемого сенсором окна, и на установку разрешений про то, что я хочу делать, и что не хочу.


Например, в разделе «VII. Désactivation de la fonction Press&Hold» описывается как выключить возможность «нажать и удерживать» (может заодно и «нажать и таскать»). Я делаю все что там описано, создаю этот атом, но Windows 8 меня не слушает, и крутит Image в ScrollBox-е как ни в чем не бывало. И на остальное типа «удерживание для правого клика» это тоже не влияет.


Я подозреваю что надо регистрировать окно и только тогда играться с атомами. И еще подозреваю что по умолчанию в Windows 8 все окна регистрируются как сенсорные со всеми включенными возможностями типа скроллинга пальцем. Но у меня программа работает во всех Windows с 95 по 8, поэтому грубо включить ссылки на DLL нельзя (а то не будет работать в XP и более ранних версиях), придется грузить DLL в процессе работы, узнавать есть ли такие функции и т.п. Неохота это делать.


Я нашел еще один грубый, но действенный (по крайней мере на моем асусе) способ — отключить устройство Microsoft Input Configuration Device в диспетчере устройств в разделе HID-устройства. После отключения этого устройства и перезагрузки компьютера весь перехват касаний с рисованием виндой «кружочков» и «крестиков» пропадает, и мой сенсорный экран начинает работать как в XP — просто как левая кнопка мыши. Но это как то нехорошо, вдруг кто-то любит так касаться экрана, долго удерживать палец для правого клика, скроллить объекты в скроллбоксах.


Как сделать это помягче? Есть ли в Windows 8 простая функция API или какая нибудь другая штука чтобы «отключить для этого конкретного окна все приблуды сенсорного экрана и пропускать касания к мышиному курсору и напрямую к окну без предварительной обработки»? Может кто нибудь сталкивался с подобной проблемой?
  • Вопрос задан
  • 5829 просмотров
Пригласить эксперта
Ответы на вопрос 1
blackstrip
@blackstrip Автор вопроса
Кому интересен ответ на этот вопрос или кто наткнется на этот пост в интернете - вот как отключить:

Для каждого компонента, с которого хотим убрать "сенсорный слой", чтобы стилус/палец мгновенно нажимал на компонент при нажатии и отпускал его при отпускании пальца без задержек, правого клика по долгому нажатию и т.д.:

1) Вызываем RegisterTouchWindow из user32.dll с двумя параметрами: HWND компонента и флаг TWF_WANTPALM (флаг говорит винде не расчитывать положение нажатия по всей ладони прижатой, а быстро взять первое касание до сенсора, чтоб не тратить время на распознавание средних координат нажатия "ладонью" на экран).

RegisterTouchWindow(Form1.Handle,TWF_WANTPALM);

Если хочется для TImage убрать сенсорный слой - то надо указать HWND родительского компонента, на котором лежит TImage.

Если у вас прога на разные версии 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);


2. После регистрации компонента как тач-компонент - вызвать эту процедуру, передав ей HWND компонента (она работает в любом Windows, даже в Windows 95, но без предыдущего шага с RegisterTouchWindows - она толком не подействует ни в Windows 8, ни в Windows 10):

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;


3. Перед закрытием программы - надо обратно "разрегистрировать" тач-компоненты примерно так:

UnregisterTouchWindow(Form1.Handle);

или для случае динамической подгрузки библиотеки:

if touchinited then utou(Form1.Handle);

А потом отпустить библиотеку (хотя, по идее, user32.dll так и останется в памяти, т.к. весьма вероятно задействована другими прогами/библиотеками):

procedure TForm1.FreeTouch();
begin
if HLib>HINSTANCE_ERROR then FreeLibrary(HLib);
end;


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

Все компоненты, которые не обвесили - будут работать как раньше (с правым кликом по долгому удерживанию и т.п.). На дочерние компоненты эта фича не распространяется (нельзя на окошко кинуть такую штуку и все его компоненты чтоб автоматически тоже стали такими с простыми нажатиями стилусом). Поэтому ручками кидаем RegisterTouchWindow и потом DisablePressAndHold на каждый отвязываемый от "тач-оверлея" компонент. И вроде бы все работает. Проверено:
- на ноутбуке с Win8 и резистивным экраном, на котором хоть стилусом, хоть пальцем, хоть зубочисткой деревянной можно нажимать
- на планшете с Win10 и электронным стилусом а ля wacom, который даже просто вблизи экрана без касания - уже елозит точкой по экрану

p.s. в инете рассматривают также вариант отслеживания очереди сообщений с выделением тач-сообщений. Можно подойти с того конца с этой проблемы, но мне хватило и с этого (надо было TImage сделать рисуемым стилусом, и еще десяток TPanel сделать нажимаемыми пальцем).
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы