Driver MacOS WACOM untuk tablet Bambu, Graphire, Intuos 1, 2 & 3 dan Cintiq 1st Gen Gen memiliki bug di dalamnya yang menyebabkan mereka benar -benar gagal untuk memulai macOS 10.15 Catalina dan versi yang lebih baru (termasuk 11 Big Sur dan 12 Monterey). Ini tidak berlaku untuk driver Windows, atau untuk driver untuk tablet mereka yang lebih baru.
Saat Anda mencoba membuka panel preferensi Wacom dengan tablet bambu, Anda akan mendapatkan pesan kesalahan yang mengatakan "menunggu sinkronisasi", maka akhirnya ada masalah dengan driver tablet Anda. Harap reboot sistem Anda. Jika masalah tetap ada kembali pemasangan kembali atau perbarui driver ". Untuk tablet Gen 1 Intuos 3 atau Cintiq, panel preferensi akan terbuka, tetapi mengklik apa pun akan menyebabkannya macet dengan pesan "Ada kesalahan dalam preferensi tablet WACOM." Untuk tablet Graphire dan Intuos 1 & 2, pemasang pengemudi bahkan tidak bisa berjalan di Catalina.
Untungnya saya dapat melacak masalah ini dan saya telah menambal driver untuk memperbaikinya!
Driver bambu tetap saya (v5.3.7-6) mendukung tablet ini:
Driver Graphire 1 & 2 dan Intuos 1 & 2 tetap saya (v6.1.6-4) mendukung tablet ini:
Driver Graphire 3 saya yang tetap (v5.2.6-5) mendukung tablet ini:
Driver Graphire 4 saya yang tetap (v5.3.0-3) mendukung tablet ini:
Dan driver Intuos 3 dan Cintiq saya yang tetap (v6.3.15-3) mendukung tablet ini:
Untuk intuos 4 perbaikan saya tidak diperlukan. Anda dapat menggunakan driver resmi WACOM V6.3.41-2 sebagai gantinya.
?? Instruksi bahasa Inggris yang disederhanakan
?? / ?? Instruções Em Português
?? 日本語で表示
?? Инстру sepeda
?? Instrucciones en Español
?? Instrukcja Po Polsku
?? Instruksi en Français
Unduh penginstal yang benar untuk tablet Anda di sini dan klik dua kali untuk menjalankannya, ini akan menginstal versi tetap saya dari driver Wacom:
Jika Anda mendapatkan pesan kesalahan bahwa Mac Anda hanya memungkinkan aplikasi diinstal dari App Store, klik kanan di atasnya dan klik "Buka" sebagai gantinya.
Setelah menginstal, ikuti instruksi di bagian berikutnya untuk memperbaiki izin tablet.
Sentuh tip pena Anda ke tablet Anda, dan itu harus meminta Anda mengunjungi System Preferences> Security & Privacy> Privacy Tab untuk memberikan izin tablet.
Pada halaman aksesibilitas, klik gembok untuk membuka kunci halaman, lalu temukan dan centang setiap PenTabletDriver
, WacomTabletDriver
TabletDriver
atau entri WacomTabletSpringboard
yang Anda lihat dalam daftar. Lakukan hal yang sama pada halaman pemantauan input.
Jika tablet Anda mendukung sentuhan, sentuh tablet dengan jari Anda, itu akan kembali meminta Anda untuk memberikan izin. Di halaman aksesibilitas, centang entri ConsumerTouchDriver
atau WacomTouchDriver
.
Dengan beberapa tablet, driver mungkin hanya muncul di halaman pemantauan input, dan Anda mungkin perlu reboot untuk kedua kalinya agar muncul di halaman aksesibilitas juga.
Anda mungkin memiliki izin yang tersisa dari pengemudi tablet sebelumnya, dan entri basi ini semua perlu dihapus seperti:
Pada halaman "Aksesibilitas" keamanan & privasi, temukan apa pun yang terkait dengan Wacom dalam daftar (misalnya PenTabletDriver
, WacomTabletDriver
, TabletDriver
, ConsumerTouchDriver
, WacomTabletSpringboard
, WacomTouchDriver
), pilih mereka, dan klik tombol minus untuk menghapusnya. Buka "Halaman Pemantauan Input" dan lakukan hal yang sama di sana.
Sekarang reboot komputer Anda, atau jalankan dua perintah ini di terminal, untuk memuat ulang driver tablet. Untuk bambu dan graphire 3 & 4 tablet:
launchctl unload /Library/LaunchAgents/com.wacom.pentablet.plist
launchctl load -w /Library/LaunchAgents/com.wacom.pentablet.plist
Untuk tablet Graphire 1 & 2, Intuos, dan Cintiq:
launchctl unload /Library/LaunchAgents/com.wacom.wacomtablet.plist
launchctl load -w /Library/LaunchAgents/com.wacom.wacomtablet.plist
Ini harus mengembalikan petunjuk untuk meminta Anda menambahkan izin, jadi sekarang mulai instruksi di bagian ini lagi.
Untuk segelintir orang, driver Wacom tidak pernah muncul dalam daftar pemantauan input untuk mereka. Untuk memperbaikinya, pertama -tama buka aplikasi "Terminal" dan tempel baris ini dan tekan Enter untuk memastikan bahwa layanan WACOM diaktifkan:
Untuk bambu dan graphire 3 & 4 tablet:
launchctl load -w /Library/LaunchAgents/com.wacom.pentablet.plist
Untuk tablet Graphire 1 & 2, Intuos, dan Cintiq:
launchctl load -w /Library/LaunchAgents/com.wacom.wacomtablet.plist
Jika itu tidak memicu untuk meminta Anda menambahkan izin pemantauan input saat Anda mencoba menggunakan tablet, Anda dapat menambahkannya secara manual.
Di Finder, klik Go -> Pergi ke folder, dan tempel jalur ini di sana dan klik OK:
/Library/Application Support/Tablet/
Di sana Anda akan melihat file "PentableTriver" (bambu), "PentabletSpringboard" (Graphire 3 & 4), atau "WacomtabletSpringboard" (Graphire 1 & 2, Intuos, Cintiq).
Buka kunci halaman pemantauan input, lalu seret file PentabletDriver / PentabletSpringboard / WacOmtabletSpringboard ke dalamnya untuk menambahkannya ke daftar, dan pastikan itu dicentang. Sekarang reboot komputer Anda, dan ketika Anda mencoba menggunakan tablet itu harus meminta Anda untuk mencentang di halaman aksesibilitas juga, setelah itu harus mulai bekerja.
Pastikan Anda tidak masih menginstal driver terbaru Wacom. Gunakan "utilitas wacom"/ "utilitas tablet" untuk sepenuhnya menghapus semua pengemudi Wacom (daripada hanya menyeretnya ke tempat sampah), lalu pasang driver saya lagi.
Preferensi korup dapat mencegah hal -hal bekerja, terutama jika Anda memasang banyak versi driver yang berbeda saat mencoba untuk membuat barang berfungsi. Gunakan utilitas Wacom untuk mengatur ulang preferensi Anda, reboot, dan coba gunakan tablet lagi.
Jika Anda menikmati tablet Anda kembali beraksi, silakan pertimbangkan untuk mengirimi saya tip!
Ini akan membantu mendanai saya dan pengembangan lebih lanjut dari driver tetap ini.
PentableTriver meluncurkan dua sub-driver untuk melakukan pekerjaan untuk itu, ConsumerTouchDriver dan TabletDriver. Untuk menemukan driver -driver di dalam folder sumber dayanya, akhirnya memanggil fungsi ini untuk mengekstrak jalur dari 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 */
}
Maafkan saya karena memparafrasekan kode C objektif asli sebagai C ++, saya tidak berbicara OBJC!
Ketika CFURL membuat jalur, jumlah rujukannya dimulai pada 1. Ini mengantri jumlah referensi yang akan dikurangi kemudian dengan memanggil autorelease()
di atasnya, lalu mengembalikannya ke pengemudi Wacom. Panggilan untuk autorelease
berpasangan dengan panggilan Wacom's retainAutoreleasedReturnValue()
, dan karenanya dan membuat jumlah referensi jalan tidak tersentuh, pada 1.
Tapi sekarang driver Wacom memanggil _objc_release()
di jalur. Ini mengurangi jumlah rujukannya menjadi 0, dan jalan segera dibebaskan!
Jalur yang dibebaskan ini digunakan saat meluncurkan sub-pengemudi, yang dapat memicu segfault di ProcessUtils::LaunchApplicationWithBundleID()
. Ini membunuh pengemudi.
Perbaikan adalah perubahan satu-byte yang menggantikan panggilan ke _objc_release()
di PathFromURL
ke panggilan ke _objc_retain()
. Ini mencegah jalan dari dibebaskan sebelum digunakan, yang menyembuhkan Segfault.
ConsumerTouchDriver juga berisi bug yang sama ini, dan tambalannya sama di sana.
Baik pengemudi pena dan pengemudi sentuh membutuhkan perbaikan untuk menghentikan mereka dari menabrak ketika gerakan multi-sentuh dilakukan, atau cincin gulir digunakan untuk memperbesar.
Ketika suatu gerakan dilakukan, fungsi CMacHIDGestureEventOSX1010::PostGesture
bertanggung jawab untuk mengirimkan gerakan itu ke sistem operasi:
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);
}
Perhatikan bagaimana hasil dari cGeventCreate dilemparkan ke suatu struktur? CGevent seharusnya menjadi tipe buram, program tidak seharusnya mengetahui atau mengandalkan tata letaknya, karena strukturnya berubah dari versi OS ke versi OS, tetapi di sini ia dilemparkan ke struktur sehingga bidang -bidangnya yang bersifat eventSubType
dan eventDirAmount
dapat ditugaskan secara langsung. Keduanya menulis menyebabkan banyak korupsi di Catalina dan memicu kecelakaan, karena tata letak CGEvent
telah berubah sejak Sierra!
Cara yang tepat untuk menyimpan nilai ke dalam suatu acara adalah dengan menggunakan CGEVENTSTETIGERVALUEFIELD API, yang memungkinkan Anda merujuk ke bidang CGEVENT dengan ID logis alih -alih posisinya dalam memori. Jadi apa ID bidang yang setara untuk keduanya menulis yang perlu dilakukan oleh pengemudi Wacom?
Saya membongkar kerangka skylight MacOS Sierra, yang berisi implementasi untuk CGEventSetIntegerValueField
, untuk melihat apa seharusnya ID untuk bidang -bidang tersebut. Tampaknya eventSubType
dapat ditulis oleh Field ID 110, dan eventDirAmount
dapat ditulis oleh ID 115. Tetapi ID bidang ini tidak dapat ditemukan dalam dokumentasi Apple, yang menjelaskan mengapa Wacom tidak dapat menggunakannya!
Saya melakukan beberapa googling dan menemukan bahwa bidang -bidang ini tidak berdokumen karena mereka adalah bagian dari API pribadi Apple. Header Webkit ini mengungkapkan nama mereka:
kCGEventGestureHIDType = 110
kCGEventGestureSwipeValue = 115
kCGEventGesturePhase = 132
Dan ladang API pribadi itu stabil dari Sierra sampai ke Big Sur! Sekarang kita mengetahui hal ini, dua tugas ke eventstruktur dapat digantikan oleh panggilan ini, dan pengemudi crash dihilangkan:
_CGEventSetIntegerValueField (eventStructure, 110 /* kCGEventGestureHIDType */ , gestureType_I);
_CGEventSetIntegerValueField (eventStructure, 115 /* kCGEventGestureSwipeValue */ , eventDirAmount);
Versi floating-point dari postgesture memiliki masalah yang sama:
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);
}
Dan kita bisa menambalnya seperti itu:
_CGEventSetIntegerValueField (eventStructure, 110 /* kCGEventGestureHIDType */ , gestureType_I);
_CGEventSetIntegerValueField (eventStructure, 115 /* kCGEventGestureSwipeValue */ , reinterpret_cast < int32_t &>(dirAmount));
_CGEventSetIntegerValueField (eventStructure, 132 /* kCGEventGesturePhase */ , this ->eventPhase);
Di panel preferensi Wacom, Wacom menjadi korban Apple Bug 8746551. Karena MacOS Catalina, panel preferensi secara efektif memecahkan operasi NSApp->mainWindow
dengan memungkinkan jenis jendela apa pun menjadi jendela aktif, bahkan lembaran, yang tidak mungkin dalam versi sebelumnya dari sebelumnya MacOS dan dalam aplikasi mandiri (dalam versi sebelumnya hanya jendela Preferensi Utama yang sebenarnya akan menjadi mainWindow
).
Ketika lembar modal terbuka, dan pengguna ingin membuka lembar baru, lembar asli perlu ditutup terlebih dahulu. Tapi bug Apple menyebabkan cek Wacom untuk melihat apakah saat ini ada lembar yang terbuka untuk gagal, karena ketika memeriksa untuk melihat apakah sebuah lembar dilampirkan ke mainWindow
, itu malah akan memeriksa lembar yang terpasang pada lembar saat ini, yang secara tidak dapat dijelaskan secara tidak dapat dijelaskan Menjadi mainWindow
. Ini memicu kecelakaan (misalnya dalam pengaturan pemetaan pena).
Saya menambal akses ke mainWindow
sehingga nilai pertama yang dibaca di-cache setelah itu, jadi selama nilai awalnya masuk akal, itu tidak rusak setelah mainWindow
diperbarui untuk menunjuk ke lembar yang dibuka pertama (lihat PenTablet.prefpane.newcode.asm
).
Driver Intuos 3 dan Cintiq memiliki bug di panel preferensi yang menyebabkannya macet segera setelah item diklik.
Salah satu fitur utama dari UI Panel Preferensi adalah daftar ikon yang mewakili tablet, alat, dan aplikasi yang dapat Anda konfigurasikan. Kontrol daftar ikon itu menggunakan fungsi seperti ini untuk mengirim acara (seperti klik) kepada anak -anaknya:
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);
}
Masalah dengan kode ini adalah bahwa ia memerlukan fungsi handler()
untuk mengembalikan objek, yang kemudian tidak digunakan secara tidak berguna () dan rilis (). Tetapi salah satu fungsi penangan yang akan dipanggil adalah OEventDispatcher_Professional::listClickAction()
, dan fungsi itu adalah fungsi void
(tanpa nilai pengembalian yang jelas)!
Jadi action:()
akhirnya memanggil retain()
dan release()
pada penunjuk sampah, yang menyebabkan segfault.
Patch di sini mudah - bahwa panggilan retain()
dan release()
yang tidak berguna dihapus. Bug yang sama ada di ONumberTextField::textDidChange:
, dengan perbaikan yang sama.
Ada masalah lain dengan pengemudi ini. Jika, saat mencoba membuat tablet Anda berfungsi, Anda secara tidak sengaja menginstal driver Wacom terbaru (yang tidak mendukung Intuos 3), itu menulis file preferensi format yang lebih baru bahwa driver Intuos 3 lama akan macet saat mencoba membaca. Dan situasi ini tidak menyelesaikan dirinya sendiri, pengguna harus secara manual menggunakan utilitas Wacom untuk menghapus preferensi tablet untuk memperbaikinya.
Ini aneh karena file preferensi mencakup nomor versi yang dirancang untuk menghindari situasi ini. Driver lama menggunakan versi 5, dan driver terbaru menggunakan versi 6:
< ImportFileVersion type = " integer " >6</ ImportFileVersion >
Dan kode driver secara eksplisit memeriksa nomor versi ini dan harus dibatalkan ketika terlalu baru:
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
}
}
...
}
Tetapi pengemudi tidak pernah membatalkan, sebaliknya crash saat mencoba memuat preferensi. Jadi apa yang salah di sini? Rahasianya terletak di dalam fungsi MigratePen()
. Fungsi ini dirancang untuk memutakhirkan file pengaturan yang lebih lama ke versi saat ini, tetapi sayangnya dalam prosesnya, ia secara tanpa syarat menimpa ImportFileVersion
dengan versi saat ini (5)! Ini membuat CTabletDriver::ReadSettings()
tidak dapat mendeteksi bahwa pengaturan terlalu baru untuk diuraikan.
Untuk menyelesaikan ini, saya meningkatkan kode deteksi versi yang tidak valid dari MigratePen()
:
if (settingsVersion < 1 ) {
// Report invalid settings version and return NULL
}
Untuk membuatnya:
if (settingsVersion < 1 || settingsVersion > 5 ) {
// Report invalid settings version and return NULL
}
Jadi sekarang jika preferensi terlalu baru, MigratePen()
tidak akan mencoba untuk meningkatkannya, dan ReadSettings()
akan dengan bersih melewatkan memuat preferensi. Ini menyebabkan preferensi tetap di default mereka, dan jika pengguna mengedit pengaturan menggunakan panel preferensi, pengaturan harus ditimpa dengan bersih.
Installer untuk driver Graphire adalah format lama yang tidak lagi didukung Catalina, jadi saya harus sepenuhnya membangunnya kembali.
Panel preferensi Graphire salah mengandalkan simbol pribadi dari perpustakaan standar macOS yang tidak lagi hadir di Catalina, sehingga tidak bisa lagi dimulai.
Misalnya, fungsi WACOM's nsnibwakingoverride :: AwakeFromnib () dipanggil selama deserialisasi GUI, dan menambahkan kontrol GUI yang dimuat ke peta sehingga dapat diakses dengan labelnya nanti:
void NSNibWakingOverride::awakeFromNib (NSControl * this ) {
OMasterDictionaryPtr-> addObject :withTag:( this , this -> _tag ));
}
Tapi ini bergantung pada membaca nscontrol._tag, yang merupakan bidang pribadi. Dalam MacOS 10.9 yang berhasil karena nscontrol didefinisikan seperti ini:
@interface NSControl : NSView
{
/* All instance variables are private */
NSInteger _tag;
id _cell;
struct __conFlags {
...
} _conFlags;
}
Tetapi dalam macOS 10.10, nscontrol direfaktor untuk memindahkan bidang _tag ke bidang _aux baru, membuatnya tidak dapat diakses:
@interface NSControl : NSView
{
/* All instance variables are private */
NSControlAuxiliary *_aux;
id _cell;
struct __conFlags {
...
} _conFlags;
}
@property NSInteger tag;
Saya menambal AwakeFromnib untuk membuatnya dengan benar memanggil fungsi aksesor publik untuk bidang ini:
void NSNibWakingOverride::awakeFromNib (NSControl * this ) {
OMasterDictionaryPtr-> addObject :withTag:( this , this -> tag ()));
}
Dalam fungsi Wacom's OpopupoutLineView :: ReloadData (), bidang nStableView._Datasource pribadi secara tidak benar dibaca secara langsung:
void OPopupOutlineView::reloadData (OPopupOutlineView * this ) {
this -> _dataSource . willReloadDataForOutlineView ( this );
...
}
Jadi saya menambal ini untuk menggunakan aksesor publik sebagai gantinya:
void OPopupOutlineView::reloadData (OPopupOutlineView * this ) {
this -> dataSource ()-> willReloadDataForOutlineView ( this );
...
}
Driver ini memiliki masalah yang sama dengan driver Graphire 3 & 4, ditambah masalah _dataSource
yang sama dalam ORadialSubMenuTableView::reloadData() method
mereka, dengan perbaikan yang sama.