HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2024
0623
youdaiHSP3 64版でwintab32.dllから筆圧等を取得したいです4解決


youdai

リンク

2024/6/23(Sun) 00:06:34|NO.101845

HSP3 64版でwintab32.dllから筆圧等を取得したいです。

wintab32.dllはペンタブレットのモジュール関連のdllです。
wintab32.dllそのものはどの社の製品のペンタブレットでも、
ドライバをインストールしていれば同時にインストールされていると思います。
もしくは最初からWindowsに入っている場合もあるかもしれません。

MIAさんのHSP2時代の32bit版のスクリプトを参考に、
HSP3に合わせた32bit版と、64bit版を作成してみたのですが、
32bit版は動作するのですが、64bit版では動作しませんでした。
64bit版用に自分なりに色々調整してみたのですが、うまくいきません。
64bit版の方は値の取得がうまくできていないのか、
それともGetProcAddressの設定がうまくいっていないのか、正常に動作しません。

64bit版の方はcallfunc等をhspint64のcallfunc64iで代用しているのですが、
おそらくその関係が自分の知識がないせいで、うまくいっていないのではないかと思います。

wintab32.dllの仕様は不明で、LogContext等の仕様に関わる部分は
MIAさんのスクリプトをそのまま参考にしています。
bcc55やmingのincludeにc++のwintab32.dllの.hが入っているかもと思って調べたのですが、
自分の持っているものには入っていませんでした。
ネットのどこかでwintab32.dllの仕様が公開されているのかもしれませんが、よく分かりませんでした。

なお、32bit版のこのサンプルは動作がとても重いのですが、今回はただ単に
ペンタブレットの筆圧対応を確認するだけのサンプルなのでこれで良しとしています。

簡単 Wintab モジュール (MIAさん)
http://taillove.jp/mia/plugins.html

hspint64 - github(inoviaさん)
https://github.com/inovia/HSPInt64

32bit版


;MIAさんの簡単 Wintab モジュールを引用・参考にしています ;簡単 Wintab モジュールは元々はHSP2時代のものだったので、HSP3用に調整してあります ;この掲示板のログからも引用・参考にしています ;wintab.dll そのものの仕様は不明 ;------------------------------------- ; 簡単 Wintab モジュール (C) MIA 2003 ;------------------------------------- ; TabletStat で取得できる配列の内容 ; .0 : 入力ペン番号(消しゴムだと 2 になったりする) ; .1 : ボタン情報(ペン入力を含む) ; .2 : 位置情報 X ; .3 : 位置情報 Y ; .4 : 位置情報 Z ; .5 : 筆圧 ; .6 : 筆圧2(スプレーの噴出量等) ; .7 : 回転角度(10分の1度表記、時計回りで上方向が 0) ; .8 : 倒れ角度(10分の1度表記、垂直が 900) #ifndef EzTablet #module EzTablet #uselib "kernel32.dll" #func global LoadLibrary "LoadLibraryA" str #func global GetProcAddress "GetProcAddress" int, sptr #func global FreeLibrary "FreeLibrary" int #deffunc TabletClose if hTab : dllret = callfunc(hTab,WTClose,1) : hTab = 0 return #deffunc TabletTerm onexit TabletClose : if hDLL : FreeLibrary hDLL : hDLL = 0 return #deffunc TabErr_ str m dialog m + "が見つかりません", 1 TabletTerm return #deffunc TabletInit ret = 1 if hDLL : return ret LoadLibrary "wintab32.dll" : hDLL = stat if stat = 0 : TabErr_ "wintab32" : ret = 0 fn = "WTInfoA" : GetProcAddress hDLL,fn : WTInfo = stat if stat = 0 : TabErr_ fn : ret = 0 fn = "WTOpenA" : GetProcAddress hDLL,fn : WTOpen = stat if stat = 0 : TabErr_ fn : ret = 0 fn = "WTPacketsGet" : GetProcAddress hDLL,fn : WTPacketsGet = stat if stat = 0 : TabErr_ fn : ret = 0 fn = "WTClose" : GetProcAddress hDLL,fn : WTClose = stat if stat = 0 : TabErr_ fn : ret = 0 return ret #deffunc TabletOpen int sx,int sy if hTab : TabletClose dim LogContext, 64 pLogContext = varptr(LogContext) param = 3,0,pLogContext dllret = callfunc(param,WTInfo,3) LogContext(16) = 0x3fe0,0,0,-1,-1 LogContext(27) = 0,0,0,sx,-sy,0 Name = "EzTablet/HSP" : l = strlen(Name) memcpy LogContext,Name,l+1 param = hWnd,pLogContext,1 dllret = callfunc(param,WTOpen,3) hTab = dllret return hTab #deffunc TabletStat array dest if hTab = 0 : return 0 pDest = varptr(dest) param = hTab,1,pDest dllret = callfunc(param,WTPacketsGet,3) return dllret #global #endif gosub *setup goto *main *setup w = 320;スクリーンの横幅 h = 240;スクリーンの縦幅 fpswt = 1000 / 59;フレームレート screen 0, w, h, 0 ; 初期化 TabletInit if stat=0 : dialog "TabletInit に失敗しました" : end ; 解像度設定とタブレットの使用開始 TabletOpen w, h if stat=0 : dialog "TabletOpen に失敗しました" : end dim tab, 9 return *draw_maru ; 座標の取得とマウス追尾 px = int(tab.2) : py = int(tab.3) ; ●を描画 redraw 0 prs = int(tab.5 / 32) color 0,0,0 circle px,py,px+prs,py+prs,1 redraw 1 return ;mainの繰り返し処理部分 *main ; タブレット情報の取得 TabletStat tab ; 筆圧入力がなければ描画しない if tab.5 = 0 : wait 1 : goto *main ; 描写 gosub *draw_maru wait 1 goto *main

