Wacom的MacOS驅動器用於竹子,Graphire,Intuos 1、2和3和Cintiq 1st Gen Tablets的蟲子中有錯誤,這使它們完全無法啟動Macos 10.15 Catalina和更高版本(包括11個Big Sur和12個蒙特雷)。這不適用於Windows驅動程序,也不適用於較新平板電腦的驅動程序。
當您嘗試使用竹平板電腦打開Wacom偏好窗格時,您會收到一條錯誤消息,說“等待同步”,最後“平板電腦驅動程序存在問題。或更新驅動程序”。對於Intuos 3或Cintiq 1st Gen Tablet,首選項窗格將打開,但是單擊任何內容會導致其崩潰,並隨消息“ Wacom Tablet Persions有錯誤”。對於Graphire和Intuos 1和2平板電腦,駕駛員的安裝程序甚至無法在Catalina上運行。
值得慶幸的是,我能夠跟踪這些問題,並修補了司機以修復它們!
我的固定竹駕駛員(v5.3.7-6)支持以下平板電腦:
我固定的Graphire 1和2和Intuos 1&2驅動程序(v6.1.6-4)支持以下平板電腦:
我固定的Graphire 3驅動程序(v5.2.6-5)支持以下平板電腦:
我固定的Graphire 4驅動程序(v5.3.0-3)支持以下平板電腦:
我的固定Intuos 3和Cintiq驅動程序(v6.3.15-3)支持以下平板電腦:
對於Intuos 4,不需要我的修復程序。您可以改用Wacom的官方驅動程序v6.3.41-2。
?簡化的英語說明
? / ??儀器
? 日本語で表示
?函
? ESPAñol
? instrukcja po polsku
?指示enfrançais
在此處為平板電腦下載正確的安裝程序,然後雙擊它運行它,這將安裝我的固定版本Wacom的驅動程序:
如果您收到一條錯誤消息,即您的Mac僅允許從App Store安裝應用程序,請右鍵單擊它,然後單擊“打開”。
安裝後,請按照下一節中的說明進行修復平板電腦的權限。
將筆小費觸摸到平板電腦,它應該提示您訪問系統首選項>安全性和隱私選項卡以授予平板電腦權限。
在“可訪問性”頁面上,單擊掛鎖以解鎖該頁面,然後查找並勾選您在列表中看到的任何PenTabletDriver
, WacomTabletDriver
TabletDriver
或WacomTabletSpringboard
條目。在輸入監視頁面上執行相同的操作。
如果平板電腦支持觸摸,請用手指觸摸平板電腦,它應該再次提示您授予權限。在“可訪問性”頁面上,勾選ConsumerTouchDriver
或WacomTouchDriver
條目。
有了一些平板電腦,該驅動程序可能僅出現在輸入監視頁面上,您可能需要第二次重新啟動它才能出現在可訪問性頁面上。
您可能有之前的平板電腦駕駛員剩下的權限,這些陳舊的條目都需要像這樣刪除:
在安全性和隱私的“可訪問性”頁面上,在列表中找到與Wacom相關的任何內容(例如PenTabletDriver
, WacomTabletDriver
, TabletDriver
, ConsumerTouchDriver
, WacomTabletSpringboard
, WacomTouchDriver
),選擇它們,然後單擊“ minus”按鈕將其刪除。轉到“輸入監視頁面”,然後在此執行同樣的操作。
現在,重新啟動計算機,或在終端運行這兩個命令,以重新加載平板電腦驅動程序。用於竹子和圖形3和4片:
launchctl unload /Library/LaunchAgents/com.wacom.pentablet.plist
launchctl load -w /Library/LaunchAgents/com.wacom.pentablet.plist
對於Graphire 1和2,Intuos和Cintiq平板電腦:
launchctl unload /Library/LaunchAgents/com.wacom.wacomtablet.plist
launchctl load -w /Library/LaunchAgents/com.wacom.wacomtablet.plist
這應該還原提示,要求您添加權限,因此現在再次開始本節中的說明。
對於少數人來說,WACOM驅動程序從未出現在輸入監視列表中。要解決此問題,請首先打開“終端”應用程序並粘貼此行並按Enter鍵,以確保啟用WACOM服務:
用於竹子和圖形3和4片:
launchctl load -w /Library/LaunchAgents/com.wacom.pentablet.plist
對於Graphire 1和2,Intuos和Cintiq平板電腦:
launchctl load -w /Library/LaunchAgents/com.wacom.wacomtablet.plist
如果沒有觸發它,以要求您在嘗試使用平板電腦時添加輸入監視權限,則可以手動添加它。
在Finder中,單擊GO->轉到文件夾,然後將此路徑粘貼到其中,然後單擊確定:
/Library/Application Support/Tablet/
在那裡,您應該看到一個“ pentableTdriver”文件(竹),“ pentabletspringboard”(Graphire 3&4)或“ wacomtabletspringboard”(Graphire 1&2,Intuos,cintiq)。
解鎖輸入監視頁面,然後將pentableTdriver / pentabletspringboard / wacomtabletspringboard文件拖動到列表中,以將其添加到列表中,並確保其被打勾。現在,重新啟動計算機,當您嘗試使用平板電腦時,它也應提示您在可訪問性頁面中勾選它,之後它應該開始工作。
確保您仍然沒有安裝Wacom的最新驅動程序。使用“ Wacom實用程序”/“平板電腦實用程序”來完全卸載Wacom的所有驅動程序(而不是將它們拖到垃圾桶中),然後再次安裝我的驅動程序。
損壞的偏好可以阻止事情工作,尤其是如果您在試圖使事情正常工作的同時安裝了許多不同的驅動程序版本時。使用WACOM實用程序重置您的首選項,重新啟動並嘗試再次使用平板電腦。
如果您喜歡將平板電腦重新使用,請考慮向我發送小費!
這將有助於為我提供資金並進一步發展這些固定驅動因素。
PentableTdriver推出了兩個子駕駛員,以為其完成這項工作,消費者和桌上驅動器。為了在其資源文件夾中找到這些驅動程序,它最終調用此功能從URL提取路徑:
CFString * MacPaths::PathFromURL (CFURL *url)
{
CFString *path;
path = _objc_retainAutoreleasedReturnValue (url-> path ());
_objc_release (path); /* Whoops, path is destroyed here! */
return path; /* Now returning a free'd path */
}
請原諒我以C ++的原始目標C代碼來解釋我不會說OBJC!
當CFURL創建路徑時,其參考計數從1開始。它排隊以稍後通過在其上調用autorelease()
,然後將其返回到Wacom的驅動程序中。該autorelease
與Wacom的retainAutoreleasedReturnValue()
呼叫,並因此將Path的參考數數毫不動搖。
但是現在WACOM驅動程序在路徑上調用_objc_release()
。這將其參考計數減少到0,而路徑立即被釋放!
在啟動子驅動器時使用此釋放路徑,該路徑可以觸發ProcessUtils::LaunchApplicationWithBundleID()
中的segfault。這殺死了駕駛員。
修復程序是一個單字節更改,將PathFromURL
中_objc_release()
的調用替換為呼叫_objc_retain()
。這樣可以防止在使用之前釋放路徑,從而固化segfault。
conviceTouchDriver還包含相同的錯誤,並且該補丁在那里相同。
筆驅動程序和触摸驅動程序都需要修復,以阻止他們在執行多點觸摸手勢時崩潰,或者使用滾動環來縮放。
執行手勢時,函數CMacHIDGestureEventOSX1010::PostGesture
負責將該手勢發送到操作系統:
void CMacHIDGestureEventOSX1010::PostGesture (EIOHIDEventType gestureType_I, int32_t eventDirAmount)
{
__CFDataOSX1010 *eventStructure;
if (gestureType_I == 61 /* kCGHIDEventTypeGestureStarted */ ) {
this -> eventPhase = 1 /* kCGSGesturePhaseBegan */ ;
} else {
this -> eventPhase = 4 /* kCGSGesturePhaseEnded */ ;
(**(code **)(*( long *) this + 0x18 ))( 0 , this ,( uint32_t ) eventDirAmount);
}
eventStructure = (__CFDataOSX1010 *) _CGEventCreate ( 0 ); // Dubious
_CGEventSetType (eventStructure, 29 /* kCGSEventGesture */ );
eventStructure-> eventSubType = gestureType_I; // Relies on the exact memory layout of CGEvent (!)
eventStructure-> eventDirAmount = eventDirAmount; // Ditto
_CGEventPost ( 0 , eventStructure);
_CFRelease (eventStructure);
}
請注意,CgeventCreate的結果是如何被投入到結構的? CGEVENT應該是不透明的類型,由於其結構從OS版本變為OS版本,因此不應該知道或依賴其佈局,但是在這裡它被鑄造為結構,以便其eventSubType
和eventDirAmount
字段可以直接分配。這兩個寫作會導致卡塔琳娜(Catalina)造成堆腐敗並引發撞車事故,因為自塞拉(Sierra)以來, CGEvent
的佈局發生了變化!
將值存儲到事件中的正確方法是使用CGEVENTETETEGERVALUEFIELD API,它允許您通過邏輯ID來引用CGEVENT的字段,而不是它們在內存中的位置。那麼,WACOM驅動程序需要製作的兩個寫作的等效字段ID是什麼?
我拆除了Macos Sierra的Skylight框架,其中包含CGEventSetIntegerValueField
的實現,以查看這些字段的ID應該是什麼。看來eventSubType
可以用字段ID 110編寫,並且eventDirAmount
可以用ID 115編寫。但是這些字段ID在Apple的文檔中找不到,這解釋了為什麼Wacom無法使用它們!
我進行了一些谷歌搜索,發現這些領域是沒有證件的,因為它們是蘋果私人API的一部分。此Webkit標頭揭示了他們的名字:
kCGEventGestureHIDType = 110
kCGEventGestureSwipeValue = 115
kCGEventGesturePhase = 132
這些私人API領域從塞拉利昂一直穩定到大蘇爾!既然我們知道這一點,可以用這些呼叫代替事件結構的兩個作業,並且消除了駕駛員撞車事故:
_CGEventSetIntegerValueField (eventStructure, 110 /* kCGEventGestureHIDType */ , gestureType_I);
_CGEventSetIntegerValueField (eventStructure, 115 /* kCGEventGestureSwipeValue */ , eventDirAmount);
Postgesture的浮點版具有相同的問題:
void CMacHIDGestureEventOSX1010::PostGesture (EIOHIDEventType eventSubType, float dirAmount)
{
__CFDataOSX1010 *eventStructure;
eventStructure = (__CFDataOSX1010 *) _CGEventCreate ( 0 );
_CGEventSetType (eventStructure, 29 /* kCGSEventGesture */ );
eventStructure-> eventSubType = eventSubType; // !
eventStructure-> eventDirAmount = reinterpret_cast < int32_t &>(dirAmount); // !
eventStructure-> eventState = this -> eventPhase ; // !
if ( this -> eventPhase == 1 /* kCGSGesturePhaseBegan */ ) {
this -> eventPhase = 2 /* kCGSGesturePhaseChanged */ ;
}
_CGEventSetLocation (eventStructure, GetMouseLocationInScreenCoordinates ());
_CGEventPost ( 0 , eventStructure);
_CFRelease (eventStructure);
}
我們可以這樣修補:
_CGEventSetIntegerValueField (eventStructure, 110 /* kCGEventGestureHIDType */ , gestureType_I);
_CGEventSetIntegerValueField (eventStructure, 115 /* kCGEventGestureSwipeValue */ , reinterpret_cast < int32_t &>(dirAmount));
_CGEventSetIntegerValueField (eventStructure, 132 /* kCGEventGesturePhase */ , this ->eventPhase);
在Wacom的偏好窗格中,Wacom成為Apple Bug 8746551的受害者。自Macos Catalina以來,偏好窗格有效地打破了NSApp->mainWindow
的操作,通過允許任何窗口類型成為活動窗口,甚至是以前版本的床單,這是不可能的MACOS和獨立應用程序(在先前的版本中,只有實際的主首選項窗口才會成為mainWindow
)。
當模態打開時,用戶想打開新的表,需要首先關閉原始表。但是蘋果的錯誤導致Wacom的檢查以查看當前是否有打開的表格失敗,因為它檢查是否將表格連接到mainWindow
上時,它最終檢查了附加到當前工作表上的表格,這是莫名其妙的成為mainWindow
。這會觸發崩潰(例如,在筆映射設置中)。
我對mainWindow
的訪問進行了修補,以便以後將讀取的第一個值被緩存,因此,只要最初的值是明智的, mainWindow
更新以指向首次開放的表格就不會被打破(請參閱PentableTET(請參閱PenTablet.prefpane.newcode.asm
)。
Intuos 3和Cintiq驅動程序的首選窗格中有一個錯誤,該錯誤在單擊一項項目後立即崩潰。
優先窗格UI的主要功能之一是代表您可以配置的平板電腦,工具和應用程序的圖標列表。圖標列表控件使用這樣的函數將事件(例如點擊)派遣到其孩子:
void WTCCPLIconList::action:(ID event, SEL param_2, ID param_3) {
int selectedIndex;
ID target;
ID action;
target = _objc_retainAutoreleasedReturnValue (event-> target ());
action = event-> action ();
selectedIndex = event-> selectedIndex ();
event-> scrollIndexToVisible (selectedIndex);
if ((target != 0 ) && (action != 0 )) {
code* handler = target-> methodForSelector (action);
Object *result = handler (target, action, event);
result = _objc_retainAutoreleasedReturnValue (result); // (!)
_objc_release (result); // (!)
}
event-> updateButtonStates ();
_objc_release (target);
}
此代碼的問題在於,它需要事件的handler()
函數返回一個對象,然後它毫無用處地保留()和版本()。但是,將被稱為的處理程序函數之一是OEventDispatcher_Professional::listClickAction()
,該函數是一個void
函數(沒有定義明確的返回值)!
因此, action:()
最終在垃圾指針上調用retain()
和release()
,這會導致Segfault。
這裡的補丁很容易 - 刪除了無用的retain()
和release()
調用。 ONumberTextField::textDidChange:
具有相同的修復程序。
這個驅動程序還有另一個問題。如果在試圖使平板電腦工作時,您不小心安裝了最新的WACOM驅動程序(不支持Intuos 3),它將寫一個舊的Intuos 3驅動程序在嘗試閱讀時會崩潰的較新的格式優先文件。而且這種情況無法解決,用戶必須手動使用WACOM實用程序來刪除平板電腦的首選項以修復它。
這很奇怪,因為優先文件包含一個版本編號,該版本旨在避免這種情況。舊驅動程序使用版本5,最新的驅動程序使用版本6:
< ImportFileVersion type = " integer " >6</ ImportFileVersion >
並且驅動程序代碼明確檢查了此版本號,並且在太新的情況下應該中止:
CTabletDriver::ReadSettings (basic_string settingsFilename, ...)
{
basic_string settingsFileContent;
CSettingsMap settingsMap;
...
ReadFromXMLFile (settingsMap, settingsFilename, settingsFileContent);
SettingsMigration *migration = SettingsMigration::MigratePen (settingsMap);
if (migration != nullptr ) {
int fileVersion = settingsMap. IntegerForKeyWithDefault ( " ImportFileVersion " , - 1 )
if (fileVersion < 1 ) {
// Report error
} else if (fileVersion <= this -> supportedVersion ) {
// Accept the loaded settings
} else {
// Report error: Settings are too new
}
}
...
}
但是驅動程序永遠不會中斷,而是在嘗試加載首選項時會崩潰。那麼這裡出了什麼問題?秘密位於MigratePen()
函數中。此功能旨在將舊設置文件升級到當前版本,但不幸的是,在此過程中,它無條件地用當前版本(5)覆蓋ImportFileVersion
!這使CTabletDriver::ReadSettings()
無法檢測到設置太新而無法解析。
為了解決這個問題,我從MigratePen()
中加強了無效版本檢測代碼:
if (settingsVersion < 1 ) {
// Report invalid settings version and return NULL
}
做到這一點:
if (settingsVersion < 1 || settingsVersion > 5 ) {
// Report invalid settings version and return NULL
}
因此,如果偏好太新, MigratePen()
將不會嘗試升級它們,並且ReadSettings()
將乾淨地跳過加載首選項。這會導致首選項保留在其默認設置中,如果用戶使用偏好窗格編輯設置,則應將設置覆蓋。
Graphire驅動程序的安裝程序是Catalina不再支持的舊格式,因此我不得不完全重建它們。
Graphire的偏好窗格錯誤地依賴於Catalina中不再存在的MacOS標準庫中的私人符號,因此無法再啟動。
例如,Wacom的NSNIBWakingOverride :: awakefromnib()函數在GUI避免序列化期間調用,並將加載的GUI控件添加到地圖中,以便稍後可以通過標籤訪問:
void NSNibWakingOverride::awakeFromNib (NSControl * this ) {
OMasterDictionaryPtr-> addObject :withTag:( this , this -> _tag ));
}
但這依賴於讀取nscontrol._tag,這是一個私人字段。在MacOS 10.9中,由於Nscontrol的定義是這樣的:
@interface NSControl : NSView
{
/* All instance variables are private */
NSInteger _tag;
id _cell;
struct __conFlags {
...
} _conFlags;
}
但是在MacOS 10.10中,NSCONTROL被重構以將_tag字段移動到一個新的_aux字段中,使其無法訪問:
@interface NSControl : NSView
{
/* All instance variables are private */
NSControlAuxiliary *_aux;
id _cell;
struct __conFlags {
...
} _conFlags;
}
@property NSInteger tag;
我修補了Awakefromnib,以使其正確調用此字段的公共訪問功能:
void NSNibWakingOverride::awakeFromNib (NSControl * this ) {
OMasterDictionaryPtr-> addObject :withTag:( this , this -> tag ()));
}
在Wacom的OpoPupoutlineView :: ReloDdata()函數中,私有nstableview._datasource字段被錯誤地直接讀取:
void OPopupOutlineView::reloadData (OPopupOutlineView * this ) {
this -> _dataSource . willReloadDataForOutlineView ( this );
...
}
因此,我對此進行了修補以使用公共訪問者:
void OPopupOutlineView::reloadData (OPopupOutlineView * this ) {
this -> dataSource ()-> willReloadDataForOutlineView ( this );
...
}
這些驅動程序與Graphire 3和4驅動程序具有相同的問題,並在其ORadialSubMenuTableView::reloadData() method
_dataSource
,還有相同的修復程序。