64bit版


#include "hsp3_64.as" #include "hspint64.as" ;inoviaさん(c) /* ---------------------------------- 引用・参考 簡単 Wintab モジュール (C) MIA 2003 ---------------------------------- TabletStat で取得できる配列の内容 .0 : 入力ペン番号(消しゴムだと 2 になったりする) .1 : ボタン情報(ペン入力を含む) .2 : 位置情報 X .3 : 位置情報 Y .4 : 位置情報 Z .5 : 筆圧 .6 : 筆圧2(スプレーの噴出量等) .7 : 回転角度(10分の1度表記、時計回りで上方向が 0) .8 : 倒れ角度(10分の1度表記、垂直が 900) ------- 修正部分 ------- ・MIAさんの元々のスクリプトはHSP2時代のものなので、それをHSP3用に修正しました。 ・hspint64でcallfuncを実装しています(callfunc64i) ・wintab.dll そのものの仕様は不明 */ #ifndef EzTablet64 #module EzTablet64 #uselib "kernel32.dll" #func LoadLibrary "LoadLibraryA" str #func GetProcAddress "GetProcAddress" int, sptr #func FreeLibrary "FreeLibrary" int #deffunc TabletClose if hTab ! 0 : dllret = callfunc64i(hTab,WTClose,1) : hTab = int64(0) return #deffunc TabletTerm onexit TabletClose if hTab ! 0 { dllret = callfunc64i(hTab, varptr64(FreeLibrary),1) hTab = int64(0) } return #deffunc TabErr_ str m dialog m + "が見つかりません", 1 TabletTerm return #deffunc TabletInit ret = 1 if hDLL ! 0 : return ret dim64 hDLL dim64 WTInfo dim64 WTOpen dim64 WTPacketsGet dim64 WTClose dim64 etc, 2 dim64 etc2 dim64 hTab dim64 pDest dim64 LogContext, 64 dim64 pLogContext dim64 param dim64 dllret dim l fn = "wintab32.dll" etc2 = varptr64(fn) hDLL = callfunc64i(etc2, varptr64(LoadLibrary), 1) if hDLL = 0 : TabErr_ "wintab32" : ret = 0 fn = "WTInfoA" etc.0 = int64(hDLL) etc.1 = varptr64(fn) WTInfo = callfunc64i(etc, varptr64(GetProcAddress), 2) if WTInfo = 0 : TabErr_ fn : ret = 0 fn = "WTOpenA" etc.0 = int64(hDLL) etc.1 = varptr64(fn) WTOpen = callfunc64i(etc, varptr64(GetProcAddress), 2) if WTOpen = 0 : TabErr_ fn : ret = 0 fn = "WTPacketsGet" etc.0 = int64(hDLL) etc.1 = varptr64(fn) WTPacketsGet = callfunc64i(etc, varptr64(GetProcAddress), 2) if WTPacketsGet = 0 : TabErr_ fn : ret = 0 fn = "WTClose" etc.0 = int64(hDLL) etc.1 = varptr64(fn) WTClose = callfunc64i(etc, varptr64(GetProcAddress), 2) if WTClose = 0 : TabErr_ fn : ret = 0 if ret = 0 : dialog "TabletInit に失敗しました" : end return 1 #deffunc TabletOpen int sx,int sy if hTab ! 0 : TabletClose pLogContext = varptr64(LogContext) param = int64(3),int64(0),pLogContext dllret = callfunc64i(param,WTInfo,3) ;LogContextの仕様は不明 ;0x3fe0の部分が64bit版では違ったりするのだろうか? LogContext(16) = int64(0x3fe0),int64(0),int64(0),int64(-1),int64(-1) LogContext(27) = int64(0),int64(0),int64(0),int64(sx),int64(-sy),int64(0);直感的ではないのでsyを逆転させました Name = "EzTablet/HSP" l = strlen(Name) memcpy LogContext,Name,l+1 param = int64(hWnd),pLogContext,int64(1) dllret = callfunc64i(param,WTOpen,3) hTab = dllret if hTab = 0 : dialog "TabletOpen に失敗しました" : end return 1 #deffunc TabletStat var dest if hTab = int64(0) : return 0 pDest = varptr64(dest) param = hTab,int64(1),pDest dllret = callfunc64i(param,WTPacketsGet,3) return 1 #global #endif gosub *setup goto *main *setup w = 640;スクリーンの横幅 h = 480;スクリーンの縦幅 fpswt = 1000 / 59;フレームレート screen 0, w, h ; 初期化 TabletInit ; 解像度設定とタブレットの使用開始 TabletOpen w, h dim64 tab, 9 return *draw_maru ; 座標の取得とマウス追尾 px = int(tab.2) : py = int(tab.3) ; ●を描画 redraw 0 prs = int(tab.5 / 32) color 0,0,0 circle px,py,px+prs,py+prs,1 redraw 1 return ;mainの繰り返し処理部分 *main ; タブレット情報の取得 TabletStat tab ; 筆圧入力がなければ描画しない if tab.5 = int64(0) : wait 1 : goto *main ; 描写 gosub *draw_maru await fpswt goto *main

なお64bit版で、wintab.dllから値を取得できれば、これら以外の実装方法でも構いません。
アドバイスお願い致します。



この記事に返信する


youdai

リンク

2024/6/23(Sun) 00:34:20|NO.101846

wintab32.dllの.hファイルと公式仕様解説ページを見つけました。

Github
https://github.com/LUXOPHIA/WacomTablet/blob/master/--------/WINTAB.H

Wacom Developer Network(インターネットアーカイブ)
https://web.archive.org/web/20160326034942/http://wdnet.jp/library/windows/wintab

Wacom Developer Networkの方の公式仕様解説ページはすでに閉鎖されていて、上記のリンクはインターネットアーカイブのものです。



usagi

リンク

2024/6/27(Thu) 20:58:37|NO.101849

こんにちわ
ヘッダが見つかったのであれば、少しCの知識が必要ですがあとは定義を移植するだけですね。
よろしかったらどうぞ。

気になった所
・必要な定数は定義した方が後々読んだ時に理解しやすいです。

・折角HSPを使うのですから、面倒なDLLのリンクは自前ではなくHSPに任せてしまえば良いと思いました。

・64bitのDLLですがLOGCONTEXT構造は32bitの変数の集まりなのでint64にする必要は無いかと思いました。
 64bitの整数やポインタなど必要な時だけ使えば宜しいかと思います。

・パケットが溜まってしまうので、割り込みで受信するのがよいかと思いました。
 とても滑らかになると思いますし、取得漏れを防げます。

・”0x3fe0の部分が64bit版では違ったりするのだろうか?”
 この部分はlcPktDataになり、ここは受信するパケットの種類を定義します。
 32,64bit版でも同じになります。例ではサンプルと同じものを定義させて頂きました。


#include "hsp3_64.as" ; ★ここをコメントすれば32bit版で動くSystem32, SysWOW64どちらにもDLLがあること #module ;WinTab #uselib "wintab32.dll" #func WTInfo "WTInfoA" int, int, var #func WTOpen "WTOpenA" int, var, int #func WTClose "WTClose" int #func WTPacket "WTPacket" int, int, var ; CONTEXT DATA DEFS #define WTI_DEFCONTEXT 3 #define lcOptions 10 #define lcPktData 16 #define lcOutOrg 27 #define lcOutExt 30 ; Options #define CXO_MESSAGES 0x0004 ; WTPKT bits #define PK_STATUS 0x0002 ; 入力ペン番号(消しゴムだと 2 になったりする) #define PK_BUTTONS 0x0040 ; ボタン情報(ペン入力を含む) #define PK_X 0x0080 ; 位置情報 X #define PK_Y 0x0100 ; 位置情報 Y #define PK_Z 0x0200 ; 位置情報 Z #define PK_NORMAL_PRESSURE 0x0400 ; 筆圧 #define PK_TANGENT_PRESSURE 0x0800 ; 筆圧2(スプレーの噴出量等) #define PK_ORIENTATION 0x1000 ; 回転角度(10分の1度表記、時計回りで上方向が 0) #define PK_ROTATION 0x2000 ; 倒れ角度(10分の1度表記、垂直が 900) ; Messages #define WT_PACKET 0x7FF0 ; 関数 #deffunc tabinit array _dst, label _cbk tabclose dim _dst, 9 : dup dst, _dst : cbk = _cbk : dim ctx, 43 ; デフォルトのコンテキストを取得して自分好みにカスタマイズ ; ********************************** WTInfo WTI_DEFCONTEXT, 0, ctx ; メッセージを受信する(割り込み) ctx.lcOptions = CXO_MESSAGES ; 取得するパケットのデータ ctx.lcPktData = PK_STATUS | PK_BUTTONS | PK_X | PK_Y | PK_Z | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION | PK_ROTATION ; タブレットの解像度(ここは好きにする) ctx.lcOutExt = ginfo_winx, -ginfo_winy ; ********************************** ; パケット受信開始 WTOpen hwnd, ctx, 1/*True*/ : hTab = stat oncmd gosub *WM, WT_PACKET return *WM WTPacket lparam, wparam, dst gosub cbk : return #deffunc tabclose onexit if hTab : WTClose hTab return #global ; サンプル screen 0, 800, 600 tabinit tab, *WM_TAB stab = "STATUS","BUTTONS","X","Y","Z","NORMAL_PRESSURE","TANGENT_PRESSURE","ORIENTATION","ROTATION" stop *WM_TAB redraw 0 : color 255,255,255 : boxf ; 情報 pos 0,0 : foreach tab : mes strf("%d: %s %d", cnt, stab.cnt, tab.cnt), 4 : loop ; 円 x = tab.2 : y = tab.3 : p = tab.5 color 64, 32, 200 : s = 100 * double(p) / 32768 circle x-s, y-s, x+s, y+s, 1 color 128,128,128 : s = 10 circle x-s, y-s, x+s, y+s, 0 redraw 1 return



youdai

リンク

2024/7/1(Mon) 11:02:49|NO.101859

> usagi さん

アドバイスありがとうございます!
動作することを確認しました!

>・パケットが溜まってしまうので、割り込みで受信するのがよいかと思いました。
> とても滑らかになると思いますし、取得漏れを防げます

すごい滑らかになっていて、びっくりしました。
パケットという概念を意識したことがなかったので、そういう理由でも動作が遅くなることがあるんだなと今回初めて知りました。

>・64bitのDLLですがLOGCONTEXT構造は32bitの変数の集まりなのでint64にする必要は無いかと思いました。
> 64bitの整数やポインタなど必要な時だけ使えば宜しいかと思います。

やっぱり自分はここらへんの理解が全然曖昧なんだなぁと今回知ることができました。
64bitのDLLだから64bitのintにしなきゃいけないのかなぁと思ってました。
64bit版のDLLの仕様の方が32bitの変数なら、それに合わせれば良かったんですね。

これで止まってた64bit版の開発がやっと再開できるようになりました!
ありがとうございました!



usagi

リンク

2024/7/8(Mon) 04:37:43|NO.101875

動いて解決されたようで良かったです♪ フォローアップとしてですが、

>そういう理由でも動作が遅くなることがあるんだなと
HSPでは普段意識する事はないですが、ハードとの通信や別スレッドなど平行して動く物を作る時は
そういった事を意識する必要がでてくる場合が多いと思います。

たとえばメイン画面の更新はゲームの様な60fpsでもタブレットの様な100fpsなど高レートで動くものは、
1メインループ1回の取得だと1秒間で40回分の取得が遅れ(溜まって)しまいます。
もっと細かいものもあり、例えばオーディオなどは48000fps(バッファサイズにもよる)で動きますので、
そういったものは色々やり方はあると思いますが、HSPだとウインドウメッセージで処理をサブルーチンで割り込んでしまうのが楽かと思いました。
(おおよそ古いライブラリはウインドウメッセージ受けれるようになっている)

>64bitのDLLだから64bitのintにしなきゃいけないのかなぁ
とりあえず、ポインタとlong型に気を付ければ大丈夫ですよ。
(興味があれば、データ型モデル ILP32 LP64 などで調べてみてくださいまし)

たとえば今回の構造体のココ "char lcName[LCNAMELEN];"
char型は環境にかかわらず1バイトです。
char = 8bit(1バイト)がLCNAMELEN(40個)なので320bit(40バイト)
HSPのint形だと4バイトなので配列0〜9までのに文字列が入る感じになります。
※ですからlcOptionsは10番目になります。

それでたとえば"char *lcName"とポインタで指定されていた場合は、
64bitだと64bit(8バイト)のポインタを渡す必要が出てきてしまうので、
"hspint64"などで文字列のポインタを取得する必要がでてしまいます。
どんな型でもポインタなら32bit環境なら、4バイト,64bit環境なら8バイトとなります。

あとは"typedef"ですかね。
WTPKT型ってなんだ?って感じですが"typedef DWORD WTPKT"とありますので以下の意味です。
WTPKT型 = DWORD型 = 32ビット符号なし整数(つまり4バイト)

一度CでDLLを作って、実験してみると理解しやすいかと思います。(C++ではなくC)
たしか以前youdaiさんも参加されていたスレでMinGWを使った簡単な
作成方法を紹介させていただきましたのでご興味があればどうぞ。
https://hsp.tv/play/pforum.php?mode=all&num=101165



記事削除

記事NO.パスワード
(質問が解決したスレッドは他の利用者に活用してもらうため、削除しないようお願いします)

NO.101845への返信

マスコット

好きなマスコットを選んでください。

名前

e-mail
HOME
  1. 初めて利用する方は、HSP3掲示板の使い方をお読みください。
  2. 不要部分の多い長いスクリプトの投稿は ご遠慮ください。
  3. 書き込みは自動改行されません。適度に改行を入れてください。
  4. スクリプトは小文字の<pre>〜</pre>で囲むと見やすく表示できます。

削除用パスワード

解決したら質問者本人がここをチェックしてください。

エラー発生時、再送信すると二重送信になることがあります。
回答が得られたら、お礼書き込み時に[解決]チェックしてください。
SPAM防止のためURLから始まる文章は投稿できません。
SPAM防止のため英文字のみの本文を投稿することはできません。

ONION software Copyright 1997-2023(c) All rights reserved.